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