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 (uint 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 132 // print selection popup menu 133 BPopUpMenu* menu = new BPopUpMenu("Select a Printer"); 134 SetupPrintersMenu(menu); 135 136 fPrinters = new BMenuField(r, "Printer", "Printer", menu); 137 fPrinters->SetDivider(40); 138 panel->AddChild(fPrinters); 139 top += fPrinters->Bounds().Height() + 10; 140 141 // page format button 142 r.OffsetTo(left, top); 143 fPageSetup = AddPictureButton(panel, r, "Page Format", "PAGE_SETUP_ON", "PAGE_SETUP_OFF", MSG_PAGE_SETUP); 144 // add description to button 145 r.OffsetTo(left + fPageSetup->Bounds().Width() + 5, top + 5); 146 AddStringView(panel, r, "Setup page format"); 147 r.OffsetBy(0, 10); 148 fPageFormatText = AddStringView(panel, r, ""); 149 top += fPageSetup->Bounds().Height() + 5; 150 151 // page selection button 152 fJobSetup = NULL; 153 if (kind == kJobSetup) { 154 r.OffsetTo(left, top); 155 fJobSetup = AddPictureButton(panel, r, "Page Selection", "JOB_SETUP_ON", "JOB_SETUP_OFF", MSG_JOB_SETUP); 156 // add description to button 157 r.OffsetTo(left + fJobSetup->Bounds().Width() + 5, top + 5); 158 AddStringView(panel, r, "Setup print job"); 159 r.OffsetBy(0, 10); 160 fJobSetupText = AddStringView(panel, r, ""); 161 top += fJobSetup->Bounds().Height() + 5; 162 } 163 top += 5; 164 165 // separator line 166 BRect line(Bounds()); 167 line.OffsetTo(0, top); 168 line.bottom = line.top+1; 169 AddChild(new BBox(line, "line", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP)); 170 top += 10; 171 172 // Cancel button 173 r.OffsetTo(left, top); 174 BButton* cancel = new BButton(r, "Cancel", "Cancel", new BMessage(B_QUIT_REQUESTED)); 175 panel->AddChild(cancel); 176 cancel->ResizeToPreferred(); 177 left = cancel->Frame().right + 10; 178 179 // OK button 180 r.OffsetTo(left, top); 181 fOk = new BButton(r, "OK", "OK", new BMessage(MSG_OK)); 182 panel->AddChild(fOk); 183 fOk->ResizeToPreferred(); 184 top += fOk->Bounds().Height() + 10; 185 186 // resize window 187 ResizeTo(fOk->Frame().right + 10, top); 188 189 AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED)); 190 191 SetDefaultButton(fOk); 192 193 fPrinters->MakeFocus(true); 194 195 UpdateSettings(true); 196 } 197 198 ConfigWindow::~ConfigWindow() { 199 if (fCurrentPrinter) fCurrentPrinter->Release(); 200 release_sem(fFinished); 201 } 202 203 void ConfigWindow::Go() { 204 sem_id sid = create_sem(0, "finished"); 205 if (sid >= 0) { 206 fFinished = sid; 207 Show(); 208 acquire_sem(sid); 209 delete_sem(sid); 210 } else { 211 Quit(); 212 } 213 } 214 215 void ConfigWindow::MessageReceived(BMessage* m) { 216 switch (m->what) { 217 case MSG_PAGE_SETUP: Setup(kPageSetup); 218 break; 219 case MSG_JOB_SETUP: Setup(kJobSetup); 220 break; 221 case MSG_PRINTER_SELECTED: { 222 BString printer; 223 if (m->FindString("name", &printer) == B_OK) { 224 UpdateAppSettings(fSenderMimeType.String(), printer.String()); 225 PrinterForMimeType(); 226 UpdateSettings(true); 227 } 228 } 229 break; 230 case MSG_OK: 231 UpdateSettings(false); 232 fSender->SetReply(fKind == kPageSetup ? &fPageSettings : &fJobSettings); 233 Quit(); 234 break; 235 case B_ABOUT_REQUESTED: AboutRequested(); 236 break; 237 default: 238 inherited::MessageReceived(m); 239 } 240 } 241 242 static const char* 243 kAbout = 244 "Printer Server\n" 245 "© 2001, 2002 OpenBeOS\n" 246 "\n" 247 "\tIthamar R. Adema - Initial Implementation\n" 248 "\tMichael Pfeiffer - Release 1 and beyond\n" 249 ; 250 251 void 252 ConfigWindow::AboutRequested() 253 { 254 BAlert *about = new BAlert("About Printer Server", kAbout, "Cool"); 255 BTextView *v = about->TextView(); 256 if (v) { 257 rgb_color red = {255, 0, 51, 255}; 258 rgb_color blue = {0, 102, 255, 255}; 259 260 v->SetStylable(true); 261 char *text = (char*)v->Text(); 262 char *s = text; 263 // set all Be in blue and red 264 while ((s = strstr(s, "Be")) != NULL) { 265 int32 i = s - text; 266 v->SetFontAndColor(i, i+1, NULL, 0, &blue); 267 v->SetFontAndColor(i+1, i+2, NULL, 0, &red); 268 s += 2; 269 } 270 // first text line 271 s = strchr(text, '\n'); 272 BFont font; 273 v->GetFontAndColor(0, &font); 274 font.SetSize(12); 275 v->SetFontAndColor(0, s-text+1, &font, B_FONT_SIZE); 276 }; 277 about->Go(); 278 } 279 280 281 void ConfigWindow::FrameMoved(BPoint p) { 282 BRect frame = GetWindowFrame(); 283 frame.OffsetTo(p); 284 SetWindowFrame(frame); 285 } 286 287 BRect ConfigWindow::GetWindowFrame() { 288 BAutolock lock(gLock); 289 if (lock.IsLocked()) { 290 return Settings::GetSettings()->ConfigWindowFrame(); 291 } 292 return BRect(30, 30, 300, 300); 293 } 294 295 void ConfigWindow::SetWindowFrame(BRect r) { 296 BAutolock lock(gLock); 297 if (lock.IsLocked()) { 298 Settings::GetSettings()->SetConfigWindowFrame(r); 299 } 300 } 301 302 BPictureButton* ConfigWindow::AddPictureButton(BView* panel, BRect frame, const char* name, const char* on, const char* off, uint32 what) { 303 BBitmap* onBM = LoadBitmap(on); 304 BBitmap* offBM = LoadBitmap(off); 305 306 BPicture* onPict = BitmapToPicture(panel, onBM); 307 BPicture* offPict = BitmapToPicture(panel, offBM); 308 309 BPictureButton* button = NULL; 310 311 if (onPict != NULL && offPict != NULL) { 312 button = new BPictureButton(frame, name, onPict, offPict, new BMessage(what)); 313 button->SetViewColor(B_TRANSPARENT_COLOR); 314 panel->AddChild(button); 315 onBM->Lock(); 316 button->ResizeTo(onBM->Bounds().Width(), onBM->Bounds().Height()); 317 onBM->Unlock(); 318 319 BPicture* disabled = BitmapToGrayedPicture(panel, offBM); 320 button->SetDisabledOn(disabled); 321 delete disabled; 322 323 disabled = BitmapToGrayedPicture(panel, onBM); 324 button->SetDisabledOff(disabled); 325 delete disabled; 326 } 327 328 delete onPict; delete offPict; 329 delete onBM; delete offBM; 330 331 return button; 332 } 333 334 BStringView* ConfigWindow::AddStringView(BView* panel, BRect frame, const char* text) { 335 // frame.bottom = frame.top ; 336 BStringView* string = new BStringView(frame, "", text); 337 string->SetViewColor(panel->ViewColor()); 338 string->SetLowColor(panel->ViewColor()); 339 panel->AddChild(string); 340 return string; 341 } 342 343 void ConfigWindow::PrinterForMimeType() { 344 BAutolock lock(gLock); 345 if (fCurrentPrinter) { 346 fCurrentPrinter->Release(); fCurrentPrinter = NULL; 347 } 348 if (lock.IsLocked()) { 349 Settings* s = Settings::GetSettings(); 350 AppSettings* app = s->FindAppSettings(fSenderMimeType.String()); 351 if (app) { 352 fPrinterName = app->GetPrinter(); 353 } else { 354 fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : ""; 355 } 356 fCurrentPrinter = Printer::Find(fPrinterName); 357 if (fCurrentPrinter) fCurrentPrinter->Acquire(); 358 } 359 } 360 361 void ConfigWindow::SetupPrintersMenu(BMenu* menu) { 362 // clear menu 363 for (int i = menu->CountItems() - 1; i >= 0; i --) { 364 delete menu->RemoveItem(i); 365 } 366 // fill menu with printer names 367 BAutolock lock(gLock); 368 if (lock.IsLocked()) { 369 BString n; 370 BMessage* m; 371 BMenuItem* item; 372 for (int i = 0; i < Printer::CountPrinters(); i ++) { 373 Printer::At(i)->GetName(n); 374 m = new BMessage(MSG_PRINTER_SELECTED); 375 m->AddString("name", n.String()); 376 menu->AddItem(item = new BMenuItem(n.String(), m)); 377 if (n == fPrinterName) item->SetMarked(true); 378 } 379 } 380 } 381 382 void ConfigWindow::UpdateAppSettings(const char* mime, const char* printer) { 383 BAutolock lock(gLock); 384 if (lock.IsLocked()) { 385 Settings* s = Settings::GetSettings(); 386 AppSettings* app = s->FindAppSettings(mime); 387 if (app) app->SetPrinter(printer); 388 else s->AddAppSettings(new AppSettings(mime, printer)); 389 } 390 } 391 392 void ConfigWindow::UpdateSettings(bool read) { 393 BAutolock lock(gLock); 394 if (lock.IsLocked()) { 395 Settings* s = Settings::GetSettings(); 396 PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String()); 397 if (p == NULL) { 398 p = new PrinterSettings(fPrinterName.String()); 399 s->AddPrinterSettings(p); 400 } 401 ASSERT(p != NULL); 402 if (read) { 403 fPageSettings = *p->GetPageSettings(); 404 fJobSettings = *p->GetJobSettings(); 405 } else { 406 p->SetPageSettings(&fPageSettings); 407 p->SetJobSettings(&fJobSettings); 408 } 409 } 410 UpdateUI(); 411 } 412 413 void ConfigWindow::UpdateUI() { 414 if (fCurrentPrinter == NULL) { 415 fPageSetup->SetEnabled(false); 416 if (fJobSetup) { 417 fJobSetup->SetEnabled(false); 418 fJobSetupText->SetText("Undefined job settings"); 419 } 420 fOk->SetEnabled(false); 421 fPageFormatText->SetText("Undefined paper format"); 422 } else { 423 fPageSetup->SetEnabled(true); 424 425 if (fJobSetup) { 426 fJobSetup->SetEnabled(fKind == kJobSetup && !fPageSettings.IsEmpty()); 427 } 428 fOk->SetEnabled(fKind == kJobSetup && !fJobSettings.IsEmpty() || 429 fKind == kPageSetup && !fPageSettings.IsEmpty()); 430 431 // display information about page format 432 BRect paperRect; 433 BString pageFormat; 434 if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) { 435 GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat); 436 437 int32 orientation = 0; 438 fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation); 439 if (orientation == 0) pageFormat << ", Portrait"; 440 else pageFormat << ", Landscape"; 441 } else { 442 pageFormat << "Undefined paper format"; 443 } 444 fPageFormatText->SetText(pageFormat.String()); 445 446 // display information about job 447 if (fKind == kJobSetup) { 448 BString job; 449 int32 first, last; 450 if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK && 451 fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) == B_OK) { 452 if (first >= 1 && first <= last && last != INT_MAX) { 453 job << "From page " << first << " to " << last; 454 } else { 455 job << "All pages"; 456 } 457 int32 copies; 458 if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies) == B_OK && copies > 1) { 459 job << ", " << copies << " copies"; 460 } 461 } else { 462 job << "Undefined job settings"; 463 } 464 465 fJobSetupText->SetText(job.String()); 466 } 467 } 468 } 469 470 void ConfigWindow::Setup(config_setup_kind kind) { 471 if (fCurrentPrinter) { 472 Hide(); 473 if (kind == kPageSetup) { 474 BMessage settings = fPageSettings; 475 if (fCurrentPrinter->ConfigurePage(settings) == B_OK) { 476 fPageSettings = settings; 477 if (!fJobSettings.IsEmpty()) AddFields(&fJobSettings, &fPageSettings); 478 } 479 } else { 480 BMessage settings; 481 if (fJobSettings.IsEmpty()) settings = fPageSettings; 482 else settings = fJobSettings; 483 484 if (fCurrentPrinter->ConfigureJob(settings) == B_OK) 485 fJobSettings = settings; 486 } 487 UpdateUI(); 488 Show(); 489 } 490 } 491