xref: /haiku/src/apps/terminal/TermWindow.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 /*
2  * Copyright (c) 2003-2004 Kian Duffy <myob@users.sourceforge.net>
3  * Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
4  * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net>
5  *
6  * Distributed unter the terms of the MIT license.
7  */
8 #include <app/Application.h>
9 #include <Menu.h>
10 #include <MenuBar.h>
11 #include <MenuItem.h>
12 #include <ScrollBar.h>
13 #include <TextControl.h>
14 #include <PrintJob.h>
15 #include <Alert.h>
16 #include <float.h>
17 #include <WindowScreen.h>
18 #include <PropertyInfo.h>
19 
20 #include <stdio.h>
21 #include <sys/time.h>
22 #include <string>
23 #include <unistd.h>
24 
25 
26 #include "TermApp.h"
27 #include "TermParse.h"
28 #include "TermWindow.h"
29 #include "TermView.h"
30 #include "TermBuffer.h"
31 #include "TermBaseView.h"
32 #include "CodeConv.h"
33 #include "TermConst.h"
34 #include "PrefDlg.h"
35 #include "PrefView.h"
36 #include "PrefHandler.h"
37 #include "MenuUtil.h"
38 #include "spawn.h"
39 #include "ColorWindow.h"
40 
41 
42 // Global Preference Handler
43 extern PrefHandler *gTermPref;
44 //
45 // help and GPL URL
46 //
47 //#define URL_PREFIX  "file:///boot/home/config/settings/MuTerminal/help/"
48 //#define INDEX_FILE  "/index.html"
49 //#define GPL_FILE  "/gpl.html"
50 //#define CHLP_FILE   "file:///boot/beos/documentation/Shell%20Tools/index.html"
51 
52 extern int gNowCoding;  /* defined TermParce.cpp */
53 char gWindowName[256] = "Terminal";
54 
55 void SetCoding(int);
56 
57 
58 TermWindow::TermWindow(BRect frame, int32 windownumber)
59 	: BWindow(frame, "Terminal", B_DOCUMENT_WINDOW, B_CURRENT_WORKSPACE)
60 {
61 	sprintf(gWindowName, "Terminal %ld", windownumber);
62 
63 	InitWindow();
64 	SetTitle(gWindowName);
65 	fPrintSettings = NULL;
66 	fPrefWindow = NULL;
67 	fFindPanel = NULL;
68 }
69 
70 
71 TermWindow::~TermWindow()
72 {
73 	delete fWindowUpdate;
74 }
75 
76 
77 //	#pragma mark - public methods
78 
79 
80 /** Initialize Window object. */
81 
82 void
83 TermWindow::InitWindow(void)
84 {
85 	// make menu bar
86 	SetupMenu();
87 
88 	// Setup font.
89 
90 	const char *family = gTermPref->getString(PREF_HALF_FONT_FAMILY);
91 
92 	BFont halfFont;
93 	halfFont.SetFamilyAndStyle(family, NULL);
94 	halfFont.SetSize(gTermPref->getFloat(PREF_HALF_FONT_SIZE));
95 	halfFont.SetSpacing(B_FIXED_SPACING);
96 
97 	family = gTermPref->getString(PREF_FULL_FONT_FAMILY);
98 
99 	BFont fullFont;
100 	fullFont.SetFamilyAndStyle(family, NULL);
101 	fullFont.SetSize(gTermPref->getFloat(PREF_FULL_FONT_SIZE));
102 	fullFont.SetSpacing(B_FIXED_SPACING);
103 
104 	// Make Terminal text view.
105 
106 	BRect textframe = Bounds();
107 	textframe.top = fMenubar->Bounds().bottom + 1.0;
108 
109 	fCodeConv = new CodeConv();
110 	fTermView = new TermView(Bounds(), fCodeConv);
111 
112 	/*
113 	 * MuTerm has two views. BaseView is window base view.
114 	 * TermView is character Terminal view on BaseView. It has paste
115 	 * on BaseView shift as VIEW_OFFSET.
116 	 */
117 	fBaseView = new TermBaseView(textframe, fTermView);
118 
119 	// Initialize TermView. (font, size and color)
120 
121 	fTermView->SetTermFont(&halfFont, &fullFont);
122 	BRect rect = fTermView->SetTermSize(gTermPref->getInt32(PREF_ROWS),
123 		gTermPref->getInt32(PREF_COLS), 1);
124 
125 	int width, height;
126 
127 	fTermView->GetFontSize(&width, &height);
128 	SetSizeLimits(MIN_COLS * width, MAX_COLS * width,
129 		MIN_COLS * height, MAX_COLS * height);
130 
131 	fTermView->SetTermColor();
132 	fBaseView->SetViewColor(gTermPref->getRGB(PREF_TEXT_BACK_COLOR));
133 
134 	// Add offset to baseview.
135 	rect.InsetBy(-VIEW_OFFSET, -VIEW_OFFSET);
136 
137 	// Resize Window
138 
139 	ResizeTo(rect.Width()+ B_V_SCROLL_BAR_WIDTH,
140 		rect.Height() + fMenubar->Bounds().Height());
141 
142 	fBaseView->ResizeTo(rect.Width(), rect.Height());
143 	fBaseView->AddChild(fTermView);
144 	fTermView->MoveBy(VIEW_OFFSET, VIEW_OFFSET);
145 
146 	// Make Scroll Bar.
147 
148 	BRect scrollRect(0, 0, B_V_SCROLL_BAR_WIDTH,
149 		rect.Height() - B_H_SCROLL_BAR_HEIGHT + 1);
150 
151 	scrollRect.OffsetBy(rect.Width() + 1, fMenubar->Bounds().Height());
152 
153 	BScrollBar *scrollBar = new BScrollBar(scrollRect, "scrollbar",
154 		fTermView, 0, 0, B_VERTICAL);
155 	fTermView->SetScrollBar(scrollBar);
156 
157 	AddChild(scrollBar);
158 	AddChild(fBaseView);
159 
160 	// Set fEditmenu's target to fTermView. (Oh!...)
161 	fEditmenu->SetTargetForItems(fTermView);
162 
163 	// Initialize TermParse
164 
165 	gNowCoding = longname2op(gTermPref->getString(PREF_TEXT_ENCODING));
166 	fTermParse = new TermParse();
167 	fTermParse->InitPtyReader(this);
168 	fTermParse->InitTermParse(fTermView, fCodeConv);
169 
170 	// Set Coding.
171 
172 	// Initialize MessageRunner.
173 	fWindowUpdate = new BMessageRunner(BMessenger(this),
174 		new BMessage (MSGRUN_WINDOW), 500000);
175 }
176 
177 
178 void
179 TermWindow::MenusBeginning(void)
180 {
181 	// Syncronize Encode Menu Pop-up menu and Preference.
182 	(fEncodingmenu->FindItem(op2longname(gNowCoding)))->SetMarked(true);
183 	BWindow::MenusBeginning();
184 }
185 
186 
187 void
188 TermWindow::SetupMenu(void)
189 {
190   PrefHandler menuText;
191 
192   LoadLocaleFile (&menuText);
193 
194   // Menu bar object.
195   fMenubar = new BMenuBar(Bounds(), "mbar");
196 
197   /*
198    * Make Fiile Menu.
199    */
200   fFilemenu = new BMenu("Terminal");
201   fFilemenu->AddItem(new BMenuItem("Switch Terminals", new BMessage(MENU_SWITCH_TERM),'G'));
202   fFilemenu->AddItem(new BMenuItem("Start New Terminal", new BMessage(MENU_NEW_TREM), 'N'));
203   fFilemenu->AddSeparatorItem();
204   fFilemenu->AddItem(new BMenuItem("Page Setup...", new BMessage(MENU_PAGE_SETUP)));
205   fFilemenu->AddItem(new BMenuItem("Print", new BMessage(MENU_PRINT),'P'));
206   fFilemenu->AddSeparatorItem();
207   fFilemenu->AddItem(new BMenuItem("About Terminal...", new BMessage(B_ABOUT_REQUESTED)));
208   fFilemenu->AddSeparatorItem();
209   fFilemenu->AddItem(new BMenuItem("Quit", new BMessage(MENU_FILE_QUIT), 'Q'));
210   fMenubar->AddItem(fFilemenu);
211 
212   /*
213    * Make Edit Menu.
214    */
215   fEditmenu = new BMenu ("Edit");
216   fEditmenu->AddItem (new BMenuItem ("Copy", new BMessage (B_COPY),'C'));
217   fEditmenu->AddItem (new BMenuItem ("Paste", new BMessage (B_PASTE),'V'));
218   fEditmenu->AddSeparatorItem ();
219   fEditmenu->AddItem (new BMenuItem ("Select All", new BMessage (B_SELECT_ALL), 'A'));
220   fEditmenu->AddItem (new BMenuItem ("Clear All", new BMessage (MENU_CLEAR_ALL), 'L'));
221 
222 /*
223   // TODO: Implement Finding
224   fEditmenu->AddSeparatorItem ();
225   fEditmenu->AddItem (new BMenuItem ("Find", new BMessage (MENU_FIND_STRING),'F'));
226   fEditmenu->AddItem (new BMenuItem ("Find Again", new BMessage (MENU_FIND_AGAIN), ']'));
227 */
228   fMenubar->AddItem (fEditmenu);
229 
230 
231   /*
232    * Make Help Menu.
233    */
234   fHelpmenu = new BMenu("Settings");
235   fWindowSizeMenu = new BMenu("Window Size");
236   	fWindowSizeMenu->AddItem(new BMenuItem("80x24", new BMessage(EIGHTYTWENTYFOUR)));
237   	fWindowSizeMenu->AddItem(new BMenuItem("80x25", new BMessage(EIGHTYTWENTYFIVE)));
238    	fWindowSizeMenu->AddItem(new BMenuItem("80x40", new BMessage(EIGHTYFORTY)));
239  	fWindowSizeMenu->AddItem(new BMenuItem("132x24", new BMessage(ONETHREETWOTWENTYFOUR)));
240  	fWindowSizeMenu->AddItem(new BMenuItem("132x25", new BMessage(ONETHREETWOTWENTYFIVE)));
241 
242  	// Considering we have this in the preferences window, this menu is not
243  	// needed and should not be shown if we are to not confuse the user
244 /*  fNewFontMenu = new BMenu("Font");
245 	fNewFontMenu->SetRadioMode(true);
246 		int32 numFamilies1 = count_font_families();
247 		for ( int32 i = 0; i < numFamilies1; i++ ) {
248 			font_family family;
249 			uint32 flags;
250 			if ( get_font_family(i, &family, &flags) == B_OK ) {
251 				fNewFontMenu->AddItem(item = new BMenuItem(family, new BMessage(MSG_FONT_CHANGED)));
252 			//	if (0 ==i) item->SetMarked(true);
253 			}
254 		}
255   fNewFontMenu->FindItem (gTermPref->getString(PREF_HALF_FONT_FAMILY))->SetMarked(true);
256 */
257 
258   fEncodingmenu = new BMenu("Font Encoding");
259   fEncodingmenu->SetRadioMode(true);
260   MakeEncodingMenu(fEncodingmenu, gNowCoding, true);
261   fHelpmenu->AddItem(fWindowSizeMenu);
262   fHelpmenu->AddItem(fEncodingmenu);
263 //  fHelpmenu->AddItem(fNewFontMenu);
264   fHelpmenu->AddSeparatorItem();
265   fHelpmenu->AddItem(new BMenuItem("Preferences", new BMessage(MENU_PREF_OPEN)));
266   fMenubar->AddItem(fHelpmenu);
267 
268   AddChild(fMenubar);
269 }
270 
271 
272 void
273 TermWindow::MessageReceived(BMessage *message)
274 {
275   int32 coding_id;
276   BRect r;
277   BFont halfFont;
278   BFont fullFont;
279 
280   switch (message->what) {
281 
282   case MENU_SWITCH_TERM:
283     be_app->PostMessage(MENU_SWITCH_TERM);
284     break;
285 
286   case MENU_NEW_TREM:
287     be_app->PostMessage(MENU_NEW_TREM);
288     break;
289 
290   case MENU_PREF_OPEN:
291     if (!fPrefWindow){
292       fPrefWindow = new PrefDlg(this);
293     }else{
294       fPrefWindow->Activate();
295     }
296     break;
297 
298   case MSG_PREF_CLOSED:
299     fPrefWindow = NULL;
300     break;
301 
302   case MENU_FILE_QUIT:
303     be_app->PostMessage(B_QUIT_REQUESTED);
304     break;
305   case MENU_ENCODING:
306     message->FindInt32 ("op", &coding_id);
307     gNowCoding = coding_id;
308     SetCoding(coding_id);
309     break;
310 
311     /*
312      * Extended B_SET_PROPERTY. Dispatch this message,
313      * Set coding ID.
314      */
315   case B_SET_PROPERTY:
316   {
317     int32 i;
318     BMessage spe;
319     message->GetCurrentSpecifier(&i, &spe);
320     if (!strcmp("encode", spe.FindString("property", i))){
321       message->FindInt32 ("data",  &coding_id);
322       gNowCoding = coding_id;
323       SetCoding (coding_id);
324 
325       message->SendReply(B_REPLY);
326     }else{
327       BWindow::MessageReceived(message);
328     }
329     break;
330   }
331 
332     /*
333      * Extended B_GET_PROPERTY. Dispatch this message,
334      * reply now coding ID.
335      */
336   case B_GET_PROPERTY:
337   {
338     int32 i;
339     BMessage spe;
340     message->GetCurrentSpecifier(&i, &spe);
341     if (!strcmp("encode", spe.FindString("property", i))){
342       BMessage reply(B_REPLY);
343       reply.AddInt32("result", gNowCoding);
344       message->SendReply(&reply);
345     }else if (!strcmp("tty", spe.FindString("property", i))){
346       BMessage reply(B_REPLY);
347       reply.AddString("result", &tty_name[8]);
348       message->SendReply(&reply);
349     }else{
350       BWindow::MessageReceived(message);
351     }
352     break;
353   }
354 
355   /*
356    * Message from Preference panel.
357    */
358   case MSG_ROWS_CHANGED:
359   case MSG_COLS_CHANGED:
360     r = fTermView->SetTermSize (gTermPref->getInt32 (PREF_ROWS),
361               gTermPref->getInt32 (PREF_COLS),
362               0);
363 
364     ResizeTo (r.Width()+ B_V_SCROLL_BAR_WIDTH + VIEW_OFFSET * 2,
365         r.Height()+fMenubar->Bounds().Height() + VIEW_OFFSET *2);
366     break;
367 
368   case MSG_HALF_FONT_CHANGED:
369   case MSG_FULL_FONT_CHANGED:
370   case MSG_HALF_SIZE_CHANGED:
371   case MSG_FULL_SIZE_CHANGED:
372 
373     halfFont.SetFamilyAndStyle (gTermPref->getString(PREF_HALF_FONT_FAMILY),
374         NULL);
375     halfFont.SetSize (gTermPref->getFloat(PREF_HALF_FONT_SIZE));
376     halfFont.SetSpacing (B_FIXED_SPACING);
377 
378     fullFont.SetFamilyAndStyle (gTermPref->getString(PREF_FULL_FONT_FAMILY),
379         NULL);
380     fullFont.SetSize (gTermPref->getFloat(PREF_FULL_FONT_SIZE));
381     fullFont.SetSpacing (B_FIXED_SPACING);
382 
383     fTermView->SetTermFont (&halfFont, &fullFont);
384     r = fTermView->SetTermSize (0, 0, 0);
385 
386     int width, height;
387 
388     fTermView->GetFontSize (&width, &height);
389 
390     SetSizeLimits (MIN_COLS * width, MAX_COLS * width,
391 		   MIN_COLS * height, MAX_COLS * height);
392 
393 
394 
395     ResizeTo (r.Width()+ B_V_SCROLL_BAR_WIDTH + VIEW_OFFSET * 2,
396         r.Height()+fMenubar->Bounds().Height() + VIEW_OFFSET * 2);
397 
398     fTermView->Invalidate();
399     break;
400 
401 	case EIGHTYTWENTYFOUR:
402 		gTermPref->setString(PREF_COLS, "80");
403 		gTermPref->setString(PREF_ROWS, "24");
404 	   	this->PostMessage (MSG_ROWS_CHANGED);
405 		this->PostMessage (MSG_COLS_CHANGED);
406 	break;
407 
408 	case EIGHTYTWENTYFIVE:
409 		gTermPref->setString(PREF_COLS, "80");
410 		gTermPref->setString(PREF_ROWS, "25");
411 	   	this->PostMessage (MSG_ROWS_CHANGED);
412 	   	this->PostMessage (MSG_COLS_CHANGED);
413 	break;
414 
415 	case EIGHTYFORTY:
416 		gTermPref->setString(PREF_COLS, "80");
417 		gTermPref->setString(PREF_ROWS, "40");
418 	   	this->PostMessage (MSG_ROWS_CHANGED);
419 	   	this->PostMessage (MSG_COLS_CHANGED);
420 	break;
421 
422 	case ONETHREETWOTWENTYFOUR:
423 		gTermPref->setString(PREF_COLS, "132");
424 		gTermPref->setString(PREF_ROWS, "24");
425 	   	this->PostMessage (MSG_ROWS_CHANGED);
426 	   	this->PostMessage (MSG_COLS_CHANGED);
427 	break;
428 
429 	case ONETHREETWOTWENTYFIVE:
430 		gTermPref->setString(PREF_COLS, "132");
431 		gTermPref->setString(PREF_ROWS, "25");
432 	   	this->PostMessage (MSG_ROWS_CHANGED);
433 	   	this->PostMessage (MSG_COLS_CHANGED);
434 	break;
435 
436 	case MSG_FONT_CHANGED:
437     	gTermPref->setString (PREF_HALF_FONT_FAMILY, fNewFontMenu->FindMarked()->Label());
438     	this->PostMessage (MSG_HALF_FONT_CHANGED);
439     break;
440 
441 
442   case MSG_COLOR_CHANGED:
443     fBaseView->SetViewColor (gTermPref->getRGB (PREF_TEXT_BACK_COLOR));
444     fTermView->SetTermColor ();
445     fBaseView->Invalidate();
446     fTermView->Invalidate();
447     break;
448 
449   case MENU_PAGE_SETUP:
450     DoPageSetup ();
451     break;
452   case MENU_PRINT:
453     DoPrint ();
454     break;
455 
456   case MSGRUN_WINDOW:
457     fTermView->UpdateSIGWINCH ();
458     break;
459 
460 	case B_ABOUT_REQUESTED:
461 		be_app->PostMessage(B_ABOUT_REQUESTED);
462 		break;
463 
464   default:
465     BWindow::MessageReceived(message);
466     break;
467   }
468 }
469 ////////////////////////////////////////////////////////////////////////////
470 // WindowActivated (bool)
471 //  Dispatch Mesasge.
472 ////////////////////////////////////////////////////////////////////////////
473 void
474 TermWindow::WindowActivated (bool )
475 {
476 
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////
480 // Quit (void)
481 //  Quit Application.
482 ////////////////////////////////////////////////////////////////////////////
483 //void
484 //TermWindow::colRequested() {
485 //	colWindow *colW=new colWindow("Colours for Terminal");
486 //	colW->Show();
487 //	}
488 
489 
490 void
491 TermWindow::Quit(void)
492 {
493   delete fTermParse;
494   delete fCodeConv;
495   if(fPrefWindow) fPrefWindow->PostMessage (B_QUIT_REQUESTED);
496     be_app->PostMessage (B_QUIT_REQUESTED, be_app);
497   BWindow::Quit ();
498 }
499 
500 
501 bool
502 TermWindow::QuitRequested(void)
503 {
504 
505   return true;
506 }
507 ////////////////////////////////////////////////////////////////////////////
508 // int GetTimeZone (void)
509 //  Get Machine Timezone.
510 ////////////////////////////////////////////////////////////////////////////
511 int
512 TermWindow::GetTimeZone ()
513 {
514   struct timeval tv;
515   struct timezone tm;
516 
517   gettimeofday (&tv, &tm);
518 
519   return -tm.tz_minuteswest / 60;
520 }
521 
522 
523 #include "spawn.h"
524 
525 
526 void
527 TermWindow::TermWinActivate()
528 {
529 	Activate();
530 
531 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
532 	if (focus_follows_mouse()) {
533 		BPoint aMouseLoc = Frame().LeftTop();
534 		set_mouse_position(int32(aMouseLoc.x + 16), int32(aMouseLoc.y + 2));
535 		be_app->SetCursor(B_HAND_CURSOR);
536 	}
537 #endif
538 }
539 
540 
541 status_t
542 TermWindow::GetSupportedSuites(BMessage *msg)
543 {
544   static property_info prop_list[] = {
545      { "encode",
546        {B_GET_PROPERTY, 0},
547        {B_DIRECT_SPECIFIER, 0},
548        "get muterminal encode"},
549      { "encode",
550        {B_SET_PROPERTY, 0},
551        {B_DIRECT_SPECIFIER, 0},
552        "set muterminal encode"},
553      { "tty",
554        {B_GET_PROPERTY, 0},
555        {B_DIRECT_SPECIFIER, 0},
556        "get tty_name."},
557      { 0  }
558 
559   };
560   msg->AddString("suites", "suite/vnd.naan-termwindow");
561   BPropertyInfo prop_info(prop_list);
562   msg->AddFlat("messages", &prop_info);
563   return BWindow::GetSupportedSuites(msg);
564 }
565 ////////////////////////////////////////////////////////////////////////////
566 // ResolveSpecifier
567 //
568 ////////////////////////////////////////////////////////////////////////////
569 BHandler*
570 TermWindow::ResolveSpecifier(BMessage *msg, int32 index,
571            BMessage *specifier, int32 form,
572            const char *property)
573 {
574   if ( (strcmp(property, "encode") == 0)
575     && ((msg->what == B_SET_PROPERTY) || (msg->what == B_GET_PROPERTY) ))
576       return this;
577   else if ( (strcmp(property, "tty") == 0)
578     &&  (msg->what == B_GET_PROPERTY) )
579       return this;
580 
581   return BWindow::ResolveSpecifier(msg, index, specifier, form, property);
582 }
583 
584 ////////////////////////////////////////////////////////////////////////////
585 // SetCoding
586 //  Set coding utility functions.
587 ////////////////////////////////////////////////////////////////////////////
588 void SetCoding (int coding)
589 {
590   const etable *p = encoding_table;
591   p += coding;
592 
593   gNowCoding = coding;
594 
595   return;
596 }
597 ////////////////////////////////////////////////////////////////////////////
598 // DoPageSetUp ()
599 //
600 ////////////////////////////////////////////////////////////////////////////
601 status_t
602 TermWindow::DoPageSetup()
603 {
604   status_t rv;
605   BPrintJob job("PageSetup");
606 
607   /* display the page configure panel */
608   rv = job.ConfigPage();
609 
610   /* save a pointer to the settings */
611   fPrintSettings = job.Settings();
612 
613   return rv;
614 }
615 
616 ////////////////////////////////////////////////////////////////////////////
617 // DoPrint ()
618 //
619 ////////////////////////////////////////////////////////////////////////////
620 void
621 TermWindow::DoPrint()
622 {
623 //#if B_BEOS_VERSION < 0x0460
624   BPrintJob job("Print");
625 
626   if((! fPrintSettings) && (DoPageSetup() != B_NO_ERROR)) {
627     (new BAlert("Cancel", "Print cancelled.", "OK"))->Go();
628   return;
629   }
630 
631   job.SetSettings(new BMessage(*fPrintSettings));
632 
633   BRect pageRect = job.PrintableRect();
634   BRect curPageRect = pageRect;
635 
636   int pHeight = (int)pageRect.Height();
637   int pWidth = (int)pageRect.Width();
638   float w,h;
639   fTermView->GetFrameSize (&w, &h);
640   int xPages = (int)ceil(w / pWidth);
641   int yPages = (int)ceil(h / pHeight);
642 
643    /* engage the print server */
644   job.BeginJob();
645 
646   /* loop through and draw each page, and write to spool */
647   for(int x = 0; x < xPages; x++)
648     for(int y = 0; y < yPages; y++){
649       curPageRect.OffsetTo(x * pWidth, y * pHeight);
650       job.DrawView(fTermView, curPageRect, BPoint(0, 0));
651       job.SpoolPage();
652 
653       if(!job.CanContinue()){
654       	  // It is likely that the only way that the job was cancelled is
655       	  // because the user hit 'Cancel' in the page setup window, in which
656       	  // case, the user does *not* need to be told that it was cancelled.
657       	  // He/she will simply expect that it was done.
658 //        (new BAlert("Cancel", "Print job cancelled", "OK"))->Go();
659         return;
660       }
661   }
662 
663   /* commit the job, send the spool file */
664   job.CommitJob();
665 //#endif
666 }
667