5 * Created by Toshi Nagata on 08/10/24.
6 * Copyright 2008 Toshi Nagata. All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
18 // For compilers that support precompilation, includes "wx/wx.h".
19 #include "wx/wxprec.h"
29 #if !wxUSE_DOC_VIEW_ARCHITECTURE
30 #error "You should have DocView architecture enabled in your wxWidgets installation."
33 #if !wxUSE_MDI_ARCHITECTURE
34 #error "You should have MDI architecture enabled in your wxWidgets installation."
37 #include "wx/filename.h"
38 #include "wx/progdlg.h"
39 #include "wx/sysopt.h"
41 #include "wx/stdpaths.h"
42 #include "wx/textfile.h"
43 #include "wx/process.h"
48 #include "MyDocument.h"
49 #include "MoleculeView.h"
50 #include "ConsoleFrame.h"
51 #include "ProgressFrame.h"
52 #include "GlobalParameterFrame.h"
53 #include "GlobalParameterFilesFrame.h"
56 #if defined(__WXMSW__)
57 #include "MyIPCSupport.h"
60 #include "../MolLib/MolLib.h"
61 #include "../MolLib/Ruby_bind/Molby.h"
62 #include "../MolLib/Missing.h"
67 #if defined(__WXMAC__)
68 #include <CoreFoundation/CoreFoundation.h>
70 #include <Carbon/Carbon.h>
71 #include "wx/mac/carbon/private.h"
72 #include <sys/wait.h> /* for waitpid() */
75 #pragma mark ====== MyApp ======
77 MyFrame *frame = (MyFrame *) NULL;
81 //IMPLEMENT_CLASS(MyApp, wxApp)
83 BEGIN_EVENT_TABLE(MyApp, wxApp)
84 //EVT_KEY_DOWN(MyApp::OnChar)
85 //EVT_MOUSE_EVENTS(MyApp::OnMouseEvent)
86 EVT_COMMAND(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, MyApp::OnScriptMenuModified)
87 EVT_COMMAND(MyDocumentEvent_openFilesByIPC, MyDocumentEvent, MyApp::OnOpenFilesByIPC)
88 EVT_UPDATE_UI_RANGE(myMenuID_MyFirstMenuItem, myMenuID_MyLastMenuItem, MyApp::OnUpdateUI)
89 EVT_MENU(myMenuID_ExecuteScript, MyApp::OnExecuteScript)
90 EVT_MENU(myMenuID_OpenConsoleWindow, MyApp::OnOpenConsoleWindow)
91 EVT_MENU(myMenuID_EmptyConsoleWindow, MyApp::OnEmptyConsoleWindow)
92 EVT_MENU(myMenuID_ViewGlobalParameters, MyApp::OnViewGlobalParameters)
93 EVT_MENU(myMenuID_ViewParameterFilesList, MyApp::OnViewParameterFilesList)
94 EVT_MENU(myMenuID_ImportAmberLib, MyApp::OnImportAmberLib)
95 #if defined(__WXMAC__)
96 EVT_ACTIVATE(MyApp::OnActivate)
98 EVT_END_PROCESS(-1, MyApp::OnEndProcess)
99 EVT_TIMER(-1, MyApp::TimerInvoked)
102 // Find the path of the directory where the relevant resources are to be found.
103 // Mac: the "Resources" directory in the application bundle.
104 // Windows: the directory in which the application executable is located.
107 MyApp::FindResourcePath()
109 #if defined(__WXMAC__)
110 CFBundleRef mainBundle = CFBundleGetMainBundle();
111 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(mainBundle);
114 if (CFURLGetFileSystemRepresentation(ref, true, buffer, sizeof buffer)) {
115 wxString dirname((const char *)buffer, WX_DEFAULT_CONV);
121 return wxEmptyString;
122 #elif defined(__WXMSW__)
124 wxString argv0 = wxTheApp->argv[0];
125 // Fix dosish path (when invoked from MSYS console, the path may be unix-like)
126 // Note: absolute paths like /c/Molby/... (== c:\Molby\...) is not supported
128 char *p = strdup(argv0.mb_str(wxConvFile));
130 wxString argv0_fixed(p, wxConvFile);
133 // Is it an absolute path?
134 if (wxIsAbsolutePath(argv0)) {
135 return wxPathOnly(argv0);
137 // Is it a relative path?
138 wxString currentDir = wxGetCwd();
139 if (currentDir.Last() != wxFILE_SEP_PATH)
140 currentDir += wxFILE_SEP_PATH;
141 str = currentDir + argv0;
142 if (wxFileExists(str))
143 return wxPathOnly(str);
147 pathList.AddEnvList(wxT("PATH"));
148 str = pathList.FindAbsoluteValidPath(argv0);
150 return wxPathOnly(str);
151 return wxEmptyString;
153 #error "FindResourcePath is not defined for UNIXes."
160 m_progressFrame = NULL;
161 m_processTerminated = false;
162 m_processExitCode = 0;
164 scriptMenuCommands = NULL;
165 scriptMenuTitles = NULL;
166 scriptMenuModifiedEventPosted = false;
167 parameterFrame = NULL;
168 parameterFilesFrame = NULL;
170 m_CountNamedFragments = 0;
171 m_NamedFragments = (char **)(-1); /* Will be set to NULL after Ruby interpreter is initialized */
172 m_pendingFilesToOpen = NULL;
173 m_CountTimerDocs = 0;
177 #if defined(__WXMSW__)
179 m_ipcServiceName = NULL;
185 bool MyApp::OnInit(void)
189 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
194 // Check if the same application is already running
196 asprintf(&buf, "Molby-%s", (const char *)wxGetUserId().mb_str(WX_DEFAULT_CONV));
197 wxString name(buf, WX_DEFAULT_CONV);
198 m_ipcServiceName = new wxString(name);
199 m_ipcServiceName->Prepend(wxT("IPC-"));
201 m_checker = new wxSingleInstanceChecker(name);
202 if (m_checker->IsAnotherRunning()) {
203 // Make a connection with the other instance and ask for opening the file(s)
205 wxConnectionBase *connection;
207 files.append(argv[1]);
208 files.append(wxT("\n"));
212 m_client = new MyClient;
213 connection = m_client->MakeConnection(wxT("localhost"), *m_ipcServiceName, MOLBY_IPC_TOPIC);
214 if (connection == NULL) {
215 wxLogError(wxT("Molby is already running; please shut it down and retry"));
219 connection->Execute(files);
223 m_server = new MyServer;
224 if (m_server->Create(*m_ipcServiceName) == false) {
232 // Create a document manager
233 m_docManager = new MyDocManager;
235 // Create templates relating drawing documents to their views
236 new wxDocTemplate(m_docManager, _T("Molby Structure File"), _T("*.mbsf"), _T(""), _T("mbsf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
237 new wxDocTemplate(m_docManager, _T("Protein Structure File"), _T("*.psf"), _T(""), _T("psf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
238 new wxDocTemplate(m_docManager, _T("Protein Data Bank File"), _T("*.pdb"), _T(""), _T("pdb"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
239 new wxDocTemplate(m_docManager, _T("Gaussian Input File"), _T("*.com;*.gjf"), _T(""), _T("com"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
240 new wxDocTemplate(m_docManager, _T("Gaussian/GAMESS Log File"), _T("*.out;*.log"), _T(""), _T("out"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
241 new wxDocTemplate(m_docManager, _T("Gaussian Checkpoint File"), _T("*.fchk;*.fch"), _T(""), _T("fchk"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
242 new wxDocTemplate(m_docManager, _T("GAMESS Input File"), _T("*.inp"), _T(""), _T("inp"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
243 new wxDocTemplate(m_docManager, _T("GAMESS DAT File"), _T("*.dat"), _T(""), _T("dat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
244 new wxDocTemplate(m_docManager, _T("ORTEP Input File"), _T("*.tep"), _T(""), _T("tep"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
245 new wxDocTemplate(m_docManager, _T("SHELX Input File"), _T("*.ins;*.res"), _T(""), _T("ins"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
246 new wxDocTemplate(m_docManager, _T("Crystallographic Information File"), _T("*.cif"), _T(""), _T("cif"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
247 new wxDocTemplate(m_docManager, _T("Cartesian"), _T("*.xyz"), _T(""), _T("xyz"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
248 new wxDocTemplate(m_docManager, _T("Any Molecule"), _T("*.*"), _T(""), _T(""), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
250 // Create the main frame window
251 frame = new MyFrame((wxDocManager *) m_docManager, (wxFrame *) NULL,
252 _T("Molby"), wxPoint(0, 0), wxSize(800, 600),
253 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
255 // Give it an icon (this is ignored in MDI mode: uses resources)
257 frame->SetIcon(wxIcon(_T("doc")));
260 frame->SetIcon(wxIcon(_T("doc.xbm")));
263 wxMenuBar *menu_bar = CreateMenuBar(0);
266 wxMenuBar::MacSetCommonMenuBar(menu_bar);
269 // Associate the menu bar with the frame
270 frame->SetMenuBar(menu_bar);
272 frame->Centre(wxBOTH);
274 #if defined(__WXMAC__)
275 frame->Move(-10000, -10000); // Set invisible
283 // Load default settings from the preference file
284 LoadDefaultSettings();
286 // Create a console window
287 consoleFrame = ConsoleFrame::CreateConsoleFrame(frame);
288 consoleFrame->Show(true);
290 /* Initialize Ruby interpreter with the startup script */
291 /* (Also read startup information) */
293 extern int gRevisionNumber;
294 static const char fname[] = "startup.rb";
295 wxString dirname = FindResourcePath();
297 dirname += wxFILE_SEP_PATH;
298 dirname += wxT("Scripts");
299 /* wxString cwd = wxGetCwd(); */
300 wxSetWorkingDirectory(dirname);
302 wxString fnamestr(fname, wxConvFile);
303 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, (const char *)dirname.mb_str(wxConvFile));
306 wxString docHome(MyAppCallback_getDocumentHomeDir(), wxConvFile);
307 wxSetWorkingDirectory(docHome);
311 /* Pasteboard type strings (includes the revision number) */
312 asprintf(&gMoleculePasteboardType, "Molecule_%d", gRevisionNumber);
313 asprintf(&gParameterPasteboardType, "Parameter_%d", gRevisionNumber);
315 MyAppCallback_showScriptMessage("%% ");
317 /* Build the predefined fragments menu */
318 m_NamedFragments = NULL;
319 UpdatePredefinedFragmentMenu(GetMainFrame()->GetMenuBar());
320 UpdatePredefinedFragmentMenu(consoleFrame->GetMenuBar());
324 /* Open given files: Ruby script is executed, other files are opened as a document */
326 #if defined(__WXMSW__)
327 m_docManager->CreateDocument(wxEmptyString, wxDOC_NEW);
332 for (i = 1; i < argc; i++) {
333 files.append(argv[i]);
334 files.append(wxT("\n"));
345 // kind == 0: main menu
346 // kind == 1: molecule window
347 // kind == 2: console window
349 MyApp::CreateMenuBar(int kind, wxMenu **out_file_history_menu, wxMenu **out_edit_menu)
353 wxMenu *file_menu = new wxMenu;
355 file_menu->Append(wxID_NEW, _T("&New...\tCtrl-N"));
356 file_menu->Append(wxID_OPEN, _T("&Open...\tCtrl-O"));
357 if (out_file_history_menu != NULL) {
358 *out_file_history_menu = new wxMenu;
359 file_menu->AppendSubMenu(*out_file_history_menu, _T("Open Recent"));
360 m_docManager->FileHistoryAddFilesToMenu(*out_file_history_menu);
361 m_docManager->FileHistoryUseMenu(*out_file_history_menu); // Should be removed when menu is discarded
363 /* Build "Open Predefined" */
364 wxMenu *predefined_menu = new wxMenu;
365 file_menu->Append(myMenuID_PredefinedFragment, _T("Open Predefined"), predefined_menu);
367 file_menu->AppendSeparator();
368 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
369 file_menu->Append(wxID_SAVE, _T("&Save\tCtrl-S"));
370 file_menu->Append(wxID_SAVEAS, _T("Save &As..."));
371 file_menu->Append(wxID_REVERT, _T("Revert to Saved"));
373 file_menu->AppendSeparator();
374 file_menu->Append(myMenuID_Import, _T("Import..."));
375 file_menu->Append(myMenuID_Export, _T("Export..."));
377 file_menu->AppendSeparator();
378 file_menu->Append(wxID_PRINT, _T("&Print...\tCtrl-P"));
379 file_menu->Append(wxID_PRINT_SETUP, _T("Print &Setup..."));
380 file_menu->Append(wxID_PREVIEW, _T("Print Pre&view"));
382 file_menu->AppendSeparator();
383 #if defined(__WXMAC__)
384 file_menu->Append(wxID_EXIT, _T("E&xit\tCtrl-Q"));
386 file_menu->Append(wxID_EXIT, _T("E&xit\tAlt-X"));
389 wxMenu *edit_menu = new wxMenu;
390 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
391 edit_menu->Append(wxID_REDO, _T("&Redo"));
392 edit_menu->AppendSeparator();
393 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
394 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
395 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
396 edit_menu->Append(wxID_CLEAR, _T("Clear"));
397 edit_menu->AppendSeparator();
398 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
399 edit_menu->Append(myMenuID_SelectFragment, _T("Select Fragment\tCtrl-F"));
400 edit_menu->Append(myMenuID_SelectReverse, _T("Select Reverse"));
401 edit_menu->AppendSeparator();
402 wxMenu *create_parameter_menu = new wxMenu;
403 create_parameter_menu->Append(myMenuID_CreateNewVdwParameter, _T("Vdw"));
404 create_parameter_menu->Append(myMenuID_CreateNewBondParameter, _T("Bond"));
405 create_parameter_menu->Append(myMenuID_CreateNewAngleParameter, _T("Angle"));
406 create_parameter_menu->Append(myMenuID_CreateNewDihedralParameter, _T("Dihedral"));
407 create_parameter_menu->Append(myMenuID_CreateNewImproperParameter, _T("Improper"));
408 create_parameter_menu->Append(myMenuID_CreateNewVdwPairParameter, _T("Vdw Pair"));
409 create_parameter_menu->Append(myMenuID_CreateNewVdwCutoffParameter, _T("Vdw Cutoff"));
410 edit_menu->Append(myMenuID_CreateNewAtom, _T("Create New Atom\tCtrl-I"));
411 edit_menu->Append(myMenuID_CreateNewParameter, _T("Create New Parameter"), create_parameter_menu);
412 edit_menu->Append(myMenuID_CreatePiAnchor, _T("Create Pi Anchor"));
413 edit_menu->AppendSeparator();
414 wxMenu *add_hydrogen_menu = new wxMenu;
415 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp3, _T("Tetrahedral sp3"));
416 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp2, _T("Trigonal sp2"));
417 add_hydrogen_menu->Append(myMenuID_AddHydrogenLinear, _T("Linear sp"));
418 add_hydrogen_menu->Append(myMenuID_AddHydrogenPyramidal, _T("Pyramidal (like NH2)"));
419 add_hydrogen_menu->Append(myMenuID_AddHydrogenBent, _T("Bent (like OH)"));
420 edit_menu->Append(myMenuID_AddHydrogen, _T("Add Hydrogen"), add_hydrogen_menu);
422 if (out_edit_menu != NULL)
423 *out_edit_menu = edit_menu; // Should be associated with the command processor if available
425 wxMenu *show_menu = new wxMenu;
426 show_menu->Append(myMenuID_FitToScreen, _T("Fit To Screen\tCtrl-T"));
427 show_menu->Append(myMenuID_CenterSelection, _T("Center Selection"));
428 show_menu->AppendSeparator();
429 show_menu->Append(myMenuID_ShowUnitCell, _T("Show Unit Cell"), _T(""), wxITEM_CHECK);
430 /* show_menu->Append(myMenuID_ShowPeriodicBox, _T("Show Periodic Box"), _T(""), wxITEM_CHECK); */
431 show_menu->Append(myMenuID_ShowHydrogens, _T("Show Hydrogen Atoms"), _T(""), wxITEM_CHECK);
432 show_menu->Append(myMenuID_ShowDummyAtoms, _T("Show Dummy Atoms"), _T(""), wxITEM_CHECK);
433 show_menu->Append(myMenuID_ShowExpandedAtoms, _T("Show Expanded Atoms"), _T(""), wxITEM_CHECK);
434 show_menu->Append(myMenuID_ShowEllipsoids, _T("Show Ellipsoids"), _T(""), wxITEM_CHECK);
435 show_menu->Append(myMenuID_ShowRotationCenter, _T("Show Rotation Center"), _T(""), wxITEM_CHECK);
436 show_menu->AppendSeparator();
437 show_menu->Append(myMenuID_HideSelected, _T("Hide Selected"), _T(""));
438 show_menu->Append(myMenuID_HideUnselected, _T("Hide Unselected"), _T(""));
439 show_menu->Append(myMenuID_HideReverse, _T("Hide Reverse"), _T(""));
440 show_menu->Append(myMenuID_ShowAllAtoms, _T("Show All Atoms"), _T(""));
441 show_menu->AppendSeparator();
442 show_menu->Append(myMenuID_ShowGraphite, _T("Show Graphite..."));
443 show_menu->AppendSeparator();
444 show_menu->Append(myMenuID_LineMode, _T("Line Mode"), _T(""), wxITEM_CHECK);
446 wxMenu *md_menu = new wxMenu;
447 md_menu->Append(myMenuID_MolecularDynamics, _T("Molecular Dynamics..."));
448 md_menu->Append(myMenuID_Minimize, _T("Minimize..."));
449 md_menu->Append(myMenuID_StopMDRun, _T("Stop\tCtrl-."));
450 md_menu->AppendSeparator();
451 // md_menu->Append(myMenuID_ReadParameters, _T("Read Parameters..."));
452 md_menu->Append(myMenuID_RunAntechamber, _T("Auto Guess MM/MD Parameters..."));
453 md_menu->Append(myMenuID_GuessUFFParameters, _T("Guess UFF Parameters..."));
454 md_menu->Append(myMenuID_ViewGlobalParameters, _T("View Global Parameters..."));
455 md_menu->Append(myMenuID_ViewParameterFilesList, _T("Load/Unload Global Parameters..."));
456 md_menu->AppendSeparator();
457 md_menu->Append(myMenuID_DefinePeriodicBox, _T("Define Unit Cell..."));
458 md_menu->Append(myMenuID_ShowPeriodicImage, _T("Show Periodic Image..."));
459 /* md_menu->Append(myMenuID_PressureControl, _T("Pressure Control...")); */
460 /* md_menu->Append(myMenuID_DefineSymmetry, _T("Define Symmetry Operations..."));
461 md_menu->Append(myMenuID_ExpandBySymmetry, _T("Expand by Symmetry...")); */
462 md_menu->AppendSeparator();
464 wxMenu *md_tools_menu = new wxMenu;
465 /* md_tools_menu->Append(myMenuID_RunAntechamber, _T("Antechamber/parmchk...")); */
466 md_tools_menu->Append(myMenuID_RunResp, _T("GAMESS/RESP..."));
467 md_tools_menu->Append(myMenuID_CreateSanderInput, _T("Create SANDER input..."));
468 md_tools_menu->Append(myMenuID_ImportAmberLib, _T("Import AMBER Lib..."));
469 md_tools_menu->Append(myMenuID_ImportAmberFrcmod, _T("Import AMBER Frcmod..."));
470 md_menu->Append(myMenuID_MDTools, _T("Tools"), md_tools_menu);
472 wxMenu *qc_menu = new wxMenu;
473 qc_menu->Append(myMenuID_CreateGamessInput, _T("Create GAMESS input..."));
474 qc_menu->Append(myMenuID_CreateMOPACInput, _T("Create MOPAC input..."));
475 qc_menu->Append(myMenuID_CreateMOCube, _T("Create MO cube..."));
477 wxMenu *script_menu = new wxMenu;
478 script_menu->Append(myMenuID_ExecuteScript, _T("Execute Script..."));
479 script_menu->Append(myMenuID_OpenConsoleWindow, _T("Open Console Window..."));
480 script_menu->Append(myMenuID_EmptyConsoleWindow, _T("Empty Console Window"));
481 script_menu->AppendSeparator();
482 countNonCustomScriptMenu = script_menu->GetMenuItemCount();
484 wxMenu *help_menu = new wxMenu;
485 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
487 wxMenuBar *menu_bar = new wxMenuBar;
489 menu_bar->Append(file_menu, _T("&File"));
490 menu_bar->Append(edit_menu, _T("&Edit"));
491 menu_bar->Append(show_menu, _T("Show"));
492 menu_bar->Append(md_menu, _T("MM/MD"));
493 menu_bar->Append(qc_menu, _T("QChem"));
494 menu_bar->Append(script_menu, _T("&Script"));
495 menu_bar->Append(help_menu, _T("&Help"));
497 UpdateScriptMenu(menu_bar);
498 if (m_NamedFragments != (char **)(-1))
499 UpdatePredefinedFragmentMenu(menu_bar);
505 /* When the application is launched without any documents, an empty document is opened.
506 This should be implemented by overriding this special method; parsing argc/argv does
507 not work, because the list of files is passed through an Apple Event. */
511 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
515 MyApp::MacOpenFile(const wxString &fileName)
517 wxString files(fileName);
521 /* Open given files: instead of calling MacOpenFile() for each entry, build a file list
522 and call MyApp::OnOpenFiles() */
524 MyApp::MacHandleAEODoc(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply))
528 DescType returnedType;
534 err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList, &docList);
538 err = AECountItems(&docList, &itemsInList);
542 ProcessSerialNumber PSN ;
543 PSN.highLongOfPSN = 0 ;
544 PSN.lowLongOfPSN = kCurrentProcess ;
545 SetFrontProcess( &PSN ) ;
547 wxString fName, fNameList;
550 for (i = 1; i <= itemsInList; i++)
553 &docList, i, typeFSRef, &keywd, &returnedType,
554 (Ptr)&theRef, sizeof(theRef), &actualSize);
555 fName = wxMacFSRefToPath( &theRef ) ;
556 fNameList.append(fName);
557 fNameList.append(wxT("\n"));
560 OnOpenFiles(fNameList);
570 SaveDefaultSettings();
580 sModifyMenuForFilterMode(wxMenuBar *mbar)
585 idx = mbar->FindMenu(wxT("Show"));
586 if (idx != wxNOT_FOUND)
587 delete mbar->Remove(idx);
588 idx = mbar->FindMenu(wxT("MM/MD"));
589 if (idx != wxNOT_FOUND)
590 delete mbar->Remove(idx);
591 idx = mbar->FindMenu(wxT("QChem"));
592 if (idx != wxNOT_FOUND)
593 delete mbar->Remove(idx);
594 idx = mbar->FindMenu(wxT("Script"));
595 if (idx != wxNOT_FOUND) {
596 menu = mbar->GetMenu(idx);
597 n = menu->GetMenuItemCount();
598 for (i = n - 1; i >= 0; i--) {
599 item = menu->FindItemByPosition(i);
601 if (id != myMenuID_OpenConsoleWindow && id != myMenuID_EmptyConsoleWindow && id != myMenuID_ExecuteScript) {
608 idx = mbar->FindMenu(wxT("Edit"));
609 if (idx != wxNOT_FOUND) {
610 menu = mbar->GetMenu(idx);
611 n = menu->GetMenuItemCount();
612 for (i = n - 1; i >= 0; i--) {
613 item = menu->FindItemByPosition(i);
615 if (id == wxID_SELECTALL)
622 idx = mbar->FindMenu(wxT("File"));
623 if (idx != wxNOT_FOUND) {
624 menu = mbar->GetMenu(idx);
625 n = menu->GetMenuItemCount();
626 for (i = n - 1; i >= 0; i--) {
627 item = menu->FindItemByPosition(i);
629 if (id != wxID_OPEN && id != wxID_EXIT) {
639 MyApp::ShowProgressPanel(const char *mes)
641 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
642 if (m_progressFrame == NULL) {
645 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
646 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
647 if (quitMenuItem != NULL)
648 quitMenuItem->Enable(false);
652 m_progressFrame = new ProgressFrame(_T("Progress"), string);
653 m_progressCanceled = false;
654 m_progressValue = -1;
659 MyApp::HideProgressPanel()
661 if (m_progressFrame != NULL) {
662 m_progressFrame->Hide();
663 m_progressFrame->Destroy();
664 m_progressFrame = NULL;
667 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
669 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
670 if (quitMenuItem != NULL)
671 quitMenuItem->Enable(true);
678 MyApp::SetProgressValue(double dval)
680 if (m_progressFrame != NULL) {
681 m_progressFrame->SetProgressValue(dval);
686 MyApp::SetProgressMessage(const char *mes)
688 if (m_progressFrame != NULL) {
689 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
690 m_progressFrame->SetProgressMessage(string);
695 MyApp::IsInterrupted()
697 if (m_progressFrame != NULL)
698 return m_progressFrame->CheckInterrupt();
700 if (::wxGetKeyState(WXK_ESCAPE))
707 #warning "TODO: Move this to MyDocument and 'import parameters' "
710 MyApp::OnReadParameters(wxCommandEvent& event)
712 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Parameter File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
713 if (dialog->ShowModal() == wxID_OK) {
714 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
716 ParameterReadFromFile(NULL, p, &wbuf, NULL);
719 AppendConsoleMessage(wbuf);
730 MyApp::OnOpenConsoleWindow(wxCommandEvent& event)
732 consoleFrame->Show(true);
733 consoleFrame->Raise();
737 MyApp::OnEmptyConsoleWindow(wxCommandEvent& event)
739 consoleFrame->EmptyBuffer();
743 MyApp::OnViewGlobalParameters(wxCommandEvent& event)
745 if (parameterFrame == NULL) {
746 parameterFrame = GlobalParameterFrame::CreateGlobalParameterFrame(GetMainFrame());
747 MainView_createColumnsForTableAtIndex(NULL, kMainViewParameterTableIndex);
749 MainView_refreshTable(NULL);
750 parameterFrame->Show(true);
751 parameterFrame->Raise();
755 MyApp::OnViewParameterFilesList(wxCommandEvent &event)
757 if (parameterFilesFrame == NULL) {
758 parameterFilesFrame = GlobalParameterFilesFrame::CreateGlobalParameterFilesFrame(GetMainFrame());
760 parameterFilesFrame->Show(true);
761 parameterFilesFrame->Raise();
765 MyApp::OnImportAmberLib(wxCommandEvent &event)
767 MolActionCreateAndPerform(NULL, SCRIPT_ACTION(""), "cmd_import_amberlib");
771 MyApp::LookupScriptMenu(const char *title)
776 for (i = 0; i < countScriptMenu; i++) {
777 if (strcmp(title, scriptMenuTitles[i]) == 0)
784 MyApp::RegisterScriptMenu(const char *cmd, const char *title)
787 if (cmd[0] == 0 && title[0] == 0)
788 i = countScriptMenu; /* A sepearator */
790 for (i = 0; i < countScriptMenu; i++) {
791 if (strcmp(cmd, scriptMenuCommands[i]) == 0) {
792 free(scriptMenuTitles[i]);
793 scriptMenuTitles[i] = strdup(title);
795 } else if (strcmp(title, scriptMenuTitles[i]) == 0) {
796 free(scriptMenuCommands[i]);
797 scriptMenuCommands[i] = strdup(cmd);
802 if (i >= countScriptMenu) {
803 if (countScriptMenu == 0) {
804 scriptMenuTitles = (char **)malloc(sizeof(char *));
805 scriptMenuCommands = (char **)malloc(sizeof(char *));
807 scriptMenuTitles = (char **)realloc(scriptMenuTitles, sizeof(char *) * (countScriptMenu + 1));
808 scriptMenuCommands = (char **)realloc(scriptMenuCommands, sizeof(char *) * (countScriptMenu + 1));
810 scriptMenuTitles[countScriptMenu] = strdup(title);
811 scriptMenuCommands[countScriptMenu] = strdup(cmd);
814 if (!scriptMenuModifiedEventPosted) {
815 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_scriptMenuModified);
816 wxPostEvent(this, myEvent);
817 scriptMenuModifiedEventPosted = true;
822 MyApp::UpdateScriptMenu(wxMenuBar *mbar)
826 wxMenu *smenu = mbar->GetMenu(myMenuIndex_Script);
830 // Remove all custom items
831 for (i = smenu->GetMenuItemCount() - 1; i >= countNonCustomScriptMenu; i--) {
832 wxMenuItem *item = smenu->FindItemByPosition(i);
833 if (!item->IsSeparator()) {
834 int n = item->GetId();
835 Disconnect(n, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
841 // Build script menu from internal array
842 for (i = 0; i < countScriptMenu; i++) {
843 const char *title = scriptMenuTitles[i];
844 if (title == NULL || title[0] == 0) {
845 smenu->AppendSeparator();
847 wxString stitle(scriptMenuTitles[i], WX_DEFAULT_CONV);
848 wxMenuItem *item = new wxMenuItem(smenu, myMenuID_CustomScript + i, stitle);
852 Connect(myMenuID_CustomScript, myMenuID_CustomScript + countScriptMenu - 1, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
856 MyApp::OnScriptMenuModified(wxCommandEvent& event)
858 scriptMenuModifiedEventPosted = false;
859 UpdateScriptMenu(GetMainFrame()->GetMenuBar());
860 UpdateScriptMenu(consoleFrame->GetMenuBar());
865 MyApp::OnScriptMenuSelected(wxCommandEvent& event)
871 int index = event.GetId() - myMenuID_CustomScript;
872 if (index < 0 || index >= countScriptMenu)
874 cmd = scriptMenuCommands[index];
875 methodType = Ruby_methodType("Molecule", cmd);
878 mview = MainViewCallback_activeView();
881 else mol = mview->mol;
882 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
883 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), cmd);
884 else if (methodType == 2) /* Class method (with molecule as an only argument) */
885 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("M"), cmd, mol);
890 MyApp::UpdatePredefinedFragmentMenu(wxMenuBar *mbar)
893 wxMenuItem *fmenuItem = mbar->FindItem(myMenuID_PredefinedFragment);
894 wxMenu *fmenu = (fmenuItem != NULL ? fmenuItem->GetSubMenu() : NULL);
897 if (m_NamedFragments == (char **)(-1))
900 /* Rebuild sNamedFragments array */
901 if (m_NamedFragments != NULL) {
902 for (i = 0; i < m_CountNamedFragments; i++) {
903 free(m_NamedFragments[i * 2]);
904 free(m_NamedFragments[i * 2 + 1]);
906 free(m_NamedFragments);
908 m_NamedFragments = NULL;
909 m_CountNamedFragments = 0;
910 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION(";i"), "proc { $named_fragments.length }", &n) != 0 || n <= 0)
912 m_CountNamedFragments = n;
913 m_NamedFragments = (char **)calloc(sizeof(char *), n * 2);
914 for (i = 0; i < n; i++) {
915 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "proc { |i| $named_fragments[i][0] }", i, &m_NamedFragments[i * 2]) != 0 ||
916 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "proc { |i| $named_fragments[i][1] }", i, &m_NamedFragments[i * 2 + 1]) != 0)
920 for (i = 0; i < m_CountNamedFragments; i++) {
921 if (m_NamedFragments[i * 2] != NULL)
922 free(m_NamedFragments[i * 2]);
923 if (m_NamedFragments[i * 2 + 1] != NULL)
924 free(m_NamedFragments[i * 2 + 1]);
926 free(m_NamedFragments);
927 m_CountNamedFragments = 0;
928 m_NamedFragments = NULL;
932 wxMenu *predefined_submenu = NULL;
935 for (i = sn = 0; i < m_CountNamedFragments; i++) {
936 if (strcmp(m_NamedFragments[i * 2 + 1], "-") == 0) {
937 if (predefined_submenu != NULL) {
938 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
940 predefined_submenu = new wxMenu;
941 stitle = wxString(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
944 wxString mtitle(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
945 (predefined_submenu != NULL ? predefined_submenu : fmenu)->Append(myMenuID_PredefinedFragment + 1 + i, mtitle);
948 if (predefined_submenu != NULL)
949 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
950 Connect(myMenuID_PredefinedFragment + 1, myMenuID_PredefinedFragment + m_CountNamedFragments, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnFragmentMenuSelected), NULL, this);
954 MyApp::OnFragmentMenuSelected(wxCommandEvent& event)
956 int index = event.GetId() - myMenuID_PredefinedFragment - 1;
957 if (index < 0 || index >= m_CountNamedFragments)
959 // Open a predefined fragment as a new file
961 Molecule *mol = MoleculeNew();
965 asprintf(&fullname, "%s/Scripts/mbsf/%s", (const char *)(FindResourcePath().mb_str(wxConvFile)), m_NamedFragments[index * 2 + 1]);
966 result = MoleculeLoadMbsfFile(mol, fullname, &errbuf);
967 if (errbuf != NULL) {
968 MyAppCallback_showScriptMessage("On loading %s:\n%s", m_NamedFragments[index * 2 + 1], errbuf);
972 MyAppCallback_errorMessageBox("Cannot open named fragment %s\n(See console for detailed message)", m_NamedFragments[index * 2]);
977 MyDocument *doc = (MyDocument *)(DocManager()->CreateDocument(wxT(""), wxDOC_NEW));
978 wxString title(m_NamedFragments[index * 2], WX_DEFAULT_CONV);
979 title = _T("*") + title + _T("*");
980 doc->SetMolecule(mol);
981 if (mol->natoms > 1000)
982 mol->mview->lineMode = 1;
983 MainView_resizeToFit(mol->mview);
985 // Change the window title
986 doc->SetTitle(title);
987 // Propagate the change of the window title
988 wxList::compatibility_iterator node = doc->GetViews().GetFirst();
990 wxView *view = (wxView *)node->GetData();
991 view->OnChangeFilename();
992 node = node->GetNext();
997 MyApp::OnUpdateUI(wxUpdateUIEvent& event)
999 int uid = event.GetId();
1000 MainView *mview = MainViewCallback_activeView();
1001 if (uid >= myMenuID_CustomScript && uid < myMenuID_CustomScript + countScriptMenu) {
1002 // Check the script menu
1006 int index = uid - myMenuID_CustomScript;
1007 cmd = scriptMenuCommands[index];
1008 methodType = Ruby_methodType("Molecule", cmd);
1009 event.Enable(false);
1010 if (methodType != 0) {
1013 else mol = mview->mol;
1014 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
1016 else if (methodType == 2) /* Class method (with molecule as an only argument) */
1019 } else if (uid >= myMenuID_PredefinedFragment && uid <= myMenuID_PredefinedFragment + m_CountNamedFragments) {
1023 case myMenuID_ExecuteScript:
1024 case myMenuID_OpenConsoleWindow:
1025 case myMenuID_EmptyConsoleWindow:
1026 case myMenuID_ViewParameterFilesList:
1027 case myMenuID_ViewGlobalParameters:
1028 case myMenuID_MDTools:
1029 case myMenuID_ImportAmberLib:
1034 event.Enable(false);
1042 MyApp::OnExecuteScript(wxCommandEvent &event)
1044 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Script File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
1045 if (dialog->ShowModal() == wxID_OK) {
1048 wxString path = dialog->GetPath();
1050 // Command line: execute_script('pathname')
1051 wxString cline(path);
1052 wxRegEx re(_T("[\\\\']")); // A backslash and a single-quote
1053 re.Replace(&cline, _T("\\\\\\0")); // A backslash followed by "\0"
1054 cline.Prepend(_T("execute_script('"));
1056 MyAppCallback_setConsoleColor(3);
1057 MyAppCallback_showScriptMessage("%s", (const char *)(cline.mb_str(wxConvFile)));
1058 MyAppCallback_showScriptMessage("\n");
1059 MyAppCallback_setConsoleColor(0);
1061 retval = MyAppCallback_executeScriptFromFile((const char *)(path.mb_str(wxConvFile)), &status);
1062 if (retval == (RubyValue)6 && status == -1)
1063 MyAppCallback_errorMessageBox("Cannot open Ruby script %s", (const char *)path.mb_str(wxConvFile));
1064 else if (status != 0)
1065 Molby_showError(status);
1071 MyApp::OnActivate(wxActivateEvent &event)
1073 #if defined(__WXMAC__)
1074 MyFrame *frame = GetMainFrame();
1075 frame->Show(false); /* Sometimes this "parent" frame gets visible and screw up the menus */
1081 MyApp::RequestOpenFilesByIPC(wxString& files)
1083 if (m_pendingFilesToOpen != NULL)
1084 m_pendingFilesToOpen->Append(files);
1086 m_pendingFilesToOpen = new wxString(files);
1087 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openFilesByIPC);
1088 wxPostEvent(this, myEvent);
1092 MyApp::OnOpenFilesByIPC(wxCommandEvent& event)
1094 if (m_pendingFilesToOpen == NULL)
1096 OnOpenFiles(*m_pendingFilesToOpen);
1097 delete m_pendingFilesToOpen;
1098 m_pendingFilesToOpen = NULL;
1102 MyApp::OnOpenFiles(const wxString &files)
1105 bool success = true;
1110 end = files.find(wxT("\n"), start);
1111 wxString file = files.Mid(start, (end == wxString::npos ? wxString::npos : end - start));
1112 if (file.Len() == 0)
1114 if (file.EndsWith(wxT(".rb")) || file.EndsWith(wxT(".mrb"))) {
1115 /* Execute the file as a Ruby script */
1116 retval = MyAppCallback_executeScriptFromFile((const char *)file.mb_str(wxConvFile), &status);
1118 if (retval == (RubyValue)6 && status == -1)
1119 MyAppCallback_errorMessageBox("Cannot open Ruby script: %s", (const char *)file.mb_str(wxConvFile));
1121 Molby_showError(status);
1125 if (NULL == wxGetApp().DocManager()->CreateDocument(file, wxDOC_SILENT))
1128 if (end == wxString::npos)
1136 MyApp::DefaultSettingsPath()
1138 wxString name = wxStandardPaths::Get().GetUserConfigDir();
1139 wxChar sep = wxFileName::GetPathSeparator();
1140 if (name[name.Len() - 1] != sep)
1142 name += _T("Molby.settings");
1147 MyApp::LoadDefaultSettings()
1149 wxString name = DefaultSettingsPath();
1150 m_defaultSettings.clear();
1151 wxTextFile file(name);
1152 if (file.Exists() && file.Open()) {
1155 for (line = file.GetFirstLine(); ; line = file.GetNextLine()) {
1158 if ((pos = line.Find('=')) != wxNOT_FOUND) {
1159 wxString key = line.Left(pos);
1160 wxString value = line.Right(line.Length() - pos - 1);
1161 SetDefaultSetting(key, value);
1171 MyApp::SaveDefaultSettings()
1173 wxString name = DefaultSettingsPath();
1174 wxTextFile file(name);
1180 MyStringHash::iterator it;
1181 for (it = m_defaultSettings.begin(); it != m_defaultSettings.end(); it++) {
1182 wxString key = it->first;
1183 wxString value = it->second;
1184 wxString line = key + _T("=") + value;
1192 MyApp::SetDefaultSetting(const wxString& key, const wxString& value)
1194 // TODO: The '=' and '#' characters may need to be escaped
1195 m_defaultSettings[key] = value;
1199 MyApp::GetDefaultSetting(const wxString& key)
1201 return m_defaultSettings[key];
1205 MyApp::GetGlobalParameterListCtrl()
1207 if (parameterFrame != NULL)
1208 return parameterFrame->GetListCtrl();
1212 #define LOG_SUBPROCESS 0
1218 MyApp::OnEndProcess(wxProcessEvent &event)
1220 m_processTerminated = true;
1221 m_processExitCode = event.GetExitCode();
1224 fprintf(fplog, "OnEndProcess called\n");
1229 MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *fpout, FILE *fperr)
1232 int callback_result = 0;
1234 bool progress_panel = false;
1236 size_t len, len_total;
1237 wxString cmdstr(cmdline, WX_DEFAULT_CONV);
1238 #if defined(__WXMSW__)
1239 extern int myKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
1241 // Show progress panel
1242 if (procname != NULL) {
1243 snprintf(buf, sizeof buf, "Running %s...", procname);
1244 ShowProgressPanel(buf);
1245 progress_panel = true;
1248 // Create log file in the document home directory
1252 char *dochome = MyAppCallback_getDocumentHomeDir();
1253 snprintf(buf, sizeof buf, "%s/%s.log", dochome, (procname ? procname : "subprocess"));
1255 fplog = fopen(buf, "w");
1261 // Create proc object and call subprocess
1262 wxProcess *proc = new wxProcess(this, -1);
1264 int flag = wxEXEC_ASYNC;
1266 flag |= wxEXEC_MAKE_GROUP_LEADER;
1268 m_processTerminated = false;
1269 m_processExitCode = 0;
1270 long pid = ::wxExecute(cmdstr, flag, proc);
1272 // MyAppCallback_errorMessageBox("Cannot start %s", procname);
1274 if (procname != NULL)
1275 HideProgressPanel();
1277 fprintf(fplog, "Cannot start '%s'\n", cmdline);
1283 fprintf(fplog, "[DEBUG]pid = %ld\n", pid);
1287 // Wait until process ends or user interrupts
1288 wxInputStream *in = proc->GetInputStream();
1289 wxInputStream *err = proc->GetErrorStream();
1291 char *membuf = NULL;
1294 while (in->CanRead()) {
1295 in->Read(buf, sizeof buf - 1);
1296 if ((len = in->LastRead()) > 0) {
1300 fprintf(fplog, "%s", buf);
1303 if (callback == DUMMY_CALLBACK) {
1304 if (memsize < len_total + 1) {
1305 char *p = (char *)realloc(membuf, len_total + 1);
1308 memmove(membuf + len_total - len, buf, len + 1);
1309 memsize = len_total + 1;
1312 } else if (fpout != NULL && fpout != (FILE *)1) {
1314 } else if (fpout == (FILE *)1) {
1315 MyAppCallback_setConsoleColor(0);
1316 MyAppCallback_showScriptMessage("%s", buf);
1320 while (err->CanRead()) {
1321 err->Read(buf, sizeof buf - 1);
1322 if ((len = err->LastRead()) > 0) {
1326 fprintf(fplog, "%s", buf);
1329 if (fperr != NULL && fperr != (FILE *)1) {
1331 } else if (fpout == (FILE *)1) {
1332 MyAppCallback_setConsoleColor(1);
1333 MyAppCallback_showScriptMessage("\n%s", buf);
1334 MyAppCallback_setConsoleColor(0);
1338 if (++count == 100) {
1339 if (progress_panel == false) {
1340 ShowProgressPanel("Running subprocess...");
1341 progress_panel = true;
1344 if (m_processTerminated || !wxProcess::Exists(pid)) {
1345 if (m_processExitCode != 0) {
1346 /* Error from subprocess */
1347 // MyAppCallback_errorMessageBox("%s failed with exit code %d.", procname, m_processExitCode);
1348 status = (m_processExitCode & 255);
1353 /* In some cases, wxProcess cannot detect the termination of the subprocess. */
1354 /* So here are the platform-dependent examination */
1357 // get the process handle to operate on
1358 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
1360 PROCESS_QUERY_INFORMATION,
1361 false, // not inheritable
1363 if (hProcess == NULL) {
1364 if (::GetLastError() != ERROR_ACCESS_DENIED) {
1365 m_processTerminated = 1;
1366 m_processExitCode = 255;
1370 if (::GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE) {
1371 m_processTerminated = 1;
1372 m_processExitCode = exitCode;
1374 ::CloseHandle(hProcess);
1376 if (m_processTerminated) {
1379 fprintf(fplog, "OnEndProcess *NOT* called\n");
1383 status = m_processExitCode & 255;
1389 if (waitpid(pid, &status, WNOHANG) != 0) {
1392 fprintf(fplog, "OnEndProcess *NOT* called\n");
1397 status = WEXITSTATUS(status);
1404 fprintf(fplog, "[DEBUG]pid %ld exists\n", pid);
1410 if (wxGetApp().IsInterrupted() || (callback != NULL && callback != DUMMY_CALLBACK && (callback_result = (*callback)(callback_data)) != 0)) {
1411 /* User interrupt */
1412 int kflag = wxKILL_CHILDREN;
1416 myKillAllChildren(pid, wxSIGKILL, &rc) != 0
1418 ::wxKill(pid, wxSIGTERM, &rc, kflag) != 0
1422 case wxKILL_BAD_SIGNAL: status = -3; break; /* No such signal */
1423 case wxKILL_ACCESS_DENIED: status = -4; break; /* Permission denied */
1424 case wxKILL_NO_PROCESS: status = -5; break; /* No such process */
1425 default: status = -6; break; /* unknown error */
1428 if (callback_result != 0)
1429 status = -3; /* Interrupt from callback */
1431 status = -2; /* User interrupt */
1442 HideProgressPanel();
1444 if (callback == DUMMY_CALLBACK) {
1446 /* Convert "\r\n" to "\n" */
1448 p = pend = membuf + strlen(membuf);
1449 while (--p >= membuf) {
1451 memmove(p, p + 1, pend - p);
1456 *((char **)callback_data) = membuf;
1459 /* if (len_total > 0)
1460 MyAppCallback_showRubyPrompt(); */
1465 static int sTimerCount = 0;
1468 MyApp::EnableTimerForDocument(MyDocument *doc)
1473 for (i = 0; i < m_CountTimerDocs; i++) {
1474 if (m_TimerDocs[i] == doc)
1477 m_TimerDocs = (MyDocument **)realloc(m_TimerDocs, sizeof(MyDocument *) * (m_CountTimerDocs + 1));
1478 m_TimerDocs[m_CountTimerDocs++] = doc;
1479 if (m_Timer == NULL)
1480 m_Timer = new wxTimer(this, -1);
1481 if (!m_Timer->IsRunning())
1482 m_Timer->Start(100, wxTIMER_CONTINUOUS);
1486 MyApp::DisableTimerForDocument(MyDocument *doc)
1491 for (i = 0; i < m_CountTimerDocs; i++) {
1492 if (m_TimerDocs[i] == doc) {
1493 // Remove this document from the array
1494 if (i < m_CountTimerDocs - 1) {
1495 memmove(&m_TimerDocs[i], &m_TimerDocs[i + 1], sizeof(MyDocument *) * (m_CountTimerDocs - 1 - i));
1498 if (m_CountTimerDocs == 0) {
1509 MyApp::TimerInvoked(wxTimerEvent &event)
1513 for (i = 0; i < m_CountTimerDocs; i++) {
1514 m_TimerDocs[i]->TimerCallback(sTimerCount);
1518 #pragma mark ====== MyFrame (top-level window) ======
1521 * This is the top-level window of the application.
1524 IMPLEMENT_CLASS(MyFrame, wxDocMDIParentFrame)
1525 BEGIN_EVENT_TABLE(MyFrame, wxDocMDIParentFrame)
1526 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
1529 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
1530 const wxPoint& pos, const wxSize& size, long type):
1531 wxDocMDIParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
1533 editMenu = (wxMenu *) NULL;
1534 #if defined(__WXMAC__)
1535 /* Avoid this "dummy" top-level window to appear in the window menu.
1536 It should not happen because MyApp::OnActivate() tries to hide this window,
1537 but this is still here just in case. */
1539 sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
1540 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
1544 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
1547 s = Molby_getDescription();
1548 wxString str(s, WX_DEFAULT_CONV);
1549 (void)wxMessageBox(str, _T("Molby"));
1553 MyFrame *GetMainFrame(void)
1558 #pragma mark ====== Plain-C interface ======
1561 MyAppCallback_getGUIDescriptionString(void)
1563 static char *desc = NULL;
1566 "AmberTools 1.3, http://ambermd.org/\n"
1567 " Copyright (C) Junmei Wang, Ross C. Walker, \n"
1568 " Michael F. Crowley, Scott Brozell and David A. Case\n"
1569 "wxWidgets %d.%d.%d, http://www.wxwidgets.org/\n"
1570 " Copyright (C) 1992-2008 Julian Smart, Robert Roebling,\n"
1571 " Vadim Zeitlin and other members of the wxWidgets team\n"
1572 " Portions (C) 1996 Artificial Intelligence Applications Institute\n",
1573 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
1579 MyAppCallback_loadGlobalSettings(void)
1581 wxGetApp().LoadDefaultSettings();
1585 MyAppCallback_saveGlobalSettings(void)
1587 wxGetApp().SaveDefaultSettings();
1590 /* Note on the global settings */
1591 /* Global settings are stored in a file in the form key="value", where
1592 the "value" is the 'inspect'-ed representation of Ruby values.
1593 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
1594 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
1595 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
1596 MyAppCallback_setGlobalSettingsWithType(). */
1598 MyAppCallback_getGlobalSettings(const char *key)
1600 wxString wxkey(key, WX_DEFAULT_CONV);
1601 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
1602 return strdup(wxvalue.mb_str(WX_DEFAULT_CONV));
1606 MyAppCallback_setGlobalSettings(const char *key, const char *value)
1608 wxString wxkey(key, WX_DEFAULT_CONV);
1609 wxString wxvalue(value, WX_DEFAULT_CONV);
1610 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
1614 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
1617 char *s = MyAppCallback_getGlobalSettings(key);
1618 char desc[] = SCRIPT_ACTION("s; ");
1619 desc[sizeof(desc) - 2] = type;
1620 retval = MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
1626 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
1628 const char *cmd = "set_global_settings";
1630 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i"), cmd, *((const Int *)ptr));
1631 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("d"), cmd, *((const Double *)ptr));
1632 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("s"), cmd, (const char *)ptr);
1633 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("v"), cmd, (const Vector *)ptr);
1634 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("t"), cmd, (const Transform *)ptr);
1636 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
1642 MyAppCallback_checkInterrupt(void)
1644 return wxGetApp().IsInterrupted();
1648 MyAppCallback_showProgressPanel(const char *msg)
1650 wxGetApp().ShowProgressPanel(msg);
1654 MyAppCallback_hideProgressPanel(void)
1656 wxGetApp().HideProgressPanel();
1660 MyAppCallback_setProgressValue(double dval)
1662 wxGetApp().SetProgressValue(dval);
1666 MyAppCallback_setProgressMessage(const char *msg)
1668 wxGetApp().SetProgressMessage(msg);
1672 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
1674 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
1675 wxStaticText *stext;
1678 wxString pstr(prompt, WX_DEFAULT_CONV);
1679 wxString defstr(buf, WX_DEFAULT_CONV);
1680 { // Vertical sizer containing [prompt, textbox, buttons]
1682 sizer1 = new wxBoxSizer(wxVERTICAL);
1683 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, wxSize(200, 22));
1684 sizer1->Add(stext, 0, wxEXPAND | wxALL, 6);
1685 tctrl = new wxTextCtrl(dialog, -1, defstr, wxDefaultPosition, wxSize(200, 22));
1686 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, 6);
1687 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
1688 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, 6);
1690 dialog->SetSizerAndFit(sizer1);
1691 dialog->Centre(wxBOTH);
1694 if (dialog->ShowModal() == wxID_OK) {
1695 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(WX_DEFAULT_CONV)), bufsize - 1);
1696 buf[bufsize - 1] = 0;
1705 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
1706 1 (information), 2 (exclamation), or 3 (stop). */
1708 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
1710 int wxflags, wxicon, retval;
1713 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
1715 case 3: wxicon = wxICON_ERROR; break;
1716 case 2: wxicon = wxICON_EXCLAMATION; break;
1717 default: wxicon = wxICON_INFORMATION; break;
1719 wxString wxmessage(message, WX_DEFAULT_CONV);
1720 wxString wxtitle(title, WX_DEFAULT_CONV);
1721 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
1722 return (retval == wxOK ? 1 : 0);
1726 MyAppCallback_errorMessageBox(const char *fmt, ...)
1732 if (strchr(fmt, '%') == 0) {
1734 } else if (strcmp(fmt, "%s") == 0) {
1735 s = va_arg(ap, char *);
1737 vasprintf(&s, fmt, ap);
1740 MyAppCallback_messageBox(s, "Error", 0, 3);
1746 MyAppCallback_getHomeDir(void)
1750 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
1751 s = getenv("USERPROFILE");
1755 return (s == NULL ? NULL : strdup(s));
1759 MyAppCallback_getDocumentHomeDir(void)
1764 s = getenv("USERPROFILE");
1765 asprintf(&ss, "%s\\My Documents", s);
1769 return (s == NULL ? NULL : strdup(s));
1774 MyAppCallback_registerScriptMenu(const char *cmd, const char *title)
1776 wxGetApp().RegisterScriptMenu(cmd, title);
1780 MyAppCallback_lookupScriptMenu(const char *title)
1782 return wxGetApp().LookupScriptMenu(title);
1786 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
1789 wxString cwd = wxFileName::GetCwd();
1790 wxString path(cpath, wxConvFile);
1791 char *p = strdup(cpath);
1792 char sep = wxFileName::GetPathSeparator();
1793 char *pp, *script = NULL;
1794 if ((pp = strrchr(p, sep)) != NULL) {
1796 wxString dirname(p, wxConvFile);
1797 wxFileName::SetCwd(dirname);
1800 /* Read the content of the file */
1801 FILE *fp = fopen(cpath, "rb");
1804 fseek(fp, 0, SEEK_END);
1806 fseek(fp, 0, SEEK_SET);
1807 script = (char *)malloc(len + 1);
1808 if (script!= NULL) {
1809 fread(script, 1, len, fp);
1815 if (script == NULL) {
1817 return (RubyValue)6; /* Cannot open file */
1820 /* Check the encoding specification, and if present convert it to default encoding */
1822 char *lp = script, *eolp;
1824 while (n < 2) { /* Check the first two lines */
1825 while (*lp && isspace(*lp))
1827 if (*lp == 0 || *lp++ != '#') /* Check only the comment line */
1831 if (*lp == '!') { /* Shebang line */
1832 while (*lp && *lp != '\n')
1833 lp++; /* Skip until end of line */
1838 for (eolp = lp; *eolp && *eolp != '\n'; eolp++);
1841 *eolp = 0; /* Limit the search area */
1842 lp = strstr(lp, "coding:");
1843 *eolp = '\n'; /* Restore original string */
1846 while (*lp && isspace(*lp))
1848 if (strncasecmp(lp, "shift-jis", 9) == 0) {
1849 wxString s(script, wxCSConv(wxT("cp932")));
1851 script = strdup(s.mb_str(WX_DEFAULT_CONV));
1852 } else if (strncasecmp(lp, "utf-8", 5) == 0) {
1853 wxString s(script, wxConvUTF8);
1855 script = strdup(s.mb_str(WX_DEFAULT_CONV));
1864 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), pp, status);
1868 wxFileName::SetCwd(cwd);
1872 void MyAppCallback_beginUndoGrouping(void)
1874 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1875 wxList::iterator iter;
1876 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1877 ((MyDocument *)(*iter))->BeginUndoGrouping();
1881 void MyAppCallback_endUndoGrouping(void)
1883 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1884 wxList::iterator iter;
1885 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1886 ((MyDocument *)(*iter))->EndUndoGrouping();
1890 int MyAppCallback_callSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *output, FILE *errout)
1892 return wxGetApp().CallSubProcess(cmdline, procname, callback, callback_data, output, errout);
1895 void MyAppCallback_showConsoleWindow(void)
1897 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
1902 void MyAppCallback_hideConsoleWindow(void)
1904 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
1908 void MyAppCallback_bell(void)
1913 int MyAppCallback_playSound(const char *filename, int flag)
1915 unsigned uflag = wxSOUND_SYNC;
1917 uflag = wxSOUND_ASYNC;
1919 uflag = wxSOUND_ASYNC | wxSOUND_LOOP;
1920 wxString fnamestr(filename, wxConvFile);
1921 bool retval = wxSound::Play(fnamestr, uflag);
1925 void MyAppCallback_stopSound(void)