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_TRANSLATE_CONTEXT 37 #define B_TRANSLATE_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 return; 232 233 // enforce job config properties 234 settings->AddInt32("copies", 1); 235 settings->AddInt32("first_page", 1); 236 settings->AddInt32("last_page", -1); 237 238 BWindow* win = new TestPageWindow(job, printer); 239 win->Show(); 240 win->PostMessage(kMsgPrintTestPage); 241 } 242 243 244 void 245 PrintersWindow::AddJob(SpoolFolder* folder, Job* job) 246 { 247 if (_IsSelected(folder->Item())) 248 fJobListView->AddJob(job); 249 fPrinterListView->UpdateItem(folder->Item()); 250 _UpdatePrinterButtons(); 251 } 252 253 254 void 255 PrintersWindow::RemoveJob(SpoolFolder* folder, Job* job) 256 { 257 if (_IsSelected(folder->Item())) 258 fJobListView->RemoveJob(job); 259 fPrinterListView->UpdateItem(folder->Item()); 260 _UpdatePrinterButtons(); 261 } 262 263 264 void 265 PrintersWindow::UpdateJob(SpoolFolder* folder, Job* job) 266 { 267 if (_IsSelected(folder->Item())) { 268 fJobListView->UpdateJob(job); 269 _UpdateJobButtons(); 270 } 271 fPrinterListView->UpdateItem(folder->Item()); 272 _UpdatePrinterButtons(); 273 } 274 275 276 // #pragma mark - 277 278 279 void 280 PrintersWindow::_BuildGUI() 281 { 282 const float boxInset = 10.0; 283 BRect r(Bounds()); 284 285 // ------------------------ First of all, create a nice grey backdrop 286 BBox * backdrop = new BBox(Bounds(), "backdrop", B_FOLLOW_ALL_SIDES, 287 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, 288 B_PLAIN_BORDER); 289 AddChild(backdrop); 290 291 // ------------------------ Next, build the printers overview box 292 BBox* printersBox = new BBox(BRect(boxInset, boxInset, 293 r.Width() - boxInset, (r.Height()/2) - (boxInset/2)), 294 "printersBox", B_FOLLOW_ALL); 295 printersBox->SetFont(be_bold_font); 296 printersBox->SetLabel(B_TRANSLATE("Printers")); 297 backdrop->AddChild(printersBox); 298 299 // Width of largest button 300 float maxWidth = 0; 301 302 // Add Button 303 BButton* addButton = new BButton(BRect(5,5,5,5), "add", 304 B_TRANSLATE("Add …"), new BMessage(kMsgAddPrinter), B_FOLLOW_RIGHT); 305 printersBox->AddChild(addButton); 306 addButton->ResizeToPreferred(); 307 308 maxWidth = addButton->Bounds().Width(); 309 310 // Remove button 311 fRemove = new BButton(BRect(5,30,5,30), "remove", 312 B_TRANSLATE("Remove"), new BMessage(kMsgRemovePrinter), 313 B_FOLLOW_RIGHT); 314 printersBox->AddChild(fRemove); 315 fRemove->ResizeToPreferred(); 316 317 if (fRemove->Bounds().Width() > maxWidth) 318 maxWidth = fRemove->Bounds().Width(); 319 320 // Make Default button 321 fMakeDefault = new BButton(BRect(5,60,5,60), "default", 322 B_TRANSLATE("Make default"), new BMessage(kMsgMakeDefaultPrinter), 323 B_FOLLOW_RIGHT); 324 printersBox->AddChild(fMakeDefault); 325 fMakeDefault->ResizeToPreferred(); 326 327 if (fMakeDefault->Bounds().Width() > maxWidth) 328 maxWidth = fMakeDefault->Bounds().Width(); 329 330 // Print Test Page button 331 fPrintTestPage = new BButton(BRect(5,60,5,60), "print_test_page", 332 B_TRANSLATE("Print test page"), new BMessage(kMsgPrintTestPage), 333 B_FOLLOW_RIGHT); 334 printersBox->AddChild(fPrintTestPage); 335 fPrintTestPage->ResizeToPreferred(); 336 337 if (fPrintTestPage->Bounds().Width() > maxWidth) 338 maxWidth = fPrintTestPage->Bounds().Width(); 339 340 341 // Resize all buttons to maximum width and align them to the right 342 float xPos = printersBox->Bounds().Width() - boxInset - maxWidth; 343 addButton->MoveTo(xPos, boxInset + 8); 344 addButton->ResizeTo(maxWidth, addButton->Bounds().Height()); 345 346 fRemove->MoveTo(xPos, 347 boxInset + addButton->Bounds().Height() + boxInset + 8); 348 fRemove->ResizeTo(maxWidth, fRemove->Bounds().Height()); 349 350 fMakeDefault->MoveTo(xPos, boxInset + addButton->Bounds().Height() + 351 boxInset + fRemove->Bounds().Height() + boxInset + 8); 352 fMakeDefault->ResizeTo(maxWidth, fMakeDefault->Bounds().Height()); 353 354 fPrintTestPage->MoveTo(xPos, boxInset + addButton->Bounds().Height() + 355 boxInset + fRemove->Bounds().Height() + 356 boxInset + fMakeDefault->Bounds().Height() + boxInset + 8); 357 fPrintTestPage->ResizeTo(maxWidth, fPrintTestPage->Bounds().Height()); 358 359 360 // Disable all selection-based buttons 361 fRemove->SetEnabled(false); 362 fMakeDefault->SetEnabled(false); 363 fPrintTestPage->SetEnabled(false); 364 365 // Create listview with scroller 366 BRect listBounds(boxInset, boxInset + 8, 367 fMakeDefault->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH, 368 printersBox->Bounds().Height()- boxInset - 3); 369 fPrinterListView = new PrinterListView(listBounds); 370 BScrollView* pscroller = new BScrollView("printer_scroller", fPrinterListView, 371 B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER); 372 printersBox->AddChild(pscroller); 373 374 // ------------------------ Lastly, build the jobs overview box 375 fJobsBox = new BBox(BRect(boxInset, r.Height() / 2 + boxInset / 2, 376 Bounds().Width() - 10, Bounds().Height() - boxInset), "jobsBox", 377 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); 378 fJobsBox->SetFont(be_bold_font); 379 fJobsBox->SetLabel(B_TRANSLATE("Print jobs: No printer selected")); 380 backdrop->AddChild(fJobsBox); 381 382 // Cancel Job Button 383 BButton* cancelButton = new BButton(BRect(5, 5, 5, 5), "cancel", 384 B_TRANSLATE("Cancel job"), new BMessage(kMsgCancelJob), 385 B_FOLLOW_RIGHT+B_FOLLOW_TOP); 386 fJobsBox->AddChild(cancelButton); 387 cancelButton->ResizeToPreferred(); 388 fCancel = cancelButton; 389 390 maxWidth = cancelButton->Bounds().Width(); 391 392 // Restart Job button 393 BButton* restartButton = new BButton(BRect(5, 30, 5, 30), "restart", 394 B_TRANSLATE("Restart job"), new BMessage(kMsgRestartJob), 395 B_FOLLOW_RIGHT | B_FOLLOW_TOP); 396 fJobsBox->AddChild(restartButton); 397 restartButton->ResizeToPreferred(); 398 fRestart = restartButton; 399 400 if (restartButton->Bounds().Width() > maxWidth) 401 maxWidth = restartButton->Bounds().Width(); 402 403 // Resize all buttons to maximum width and align them to the right 404 xPos = fJobsBox->Bounds().Width() - boxInset - maxWidth; 405 cancelButton->MoveTo(xPos, boxInset + 8); 406 cancelButton->ResizeTo(maxWidth, cancelButton->Bounds().Height()); 407 408 restartButton->MoveTo(xPos, boxInset + cancelButton->Bounds().Height() 409 + boxInset + 8); 410 restartButton->ResizeTo(maxWidth, restartButton->Bounds().Height()); 411 412 // Disable all selection-based buttons 413 cancelButton->SetEnabled(false); 414 restartButton->SetEnabled(false); 415 416 // Create listview with scroller 417 listBounds = BRect(boxInset, boxInset + 8, 418 cancelButton->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH, 419 fJobsBox->Bounds().Height() - boxInset - 3); 420 fJobListView = new JobListView(listBounds); 421 BScrollView* jscroller = new BScrollView("jobs_scroller", fJobListView, 422 B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER); 423 fJobsBox->AddChild(jscroller); 424 425 // Determine min width 426 float width = (jscroller->Bounds().Width() < pscroller->Bounds().Width()) 427 ? jscroller->Bounds().Width() : pscroller->Bounds().Width(); 428 429 // Resize boxes to the same size 430 jscroller->ResizeTo(width, jscroller->Bounds().Height()); 431 pscroller->ResizeTo(width, pscroller->Bounds().Height()); 432 } 433 434 435 bool 436 PrintersWindow::_IsSelected(PrinterItem* printer) 437 { 438 return fSelectedPrinter && fSelectedPrinter == printer; 439 } 440 441 442 void 443 PrintersWindow::_UpdatePrinterButtons() 444 { 445 PrinterItem* item = fPrinterListView->SelectedItem(); 446 fRemove->SetEnabled(item && !item->HasPendingJobs()); 447 fMakeDefault->SetEnabled(item && !item->IsActivePrinter()); 448 fPrintTestPage->SetEnabled(item); 449 } 450 451 452 void 453 PrintersWindow::_UpdateJobButtons() 454 { 455 JobItem* item = fJobListView->SelectedItem(); 456 if (item != NULL) { 457 Job* job = item->GetJob(); 458 fCancel->SetEnabled(job->Status() != kProcessing); 459 fRestart->SetEnabled(job->Status() == kFailed); 460 } else { 461 fCancel->SetEnabled(false); 462 fRestart->SetEnabled(false); 463 } 464 } 465 466 467