1 // InfoWindow.cpp
2 // Generated by Interface Elements (Window v2.3) on Feb 23 2004
3 // This is a user written class and will not be overwritten.
4
5 #include <Beep.h>
6 #include <File.h>
7 #include <Resources.h>
8 #include <StorageKit.h>
9 #include <SupportKit.h>
10 #include <AppKit.h>
11 #include <iostream.h>
12
13 #include "InfoWindow.h"
14
15 // A couple helpers classes and functions.
16
17 struct IDItem : public BStringItem
18 {
19 IDItem(const char *name, int32 i);
20 int32 id;
21 };
22
23 /*------------------------------------------------------------*/
24 struct match_info
25 {
match_infomatch_info26 match_info(image_id i) { id = i; found = false; };
27 image_id id;
28 bool found;
29 };
30
31
match_id(BListItem * item,void * data)32 bool match_id(BListItem *item, void *data)
33 {
34 match_info *mi = (match_info *) (data);
35 IDItem *my = dynamic_cast<IDItem*>(item);
36 if (my->id == (mi)->id)
37 {
38 (mi)->found = true;
39 return true;
40 }
41 return false;
42 }
43
44
IDItem(const char * name,int32 i)45 IDItem :: IDItem(const char *name, int32 i)
46 : BStringItem(name)
47 {
48 id = i;
49 };
50
51
52
InfoWindow(void)53 InfoWindow :: InfoWindow(void)
54 : IEWindow("InfoWindow"),
55 fTickToken( BMessenger(this), new BMessage(CMD_TICK), 500000 ), // send message periodically
56 fImportLoc(10,15) // position of imported replicant
57 {
58 Lock();
59 CreateViews();
60 Unlock();
61 }
62
63
~InfoWindow(void)64 InfoWindow::~InfoWindow(void)
65 {
66 SetPrefs();
67 if (fPrefs != NULL) delete fPrefs; // now prefs are saved
68 }
69
70
QuitRequested()71 bool InfoWindow :: QuitRequested()
72 {
73 long c = be_app->CountWindows();
74
75 if (c == 1)
76 {
77 be_app->PostMessage(B_QUIT_REQUESTED);
78 }
79 return true;
80 }
81
82
83 // Handling of user interface and other events
MessageReceived(BMessage * msg)84 void InfoWindow::MessageReceived(BMessage *msg)
85 {
86
87 switch(msg->what)
88 {
89 case CMD_UPDATE_CONTAINER_ITEM:
90 {
91 BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
92 BMenuItem *theItem = theMenu -> FindItem(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
93 theItem -> SetMarked(true);
94 PostMessage(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
95 }
96 break;
97
98 case CMD_TICK:
99 {
100 UpdateLists(false);
101 break;
102 }
103
104 case IE_INFOWINDOW_DELETEBUTTON: // 'DeleteButton' is pressed...
105 {
106 int32 sel = fReplicantList->CurrentSelection();
107 IDItem *item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel));
108 ASSERT(sel >= 0);
109 ASSERT(item);
110 DeleteReplicant(item->id);
111 }
112 break;
113
114
115
116 case IE_INFOWINDOW_COPYBUTTON: // 'CopyButton' is pressed...
117 {
118 BAlert *alert = new BAlert("",
119 "Warning, not all replicants are importable. Importing a "
120 "replicant can crash the Container Demo application. Are you "
121 "willing to give it a try?", "Cancel", "Import", NULL,
122 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
123 BInvoker *inv = new BInvoker(new BMessage(CMD_IMPORT_REPLICANT),this);
124 alert->Go(inv);
125 }
126 break;
127
128
129 case CMD_IMPORT_REPLICANT:
130 {
131 // This message was posted by the Alert above. If 'which' is 1 then
132 // the user pressed the Import button. Otherwise they pressed Cancel.
133 int32 r = msg->FindInt32("which");
134 if (r == 1)
135 {
136 int32 sel = fReplicantList->CurrentSelection();
137 IDItem *item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel));
138 ASSERT(sel >= 0);
139 ASSERT(item);
140 ImportReplicant(item->id);
141 }
142 }
143 break;
144
145
146 case IE_INFOWINDOW_REPLICANTLIST_SELECTION: // list item is selected in 'ReplicantList'
147 {
148 bool enabled;
149 enabled = (fReplicantList->CurrentSelection() >= 0);
150 fDeleteRep->SetEnabled(enabled);
151 fCopyRep -> SetEnabled(enabled);
152 }
153 break;
154
155 case IE_INFOWINDOW_REPLICANTLIST_INVOCATION: // list item is invoked in 'ReplicantList'
156 break;
157
158
159
160 case IE_INFOWINDOW_LIBRARYLIST_SELECTION: // list item is selected in 'LibraryList'
161 {
162 bool enabled;
163 enabled = (fLibraryList->CurrentSelection() >= 0);
164 fUnloadLib->SetEnabled(enabled);
165 }
166 break;
167
168 case IE_INFOWINDOW_LIBRARYLIST_INVOCATION: // list item is invoked in 'LibraryList'
169 break;
170
171 case IE_INFOWINDOW_UNLOADBUTTON: // 'UnloadButton' is pressed...
172 {
173 BAlert *alert = new BAlert("",
174 "Warning, unloading a library that is still in use is pretty bad. "
175 "Are you sure you want to unload this library?",
176 "Cancel", "Unload", NULL,
177 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
178 BInvoker *inv = new BInvoker(new BMessage(CMD_UNLOAD_LIBRARY),this);
179 alert->Go(inv);
180 }
181 break;
182
183 case CMD_UNLOAD_LIBRARY:
184 {
185 // This message was posted by the Alert above. If 'which' is 1 then
186 // the user pressed the Import button. Otherwise they pressed Cancel.
187 int32 r = msg->FindInt32("which");
188 if (r == 1)
189 {
190 int32 sel = fLibraryList->CurrentSelection();
191 IDItem *item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(sel));
192 ASSERT(sel >= 0);
193 ASSERT(item);
194 unload_add_on(item->id);
195 }
196 break;
197 }
198
199 case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW:
200 case IE_POPUPMENU_TARGETPOPUP_DESKBAR:
201 case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW:
202 {
203 fTarget = MessengerForTarget(msg->what);
204 UpdateLists(true);
205 }
206 break;
207
208 case IE_INFOWINDOW_MAINBAR_FILE_NEW: // "New" is selected from menu…
209 break;
210
211 case IE_INFOWINDOW_MAINBAR_FILE_OPEN___: // "Open…" is selected from menu…
212 break;
213
214 case IE_INFOWINDOW_MAINBAR_FILE_SAVE: // "Save" is selected from menu…
215 break;
216
217 case IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___: // "Save As…" is selected from menu…
218 break;
219
220 case IE_INFOWINDOW_MAINBAR_FILE_ABOUT___: // "About…" is selected from menu…
221 PostMessage(B_ABOUT_REQUESTED);
222 break;
223
224 case IE_INFOWINDOW_MAINBAR_FILE_QUIT: // "Quit" is selected from menu…
225 PostMessage(B_QUIT_REQUESTED);
226 break;
227
228 case IE_INFOWINDOW_MAINBAR_EDIT_UNDO: // "Undo" is selected from menu…
229 break;
230
231 case IE_INFOWINDOW_MAINBAR_EDIT_CUT: // "Cut" is selected from menu…
232 break;
233
234 case IE_INFOWINDOW_MAINBAR_EDIT_COPY: // "Copy" is selected from menu…
235 break;
236
237 case IE_INFOWINDOW_MAINBAR_EDIT_PASTE: // "Paste" is selected from menu…
238 break;
239
240
241 case B_ABOUT_REQUESTED:
242 {
243 BAlert *alert = new BAlert("", "XShelfInspector (H.Reh, dr.hartmut.reh@gmx.de) " "\n" "\n"
244 "Based upon ShelfInspector from Be Inc." "\n"
245 "The GUI was created with InterfaceElements (Attila Mezei)" "\n"
246 "Please read the ***Be Sample Code License*** " "\n"
247 ,"OK");
248 alert -> Go(NULL);
249 }
250 break;
251
252
253 default:
254 inherited::MessageReceived(msg);
255 break;
256 }
257
258 }
259
260
EmptyLists()261 void InfoWindow :: EmptyLists()
262 {
263 fReplicantList -> MakeEmpty();
264 fLibraryList -> MakeEmpty();
265 }
266
267
UpdateLists(bool make_empty)268 void InfoWindow::UpdateLists(bool make_empty)
269 {
270 bool deleted_something = false;
271
272 if (!fTarget.IsValid())
273 {
274 EmptyLists();
275 PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION);
276 PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION);
277 return;
278 }
279 if (make_empty)
280 {
281 EmptyLists();
282 deleted_something = true;
283 }
284
285 /*
286 I'm not worried about the allgorithms used below to maintain the 2 lists.
287 That isn't the point of this sample app.
288 */
289
290 image_info info;
291
292 if (!make_empty)
293 {
294 // walk through the current list of images and remove any that are
295 // no longer loaded
296 IDItem *item;
297 int32 i = fLibraryList->CountItems();
298 while ((item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(--i))) != NULL)
299 {
300 image_id id = (image_id) item->id;
301 if (get_image_info(id, &info) != B_OK)
302 {
303 fLibraryList->RemoveItem(item);
304 delete item;
305 deleted_something = true;
306 }
307 }
308 }
309
310 // get all the images for the 'team' of the target. If the image isn't in the
311 // list then add
312 team_id team = fTarget.Team();
313 int32 cookie = 0;
314
315 while (get_next_image_info(team, &cookie, &info) == B_OK)
316 {
317 match_info mi(info.id);
318 fLibraryList->DoForEach(match_id, &mi);
319 if (!mi.found)
320 {
321 fLibraryList->AddItem(new IDItem(info.name, info.id));
322 }
323 }
324
325 // Now it's time to deal with the replicant list
326
327 if (!make_empty)
328 {
329 // walk through the current list of replicants and remove any that are
330 // no longer loaded
331 IDItem *item;
332 int32 i = fReplicantList->CountItems();
333 while ((item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(--i))) != NULL)
334 {
335 int32 uid = item->id;
336 if (IsReplicantLoaded(uid) == false)
337 {
338 fReplicantList->RemoveItem(item);
339 delete item;
340 deleted_something = true;
341 }
342 }
343 }
344
345 // Now get all the replicants from the shelf and make sure that they are in
346 // the list
347 int32 index = 0;
348 int32 uid;
349 while ((uid = GetReplicantAt(index++)) >= B_OK)
350 {
351 // if this uid is already in the list then skip it
352 match_info mi(uid);
353 fReplicantList->DoForEach(match_id, &mi);
354 if (mi.found)
355 {
356 continue;
357 }
358
359 BMessage rep_info;
360 if (GetReplicantName(uid, &rep_info) != B_OK)
361 {
362 continue;
363 }
364
365 const char *name;
366 if (rep_info.FindString("result", &name) == B_OK)
367 {
368 fReplicantList->AddItem(new IDItem(name, uid));
369 }
370 }
371
372
373 if (deleted_something)
374 {
375 PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION);
376 PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION);
377 }
378 }
379
380
381
GetReplicantName(int32 uid,BMessage * reply) const382 status_t InfoWindow :: GetReplicantName(int32 uid, BMessage *reply) const
383 {
384 /*
385 We send a message to the target shelf, asking it for the Name of the
386 replicant with the given unique id.
387 */
388
389 BMessage request(B_GET_PROPERTY);
390 BMessage uid_specifier(B_ID_SPECIFIER); // specifying via ID
391 status_t err;
392 status_t e;
393
394 request.AddSpecifier("Name"); // ask for the Name of the replicant
395
396 // IDs are specified using code like the following 3 lines:
397 uid_specifier.AddInt32("id", uid);
398 uid_specifier.AddString("property", "Replicant");
399 request.AddSpecifier(&uid_specifier);
400
401 if ((err = fTarget.SendMessage(&request, reply)) != B_OK)
402 return err;
403
404 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK))
405 return err ? err : e;
406
407 return B_OK;
408 }
409
IsReplicantLoaded(int32 uid) const410 bool InfoWindow :: IsReplicantLoaded(int32 uid) const
411 {
412 /*
413 determine if the specified replicant (the unique ID of the replicant)
414 still exists in the target container/shelf. If we can get the name then the
415 replicant still exists.
416 */
417 BMessage reply;
418 status_t err = GetReplicantName(uid, &reply);
419 return (err == B_OK);
420 }
421
422
GetReplicantAt(int32 index) const423 int32 InfoWindow::GetReplicantAt(int32 index) const
424 {
425 /*
426 So here we want to get the Unique ID of the replicant at the given index
427 in the target Shelf.
428 */
429
430 BMessage request(B_GET_PROPERTY); // We're getting the ID property
431 BMessage reply;
432 status_t err;
433
434 request.AddSpecifier("ID"); // want the ID
435 request.AddSpecifier("Replicant", index); // of the index'th replicant
436
437 if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
438 return err;
439
440 int32 uid;
441 if ((err = reply.FindInt32("result", &uid)) != B_OK)
442 return err;
443
444 return uid;
445 }
446
447
MessengerForTarget(type_code w) const448 BMessenger InfoWindow :: MessengerForTarget(type_code w) const
449 {
450 /*
451 This function determines the BMessenger to the various Shelf objects
452 that this app can talk with.
453 */
454 BMessage request(B_GET_PROPERTY);
455 BMessenger to;
456 BMessenger result;
457
458 request.AddSpecifier("Messenger");
459 request.AddSpecifier("Shelf");
460
461 switch (w)
462 {
463 case IE_POPUPMENU_TARGETPOPUP_DESKBAR:
464 {
465 request.AddSpecifier("View", "Status");
466 request.AddSpecifier("Window", "Deskbar");
467 to = BMessenger("application/x-vnd.Be-TSKB", -1);
468 break;
469 }
470
471 case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW:
472 {
473 // The Desktop is owned by Tracker and the Shelf is in the
474 // View "PoseView" in Window "Desktop"
475 request.AddSpecifier("View", "PoseView");
476 request.AddSpecifier("Window", "/boot/home/Desktop");
477 to = BMessenger("application/x-vnd.Be-TRAK", -1);
478 break;
479 }
480
481 case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW:
482 {
483 // In the COntainer Demo app the View "MainView" in the only window
484 // is the Shelf.
485 request.AddSpecifier("View", "ContainerView"); // Hier werden Replikanten abgelegt
486 request.AddSpecifier("Window", (int32) 0);
487 to = BMessenger(XCONTAINER_APP, -1);
488 // This demo app isn't worried about the Container app going away
489 // (quitting) unexpectedly.
490 break;
491 }
492 }
493
494 BMessage reply;
495
496 if (to.SendMessage(&request, &reply) == B_OK)
497 {
498 //reply.PrintToStream();
499 reply.FindMessenger("result", &result);
500 }
501 return result;
502 }
503
504
DeleteReplicant(int32 uid)505 status_t InfoWindow :: DeleteReplicant(int32 uid)
506 {
507 // delete the given replicant from the current target shelf
508
509 BMessage request(B_DELETE_PROPERTY); // Delete
510 BMessage uid_specifier(B_ID_SPECIFIER); // specifying via ID
511 BMessage reply;
512 status_t err;
513 status_t e;
514
515 // IDs are specified using code like the following 3 lines:
516 uid_specifier.AddInt32("id", uid);
517 uid_specifier.AddString("property", "Replicant");
518 request.AddSpecifier(&uid_specifier);
519
520 if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
521 return err;
522
523 if ((err = reply.FindInt32("error", &e)) != B_OK)
524 return err;
525
526 return e;
527 }
528
529
ImportReplicant(int32 uid)530 status_t InfoWindow :: ImportReplicant(int32 uid)
531 {
532 // Import the given replicant from the current target shelf
533 // That is get a copy and recreate it in the "Container" window of
534 // this app.
535
536 BMessage request(B_GET_PROPERTY); // Get will return the archive msg
537 BMessage uid_specifier(B_ID_SPECIFIER); // specifying via ID
538 BMessage reply;
539 status_t err;
540 status_t e;
541
542 // IDs are specified using code like the following 3 lines:
543 uid_specifier.AddInt32("id", uid);
544 uid_specifier.AddString("property", "Replicant");
545 request.AddSpecifier(&uid_specifier);
546
547 if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
548 return err;
549
550 if (((err = reply.FindInt32("error", &e)) != B_OK) || (e != B_OK))
551 return err;
552
553 // OK, let's get the archive message
554 BMessage data;
555 reply.FindMessage("result", &data);
556
557 // Now send this to the container window. If someone closed it then the
558 // Send will fail. Oh well.
559 BMessenger mess = MessengerForTarget(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
560 BMessage msg(B_CREATE_PROPERTY);
561
562 msg.AddMessage("data", &data);
563
564 // As this is a Demo I'm not going to worry about some fancy layout
565 // algorithm. Just keep placing new replicants going down the window
566 msg.AddPoint("location", fImportLoc);
567 fImportLoc.y += 40;
568
569 return mess.SendMessage(&msg, &reply);
570 }
571
572
573
574 // Update the menu items before they appear on screen
MenusBeginning()575 void InfoWindow::MenusBeginning()
576 {
577 // Complete the SetEnabled argument or do anything with the source below...
578 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_NEW)->SetEnabled(false); // "New"
579 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_OPEN___)->SetEnabled(false); // "Open…"
580 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE)->SetEnabled(false); // "Save"
581 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___)->SetEnabled(false); // "Save As…"
582 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_ABOUT___)->SetEnabled(true); // "About…"
583 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_QUIT)->SetEnabled(true); // "Quit"
584 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_UNDO)->SetEnabled(false); // "Undo"
585 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_CUT)->SetEnabled(false); // "Cut"
586 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_COPY)->SetEnabled(false); // "Copy"
587 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_PASTE)->SetEnabled(false); // "Paste"
588 }
589
590
591
592
ReadMessageFromResource(const char * resName)593 BMessage *InfoWindow :: ReadMessageFromResource(const char *resName)
594 {
595 // Hier wird aus der Resource die Message gelesen
596 app_info ai;
597 BFile file;
598 BResources res;
599 size_t res_size;
600 const void* res_addr;
601
602 BMessage* archive = new BMessage;
603
604 if( (be_app->GetAppInfo(&ai) != B_OK)
605 ||(file.SetTo(&ai.ref,B_READ_ONLY) != B_OK)
606 ||(res.SetTo(&file) != B_OK)
607 ||((res_addr = res.LoadResource('ARCV',resName,&res_size)) == NULL)
608 ||(archive -> Unflatten((const char*)res_addr) != B_OK) )
609 // Resource muss 'ARCV' - Typ sein -> in IE einstellen
610 // Resource of type 'ARCV'
611 {
612 delete archive;
613 return NULL;
614 }
615 return archive;
616 }
617
618
CreateViews()619 void InfoWindow:: CreateViews()
620 {
621 BMessage *archive = ReadMessageFromResource("PopUpMenu"); // Menu Feld from Resource
622 if (archive)
623 {
624 fMenuField = new BMenuField(archive);
625 delete archive;
626 }
627
628 fMainBox = (BBox *)FindView("MainBox"); // Pointer to MainBox
629 fMainBox->SetLabel(fMenuField); // Replace Label
630
631 fReplicantList = (BListView *) FindView("ReplicantList");
632 fLibraryList = (BListView *) FindView("LibraryList");
633
634 fDeleteRep = (BButton *) FindView("DeleteButton");
635 fCopyRep = (BButton *) FindView("CopyButton");
636 fUnloadLib = (BButton *) FindView("UnloadButton");
637
638 BScrollView *libScrollView = (BScrollView *)FindView("LibraryScroll");
639 BScrollBar *horLibScrollBar = libScrollView -> ScrollBar(B_HORIZONTAL);
640 horLibScrollBar -> SetRange(0, 400);
641 horLibScrollBar -> SetProportion(0.4);
642
643 BScrollView *repScrollView = (BScrollView *)FindView("ReplicantScroll");
644 BScrollBar *horRepScrollBar = repScrollView -> ScrollBar(B_HORIZONTAL);
645 horRepScrollBar -> SetRange(0, 400);
646 horRepScrollBar -> SetProportion(0.4);
647 }
648
649
GetPrefs()650 void InfoWindow :: GetPrefs()
651 {
652 status_t err;
653 BRect windFrame;
654 int32 targetShelf;
655
656 fPrefs = new TPreferences ("XShelfInspector/preferences"); // Name des Prefs-Files
657 if (fPrefs -> InitCheck() != B_OK) // falls keine Prefs -> erzeugen
658 {
659 windFrame = Frame(); // Window Frame aus Resource ermitteln
660 fPrefs -> SetRect ("WindowFrame", windFrame );
661
662 targetShelf = IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW; // XContainerWindow
663 fPrefs -> SetInt32 ("TargetShelf", targetShelf );
664 }
665
666 err = (fPrefs -> FindRect ("WindowFrame", &windFrame) );
667 if (err == B_OK)
668 {
669 ResizeTo(windFrame.Width(), windFrame.Height() ); // Fensterposition und Größe
670 MoveTo(windFrame.left, windFrame.top); // aus Preferences
671 }
672
673 err = (fPrefs -> FindInt32 ("TargetShelf", &targetShelf ) );
674 if (err == B_OK)
675 {
676 BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
677 BMenuItem *theItem = theMenu -> FindItem(targetShelf);
678 theItem -> SetMarked(true);
679 PostMessage(targetShelf); // TargetShelf
680 }
681 }
682
683
SetPrefs()684 void InfoWindow :: SetPrefs()
685 {
686 fPrefs -> SetRect ("WindowFrame", Frame() );
687
688 BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
689 BMenuItem *theItem = theMenu -> FindMarked();
690 int32 targetShelf = theItem -> Command();
691 fPrefs -> SetInt32("TargetShelf", targetShelf);
692 }
693
694
695