00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define Uses_MsgBox
00036 #define Uses_TDeskTop
00037 #define Uses_TEvent
00038 #define Uses_TFileDialog
00039 #define Uses_TKeys
00040 #define Uses_TMenuBar
00041 #define Uses_TMenuItem
00042 #define Uses_TStatusDef
00043 #define Uses_TStatusItem
00044 #define Uses_TStatusLine
00045 #define Uses_TSubMenu
00046
00047 #include <cstring.h>
00048 #include <fstream.h>
00049
00050 #include <bcarchst.h>
00051 #include <bclarch.h>
00052 #include <bclist.h>
00053 #include <bellcode.h>
00054 #include <callback.h>
00055 #include <lptnote.h>
00056 #include <mytrace.h>
00057 #include <pcbell.h>
00058 #include <sgarchst.h>
00059 #include <sgmlist.h>
00060 #include <sgnlman.h>
00061 #include <spkrnote.h>
00062 #include <tapper.h>
00063 #include <timeout.h>
00064 #include <tmoutlst.h>
00065
00066 #include "bmcdwin.h"
00067 #include "bmconst.h"
00068 #include "bmsgwin.h"
00069 #include "bmsplwin.h"
00070 #include "bmsqwin.h"
00071 #include "bmtprwin.h"
00072
00073
00074 #include "bmapp.h"
00075
00076
00077
00078 using namespace Monitor::BellMaster;
00079 namespace Ut = Monitor::Utility;
00080
00081
00082
00083 static LptNote appLpt(1, 7);
00084 static SpeakerNote appSpeaker(587, 93);
00085 static PcBell localBell(appLpt);
00086 static PcBell remoteBell(appSpeaker);
00087 static Tapper localTapper(remoteBell);
00088 static Tapper remoteTapper(localBell);
00089 static const char* applicationVersion = "2.0";
00090
00091
00092
00093 class AppStatusLine : public TStatusLine
00094 {
00095 public:
00096 AppStatusLine(const TRect& bounds, TStatusDef& aDefs) :
00097 TStatusLine(bounds, aDefs)
00098 {
00099 _USEMYTRACE_("AppStatusLine::AppStatusLine")
00100 }
00101
00102 virtual const char* hint(ushort aHelpCtx);
00103 };
00104
00105
00106
00107 const char*
00108 AppStatusLine::hint(ushort aHelpCtx)
00109 {
00110 _USEMYTRACE_("AppStatusLine::hint")
00111
00112 const char *commandHint("Guess");
00113
00114 switch (aHelpCtx)
00115 {
00116 case Const::hcLoadCodes:
00117 {
00118 commandHint = "Load bell codes from a file";
00119 break;
00120 }
00121 case Const::hcQuit:
00122 {
00123 commandHint = "Exit Bellmaster";
00124 break;
00125 }
00126 case Const::hcBeatCode:
00127 {
00128 commandHint = "Beat a bell code";
00129 break;
00130 }
00131 case Const::hcSignalmanRingCode:
00132 {
00133 commandHint = "Get a signalman to beat out a bell code";
00134 break;
00135 }
00136 case Const::hcLoadSignalman:
00137 {
00138 commandHint = "Load a signalman from a description file";
00139 break;
00140 }
00141 case Const::hcUnloadSignalman:
00142 {
00143 commandHint = "Remove a signalman from the simulation";
00144 break;
00145 }
00146 case Const::hcAbout:
00147 {
00148 commandHint = "Display Bell Master build information";
00149 break;
00150 }
00151 default:
00152 {
00153 commandHint = "";
00154 break;
00155 }
00156 }
00157
00158 return commandHint;
00159 }
00160
00161
00162
00163 App::App() :
00164 TProgInit(&App::initStatusLine,
00165 &App::initMenuBar,
00166 &App::initDeskTop),
00167 bellCodes(new BellCodeList), signalmen(new SignalmanList),
00168 listeningSignalman(0)
00169 {
00170 _USEMYTRACE_("App::App")
00171
00172
00173 SplashWin* splashWindow = new SplashWin(applicationVersion);
00174
00175 new Ut::Timeout(Ut::DataCallback< App, TView* >(*this,
00176 &App::closeModal,
00177 splashWindow),
00178 3000,
00179 "close splash");
00180
00181 TEvent initialEvent;
00182
00183 initialEvent.what = evCommand;
00184 initialEvent.message.command = Const::cmDisplayModal;
00185 initialEvent.message.infoPtr = splashWindow;
00186
00187 putEvent(initialEvent);
00188
00189 loadBellCodesFromFile("default.bcd");
00190 loadSignalmanFromFile("default.sgm");
00191 }
00192
00193
00194
00195 App::~App()
00196 {
00197 _USEMYTRACE_("App::~App")
00198
00199 delete bellCodes, bellCodes = 0;
00200 delete signalmen, signalmen = 0;
00201 }
00202
00203
00204
00205 TStatusLine*
00206 App::initStatusLine(TRect r)
00207 {
00208 _USEMYTRACE_("App::initStatusLine")
00209
00210 r.a.y = r.b.y - 1;
00211 return new AppStatusLine(r,
00212 *new TStatusDef(0,-1) +
00213 *new TStatusItem(0,
00214 kbF10,
00215 cmMenu));
00216 }
00217
00218
00219
00220 TMenuBar*
00221 App::initMenuBar(TRect r)
00222 {
00223 _USEMYTRACE_("App::initMenuBar")
00224
00225 r.b.y = r.a.y + 1;
00226 return new TMenuBar(
00227 r,
00228 *new TSubMenu("~S~imulation",
00229 kbAltS) +
00230 *new TMenuItem("E~x~it",
00231 cmQuit,
00232 kbAltX,
00233 Const::hcQuit,
00234 "Alt-X") +
00235 *new TSubMenu("~C~ode",
00236 kbAltC) +
00237 *new TMenuItem("~B~eat",
00238 Const::cmBeatCode,
00239 kbAltB,
00240 Const::hcBeatCode,
00241 "Alt-B") +
00242 newLine() +
00243 *new TMenuItem("~L~oad",
00244 Const::cmLoadCodes,
00245 kbAltL,
00246 Const::hcLoadCodes,
00247 "Alt-L") +
00248 *new TSubMenu("Si~g~nalman",
00249 kbAltG) +
00250 *new TMenuItem("~R~ing code",
00251 Const::cmSignalmanRingCode,
00252 kbAltR,
00253 Const::hcSignalmanRingCode,
00254 "Alt-R") +
00255 newLine() +
00256 *new TMenuItem("l~O~ad",
00257 Const::cmLoadSignalman,
00258 kbAltO,
00259 Const::hcLoadSignalman,
00260 "Alt-O") +
00261 *new TMenuItem("~U~nload",
00262 Const::cmUnloadSignalman,
00263 kbAltU,
00264 Const::hcUnloadSignalman,
00265 "Alt-U") +
00266 *new TSubMenu("~H~elp",
00267 kbAltH) +
00268 *new TMenuItem("~A~bout",
00269 Const::cmAbout,
00270 kbAltA,
00271 Const::hcAbout,
00272 "Alt-A"));
00273 }
00274
00275
00276
00277 void
00278 App::handleEvent(TEvent& event)
00279 {
00280 TApplication::handleEvent(event);
00281
00282 if (event.what == evCommand)
00283 {
00284 switch (event.message.command)
00285 {
00286 case Const::cmLoadCodes:
00287 loadBellCodeFile();
00288 break;
00289 case Const::cmBeatCode:
00290 beatBellCode(localTapper);
00291 break;
00292 case Const::cmSignalmanRingCode:
00293 signalmanRingCode(remoteTapper);
00294 break;
00295 case Const::cmLoadSignalman:
00296 loadSignalmanFile();
00297 break;
00298 case Const::cmUnloadSignalman:
00299 unloadSignalman();
00300 break;
00301 case Const::cmAbout:
00302 event.message.infoPtr = new SplashWin(applicationVersion);
00303 case Const::cmDisplayModal:
00304 showModal((TView*)event.message.infoPtr);
00305 break;
00306 default:
00307 return;
00308 }
00309
00310 clearEvent(event);
00311 }
00312 }
00313
00314
00315
00316 void
00317 App::idle()
00318 {
00319 TApplication::idle();
00320
00321 TimeoutList::runTimeouts();
00322 }
00323
00324
00325
00326 void
00327 App::loadBellCodeFile()
00328 {
00329 _USEMYTRACE_("App::loadBellCodeFile")
00330
00331 TFileDialog* fileDialog = new TFileDialog("*.bcd",
00332 "Load localBell codes",
00333 "Bell code file",
00334 fdOpenButton,
00335 0);
00336
00337 if (cmCancel != deskTop->execView(fileDialog))
00338 {
00339 char fileName[MAXPATH] = { '\0' };
00340
00341 fileDialog->getFileName(fileName);
00342
00343 loadBellCodesFromFile(fileName);
00344 }
00345
00346 destroy(fileDialog);
00347 }
00348
00349
00350
00351 void
00352 App::loadBellCodesFromFile(const char* fileName)
00353 {
00354 _USEMYTRACE_("App::loadBellCodesFromFile")
00355
00356 fstream localBellCodeStream;
00357
00358 localBellCodeStream.open(fileName, ios::in);
00359
00360 if (localBellCodeStream.rdbuf()->is_open())
00361 {
00362 BellCodeArchiveStream
00363 localBellCodeArchive(localBellCodeStream);
00364 BellCodeListArchive
00365 localBellCodeListArchive(localBellCodeArchive);
00366
00367 localBellCodeListArchive.retrieve(*bellCodes);
00368 }
00369 }
00370
00371
00372
00373 BellCode*
00374 App::selectBellCode(BellCodeList &availableCodes)
00375 {
00376 _USEMYTRACE_("App::selectBellCode")
00377
00378 BellCode *selectedBellCode = 0;
00379
00380 if (1 > availableCodes.size())
00381 {
00382 messageBox("There are no localBell codes available",
00383 mfError | mfOKButton);
00384 }
00385 else
00386 {
00387 TRect bounds = getExtent();
00388 TRect r(bounds.a.x, bounds.a.y, bounds.b.x, bounds.b.y - 2);
00389
00390 CodeWindow* window = new CodeWindow(availableCodes, r);
00391
00392 if (cmCancel != deskTop->execView(window))
00393 {
00394 selectedBellCode = window->getSelectedBellCode();
00395 }
00396
00397 destroy(window);
00398 }
00399
00400 return selectedBellCode;
00401 }
00402
00403
00404
00405 void
00406 App::beatBellCode(Tapper& tapper)
00407 {
00408 _USEMYTRACE_("App::beatBellCode(tapper)")
00409
00410
00411 TapperWin* tapperWindow = new TapperWin(tapper);
00412
00413 remoteBell.addListener(
00414 Ut::DataCallback< App, TapperWin* >(*this,
00415 &App::signalmanHearBell,
00416 tapperWindow));
00417
00418 deskTop->execView(tapperWindow);
00419
00420 destroy(tapperWindow);
00421
00422
00423 if (0 != listeningSignalman)
00424 {
00425 remoteBell.removeListener(listeningSignalman);
00426
00427 const string
00428 heardSequence(listeningSignalman->stopListeningToBell());
00429
00430 TRect bounds = getExtent();
00431 TRect r(bounds.a.x, bounds.a.y, bounds.b.x, bounds.b.y - 2);
00432
00433
00434 BellCodeList matchingBellCodes =
00435 bellCodes->matchSequence(heardSequence);
00436
00437 SequenceWindow* window =
00438 new SequenceWindow(heardSequence, matchingBellCodes, r);
00439
00440 if (cmOK == deskTop->execView(window))
00441 {
00442 listeningSignalman->beatSequence(remoteTapper,
00443 heardSequence);
00444 }
00445
00446 destroy(window);
00447
00448 listeningSignalman = 0;
00449 }
00450 }
00451
00452
00453
00454 void
00455 App::signalmanHearBell(TapperWin* tapperWindow)
00456 {
00457 _USEMYTRACE_("App::signalmanHearBell(tapperWindow)")
00458
00459 listeningSignalman = selectSignalman(*signalmen);
00460
00461 if ((0 != listeningSignalman) && (!listeningSignalman->isBusy()))
00462 {
00463 remoteBell.removeListener(this);
00464
00465 listeningSignalman->listenToBell(
00466 remoteBell,
00467 Ut::DataCallback< App, TView* >(*this,
00468 &App::closeModal,
00469 tapperWindow));
00470 }
00471 }
00472
00473
00474
00475 void
00476 App::signalmanRingCode(Tapper& tapper)
00477 {
00478 _USEMYTRACE_("App::signalmanRingCode(tapper)")
00479
00480 Signalman *selectedSignalman = selectSignalman(*signalmen);
00481
00482 if (0 != selectedSignalman)
00483 {
00484 BellCode *selectedBellCode = selectBellCode(*bellCodes);
00485
00486 if (0 != selectedBellCode)
00487 {
00488 selectedSignalman->beatSequence(tapper,
00489 selectedBellCode->getSequence());
00490 }
00491 }
00492 }
00493
00494
00495
00496 void
00497 App::loadSignalmanFile()
00498 {
00499 _USEMYTRACE_("App::loadSignalmanFile")
00500
00501 TFileDialog* fileDialog = new TFileDialog("*.sgm",
00502 "Load signalman",
00503 "Signalman file",
00504 fdOpenButton,
00505 0);
00506
00507 if (cmCancel != deskTop->execView(fileDialog))
00508 {
00509 char fileName[MAXPATH] = { '\0' };
00510
00511 fileDialog->getFileName(fileName);
00512
00513 loadSignalmanFromFile(fileName);
00514 }
00515
00516 destroy(fileDialog);
00517 }
00518
00519
00520
00521 void
00522 App::loadSignalmanFromFile(const char* fileName)
00523 {
00524 _USEMYTRACE_("App::loadSignalmanFromFile")
00525
00526 fstream signalmanStream;
00527
00528 signalmanStream.open(fileName, ios::in);
00529
00530 if (signalmanStream.rdbuf()->is_open())
00531 {
00532 SignalmanArchiveStream signalmanArchive(signalmanStream);
00533
00534 Signalman retrievedSignalman;
00535
00536 signalmanArchive.retrieve(retrievedSignalman);
00537
00538 signalmen->addSignalman(retrievedSignalman);
00539 }
00540 }
00541
00542
00543
00544 void
00545 App::unloadSignalman()
00546 {
00547 _USEMYTRACE_("App::unloadSignalman")
00548
00549 Signalman *selectedSignalman = selectSignalman(*signalmen);
00550
00551 if (0 != selectedSignalman)
00552 {
00553 signalmen->removeSignalman(*selectedSignalman);
00554 }
00555 }
00556
00557
00558
00559 Signalman*
00560 App::selectSignalman(SignalmanList& availableSignalmen)
00561 {
00562 _USEMYTRACE_("App::selectSignalman")
00563
00564 Signalman *selectedSignalman = 0;
00565
00566 if (1 > availableSignalmen.size())
00567 {
00568 messageBox("There are no signalmen available", mfError | mfOKButton);
00569 }
00570 else if (1 == availableSignalmen.size())
00571 {
00572 selectedSignalman = &availableSignalmen[0];
00573 }
00574 else
00575 {
00576 TRect bounds = getExtent();
00577 TRect r(bounds.a.x, bounds.a.y, bounds.b.x / 2, bounds.b.y / 2);
00578
00579 SignalmanWindow* window =
00580 new SignalmanWindow(availableSignalmen, r);
00581
00582 if (cmCancel != deskTop->execView(window))
00583 {
00584 selectedSignalman = window->getSelectedSignalman();
00585 }
00586
00587 destroy(window);
00588 }
00589
00590 return selectedSignalman;
00591 }
00592
00593
00594
00595 void
00596 App::closeModal(TView* oldView)
00597 {
00598 _USEMYTRACE_("App::closeModal(oldView)")
00599
00600
00601 if (deskTop->TopView() == oldView)
00602 {
00603 oldView->endModal(cmCancel);
00604 }
00605 }
00606
00607
00608
00609 void
00610 App::showModal(TView* newView)
00611 {
00612 _USEMYTRACE_("App::showModal(newView)")
00613
00614
00615 deskTop->execView(newView);
00616 destroy(newView);
00617 }