// =========================================================================== // CSimlabDoc.cp ©1995 J. Rodden, DD/MF & Associates. All rights reserved // =========================================================================== #include "RuntimeTypes.h" #include "RuntimeMessages.h" #include "RuntimeResources.h" #include "CSimlabApp.h" #include "CSimlabDoc.h" #include "CSimlabToolbar.h" #include "CSimlabConstPanel.h" #include "CSimlabEditListRec.h" #include "CSimlabListBox.h" #include "CSimlabPropsListBox.h" #include "CSimlabHVarListBox.h" #include "SModel.h" #include <3DAttachments.h> #include <3DDrawingUtils.h> #include #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- const Int16 kWinPosOffset = 10; const Int16 kWinVertOffset = GetMBarHeight() + 10; const Int32 kConstPaneHeight = 22; const ResIDT res_ProjWinState = 1; const ResIDT res_InputWinState = 2; const ResIDT res_StateWinState = 3; const ResIDT res_OutputsWinState = 4; const ResIDT res_GraphsListState = 5; const ResIDT res_SettingsTblState = 6; const ResType rSettingsType = 'STNG'; const ResType rGraphsType = 'GRPH'; const ResType rInputsType = 'INPT'; const ResType rStateVarType = 'STAT'; const ResType rOutputsType = 'OUTP'; // --------------------------------------------------------------------------- static StringPtr sSimlabGraphData[] = { "\pGraph1", "\pGraph2", "\pGraph3", "\pGraph4", "\pGraph5", "\pGraph6", "\pGraph7", "\pGraph8", "\pGraph9" } ; static StringPtr sSimlabConstData[] = { "\pConstant1", "\pConstant2", "\pConstant3", "\pConstant4", "\pConstant5", "\pConstant6", "\pConstant7", "\pConstant8", "\pConstant9" } ; static StringPtr sSimlabSetupData[] = { "\pSetupVar1", "\pSetupVar2", "\pSetupVar3", "\pSetupVar4", "\pSetupVar5", "\pSetupVar6" } ; static StringPtr sInputs[] = { "\pInputVar1", "\pInputVar2", "\pInputVar3", "\pInputVar4" } ; static StringPtr sStateVars[] = { "\pStateVar1", "\pStateVar2", "\pStateVar3", "\pStateVar4", "\pStateVar5", "\pStateVar6" } ; static StringPtr sOutputs[] = { "\pOutputVar1", "\pOutputVar2", "\pOutputVar3", "\pOutputVar4", "\pOutputVar5" } ; // --------------------------------------------------------------------------- // € Prototypes for local functions // --------------------------------------------------------------------------- static void SetupGraphsList( CSimlabListBox* inListBox); static void SetupVariablesList( CSimlabHVarListBox* inListBox); static void SetupConstsList(LView* inView, LCommander* inCommander, LListener* inListener); static void AddToBottomPanel(LView* inView, Int32 inTop, Str255 inString, SimlabListTag inTag, LCommander* inCommander, LListener* inListener); static void FillHierList( CSimlabHierListBox* inListBox, ResType inResType, short inElementList); static void DeleteResource(ResType inResType, short index); // --------------------------------------------------------------------------- // € CSimlabDoc(LCommander*, FSSpec*) // --------------------------------------------------------------------------- // Construct a SimlabDoc associated with the specified file // // If inFileSpec is nil, then create an empty, untitled document CSimlabDoc::CSimlabDoc( LCommander *inSuper, FSSpec *inFileSpec) : CWindowedDoc( inSuper, inFileSpec, WIND_ProjectWin, res_ProjWinState), mSubWindows(sizeof(LWindow*)), mModel(nil), mModelStatus(NotExecutable) { if ( mFile != nil ) { OpenFile(); } else { SysBeep(1); delete this; return; } SetupDisplays(); mWindow->Show(); AddListener( ((CSimlabApp*) GetSuperCommander())->GetToolbar() ); BroadcastMessage( msg_AdjustState, &mModelStatus); } // --------------------------------------------------------------------------- // € ~CSimlabDoc // --------------------------------------------------------------------------- CSimlabDoc::~CSimlabDoc() { // Close all windows BEFORE broadcasting that we're going away // so that views menu is properly emptied of document views // before app does its view menu cleanup. CloseAllSubWindows(); mModelStatus = NoModel; BroadcastMessage(msg_AdjustState,&mModelStatus); BroadcastMessage(msg_DocumentDied,this); if ( mModel ) delete mModel; } // --------------------------------------------------------------------------- // € GetDescriptor // --------------------------------------------------------------------------- // Pass back the name of a Document StringPtr CSimlabDoc::GetDescriptor( Str255 outDescriptor) const { CopyPStr("\p€", outDescriptor); return outDescriptor; } // --------------------------------------------------------------------------- // € DoCommand // --------------------------------------------------------------------------- // Functions the same as ObeyCommand, but called by CSimlabApp // Respond to commands Boolean CSimlabDoc::DoCommand( CommandT inCommand, void *ioParam) { Boolean cmdHandled = true; Str255 theString; Int16 menuItem; if ( ::IsSyntheticCommand( inCommand, MENU_Views, menuItem, theString) ) { ActivateSubWindow(theString); return true; } switch (inCommand) { // Model Menu commands case cmd_Graphs: case cmd_GraphNew: case cmd_GraphEdit: SetupGraphDefWin(); break; case cmd_Settings: case cmd_SettingSave: LWindow::CreateWindow(DIAG_Setting, this); break; case cmd_SettingDefault: break; // Control Menu commands case cmd_InputFrom: case cmd_OutputTo: break; case cmd_Run: case cmd_Pause: case cmd_Stop: case cmd_Step: case cmd_Reset: UpdateStatus(inCommand); break; // Views Menu Commands case cmd_Arrange: ArrangeSubWindows(); break; case cmd_CloseAll: CloseAllSubWindows(); break; case cmd_ProjectWindow: UDesktop::SelectDeskWindow(mWindow); break; case cmd_OpenDescription: FSSpec fileSpec; mFile->GetSpecifier(fileSpec); LaunchApplication(SimlabEditorSignature); SendAppAEOpen(fileSpec, SimlabEditorSignature); break; case cmd_GraphList: ::GetIndString( theString, STRx_SubWin_Strs, str_Graphs); OpenSubWindow( WIND_Graphs, res_GraphsListState, msg_CloseGraphList, theString); break; case cmd_SettingsTbl: ::GetIndString( theString, STRx_SubWin_Strs, str_Settings); OpenSubWindow( WIND_SttingsTbl, res_SettingsTblState, msg_CloseStngsTbl, theString); break; case cmd_ModelInputsWin: case cmd_StateVarsWin: case cmd_ModelOutputsWin: OpenVarWindow(inCommand); break; } return cmdHandled; } // --------------------------------------------------------------------------- // € ListenToMessage // --------------------------------------------------------------------------- void CSimlabDoc::ListenToMessage(MessageT inMessage, void *ioParam) { Handle theHandle = nil; AliasHandle theAlias = nil; short resIndex = *((short*)ioParam); ::UseResFile(mFile->GetResourceForkRefNum()); switch ( LoWord(inMessage) ) { case msg_OpenSettings: case msg_OpenGraph: SysBeep(1); break; case cmd_ModelInputsWin: case cmd_StateVarsWin: case cmd_ModelOutputsWin: DoCommand(LoWord(inMessage),nil); break; case msg_CloseGraphList: case msg_CloseStngsTbl: case msg_CloseInputsWin: case msg_CloseStateWin: case msg_CloseOutputsWin: case msg_CloseGraphDef: CloseSubWindow(LoWord(inMessage),(LWindow*)ioParam); break; case msg_DeleteSetting: if ( resIndex > 1 ) DeleteResource( rSettingsType, resIndex); break; case msg_DeleteGraph: if ( resIndex > 0 ) DeleteResource( rGraphsType, resIndex); break; /* case msg_OpenSourceFile: // This one has some work done here, then gets passed up the command chain FSSpec theFileSpec; if ( resIndex == 1 ) { // Open this FSSpec mFile->GetSpecifier(theFileSpec); } else if ( resIndex > 1 ) { // Open stored FSSpec (an alias) Boolean wasChanged; theAlias = (AliasHandle) ::Get1IndResource( rAliasType, resIndex - 1); ::ResolveAlias( nil, theAlias, &theFileSpec, &wasChanged); } ioParam = &theFileSpec; */ default: BroadcastMessage(inMessage,ioParam); } if ( theHandle != nil ) ::ReleaseResource(theHandle); if ( theAlias != nil ) ::ReleaseResource(Handle(theAlias)); } // --------------------------------------------------------------------------- // € GetCommandStatus // --------------------------------------------------------------------------- // Functions the same as FindCommandStatus, but called by CSimlabApp // Return whether a Command is enabled and/or marked (in a Menu) Boolean CSimlabDoc::GetCommandStatus( CommandT inCommand, Boolean &outEnabled, Boolean &outUsesMark, Char16 &outMark, Str255 outName) { Boolean cmdHandled = true; outUsesMark = false; switch (inCommand) { case MENU_Graphs: case cmd_Graphs: case cmd_GraphNew: case cmd_GraphEdit: case MENU_Settings: case cmd_Settings: case cmd_SettingSave: case cmd_SettingDefault: case cmd_Run: case cmd_Pause: case cmd_Stop: case cmd_Step: case cmd_Reset: //case cmd_InputFrom: //case cmd_OutputTo: outEnabled = ( mModelStatus != NotExecutable ); break; case cmd_Arrange: case cmd_CloseAll: case cmd_ProjectWindow: case cmd_OpenDescription: case cmd_GraphList: case cmd_SettingsTbl: case cmd_ModelInputsWin: case cmd_StateVarsWin: case cmd_ModelOutputsWin: outEnabled = true; break; default: cmdHandled = false; break; } return cmdHandled; } // --------------------------------------------------------------------------- // € UpdateStatus // --------------------------------------------------------------------------- Boolean CSimlabDoc::IsCurrentProjectFile(FSSpec& inFileSpec) { FSSpec theFileSpec; mFile->GetSpecifier(theFileSpec); return ( inFileSpec.vRefNum == theFileSpec.vRefNum && inFileSpec.parID == theFileSpec.parID && EqualString( inFileSpec.name, theFileSpec.name, false, true) ); } // --------------------------------------------------------------------------- // € UpdateStatus // --------------------------------------------------------------------------- void CSimlabDoc::UpdateStatus(CommandT inCommand) { switch (inCommand) { case cmd_Reset: //assert(mModelStatus != NotExecutable); break; case cmd_Stop: //assert(mModelStatus != NotExecutable); mModelStatus = Stopped; break; case cmd_Pause: //assert(mModelStatus != NotExecutable); mModelStatus = Paused; break; case cmd_Run: //assert(mModelStatus != NotExecutable); mModelStatus = Running; break; } BroadcastMessage(msg_AdjustState,&mModelStatus); } // --------------------------------------------------------------------------- // € SetupGraphDefWin // --------------------------------------------------------------------------- void CSimlabDoc::SetupGraphDefWin() { Try_ { LWindow* theWin = LWindow::CreateWindow(WIND_GraphDef, this); ThrowIfNil_(theWin); theWin->SetUserCon(msg_CloseGraphDef); theWin->Show(); mSubWindows.InsertItemsAt( 1, arrayIndex_Last, &theWin); } Catch_(inErr) { SysBeep(1); } EndCatch_ } // --------------------------------------------------------------------------- // € OpenVarWindow // --------------------------------------------------------------------------- void CSimlabDoc::OpenVarWindow(MessageT inMessage) { Int16 strIndex = 0; MessageT winMessage = 0; ResIDT winStateResID = 0; switch ( inMessage ) { case cmd_ModelInputsWin: strIndex = str_ModelInputs; winMessage = msg_CloseInputsWin; winStateResID = res_InputWinState; break; case cmd_StateVarsWin: strIndex = str_StateVariables; winMessage = msg_CloseStateWin; winStateResID = res_StateWinState; break; case cmd_ModelOutputsWin: strIndex = str_ModelOutputs; winMessage = msg_CloseOutputsWin; winStateResID = res_OutputsWinState; break; }; Str255 theString; ::GetIndString( theString, STRx_VarList_Strs, strIndex); LWindow* theWin = OpenSubWindow( WIND_Variables, winStateResID, winMessage, theString, false); if (theWin != nil) { CSimlabListBox* theListBox = (CSimlabListBox*) theWin->FindPaneByID(PaneID_VarsListBox); if (theListBox) theListBox->SetEmptyStringID(str_NoVariables); theWin->Show(); } } // --------------------------------------------------------------------------- // € OpenSubWindow // --------------------------------------------------------------------------- LWindow* CSimlabDoc::OpenSubWindow( ResIDT inWindowID, ResIDT inStateResID, MessageT inWinMessage, Str255 inString, Boolean inShowIt) { UHiddenWindow* theWin = (UHiddenWindow*) FindSubWindow(inString); if ( theWin == nil ) { Try_ { theWin = (UHiddenWindow*) LWindow::CreateWindow(inWindowID, this); ThrowIfNil_(theWin); theWin->SetUserCon(inWinMessage); theWin->SetDescriptor(inString); theWin->AddListener(this); UWindowState::RestoreWindowState( mFile, theWin, inStateResID); mSubWindows.InsertItemsAt( 1, arrayIndex_Last, &theWin); UDynamicMenu::AppendItem( MENU_Views, inString, true, viewMenuLine2Pos); if (inShowIt) theWin->Show(); } Catch_(inErr) { SysBeep(1); } EndCatch_ } else { UDesktop::SelectDeskWindow(theWin); } return theWin; } // --------------------------------------------------------------------------- // € FindSubWindow // --------------------------------------------------------------------------- LWindow* CSimlabDoc::FindSubWindow(Str255 inWinTitle) { Str255 winName; LWindow* theWin = nil; LListIterator iterator(mSubWindows, iterate_FromStart); while (iterator.Next(&theWin)) { theWin->GetDescriptor(winName); if (IUEqualString(inWinTitle, winName) == 0) break; else theWin = nil; } return theWin; } // --------------------------------------------------------------------------- // € ActivateSubWindow // --------------------------------------------------------------------------- void CSimlabDoc::ActivateSubWindow(Str255 inWinTitle) { LWindow* theWin = FindSubWindow(inWinTitle); if (theWin) UDesktop::SelectDeskWindow(theWin); } // --------------------------------------------------------------------------- // € CloseSubWindow // --------------------------------------------------------------------------- void CSimlabDoc::CloseSubWindow(MessageT inMessage, LWindow* inWindow) { ResIDT winStateResID = 0; if ( inWindow != nil ) { Str255 winTitle; inWindow->GetDescriptor(winTitle); UDynamicMenu::RemoveItem(MENU_Views, winTitle, true, viewMenuLine2Pos); switch ( inMessage ) { case msg_CloseInputsWin: winStateResID = res_InputWinState; break; case msg_CloseStateWin: winStateResID = res_StateWinState; break; case msg_CloseOutputsWin: winStateResID = res_OutputsWinState; break; case msg_CloseGraphList: winStateResID = res_GraphsListState; break; case msg_CloseStngsTbl: winStateResID = res_SettingsTblState; break; } if (winStateResID) UWindowState::SaveWindowState( mFile, inWindow, winStateResID); mSubWindows.Remove(&inWindow); delete inWindow; } } // --------------------------------------------------------------------------- // € CloseAllSubWindows // --------------------------------------------------------------------------- void CSimlabDoc::CloseAllSubWindows() { LWindow *theWin = nil; while (mSubWindows.GetCount() > 0) { mSubWindows.FetchItemAt( 1, &theWin); CloseSubWindow( theWin->GetUserCon(), theWin); } } // --------------------------------------------------------------------------- // € ArrangeSubWindows // --------------------------------------------------------------------------- void CSimlabDoc::ArrangeSubWindows() { LWindow* theWin = nil; Point winPos = { kWinVertOffset + kWinPosOffset, kWinPosOffset}; LListIterator iterator( mSubWindows, iterate_FromStart); while ( iterator.Next(&theWin) ) { UDesktop::SelectDeskWindow(theWin); theWin->DoSetPosition(winPos); winPos.v += kWinPosOffset; winPos.h += kWinPosOffset; } } // --------------------------------------------------------------------------- // € NameNewDoc // --------------------------------------------------------------------------- void CSimlabDoc::NameNewDoc() { StandardFileReply macFileReply; UDesktop::Deactivate(); ::StandardPutFile( "\pSave New Model As", "\pUntitled.µ", &macFileReply); UDesktop::Activate(); if (macFileReply.sfGood) { mFile = new LFile(macFileReply.sfFile); OpenFile(); } } // --------------------------------------------------------------------------- // € OpenFile // --------------------------------------------------------------------------- // Open a new document for the specified File void CSimlabDoc::OpenFile() { // read in Simlab model information. Try_ { ::UseResFile(mFile->OpenResourceFork(fsRdWrShPerm)); FSSpec fileSpec; mFile->GetSpecifier(fileSpec); PtoCstr(fileSpec.name); Handle theXCODh, theSYMBh; if ( (theXCODh = ::Get1Resource(XCOD, 128)) != nil && (theSYMBh = ::Get1Resource(SYMB, 128)) != nil ) { mModel = new SModel; ThrowIfNil_(mModel); ::DetachResource(theXCODh); ::DetachResource(theSYMBh); mModelStatus = Executable; //mModel->LoadResources( (char*)fileSpec.name, theXCODh, theSYMBh); if ( mModelStatus == NotExecutable ) mModel = nil; } else { mModelStatus = NotExecutable; } } Catch_(inErr) { delete this; Throw_(inErr); } EndCatch_ } // --------------------------------------------------------------------------- // € SettupDisplays // --------------------------------------------------------------------------- void CSimlabDoc::SetupDisplays() { LPane* theListBox; ::UseResFile(mFile->GetResourceForkRefNum()); // ------------------------------ // Setup Graphs List theListBox = mWindow->FindPaneByID(PaneID_GraphsListBx); if (theListBox) { ((CSimlabListBox*)theListBox)->AddListener(this); SetupGraphsList((CSimlabListBox*)theListBox); } // -------------------- // Setup Variables List theListBox = mWindow->FindPaneByID(PaneID_VarsListBox); if (theListBox) { ((CSimlabHVarListBox*)theListBox)->AddListener(this); SetupVariablesList((CSimlabHVarListBox*)theListBox); } // -------------------- // Setup Project Window's Divided View CDividedView* theDividedView; theDividedView = (CDividedView*) mWindow->FindPaneByID(PaneID_TopPanel); theDividedView->InstallFirstView((LView*) mWindow->FindPaneByID(PaneID_GraphsView),true); theDividedView->InstallSecondView((LView*) mWindow->FindPaneByID(PaneID_VarsView),true); theDividedView->AddAttachment(new C3DRaisedBorderAttachment); theDividedView = (CDividedView*) mWindow->FindPaneByID(PaneID_MainDivdView); theDividedView->InstallFirstView((LView*) mWindow->FindPaneByID(PaneID_TopPanel),true); theDividedView->InstallSecondView((LView*) mWindow->FindPaneByID(PaneID_BtmPanel),true); theDividedView->AddAttachment(new C3DRaisedPanelAttachment); // ------------------------------ // Setup Bottom Panel LView* theBottomPanel = (LView*) mWindow->FindPaneByID(PaneID_ConstView); theBottomPanel->AddAttachment(new C3DRaisedBorderAttachment); SetupConstsList( theBottomPanel, mWindow, this); // -------------------- // Setup Project Window's Focus Boxes //LFocusBox* theFocusBox; // //theFocusBox = new LFocusBox; //theFocusBox->AttachPane(mWindow->FindPaneByID(PaneID_GraphsFocus)); // //theFocusBox = new LFocusBox; //theFocusBox->AttachPane(mWindow->FindPaneByID(PaneID_VarsFocus)); } // --------------------------------------------------------------------------- // € SetupGraphsList [static] // --------------------------------------------------------------------------- void SetupGraphsList( CSimlabListBox* inListBox) { short num; inListBox->ClearDisplay(str_NoGraphs); ::LSetDrawingMode( false, inListBox->GetMacListH()); num = sizeof (sSimlabGraphData) / sizeof(StringPtr); for ( short i = 0 ; i < num ; i++) { inListBox->AppendElement( sSimlabGraphData[i], tagGraph); } ::LSetDrawingMode( true, inListBox->GetMacListH()); } // --------------------------------------------------------------------------- // € SetupVariablesList [static] // --------------------------------------------------------------------------- void SetupVariablesList( CSimlabHVarListBox* inListBox) { Cell theCell = { 0, 0}; Str255 theString; inListBox->SetIndentDistance(0); ::LSetDrawingMode( false, inListBox->GetMacListH()); for ( short i = 1 ; i <= num_VarList_Strs ; i++, theCell.v++) { ::GetIndString( theString, STRx_VarList_Strs, i); CSimlabListRec* newElement = new CSimlabEditListRec( SimlabListTag(tagInput+i-1), theString); inListBox->AddElementData( theCell, (Ptr)newElement, true, 0); } ::LSetDrawingMode( true, inListBox->GetMacListH()); // Fill in dummy values short num; ::LSetDrawingMode( false, inListBox->GetMacListH()); num = sizeof (sInputs) / sizeof(StringPtr); for ( short i = 0 ; i < num ; i++) { inListBox->AddSubListElement( 1, sInputs[i]); } num = sizeof (sStateVars) / sizeof(StringPtr); for ( short i = 0 ; i < num ; i++) { inListBox->AddSubListElement( 2, sStateVars[i]); } num = sizeof (sOutputs) / sizeof(StringPtr); for ( short i = 0 ; i < num ; i++) { inListBox->AddSubListElement( 3, sOutputs[i]); } ::LSetDrawingMode( true, inListBox->GetMacListH()); //FillHierList( inListBox, rInputsType, 1); //FillHierList( inListBox, rStateVarType, 2); //FillHierList( inListBox, rOutputsType, 3); } // --------------------------------------------------------------------------- // € SetupConstsList [static] // --------------------------------------------------------------------------- void SetupConstsList(LView* inView, LCommander* inCommander, LListener* inListener) { short i, j, num; num = sizeof (sSimlabConstData) / sizeof(StringPtr); for ( i = 0 ; i < num ; i++) { AddToBottomPanel( inView, i, sSimlabConstData[i], tagConstant, inCommander, inListener); } num = sizeof (sSimlabSetupData) / sizeof(StringPtr); for ( j = 0 ; j < num ; j++, i++) { AddToBottomPanel( inView, i, sSimlabSetupData[j], tagSetupVar, inCommander, inListener); } } // --------------------------------------------------------------------------- // € AddToBottomPanel [static] // --------------------------------------------------------------------------- void AddToBottomPanel( LView* inView, Int32 inPaneID, Str255 inString, SimlabListTag inTag, LCommander* inCommander, LListener* inListener) { SDimension16 inViewSize; inView->GetFrameSize(inViewSize); SViewInfo theViewInfo = { { 0, 0}, { 0, 0}, { 1, 1}, false}; SPaneInfo thePaneInfo; // Universal pane settings thePaneInfo.userCon = 0; thePaneInfo.paneID = inPaneID; thePaneInfo.visible = true; thePaneInfo.enabled = true; thePaneInfo.bindings.left = true; thePaneInfo.bindings.top = false; thePaneInfo.bindings.right = true; thePaneInfo.bindings.bottom = false; // Setup containing view thePaneInfo.left = 0; thePaneInfo.top = inPaneID*kConstPaneHeight; thePaneInfo.width = inViewSize.width; thePaneInfo.height = kConstPaneHeight; thePaneInfo.superView = inView; new CSimlabConstPanel(thePaneInfo, theViewInfo, inCommander, inListener, inString, inTag); inView->ResizeImageBy(0,kConstPaneHeight,true); } // --------------------------------------------------------------------------- // € FillHierList [static] // --------------------------------------------------------------------------- void FillHierList( CSimlabHierListBox* inListBox, ResType inResType, short inElementList) { Str255 theString; short num = ::Count1Resources(inResType); for ( short i = 0; i <= num ; i++) { Handle theHandle = ::Get1IndResource( inResType, i); if ( theHandle != nil ) { short rID; ResType rType; ::GetResInfo( theHandle, &rID, &rType, theString); inListBox->AddSubListElement( inElementList, theString); } } } // --------------------------------------------------------------------------- // € DeleteResource [static] // --------------------------------------------------------------------------- void DeleteResource(ResType inResType, short index) { Handle theHandle = ::Get1IndResource( inResType, index); ::RemoveResource(theHandle); ::DisposeHandle(theHandle); }