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