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