1 /*****************************************************************************/ 2 // ConfigWindow 3 // 4 // Author 5 // Michael Pfeiffer 6 // 7 // This application and all source files used in its construction, except 8 // where noted, are licensed under the MIT License, and have been written 9 // and are: 10 // 11 // Copyright (c) 2002 OpenBeOS Project 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a 14 // copy of this software and associated documentation files (the "Software"), 15 // to deal in the Software without restriction, including without limitation 16 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 17 // and/or sell copies of the Software, and to permit persons to whom the 18 // Software is furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included 21 // in all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 // DEALINGS IN THE SOFTWARE. 30 /*****************************************************************************/ 31 32 33 #include "pr_server.h" 34 #include "Printer.h" 35 #include "PrintServerApp.h" 36 #include "ConfigWindow.h" 37 #include "BeUtils.h" 38 39 // posix 40 #include <limits.h> 41 #include <math.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 // BeOS 46 #include <Application.h> 47 #include <Autolock.h> 48 #include <Window.h> 49 50 static const float a0_width = 2380.0; 51 static const float a0_height = 3368.0; 52 static const float a1_width = 1684.0; 53 static const float a1_height = 2380.0; 54 static const float a2_width = 1190.0; 55 static const float a2_height = 1684.0; 56 static const float a3_width = 842.0; 57 static const float a3_height = 1190.0; 58 static const float a4_width = 595.0; 59 static const float a4_height = 842.0; 60 static const float a5_width = 421.0; 61 static const float a5_height = 595.0; 62 static const float a6_width = 297.0; 63 static const float a6_height = 421.0; 64 static const float b5_width = 501.0; 65 static const float b5_height = 709.0; 66 static const float letter_width = 612.0; 67 static const float letter_height = 792.0; 68 static const float legal_width = 612.0; 69 static const float legal_height = 1008.0; 70 static const float ledger_width = 1224.0; 71 static const float ledger_height = 792.0; 72 static const float p11x17_width = 792.0; 73 static const float p11x17_height = 1224.0; 74 75 static struct PageFormat 76 { 77 char *label; 78 float width; 79 float height; 80 } pageFormat[] = 81 { 82 {"Letter", letter_width, letter_height }, 83 {"Legal", legal_width, legal_height }, 84 {"Ledger", ledger_width, ledger_height }, 85 {"p11x17", p11x17_width, p11x17_height }, 86 {"A0", a0_width, a0_height }, 87 {"A1", a1_width, a1_height }, 88 {"A2", a2_width, a2_height }, 89 {"A3", a3_width, a3_height }, 90 {"A4", a4_width, a4_height }, 91 {"A5", a5_width, a5_height }, 92 {"A6", a6_width, a6_height }, 93 {"B5", b5_width, b5_height }, 94 }; 95 96 static void GetPageFormat(float w, float h, BString& label) { 97 w = floor(w + 0.5); h = floor(h + 0.5); 98 for (int i = 0; i < sizeof(pageFormat) / sizeof(struct PageFormat); i ++) { 99 struct PageFormat& pf = pageFormat[i]; 100 if (pf.width == w && pf.height == h || pf.width == h && pf.height == w) { 101 label = pf.label; return; 102 } 103 } 104 105 float unit = 72.0; // currently inc[h]es only 106 label << (w / unit) << "x" << (h / unit) << " in."; 107 } 108 109 ConfigWindow::ConfigWindow(config_setup_kind kind, Printer* defaultPrinter, BMessage* settings, AutoReply* sender) 110 : BWindow(ConfigWindow::GetWindowFrame(), "Page Setup", 111 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) 112 , fKind(kind) 113 , fDefaultPrinter(defaultPrinter) 114 , fSettings(settings) 115 , fSender(sender) 116 , fCurrentPrinter(NULL) 117 { 118 MimeTypeForSender(settings, fSenderMimeType); 119 PrinterForMimeType(); 120 121 if (kind == kJobSetup) SetTitle("Print Setup"); 122 123 BView* panel = new BBox(Bounds(), "top_panel", B_FOLLOW_ALL, 124 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, 125 B_PLAIN_BORDER); 126 127 AddChild(panel); 128 129 float left = 10, top = 5; 130 BRect r(left, top, 160, 15); 131 BStringView* string; 132 133 // print selection popup menu 134 BPopUpMenu* menu = new BPopUpMenu("Select a Printer"); 135 SetupPrintersMenu(menu); 136 137 fPrinters = new BMenuField(r, "Printer", "Printer", menu); 138 fPrinters->SetDivider(40); 139 panel->AddChild(fPrinters); 140 top += fPrinters->Bounds().Height() + 10; 141 142 // page format button 143 r.OffsetTo(left, top); 144 fPageSetup = AddPictureButton(panel, r, "Page Format", "PAGE_SETUP_ON", "PAGE_SETUP_OFF", MSG_PAGE_SETUP); 145 // add description to button 146 r.OffsetTo(left + fPageSetup->Bounds().Width() + 5, top + 5); 147 AddStringView(panel, r, "Setup page format"); 148 r.OffsetBy(0, 10); 149 fPageFormatText = AddStringView(panel, r, ""); 150 top += fPageSetup->Bounds().Height() + 5; 151 152 // page selection button 153 fJobSetup = NULL; 154 if (kind == kJobSetup) { 155 r.OffsetTo(left, top); 156 fJobSetup = AddPictureButton(panel, r, "Page Selection", "JOB_SETUP_ON", "JOB_SETUP_OFF", MSG_JOB_SETUP); 157 // add description to button 158 r.OffsetTo(left + fJobSetup->Bounds().Width() + 5, top + 5); 159 AddStringView(panel, r, "Setup print job"); 160 r.OffsetBy(0, 10); 161 fJobSetupText = AddStringView(panel, r, ""); 162 top += fJobSetup->Bounds().Height() + 5; 163 } 164 top += 5; 165 166 // separator line 167 BRect line(Bounds()); 168 line.OffsetTo(0, top); 169 line.bottom = line.top+1; 170 AddChild(new BBox(line, "line", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP)); 171 top += 10; 172 173 // Cancel button 174 r.OffsetTo(left, top); 175 BButton* cancel = new BButton(r, "Cancel", "Cancel", new BMessage(B_QUIT_REQUESTED)); 176 panel->AddChild(cancel); 177 cancel->ResizeToPreferred(); 178 left = cancel->Frame().right + 10; 179 180 // OK button 181 r.OffsetTo(left, top); 182 fOk = new BButton(r, "OK", "OK", new BMessage(MSG_OK)); 183 panel->AddChild(fOk); 184 fOk->ResizeToPreferred(); 185 top += fOk->Bounds().Height() + 10; 186 187 // resize window 188 ResizeTo(fOk->Frame().right + 10, top); 189 190 AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED)); 191 192 SetDefaultButton(fOk); 193 194 fPrinters->MakeFocus(true); 195 196 UpdateSettings(true); 197 } 198 199 ConfigWindow::~ConfigWindow() { 200 if (fCurrentPrinter) fCurrentPrinter->Release(); 201 release_sem(fFinished); 202 } 203 204 void ConfigWindow::Go() { 205 sem_id sid = create_sem(0, "finished"); 206 if (sid >= 0) { 207 fFinished = sid; 208 Show(); 209 acquire_sem(sid); 210 delete_sem(sid); 211 } else { 212 Quit(); 213 } 214 } 215 216 void ConfigWindow::MessageReceived(BMessage* m) { 217 switch (m->what) { 218 case MSG_PAGE_SETUP: Setup(kPageSetup); 219 break; 220 case MSG_JOB_SETUP: Setup(kJobSetup); 221 break; 222 case MSG_PRINTER_SELECTED: { 223 BString printer; 224 if (m->FindString("name", &printer) == B_OK) { 225 UpdateAppSettings(fSenderMimeType.String(), printer.String()); 226 PrinterForMimeType(); 227 UpdateSettings(true); 228 } 229 } 230 break; 231 case MSG_OK: 232 UpdateSettings(false); 233 fSender->SetReply(fKind == kPageSetup ? &fPageSettings : &fJobSettings); 234 Quit(); 235 break; 236 case B_ABOUT_REQUESTED: AboutRequested(); 237 break; 238 default: 239 inherited::MessageReceived(m); 240 } 241 } 242 243 static const char* 244 kAbout = 245 "Printer Server\n" 246 "© 2001, 2002 OpenBeOS\n" 247 "\n" 248 "\tIthamar R. Adema - Initial Implementation\n" 249 "\tMichael Pfeiffer - Release 1 and beyond\n" 250 ; 251 252 void 253 ConfigWindow::AboutRequested() 254 { 255 BAlert *about = new BAlert("About Printer Server", kAbout, "Cool"); 256 BTextView *v = about->TextView(); 257 if (v) { 258 rgb_color red = {255, 0, 51, 255}; 259 rgb_color blue = {0, 102, 255, 255}; 260 261 v->SetStylable(true); 262 char *text = (char*)v->Text(); 263 char *s = text; 264 // set all Be in blue and red 265 while ((s = strstr(s, "Be")) != NULL) { 266 int32 i = s - text; 267 v->SetFontAndColor(i, i+1, NULL, 0, &blue); 268 v->SetFontAndColor(i+1, i+2, NULL, 0, &red); 269 s += 2; 270 } 271 // first text line 272 s = strchr(text, '\n'); 273 BFont font; 274 v->GetFontAndColor(0, &font); 275 font.SetSize(12); 276 v->SetFontAndColor(0, s-text+1, &font, B_FONT_SIZE); 277 }; 278 about->Go(); 279 } 280 281 282 void ConfigWindow::FrameMoved(BPoint p) { 283 BRect frame = GetWindowFrame(); 284 frame.OffsetTo(p); 285 SetWindowFrame(frame); 286 } 287 288 BRect ConfigWindow::GetWindowFrame() { 289 BAutolock lock(gLock); 290 if (lock.IsLocked()) { 291 return Settings::GetSettings()->ConfigWindowFrame(); 292 } 293 return BRect(30, 30, 300, 300); 294 } 295 296 void ConfigWindow::SetWindowFrame(BRect r) { 297 BAutolock lock(gLock); 298 if (lock.IsLocked()) { 299 Settings::GetSettings()->SetConfigWindowFrame(r); 300 } 301 } 302 303 BPictureButton* ConfigWindow::AddPictureButton(BView* panel, BRect frame, const char* name, const char* on, const char* off, uint32 what) { 304 BBitmap* onBM = LoadBitmap(on); 305 BBitmap* offBM = LoadBitmap(off); 306 307 BPicture* onPict = BitmapToPicture(panel, onBM); 308 BPicture* offPict = BitmapToPicture(panel, offBM); 309 310 BPictureButton* button = NULL; 311 312 if (onPict != NULL && offPict != NULL) { 313 button = new BPictureButton(frame, name, onPict, offPict, new BMessage(what)); 314 button->SetViewColor(B_TRANSPARENT_COLOR); 315 panel->AddChild(button); 316 onBM->Lock(); 317 button->ResizeTo(onBM->Bounds().Width(), onBM->Bounds().Height()); 318 onBM->Unlock(); 319 320 BPicture* disabled = BitmapToGrayedPicture(panel, offBM); 321 button->SetDisabledOn(disabled); 322 delete disabled; 323 324 disabled = BitmapToGrayedPicture(panel, onBM); 325 button->SetDisabledOff(disabled); 326 delete disabled; 327 } 328 329 delete onPict; delete offPict; 330 delete onBM; delete offBM; 331 332 return button; 333 } 334 335 BStringView* ConfigWindow::AddStringView(BView* panel, BRect frame, const char* text) { 336 // frame.bottom = frame.top ; 337 BStringView* string = new BStringView(frame, "", text); 338 string->SetViewColor(panel->ViewColor()); 339 string->SetLowColor(panel->ViewColor()); 340 panel->AddChild(string); 341 return string; 342 } 343 344 void ConfigWindow::PrinterForMimeType() { 345 BAutolock lock(gLock); 346 if (fCurrentPrinter) { 347 fCurrentPrinter->Release(); fCurrentPrinter = NULL; 348 } 349 if (lock.IsLocked()) { 350 Settings* s = Settings::GetSettings(); 351 AppSettings* app = s->FindAppSettings(fSenderMimeType.String()); 352 if (app) { 353 fPrinterName = app->GetPrinter(); 354 } else { 355 fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : ""; 356 } 357 fCurrentPrinter = Printer::Find(fPrinterName); 358 if (fCurrentPrinter) fCurrentPrinter->Acquire(); 359 } 360 } 361 362 void ConfigWindow::SetupPrintersMenu(BMenu* menu) { 363 // clear menu 364 for (int i = menu->CountItems() - 1; i >= 0; i --) { 365 delete menu->RemoveItem(i); 366 } 367 // fill menu with printer names 368 BAutolock lock(gLock); 369 if (lock.IsLocked()) { 370 BString n; 371 Printer* p; 372 BMessage* m; 373 BMenuItem* item; 374 for (int i = 0; i < Printer::CountPrinters(); i ++) { 375 Printer::At(i)->GetName(n); 376 m = new BMessage(MSG_PRINTER_SELECTED); 377 m->AddString("name", n.String()); 378 menu->AddItem(item = new BMenuItem(n.String(), m)); 379 if (n == fPrinterName) item->SetMarked(true); 380 } 381 } 382 } 383 384 void ConfigWindow::UpdateAppSettings(const char* mime, const char* printer) { 385 BAutolock lock(gLock); 386 if (lock.IsLocked()) { 387 Settings* s = Settings::GetSettings(); 388 AppSettings* app = s->FindAppSettings(mime); 389 if (app) app->SetPrinter(printer); 390 else s->AddAppSettings(new AppSettings(mime, printer)); 391 } 392 } 393 394 void ConfigWindow::UpdateSettings(bool read) { 395 BAutolock lock(gLock); 396 if (lock.IsLocked()) { 397 Settings* s = Settings::GetSettings(); 398 PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String()); 399 if (p == NULL) { 400 p = new PrinterSettings(fPrinterName.String()); 401 s->AddPrinterSettings(p); 402 } 403 ASSERT(p != NULL); 404 if (read) { 405 fPageSettings = *p->GetPageSettings(); 406 fJobSettings = *p->GetJobSettings(); 407 } else { 408 p->SetPageSettings(&fPageSettings); 409 p->SetJobSettings(&fJobSettings); 410 } 411 } 412 UpdateUI(); 413 } 414 415 void ConfigWindow::UpdateUI() { 416 if (fCurrentPrinter == NULL) { 417 fPageSetup->SetEnabled(false); 418 if (fJobSetup) { 419 fJobSetup->SetEnabled(false); 420 fJobSetupText->SetText("Undefined job settings"); 421 } 422 fOk->SetEnabled(false); 423 fPageFormatText->SetText("Undefined paper format"); 424 } else { 425 fPageSetup->SetEnabled(true); 426 427 if (fJobSetup) { 428 fJobSetup->SetEnabled(fKind == kJobSetup && !fPageSettings.IsEmpty()); 429 } 430 fOk->SetEnabled(fKind == kJobSetup && !fJobSettings.IsEmpty() || 431 fKind == kPageSetup && !fPageSettings.IsEmpty()); 432 433 // display information about page format 434 BRect paperRect; 435 BString pageFormat; 436 if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) { 437 GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat); 438 439 int32 orientation = 0; 440 fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation); 441 if (orientation == 0) pageFormat << ", Portrait"; 442 else pageFormat << ", Landscape"; 443 } else { 444 pageFormat << "Undefined paper format"; 445 } 446 fPageFormatText->SetText(pageFormat.String()); 447 448 // display information about job 449 if (fKind == kJobSetup) { 450 BString job; 451 int32 first, last, copies; 452 if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK && 453 fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) == B_OK) { 454 if (first >= 1 && first <= last && last != INT_MAX) { 455 job << "From page " << first << " to " << last; 456 } else { 457 job << "All pages"; 458 } 459 int32 copies; 460 if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies) == B_OK && copies > 1) { 461 job << ", " << copies << " copies"; 462 } 463 } else { 464 job << "Undefined job settings"; 465 } 466 467 fJobSetupText->SetText(job.String()); 468 } 469 } 470 } 471 472 void ConfigWindow::Setup(config_setup_kind kind) { 473 if (fCurrentPrinter) { 474 Hide(); 475 if (kind == kPageSetup) { 476 BMessage settings = fPageSettings; 477 if (fCurrentPrinter->ConfigurePage(settings) == B_OK) { 478 fPageSettings = settings; 479 if (!fJobSettings.IsEmpty()) AddFields(&fJobSettings, &fPageSettings); 480 } 481 } else { 482 BMessage settings; 483 if (fJobSettings.IsEmpty()) settings = fPageSettings; 484 else settings = fJobSettings; 485 486 if (fCurrentPrinter->ConfigureJob(settings) == B_OK) 487 fJobSettings = settings; 488 } 489 UpdateUI(); 490 Show(); 491 } 492 } 493