1 /* 2 * Copyright 2001-2011, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Pfeiffer 7 * Philippe Houdoin 8 */ 9 10 11 #include "PrintersWindow.h" 12 13 #include <stdio.h> 14 15 #include <Application.h> 16 #include <Button.h> 17 #include <Catalog.h> 18 #include <ControlLook.h> 19 #include <FindDirectory.h> 20 #include <GroupLayout.h> 21 #include <Layout.h> 22 #include <LayoutBuilder.h> 23 #include <ListView.h> 24 #include <Locale.h> 25 #include <PrintJob.h> 26 #include <ScrollView.h> 27 28 #include "pr_server.h" 29 #include "AddPrinterDialog.h" 30 #include "Globals.h" 31 #include "JobListView.h" 32 #include "Messages.h" 33 #include "PrinterListView.h" 34 #include "TestPageView.h" 35 #include "ScreenSettings.h" 36 #include "SpoolFolder.h" 37 38 39 #undef B_TRANSLATION_CONTEXT 40 #define B_TRANSLATION_CONTEXT "PrintersWindow" 41 42 43 class TestPageWindow : public BWindow { 44 public: 45 TestPageWindow(BPrintJob* job, PrinterItem* printer); 46 virtual ~TestPageWindow(); 47 48 void MessageReceived(BMessage* message); 49 private: 50 BPrintJob* fJob; 51 TestPageView* fTestPage; 52 }; 53 54 55 TestPageWindow::TestPageWindow(BPrintJob* job, PrinterItem* printer) 56 : BWindow(job->PaperRect().OffsetByCopy(-20000, -20000), 57 B_TRANSLATE("Test page"), 58 B_TITLED_WINDOW, 0), fJob(job) 59 { 60 fTestPage = new TestPageView(job->PrintableRect(), printer); 61 62 // SetLayout(new BGroupLayout(B_VERTICAL)); 63 AddChild(fTestPage); 64 } 65 66 67 TestPageWindow::~TestPageWindow() 68 { 69 delete fJob; 70 } 71 72 73 void 74 TestPageWindow::MessageReceived(BMessage* message) 75 { 76 if (message->what != kMsgPrintTestPage) { 77 BWindow::MessageReceived(message); 78 return; 79 } 80 81 fJob->BeginJob(); 82 83 fJob->DrawView(fTestPage, fTestPage->Bounds(), B_ORIGIN); 84 fJob->SpoolPage(); 85 86 if (!fJob->CanContinue()) 87 return; 88 89 fJob->CommitJob(); 90 91 Quit(); 92 } 93 94 95 // #pragma mark PrintersWindow main class 96 97 98 PrintersWindow::PrintersWindow(ScreenSettings* settings) 99 : 100 BWindow(settings->WindowFrame(), B_TRANSLATE_SYSTEM_NAME("Printers"), 101 B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS), 102 fSettings(settings), 103 fSelectedPrinter(NULL), 104 fAddingPrinter(false) 105 { 106 _BuildGUI(); 107 MoveOnScreen(); 108 } 109 110 111 PrintersWindow::~PrintersWindow() 112 { 113 delete fSettings; 114 } 115 116 117 bool 118 PrintersWindow::QuitRequested() 119 { 120 fSettings->SetWindowFrame(Frame()); 121 122 bool result = Inherited::QuitRequested(); 123 if (result) 124 be_app->PostMessage(B_QUIT_REQUESTED); 125 126 return result; 127 } 128 129 130 void 131 PrintersWindow::MessageReceived(BMessage* msg) 132 { 133 switch (msg->what) { 134 case kMsgPrinterSelected: 135 { 136 fSelectedPrinter = fPrinterListView->SelectedItem(); 137 if (fSelectedPrinter) { 138 BString text = B_TRANSLATE("Print jobs for %printer_name%"); 139 text.ReplaceFirst("%printer_name%", fSelectedPrinter->Name()); 140 141 fJobsBox->SetLabel(text); 142 fMakeDefault->SetEnabled(true); 143 fRemove->SetEnabled(true); 144 fJobListView->SetSpoolFolder(fSelectedPrinter->Folder()); 145 } else { 146 fJobsBox->SetLabel( 147 B_TRANSLATE("Print jobs: No printer selected")); 148 fMakeDefault->SetEnabled(false); 149 fRemove->SetEnabled(false); 150 fSelectedPrinter = NULL; 151 fJobListView->SetSpoolFolder(NULL); 152 } 153 _UpdateJobButtons(); 154 _UpdatePrinterButtons(); 155 break; 156 } 157 158 case kMsgAddPrinter: 159 if (!fAddingPrinter) { 160 fAddingPrinter = true; 161 new AddPrinterDialog(this); 162 } 163 break; 164 165 case kMsgAddPrinterClosed: 166 fAddingPrinter = false; 167 break; 168 169 case kMsgRemovePrinter: 170 { 171 fSelectedPrinter = fPrinterListView->SelectedItem(); 172 if (fSelectedPrinter) 173 fSelectedPrinter->Remove(fPrinterListView); 174 break; 175 } 176 177 case kMsgMakeDefaultPrinter: 178 { 179 PrinterItem* printer = fPrinterListView->SelectedItem(); 180 if (printer && printer == fPrinterListView->ActivePrinter()) 181 break; 182 BMessenger msgr; 183 if (printer && GetPrinterServerMessenger(msgr) == B_OK) { 184 BMessage setActivePrinter(B_SET_PROPERTY); 185 setActivePrinter.AddSpecifier("ActivePrinter"); 186 setActivePrinter.AddString("data", printer->Name()); 187 msgr.SendMessage(&setActivePrinter); 188 _UpdatePrinterButtons(); 189 } 190 break; 191 } 192 193 case kMsgPrintTestPage: 194 { 195 fSelectedPrinter = fPrinterListView->SelectedItem(); 196 if (fSelectedPrinter) 197 PrintTestPage(fSelectedPrinter); 198 break; 199 } 200 201 case kMsgCancelJob: 202 fJobListView->CancelJob(); 203 break; 204 205 case kMsgRestartJob: 206 fJobListView->RestartJob(); 207 break; 208 209 case kMsgJobSelected: 210 _UpdateJobButtons(); 211 break; 212 213 case B_PRINTER_CHANGED: 214 { 215 // active printer could have been changed, even outside of prefs 216 BString activePrinterName(ActivePrinterName()); 217 PrinterItem* item = fPrinterListView->ActivePrinter(); 218 if (item && item->Name() != activePrinterName) 219 fPrinterListView->UpdateItem(item); 220 221 for (int32 i = 0; i < fPrinterListView->CountItems(); ++i) { 222 item = dynamic_cast<PrinterItem*>(fPrinterListView->ItemAt(i)); 223 if (item && item->Name() == activePrinterName) { 224 fPrinterListView->UpdateItem(item); 225 fPrinterListView->SetActivePrinter(item); 226 break; 227 } 228 } 229 } break; 230 231 default: 232 Inherited::MessageReceived(msg); 233 } 234 } 235 236 237 void 238 PrintersWindow::PrintTestPage(PrinterItem* printer) 239 { 240 BPrintJob* job = new BPrintJob(B_TRANSLATE("Test page")); 241 job->ConfigPage(); 242 243 // job->ConfigJob(); 244 245 BMessage* settings = job->Settings(); 246 if (settings == NULL) { 247 delete job; 248 return; 249 } 250 251 // enforce job config properties 252 settings->AddInt32("copies", 1); 253 settings->AddInt32("first_page", 1); 254 settings->AddInt32("last_page", -1); 255 256 BWindow* win = new TestPageWindow(job, printer); 257 win->Show(); 258 win->PostMessage(kMsgPrintTestPage); 259 } 260 261 262 void 263 PrintersWindow::AddJob(SpoolFolder* folder, Job* job) 264 { 265 if (_IsSelected(folder->Item())) 266 fJobListView->AddJob(job); 267 fPrinterListView->UpdateItem(folder->Item()); 268 _UpdatePrinterButtons(); 269 } 270 271 272 void 273 PrintersWindow::RemoveJob(SpoolFolder* folder, Job* job) 274 { 275 if (_IsSelected(folder->Item())) 276 fJobListView->RemoveJob(job); 277 fPrinterListView->UpdateItem(folder->Item()); 278 _UpdatePrinterButtons(); 279 } 280 281 282 void 283 PrintersWindow::UpdateJob(SpoolFolder* folder, Job* job) 284 { 285 if (_IsSelected(folder->Item())) { 286 fJobListView->UpdateJob(job); 287 _UpdateJobButtons(); 288 } 289 fPrinterListView->UpdateItem(folder->Item()); 290 _UpdatePrinterButtons(); 291 } 292 293 294 // #pragma mark - 295 296 297 void 298 PrintersWindow::_BuildGUI() 299 { 300 // ------------------------ Next, build the printers overview box 301 BBox* printersBox = new BBox("printersBox"); 302 printersBox->SetFont(be_bold_font); 303 printersBox->SetLabel(B_TRANSLATE("Printers")); 304 305 // Add Button 306 BButton* addButton = new BButton("add", 307 B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddPrinter)); 308 addButton->SetExplicitMaxSize( 309 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 310 311 // Remove button 312 fRemove = new BButton("remove", 313 B_TRANSLATE("Remove"), new BMessage(kMsgRemovePrinter)); 314 fRemove->SetExplicitMaxSize( 315 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 316 317 // Make Default button 318 fMakeDefault = new BButton("default", 319 B_TRANSLATE("Make default"), new BMessage(kMsgMakeDefaultPrinter)); 320 fMakeDefault->SetExplicitMaxSize( 321 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 322 323 // Print Test Page button 324 fPrintTestPage = new BButton("print_test_page", 325 B_TRANSLATE("Print test page"), new BMessage(kMsgPrintTestPage)); 326 fPrintTestPage->SetExplicitMaxSize( 327 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 328 329 // Disable all selection-based buttons 330 fRemove->SetEnabled(false); 331 fMakeDefault->SetEnabled(false); 332 fPrintTestPage->SetEnabled(false); 333 334 // Create listview with scroller 335 fPrinterListView = new PrinterListView(BRect()); 336 BScrollView* printerScrollView = new BScrollView("printer_scroller", 337 fPrinterListView, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, 338 false, true, B_FANCY_BORDER); 339 340 printerScrollView->SetExplicitMinSize( 341 BSize(be_plain_font->Size() * 30, B_SIZE_UNSET)); 342 343 float padding = be_control_look->DefaultItemSpacing(); 344 345 BLayoutBuilder::Group<>(printersBox, B_HORIZONTAL, padding) 346 .SetInsets(padding, padding * 2, padding, padding) 347 .Add(printerScrollView) 348 .AddGroup(B_VERTICAL, padding / 2, 0.0f) 349 .SetInsets(0) 350 .Add(addButton) 351 .Add(fRemove) 352 .Add(fMakeDefault) 353 .Add(fPrintTestPage) 354 .AddGlue(); 355 356 // ------------------------ Lastly, build the jobs overview box 357 fJobsBox = new BBox("jobsBox"); 358 fJobsBox->SetFont(be_bold_font); 359 fJobsBox->SetLabel(B_TRANSLATE("Print jobs: No printer selected")); 360 361 // Cancel Job Button 362 fCancel = new BButton("cancel", 363 B_TRANSLATE("Cancel job"), new BMessage(kMsgCancelJob)); 364 fCancel->SetExplicitMaxSize( 365 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 366 367 // Restart Job button 368 fRestart = new BButton("restart", 369 B_TRANSLATE("Restart job"), new BMessage(kMsgRestartJob)); 370 fRestart->SetExplicitMaxSize( 371 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 372 373 // Disable all selection-based buttons 374 fCancel->SetEnabled(false); 375 fRestart->SetEnabled(false); 376 377 // Create listview with scroller 378 fJobListView = new JobListView(BRect()); 379 BScrollView* jobScrollView = new BScrollView("jobs_scroller", 380 fJobListView, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, 381 false, true, B_FANCY_BORDER); 382 383 BLayoutBuilder::Group<>(fJobsBox, B_HORIZONTAL, padding) 384 .SetInsets(padding, padding * 2, padding, padding) 385 .Add(jobScrollView) 386 .AddGroup(B_VERTICAL, padding / 2, 0.0f) 387 .SetInsets(0) 388 .Add(fCancel) 389 .Add(fRestart) 390 .AddGlue(); 391 392 BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 393 .SetInsets(B_USE_WINDOW_SPACING) 394 .Add(printersBox) 395 .AddStrut(B_USE_DEFAULT_SPACING) 396 .Add(fJobsBox); 397 398 // There is a better solution? 399 Layout(true); 400 if (fPrintTestPage->Bounds().Width() > fRestart->Bounds().Width()) 401 fRestart->SetExplicitMinSize( 402 BSize(fPrintTestPage->Bounds().Width(), B_SIZE_UNSET)); 403 else 404 fPrintTestPage->SetExplicitMinSize( 405 BSize(fRestart->Bounds().Width(), B_SIZE_UNSET)); 406 } 407 408 409 bool 410 PrintersWindow::_IsSelected(PrinterItem* printer) 411 { 412 return fSelectedPrinter && fSelectedPrinter == printer; 413 } 414 415 416 void 417 PrintersWindow::_UpdatePrinterButtons() 418 { 419 PrinterItem* item = fPrinterListView->SelectedItem(); 420 fRemove->SetEnabled(item && !item->HasPendingJobs()); 421 fMakeDefault->SetEnabled(item && !item->IsActivePrinter()); 422 fPrintTestPage->SetEnabled(item); 423 } 424 425 426 void 427 PrintersWindow::_UpdateJobButtons() 428 { 429 JobItem* item = fJobListView->SelectedItem(); 430 if (item != NULL) { 431 Job* job = item->GetJob(); 432 fCancel->SetEnabled(job->Status() != kProcessing); 433 fRestart->SetEnabled(job->Status() == kFailed); 434 } else { 435 fCancel->SetEnabled(false); 436 fRestart->SetEnabled(false); 437 } 438 } 439 440 441