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_extern.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 const char *gSettingQuitOnCloseLastWindow = "quit_on_close_last_window";
79 MyFrame *frame = (MyFrame *) NULL;
81 bool gInitCompleted = false;
85 //IMPLEMENT_CLASS(MyApp, wxApp)
87 BEGIN_EVENT_TABLE(MyApp, wxApp)
88 //EVT_KEY_DOWN(MyApp::OnChar)
89 //EVT_MOUSE_EVENTS(MyApp::OnMouseEvent)
90 EVT_COMMAND(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, MyApp::OnScriptMenuModified)
91 EVT_COMMAND(MyDocumentEvent_openFilesByIPC, MyDocumentEvent, MyApp::OnOpenFilesByIPC)
92 EVT_UPDATE_UI_RANGE(myMenuID_MyFirstMenuItem, myMenuID_MyLastMenuItem, MyApp::OnUpdateUI)
93 EVT_MENU(myMenuID_ExecuteScript, MyApp::OnExecuteScript)
94 EVT_MENU(myMenuID_OpenConsoleWindow, MyApp::OnOpenConsoleWindow)
95 EVT_MENU(myMenuID_EmptyConsoleWindow, MyApp::OnEmptyConsoleWindow)
96 EVT_MENU(myMenuID_ViewGlobalParameters, MyApp::OnViewGlobalParameters)
97 EVT_MENU(myMenuID_ViewParameterFilesList, MyApp::OnViewParameterFilesList)
98 EVT_MENU(myMenuID_ImportAmberLib, MyApp::OnImportAmberLib)
99 #if defined(__WXMAC__)
100 EVT_ACTIVATE(MyApp::OnActivate)
102 EVT_END_PROCESS(-1, MyApp::OnEndProcess)
103 EVT_TIMER(-1, MyApp::TimerInvoked)
104 EVT_COMMAND(myMenuID_Internal_CheckIfAllWindowsAreGone, MyDocumentEvent, MyApp::CheckIfAllWindowsAreGoneHandler)
107 // Find the path of the directory where the relevant resources are to be found.
108 // Mac: the "Resources" directory in the application bundle.
109 // Windows: the directory in which the application executable is located.
112 MyApp::FindResourcePath()
114 #if defined(__WXMAC__)
115 CFBundleRef mainBundle = CFBundleGetMainBundle();
116 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(mainBundle);
119 if (CFURLGetFileSystemRepresentation(ref, true, buffer, sizeof buffer)) {
120 wxString dirname((const char *)buffer, WX_DEFAULT_CONV);
126 return wxEmptyString;
127 #elif defined(__WXMSW__)
129 wxString argv0 = wxTheApp->argv[0];
130 // Fix dosish path (when invoked from MSYS console, the path may be unix-like)
131 // Note: absolute paths like /c/Molby/... (== c:\Molby\...) is not supported
133 char *p = strdup(argv0.mb_str(wxConvFile));
135 wxString argv0_fixed(p, wxConvFile);
138 // Is it an absolute path?
139 if (wxIsAbsolutePath(argv0)) {
140 return wxPathOnly(argv0);
142 // Is it a relative path?
143 wxString currentDir = wxGetCwd();
144 if (currentDir.Last() != wxFILE_SEP_PATH)
145 currentDir += wxFILE_SEP_PATH;
146 str = currentDir + argv0;
147 if (wxFileExists(str))
148 return wxPathOnly(str);
152 pathList.AddEnvList(wxT("PATH"));
153 str = pathList.FindAbsoluteValidPath(argv0);
155 return wxPathOnly(str);
156 return wxEmptyString;
158 #error "FindResourcePath is not defined for UNIXes."
165 m_progressFrame = NULL;
166 m_processTerminated = false;
167 m_processExitCode = 0;
169 scriptMenuCommands = NULL;
170 scriptMenuTitles = NULL;
171 scriptMenuModifiedEventPosted = false;
172 parameterFrame = NULL;
173 parameterFilesFrame = NULL;
175 m_CountNamedFragments = 0;
176 m_NamedFragments = (char **)(-1); /* Will be set to NULL after Ruby interpreter is initialized */
177 m_pendingFilesToOpen = NULL;
178 m_CountTimerDocs = 0;
182 #if defined(__WXMSW__)
184 m_ipcServiceName = NULL;
190 bool MyApp::OnInit(void)
194 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
195 wxSystemOptions::SetOption(wxT("osx.openfiledialog.always-show-types"), 1);
200 // Check if the same application is already running
202 asprintf(&buf, "Molby-%s", (const char *)wxGetUserId().mb_str(WX_DEFAULT_CONV));
203 wxString name(buf, WX_DEFAULT_CONV);
204 m_ipcServiceName = new wxString(name);
205 m_ipcServiceName->Prepend(wxT("IPC-"));
207 m_checker = new wxSingleInstanceChecker(name);
208 if (m_checker->IsAnotherRunning()) {
209 // Make a connection with the other instance and ask for opening the file(s)
211 wxConnectionBase *connection;
213 for (i = 1; i < argc; i++) {
214 files.append(argv[i]);
215 files.append(wxT("\n"));
217 m_client = new MyClient;
218 connection = m_client->MakeConnection(wxT("localhost"), *m_ipcServiceName, MOLBY_IPC_TOPIC);
219 if (connection == NULL) {
220 wxLogError(wxT("Molby is already running; please shut it down and retry"));
224 connection->Execute(files);
228 m_server = new MyServer;
229 if (m_server->Create(*m_ipcServiceName) == false) {
237 // Create a document manager
238 m_docManager = new MyDocManager;
240 // Create templates relating drawing documents to their views
241 new wxDocTemplate(m_docManager, _T("Molby Structure File"), _T("*.mbsf"), _T(""), _T("mbsf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
242 new wxDocTemplate(m_docManager, _T("Protein Structure File"), _T("*.psf"), _T(""), _T("psf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
243 new wxDocTemplate(m_docManager, _T("Protein Data Bank File"), _T("*.pdb"), _T(""), _T("pdb"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
244 new wxDocTemplate(m_docManager, _T("Gaussian Input File"), _T("*.com;*.gjf"), _T(""), _T("com"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
245 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));
246 new wxDocTemplate(m_docManager, _T("Gaussian Checkpoint File"), _T("*.fchk;*.fch"), _T(""), _T("fchk"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
247 new wxDocTemplate(m_docManager, _T("GAMESS Input File"), _T("*.inp"), _T(""), _T("inp"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
248 new wxDocTemplate(m_docManager, _T("GAMESS DAT File"), _T("*.dat"), _T(""), _T("dat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
249 new wxDocTemplate(m_docManager, _T("ORTEP Input File"), _T("*.tep"), _T(""), _T("tep"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
250 new wxDocTemplate(m_docManager, _T("SHELX Input File"), _T("*.ins;*.res"), _T(""), _T("ins"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
251 new wxDocTemplate(m_docManager, _T("Crystallographic Information File"), _T("*.cif"), _T(""), _T("cif"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
252 new wxDocTemplate(m_docManager, _T("Cartesian"), _T("*.xyz"), _T(""), _T("xyz"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
253 new wxDocTemplate(m_docManager, _T("Any Molecule"), _T("*.*"), _T(""), _T(""), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
255 // Create the main frame window
256 frame = new MyFrame((wxDocManager *) m_docManager, (wxFrame *) NULL,
257 _T("Molby"), wxPoint(0, 0), wxSize(800, 600),
258 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
260 // Give it an icon (this is ignored in MDI mode: uses resources)
262 frame->SetIcon(wxIcon(_T("doc")));
265 frame->SetIcon(wxIcon(_T("doc.xbm")));
268 wxMenuBar *menu_bar = CreateMenuBar(0);
271 wxMenuBar::MacSetCommonMenuBar(menu_bar);
274 // Associate the menu bar with the frame
275 frame->SetMenuBar(menu_bar);
277 frame->Centre(wxBOTH);
279 #if defined(__WXMAC__) || defined(__WXMSW__)
280 frame->Move(-10000, -10000); // Set invisible
288 // Load default settings from the preference file
289 LoadDefaultSettings();
291 // Create a console window
292 consoleFrame = ConsoleFrame::CreateConsoleFrame(frame);
293 consoleFrame->Show(true);
295 /* Initialize Ruby interpreter with the startup script */
296 /* (Also read startup information) */
298 extern int gRevisionNumber;
299 static const char fname[] = "startup.rb";
300 wxString dirname = FindResourcePath();
302 dirname += wxFILE_SEP_PATH;
303 dirname += wxT("Scripts");
304 /* wxString cwd = wxGetCwd(); */
305 wxSetWorkingDirectory(dirname);
307 wxString fnamestr(fname, wxConvFile);
308 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, (const char *)dirname.mb_str(wxConvFile));
311 wxString docHome(MyAppCallback_getDocumentHomeDir(), wxConvFile);
312 wxSetWorkingDirectory(docHome);
316 /* Pasteboard type strings (includes the revision number) */
317 asprintf(&gMoleculePasteboardType, "Molecule_%d", gRevisionNumber);
318 asprintf(&gParameterPasteboardType, "Parameter_%d", gRevisionNumber);
320 MyAppCallback_showScriptMessage("%% ");
322 /* Build the predefined fragments menu */
323 m_NamedFragments = NULL;
324 // UpdatePredefinedFragmentMenu(GetMainFrame()->GetMenuBar());
325 UpdatePredefinedFragmentMenu(consoleFrame->GetMenuBar());
329 /* Open given files: Ruby script is executed, other files are opened as a document */
331 #if defined(__WXMSW__)
332 m_docManager->CreateDocument(wxEmptyString, wxDOC_NEW);
337 for (i = 1; i < argc; i++) {
338 files.append(argv[i]);
339 files.append(wxT("\n"));
344 gInitCompleted = true;
350 // kind == 0: main menu
351 // kind == 1: molecule window
352 // kind == 2: console window
354 MyApp::CreateMenuBar(int kind, wxMenu **out_file_history_menu, wxMenu **out_edit_menu)
358 wxMenu *file_menu = new wxMenu;
360 file_menu->Append(wxID_NEW, _T("&New...\tCtrl-N"));
361 file_menu->Append(wxID_OPEN, _T("&Open...\tCtrl-O"));
362 if (out_file_history_menu != NULL) {
363 *out_file_history_menu = new wxMenu;
364 file_menu->AppendSubMenu(*out_file_history_menu, _T("Open Recent"));
365 m_docManager->FileHistoryAddFilesToMenu(*out_file_history_menu);
366 m_docManager->FileHistoryUseMenu(*out_file_history_menu); // Should be removed when menu is discarded
368 /* Build "Open Predefined" */
369 wxMenu *predefined_menu = new wxMenu;
370 file_menu->Append(myMenuID_PredefinedFragment, _T("Open Predefined"), predefined_menu);
372 file_menu->AppendSeparator();
373 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
374 file_menu->Append(wxID_SAVE, _T("&Save\tCtrl-S"));
375 file_menu->Append(wxID_SAVEAS, _T("Save &As..."));
376 file_menu->Append(wxID_REVERT, _T("Revert to Saved"));
378 file_menu->AppendSeparator();
379 file_menu->Append(myMenuID_Import, _T("Import..."));
380 file_menu->Append(myMenuID_Export, _T("Export..."));
382 file_menu->AppendSeparator();
383 file_menu->Append(wxID_PRINT, _T("&Print...\tCtrl-P"));
384 file_menu->Append(wxID_PRINT_SETUP, _T("Print &Setup..."));
385 file_menu->Append(wxID_PREVIEW, _T("Print Pre&view"));
387 file_menu->AppendSeparator();
388 #if defined(__WXMAC__)
389 file_menu->Append(wxID_EXIT, _T("E&xit\tCtrl-Q"));
391 file_menu->Append(wxID_EXIT, _T("E&xit\tAlt-X"));
394 wxMenu *edit_menu = new wxMenu;
395 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
396 edit_menu->Append(wxID_REDO, _T("&Redo"));
397 edit_menu->AppendSeparator();
398 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
399 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
400 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
401 edit_menu->Append(wxID_CLEAR, _T("Clear"));
402 edit_menu->AppendSeparator();
403 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
404 edit_menu->Append(myMenuID_SelectFragment, _T("Select Fragment\tCtrl-F"));
405 edit_menu->Append(myMenuID_SelectReverse, _T("Select Reverse"));
406 edit_menu->AppendSeparator();
407 wxMenu *create_parameter_menu = new wxMenu;
408 create_parameter_menu->Append(myMenuID_CreateNewVdwParameter, _T("Vdw"));
409 create_parameter_menu->Append(myMenuID_CreateNewBondParameter, _T("Bond"));
410 create_parameter_menu->Append(myMenuID_CreateNewAngleParameter, _T("Angle"));
411 create_parameter_menu->Append(myMenuID_CreateNewDihedralParameter, _T("Dihedral"));
412 create_parameter_menu->Append(myMenuID_CreateNewImproperParameter, _T("Improper"));
413 create_parameter_menu->Append(myMenuID_CreateNewVdwPairParameter, _T("Vdw Pair"));
414 create_parameter_menu->Append(myMenuID_CreateNewVdwCutoffParameter, _T("Vdw Cutoff"));
415 edit_menu->Append(myMenuID_CreateNewAtom, _T("Create New Atom\tCtrl-I"));
416 edit_menu->Append(myMenuID_CreateNewParameter, _T("Create New Parameter"), create_parameter_menu);
417 edit_menu->Append(myMenuID_CreatePiAnchor, _T("Create Pi Anchor"));
418 edit_menu->AppendSeparator();
419 wxMenu *add_hydrogen_menu = new wxMenu;
420 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp3, _T("Tetrahedral sp3"));
421 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp2, _T("Trigonal sp2"));
422 add_hydrogen_menu->Append(myMenuID_AddHydrogenLinear, _T("Linear sp"));
423 add_hydrogen_menu->Append(myMenuID_AddHydrogenPyramidal, _T("Pyramidal (like NH2)"));
424 add_hydrogen_menu->Append(myMenuID_AddHydrogenBent, _T("Bent (like OH)"));
425 edit_menu->Append(myMenuID_AddHydrogen, _T("Add Hydrogen"), add_hydrogen_menu);
427 if (out_edit_menu != NULL)
428 *out_edit_menu = edit_menu; // Should be associated with the command processor if available
430 wxMenu *show_menu = new wxMenu;
431 show_menu->Append(myMenuID_FitToScreen, _T("Fit To Screen\tCtrl-T"));
432 show_menu->Append(myMenuID_CenterSelection, _T("Center Selection"));
433 show_menu->AppendSeparator();
434 show_menu->Append(myMenuID_ShowUnitCell, _T("Show Unit Cell"), _T(""), wxITEM_CHECK);
435 /* show_menu->Append(myMenuID_ShowPeriodicBox, _T("Show Periodic Box"), _T(""), wxITEM_CHECK); */
436 show_menu->Append(myMenuID_ShowHydrogens, _T("Show Hydrogen Atoms"), _T(""), wxITEM_CHECK);
437 show_menu->Append(myMenuID_ShowDummyAtoms, _T("Show Dummy Atoms"), _T(""), wxITEM_CHECK);
438 show_menu->Append(myMenuID_ShowExpandedAtoms, _T("Show Expanded Atoms"), _T(""), wxITEM_CHECK);
439 show_menu->Append(myMenuID_ShowEllipsoids, _T("Show Ellipsoids"), _T(""), wxITEM_CHECK);
440 show_menu->Append(myMenuID_ShowRotationCenter, _T("Show Rotation Center"), _T(""), wxITEM_CHECK);
441 show_menu->AppendSeparator();
442 show_menu->Append(myMenuID_HideSelected, _T("Hide Selected"), _T(""));
443 show_menu->Append(myMenuID_HideUnselected, _T("Hide Unselected"), _T(""));
444 show_menu->Append(myMenuID_HideReverse, _T("Hide Reverse"), _T(""));
445 show_menu->Append(myMenuID_ShowAllAtoms, _T("Show All Atoms"), _T(""));
446 show_menu->AppendSeparator();
447 show_menu->Append(myMenuID_ShowGraphite, _T("Show Graphite..."));
448 show_menu->AppendSeparator();
449 show_menu->Append(myMenuID_LineMode, _T("Line Mode"), _T(""), wxITEM_CHECK);
451 wxMenu *md_menu = new wxMenu;
452 md_menu->Append(myMenuID_MolecularDynamics, _T("Molecular Dynamics..."));
453 md_menu->Append(myMenuID_Minimize, _T("Minimize..."));
454 md_menu->Append(myMenuID_StopMDRun, _T("Stop\tCtrl-."));
455 md_menu->AppendSeparator();
456 // md_menu->Append(myMenuID_ReadParameters, _T("Read Parameters..."));
457 md_menu->Append(myMenuID_RunAntechamber, _T("Auto Guess MM/MD Parameters..."));
458 md_menu->Append(myMenuID_GuessUFFParameters, _T("Guess UFF Parameters..."));
459 md_menu->Append(myMenuID_ViewGlobalParameters, _T("View Global Parameters..."));
460 md_menu->Append(myMenuID_ViewParameterFilesList, _T("Load/Unload Global Parameters..."));
461 md_menu->AppendSeparator();
462 md_menu->Append(myMenuID_DefinePeriodicBox, _T("Define Unit Cell..."));
463 md_menu->Append(myMenuID_ShowPeriodicImage, _T("Show Periodic Image..."));
464 /* md_menu->Append(myMenuID_PressureControl, _T("Pressure Control...")); */
465 /* md_menu->Append(myMenuID_DefineSymmetry, _T("Define Symmetry Operations..."));
466 md_menu->Append(myMenuID_ExpandBySymmetry, _T("Expand by Symmetry...")); */
467 md_menu->AppendSeparator();
469 wxMenu *md_tools_menu = new wxMenu;
470 /* md_tools_menu->Append(myMenuID_RunAntechamber, _T("Antechamber/parmchk...")); */
471 md_tools_menu->Append(myMenuID_RunResp, _T("GAMESS/RESP..."));
472 md_tools_menu->Append(myMenuID_CreateSanderInput, _T("Create SANDER input..."));
473 md_tools_menu->Append(myMenuID_ImportAmberLib, _T("Import AMBER Lib..."));
474 md_tools_menu->Append(myMenuID_ImportAmberFrcmod, _T("Import AMBER Frcmod..."));
475 md_menu->Append(myMenuID_MDTools, _T("Tools"), md_tools_menu);
477 wxMenu *qc_menu = new wxMenu;
478 qc_menu->Append(myMenuID_CreateGamessInput, _T("Create GAMESS input..."));
479 qc_menu->Append(myMenuID_CreateMOPACInput, _T("Create MOPAC input..."));
480 qc_menu->Append(myMenuID_CreateMOCube, _T("Create MO cube..."));
482 wxMenu *script_menu = new wxMenu;
483 script_menu->Append(myMenuID_ExecuteScript, _T("Execute Script..."));
484 script_menu->Append(myMenuID_OpenConsoleWindow, _T("Open Console Window"));
485 script_menu->Append(myMenuID_EmptyConsoleWindow, _T("Empty Console Window"));
486 script_menu->AppendSeparator();
487 countNonCustomScriptMenu = script_menu->GetMenuItemCount();
489 wxMenu *help_menu = new wxMenu;
490 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
492 wxMenuBar *menu_bar = new wxMenuBar;
494 menu_bar->Append(file_menu, _T("&File"));
495 menu_bar->Append(edit_menu, _T("&Edit"));
496 menu_bar->Append(show_menu, _T("Show"));
497 menu_bar->Append(md_menu, _T("MM/MD"));
498 menu_bar->Append(qc_menu, _T("QChem"));
499 menu_bar->Append(script_menu, _T("&Script"));
500 menu_bar->Append(help_menu, _T("&Help"));
502 UpdateScriptMenu(menu_bar);
503 if (m_NamedFragments != (char **)(-1))
504 UpdatePredefinedFragmentMenu(menu_bar);
510 /* When the application is launched without any documents, an empty document is opened.
511 This should be implemented by overriding this special method; parsing argc/argv does
512 not work, because the list of files is passed through an Apple Event. */
516 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
520 MyApp::MacOpenFile(const wxString &fileName)
522 wxString files(fileName);
526 /* Open given files: instead of calling MacOpenFile() for each entry, build a file list
527 and call MyApp::OnOpenFiles() */
529 MyApp::MacHandleAEODoc(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply))
533 DescType returnedType;
539 return noErr; /* TODO: handle open Apple event */
541 err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList, &docList);
545 err = AECountItems(&docList, &itemsInList);
549 ProcessSerialNumber PSN ;
550 PSN.highLongOfPSN = 0 ;
551 PSN.lowLongOfPSN = kCurrentProcess ;
552 SetFrontProcess( &PSN ) ;
554 wxString fName, fNameList;
557 for (i = 1; i <= itemsInList; i++)
560 &docList, i, typeFSRef, &keywd, &returnedType,
561 (Ptr)&theRef, sizeof(theRef), &actualSize);
562 // fName = wxMacFSRefToPath( &theRef ) ;
563 fNameList.append(fName);
564 fNameList.append(wxT("\n"));
567 OnOpenFiles(fNameList);
577 SaveDefaultSettings();
587 sModifyMenuForFilterMode(wxMenuBar *mbar)
592 idx = mbar->FindMenu(wxT("Show"));
593 if (idx != wxNOT_FOUND)
594 delete mbar->Remove(idx);
595 idx = mbar->FindMenu(wxT("MM/MD"));
596 if (idx != wxNOT_FOUND)
597 delete mbar->Remove(idx);
598 idx = mbar->FindMenu(wxT("QChem"));
599 if (idx != wxNOT_FOUND)
600 delete mbar->Remove(idx);
601 idx = mbar->FindMenu(wxT("Script"));
602 if (idx != wxNOT_FOUND) {
603 menu = mbar->GetMenu(idx);
604 n = menu->GetMenuItemCount();
605 for (i = n - 1; i >= 0; i--) {
606 item = menu->FindItemByPosition(i);
608 if (id != myMenuID_OpenConsoleWindow && id != myMenuID_EmptyConsoleWindow && id != myMenuID_ExecuteScript) {
615 idx = mbar->FindMenu(wxT("Edit"));
616 if (idx != wxNOT_FOUND) {
617 menu = mbar->GetMenu(idx);
618 n = menu->GetMenuItemCount();
619 for (i = n - 1; i >= 0; i--) {
620 item = menu->FindItemByPosition(i);
622 if (id == wxID_SELECTALL)
629 idx = mbar->FindMenu(wxT("File"));
630 if (idx != wxNOT_FOUND) {
631 menu = mbar->GetMenu(idx);
632 n = menu->GetMenuItemCount();
633 for (i = n - 1; i >= 0; i--) {
634 item = menu->FindItemByPosition(i);
636 if (id != wxID_OPEN && id != wxID_EXIT) {
646 MyApp::ShowProgressPanel(const char *mes)
648 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
649 if (m_progressFrame == NULL) {
652 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
653 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
654 if (quitMenuItem != NULL)
655 quitMenuItem->Enable(false);
659 m_progressFrame = new ProgressFrame(_T("Progress"), string);
660 m_progressCanceled = false;
661 m_progressValue = -1;
666 MyApp::HideProgressPanel()
668 if (m_progressFrame != NULL) {
669 m_progressFrame->Hide();
670 m_progressFrame->Destroy();
671 m_progressFrame = NULL;
674 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
676 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
677 if (quitMenuItem != NULL)
678 quitMenuItem->Enable(true);
685 MyApp::SetProgressValue(double dval)
687 if (m_progressFrame != NULL) {
688 m_progressFrame->SetProgressValue(dval);
693 MyApp::SetProgressMessage(const char *mes)
695 if (m_progressFrame != NULL) {
696 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
697 m_progressFrame->SetProgressMessage(string);
702 MyApp::IsInterrupted()
704 if (m_progressFrame != NULL)
705 return m_progressFrame->CheckInterrupt();
707 if (::wxGetKeyState(WXK_ESCAPE))
714 #warning "TODO: Move this to MyDocument and 'import parameters' "
717 MyApp::OnReadParameters(wxCommandEvent& event)
719 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Parameter File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
720 if (dialog->ShowModal() == wxID_OK) {
721 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
723 ParameterReadFromFile(NULL, p, &wbuf, NULL);
726 AppendConsoleMessage(wbuf);
737 MyApp::OnOpenConsoleWindow(wxCommandEvent& event)
739 consoleFrame->Show(true);
740 consoleFrame->Raise();
744 MyApp::OnEmptyConsoleWindow(wxCommandEvent& event)
746 consoleFrame->EmptyBuffer();
750 MyApp::OnViewGlobalParameters(wxCommandEvent& event)
752 if (parameterFrame == NULL) {
753 parameterFrame = GlobalParameterFrame::CreateGlobalParameterFrame(GetMainFrame());
754 MainView_createColumnsForTableAtIndex(NULL, kMainViewParameterTableIndex);
756 MainView_refreshTable(NULL);
757 parameterFrame->Show(true);
758 parameterFrame->Raise();
762 MyApp::OnViewParameterFilesList(wxCommandEvent &event)
764 if (parameterFilesFrame == NULL) {
765 parameterFilesFrame = GlobalParameterFilesFrame::CreateGlobalParameterFilesFrame(GetMainFrame());
767 parameterFilesFrame->Show(true);
768 parameterFilesFrame->Raise();
772 MyApp::OnImportAmberLib(wxCommandEvent &event)
774 MolActionCreateAndPerform(NULL, SCRIPT_ACTION(""), "cmd_import_amberlib");
778 MyApp::LookupScriptMenu(const char *title)
783 for (i = 0; i < countScriptMenu; i++) {
784 if (strcmp(title, scriptMenuTitles[i]) == 0)
791 MyApp::RegisterScriptMenu(const char *cmd, const char *title)
794 if (cmd[0] == 0 && title[0] == 0)
795 i = countScriptMenu; /* A sepearator */
797 for (i = 0; i < countScriptMenu; i++) {
798 if (strcmp(cmd, scriptMenuCommands[i]) == 0) {
799 free(scriptMenuTitles[i]);
800 scriptMenuTitles[i] = strdup(title);
802 } else if (strcmp(title, scriptMenuTitles[i]) == 0) {
803 free(scriptMenuCommands[i]);
804 scriptMenuCommands[i] = strdup(cmd);
809 if (i >= countScriptMenu) {
810 if (countScriptMenu == 0) {
811 scriptMenuTitles = (char **)malloc(sizeof(char *));
812 scriptMenuCommands = (char **)malloc(sizeof(char *));
814 scriptMenuTitles = (char **)realloc(scriptMenuTitles, sizeof(char *) * (countScriptMenu + 1));
815 scriptMenuCommands = (char **)realloc(scriptMenuCommands, sizeof(char *) * (countScriptMenu + 1));
817 scriptMenuTitles[countScriptMenu] = strdup(title);
818 scriptMenuCommands[countScriptMenu] = strdup(cmd);
821 if (!scriptMenuModifiedEventPosted) {
822 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_scriptMenuModified);
823 wxPostEvent(this, myEvent);
824 scriptMenuModifiedEventPosted = true;
829 MyApp::UpdateScriptMenu(wxMenuBar *mbar)
833 wxMenu *smenu = mbar->GetMenu(myMenuIndex_Script);
837 // Remove all custom items
838 for (i = smenu->GetMenuItemCount() - 1; i >= countNonCustomScriptMenu; i--) {
839 wxMenuItem *item = smenu->FindItemByPosition(i);
840 if (!item->IsSeparator()) {
841 int n = item->GetId();
842 Disconnect(n, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
848 // Build script menu from internal array
849 for (i = 0; i < countScriptMenu; i++) {
850 const char *title = scriptMenuTitles[i];
851 if (title == NULL || title[0] == 0) {
852 smenu->AppendSeparator();
854 wxString stitle(scriptMenuTitles[i], WX_DEFAULT_CONV);
855 wxMenuItem *item = new wxMenuItem(smenu, myMenuID_CustomScript + i, stitle);
859 if (countScriptMenu > 0)
860 Connect(myMenuID_CustomScript, myMenuID_CustomScript + countScriptMenu - 1, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
864 MyApp::OnScriptMenuModified(wxCommandEvent& event)
866 scriptMenuModifiedEventPosted = false;
867 // UpdateScriptMenu(GetMainFrame()->GetMenuBar());
868 UpdateScriptMenu(consoleFrame->GetMenuBar());
873 MyApp::OnScriptMenuSelected(wxCommandEvent& event)
879 int index = event.GetId() - myMenuID_CustomScript;
880 if (index < 0 || index >= countScriptMenu)
882 cmd = scriptMenuCommands[index];
883 methodType = Ruby_methodType("Molecule", cmd);
886 mview = MainViewCallback_activeView();
889 else mol = mview->mol;
890 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
891 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), cmd);
892 else if (methodType == 2) /* Class method (with molecule as an only argument) */
893 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("M"), cmd, mol);
898 MyApp::UpdatePredefinedFragmentMenu(wxMenuBar *mbar)
901 wxMenuItem *fmenuItem = mbar->FindItem(myMenuID_PredefinedFragment);
902 wxMenu *fmenu = (fmenuItem != NULL ? fmenuItem->GetSubMenu() : NULL);
905 if (m_NamedFragments == (char **)(-1))
908 /* Rebuild sNamedFragments array */
909 if (m_NamedFragments != NULL) {
910 for (i = 0; i < m_CountNamedFragments; i++) {
911 free(m_NamedFragments[i * 2]);
912 free(m_NamedFragments[i * 2 + 1]);
914 free(m_NamedFragments);
916 m_NamedFragments = NULL;
917 m_CountNamedFragments = 0;
918 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION(";i"), "lambda { $named_fragments.length }", &n) != 0 || n <= 0)
920 m_CountNamedFragments = n;
921 m_NamedFragments = (char **)calloc(sizeof(char *), n * 2);
922 for (i = 0; i < n; i++) {
923 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "lambda { |i| $named_fragments[i][0] }", i, &m_NamedFragments[i * 2]) != 0 ||
924 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "lambda { |i| $named_fragments[i][1] }", i, &m_NamedFragments[i * 2 + 1]) != 0)
928 for (i = 0; i < m_CountNamedFragments; i++) {
929 if (m_NamedFragments[i * 2] != NULL)
930 free(m_NamedFragments[i * 2]);
931 if (m_NamedFragments[i * 2 + 1] != NULL)
932 free(m_NamedFragments[i * 2 + 1]);
934 free(m_NamedFragments);
935 m_CountNamedFragments = 0;
936 m_NamedFragments = NULL;
940 wxMenu *predefined_submenu = NULL;
943 for (i = sn = 0; i < m_CountNamedFragments; i++) {
944 if (strcmp(m_NamedFragments[i * 2 + 1], "-") == 0) {
945 if (predefined_submenu != NULL) {
946 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
948 predefined_submenu = new wxMenu;
949 stitle = wxString(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
952 wxString mtitle(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
953 (predefined_submenu != NULL ? predefined_submenu : fmenu)->Append(myMenuID_PredefinedFragment + 1 + i, mtitle);
956 if (predefined_submenu != NULL)
957 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
958 Connect(myMenuID_PredefinedFragment + 1, myMenuID_PredefinedFragment + m_CountNamedFragments, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnFragmentMenuSelected), NULL, this);
962 MyApp::OnFragmentMenuSelected(wxCommandEvent& event)
964 int index = event.GetId() - myMenuID_PredefinedFragment - 1;
965 if (index < 0 || index >= m_CountNamedFragments)
967 // Open a predefined fragment as a new file
969 Molecule *mol = MoleculeNew();
973 asprintf(&fullname, "%s/Scripts/mbsf/%s", (const char *)(FindResourcePath().mb_str(wxConvFile)), m_NamedFragments[index * 2 + 1]);
974 result = MoleculeLoadMbsfFile(mol, fullname, &errbuf);
975 if (errbuf != NULL) {
976 MyAppCallback_showScriptMessage("On loading %s:\n%s", m_NamedFragments[index * 2 + 1], errbuf);
980 MyAppCallback_errorMessageBox("Cannot open named fragment %s\n(See console for detailed message)", m_NamedFragments[index * 2]);
985 MyDocument *doc = (MyDocument *)(DocManager()->CreateDocument(wxT(""), wxDOC_NEW));
986 wxString title(m_NamedFragments[index * 2], WX_DEFAULT_CONV);
987 title = _T("*") + title + _T("*");
988 doc->SetMolecule(mol);
989 if (mol->natoms > 1000)
990 mol->mview->lineMode = 1;
991 MainView_resizeToFit(mol->mview);
993 // Change the window title
994 doc->SetTitle(title);
995 // Propagate the change of the window title
996 wxList::compatibility_iterator node = doc->GetViews().GetFirst();
998 wxView *view = (wxView *)node->GetData();
999 view->OnChangeFilename();
1000 node = node->GetNext();
1005 MyApp::OnUpdateUI(wxUpdateUIEvent& event)
1007 int uid = event.GetId();
1008 MainView *mview = MainViewCallback_activeView();
1009 if (uid >= myMenuID_CustomScript && uid < myMenuID_CustomScript + countScriptMenu) {
1010 // Check the script menu
1014 int index = uid - myMenuID_CustomScript;
1015 cmd = scriptMenuCommands[index];
1016 methodType = Ruby_methodType("Molecule", cmd);
1017 event.Enable(false);
1018 if (methodType != 0) {
1021 else mol = mview->mol;
1022 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
1024 else if (methodType == 2) /* Class method (with molecule as an only argument) */
1027 } else if (uid >= myMenuID_PredefinedFragment && uid <= myMenuID_PredefinedFragment + m_CountNamedFragments) {
1031 case myMenuID_ExecuteScript:
1032 case myMenuID_OpenConsoleWindow:
1033 case myMenuID_EmptyConsoleWindow:
1034 case myMenuID_ViewParameterFilesList:
1035 case myMenuID_ViewGlobalParameters:
1036 case myMenuID_MDTools:
1037 case myMenuID_ImportAmberLib:
1042 event.Enable(false);
1050 MyApp::OnExecuteScript(wxCommandEvent &event)
1052 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Script File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
1053 if (dialog->ShowModal() == wxID_OK) {
1056 wxString path = dialog->GetPath();
1058 // Command line: execute_script('pathname')
1059 wxString cline(path);
1060 wxRegEx re(_T("[\\\\']")); // A backslash and a single-quote
1061 re.Replace(&cline, _T("\\\\\\0")); // A backslash followed by "\0"
1062 cline.Prepend(_T("execute_script('"));
1064 MyAppCallback_setConsoleColor(3);
1065 MyAppCallback_showScriptMessage("%s", (const char *)(cline.mb_str(wxConvFile)));
1066 MyAppCallback_showScriptMessage("\n");
1067 MyAppCallback_setConsoleColor(0);
1069 retval = MyAppCallback_executeScriptFromFile((const char *)(path.mb_str(wxConvFile)), &status);
1070 if (retval == (RubyValue)6 && status == -1)
1071 MyAppCallback_errorMessageBox("Cannot open Ruby script %s", (const char *)path.mb_str(wxConvFile));
1072 else if (status != 0)
1073 Molby_showError(status);
1079 MyApp::OnActivate(wxActivateEvent &event)
1081 #if defined(__WXMAC__) || defined(__WXMSW__)
1082 MyFrame *frame = GetMainFrame();
1084 frame->Show(false); /* Sometimes this "parent" frame gets visible and screw up the menus */
1090 MyApp::RequestOpenFilesByIPC(wxString& files)
1092 if (m_pendingFilesToOpen != NULL)
1093 m_pendingFilesToOpen->Append(files);
1095 m_pendingFilesToOpen = new wxString(files);
1096 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openFilesByIPC);
1097 wxPostEvent(this, myEvent);
1101 MyApp::OnOpenFilesByIPC(wxCommandEvent& event)
1103 if (m_pendingFilesToOpen == NULL)
1105 OnOpenFiles(*m_pendingFilesToOpen);
1106 delete m_pendingFilesToOpen;
1107 m_pendingFilesToOpen = NULL;
1111 MyApp::OnOpenFiles(const wxString &files)
1114 bool success = true;
1119 end = files.find(wxT("\n"), start);
1120 wxString file = files.Mid(start, (end == wxString::npos ? wxString::npos : end - start));
1121 if (file.Len() == 0)
1123 if (file.EndsWith(wxT(".rb")) || file.EndsWith(wxT(".mrb"))) {
1124 /* Execute the file as a Ruby script */
1125 retval = MyAppCallback_executeScriptFromFile((const char *)file.mb_str(wxConvFile), &status);
1127 if (retval == (RubyValue)6 && status == -1)
1128 MyAppCallback_errorMessageBox("Cannot open Ruby script: %s", (const char *)file.mb_str(wxConvFile));
1130 Molby_showError(status);
1134 if (NULL == wxGetApp().DocManager()->CreateDocument(file, wxDOC_SILENT))
1137 if (end == wxString::npos)
1145 MyApp::DefaultSettingsPath()
1147 wxString name = wxStandardPaths::Get().GetUserConfigDir();
1148 wxChar sep = wxFileName::GetPathSeparator();
1149 if (name[name.Len() - 1] != sep)
1151 name += _T("Molby.settings");
1156 MyApp::LoadDefaultSettings()
1158 wxString name = DefaultSettingsPath();
1159 m_defaultSettings.clear();
1160 wxTextFile file(name);
1161 if (file.Exists() && file.Open()) {
1164 for (line = file.GetFirstLine(); ; line = file.GetNextLine()) {
1167 if ((pos = line.Find('=')) != wxNOT_FOUND) {
1168 wxString key = line.Left(pos);
1169 wxString value = line.Right(line.Length() - pos - 1);
1170 SetDefaultSetting(key, value);
1180 MyApp::SaveDefaultSettings()
1182 wxString name = DefaultSettingsPath();
1183 wxTextFile file(name);
1189 MyStringHash::iterator it;
1190 for (it = m_defaultSettings.begin(); it != m_defaultSettings.end(); it++) {
1191 wxString key = it->first;
1192 wxString value = it->second;
1193 wxString line = key + _T("=") + value;
1201 MyApp::SetDefaultSetting(const wxString& key, const wxString& value)
1203 // TODO: The '=' and '#' characters may need to be escaped
1204 m_defaultSettings[key] = value;
1208 MyApp::GetDefaultSetting(const wxString& key)
1210 return m_defaultSettings[key];
1214 MyApp::GetGlobalParameterListCtrl()
1216 if (parameterFrame != NULL)
1217 return parameterFrame->GetListCtrl();
1221 #define LOG_SUBPROCESS 0
1227 MyApp::OnEndProcess(wxProcessEvent &event)
1229 m_processTerminated = true;
1230 m_processExitCode = event.GetExitCode();
1233 fprintf(fplog, "OnEndProcess called\n");
1238 MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *fpout, FILE *fperr)
1241 int callback_result = 0;
1243 bool progress_panel = false;
1245 size_t len, len_total;
1246 wxString cmdstr(cmdline, WX_DEFAULT_CONV);
1247 #if defined(__WXMSW__)
1248 extern int myKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
1250 // Show progress panel
1251 if (procname != NULL) {
1252 snprintf(buf, sizeof buf, "Running %s...", procname);
1253 ShowProgressPanel(buf);
1254 progress_panel = true;
1257 // Create log file in the document home directory
1261 char *dochome = MyAppCallback_getDocumentHomeDir();
1262 snprintf(buf, sizeof buf, "%s/%s.log", dochome, (procname ? procname : "subprocess"));
1264 fplog = fopen(buf, "w");
1270 // Create proc object and call subprocess
1271 wxProcess *proc = new wxProcess(this, -1);
1273 int flag = wxEXEC_ASYNC;
1275 flag |= wxEXEC_MAKE_GROUP_LEADER;
1277 m_processTerminated = false;
1278 m_processExitCode = 0;
1279 long pid = ::wxExecute(cmdstr, flag, proc);
1281 // MyAppCallback_errorMessageBox("Cannot start %s", procname);
1283 if (procname != NULL)
1284 HideProgressPanel();
1286 fprintf(fplog, "Cannot start '%s'\n", cmdline);
1292 fprintf(fplog, "[DEBUG]pid = %ld\n", pid);
1296 // Wait until process ends or user interrupts
1297 wxInputStream *in = proc->GetInputStream();
1298 wxInputStream *err = proc->GetErrorStream();
1300 char *membuf = NULL;
1303 while (in->CanRead()) {
1304 in->Read(buf, sizeof buf - 1);
1305 if ((len = in->LastRead()) > 0) {
1309 fprintf(fplog, "%s", buf);
1312 if (callback == DUMMY_CALLBACK) {
1313 if (memsize < len_total + 1) {
1314 char *p = (char *)realloc(membuf, len_total + 1);
1317 memmove(membuf + len_total - len, buf, len + 1);
1318 memsize = len_total + 1;
1321 } else if (fpout != NULL && fpout != (FILE *)1) {
1323 } else if (fpout == (FILE *)1) {
1324 MyAppCallback_setConsoleColor(0);
1325 MyAppCallback_showScriptMessage("%s", buf);
1329 while (err->CanRead()) {
1330 err->Read(buf, sizeof buf - 1);
1331 if ((len = err->LastRead()) > 0) {
1335 fprintf(fplog, "%s", buf);
1338 if (fperr != NULL && fperr != (FILE *)1) {
1340 } else if (fpout == (FILE *)1) {
1341 MyAppCallback_setConsoleColor(1);
1342 MyAppCallback_showScriptMessage("\n%s", buf);
1343 MyAppCallback_setConsoleColor(0);
1347 if (++count == 100) {
1348 if (progress_panel == false) {
1349 ShowProgressPanel("Running subprocess...");
1350 progress_panel = true;
1353 if (m_processTerminated || !wxProcess::Exists(pid)) {
1354 if (m_processExitCode != 0) {
1355 /* Error from subprocess */
1356 // MyAppCallback_errorMessageBox("%s failed with exit code %d.", procname, m_processExitCode);
1357 status = (m_processExitCode & 255);
1362 /* In some cases, wxProcess cannot detect the termination of the subprocess. */
1363 /* So here are the platform-dependent examination */
1366 // get the process handle to operate on
1367 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
1369 PROCESS_QUERY_INFORMATION,
1370 false, // not inheritable
1372 if (hProcess == NULL) {
1373 if (::GetLastError() != ERROR_ACCESS_DENIED) {
1374 m_processTerminated = 1;
1375 m_processExitCode = 255;
1379 if (::GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE) {
1380 m_processTerminated = 1;
1381 m_processExitCode = exitCode;
1383 ::CloseHandle(hProcess);
1385 if (m_processTerminated) {
1388 fprintf(fplog, "OnEndProcess *NOT* called\n");
1392 status = m_processExitCode & 255;
1398 if (waitpid(pid, &status, WNOHANG) != 0) {
1401 fprintf(fplog, "OnEndProcess *NOT* called\n");
1406 status = WEXITSTATUS(status);
1413 fprintf(fplog, "[DEBUG]pid %ld exists\n", pid);
1419 if (wxGetApp().IsInterrupted() || (callback != NULL && callback != DUMMY_CALLBACK && (callback_result = (*callback)(callback_data)) != 0)) {
1420 /* User interrupt */
1421 int kflag = wxKILL_CHILDREN;
1425 myKillAllChildren(pid, wxSIGKILL, &rc) != 0
1427 ::wxKill(pid, wxSIGTERM, &rc, kflag) != 0
1431 case wxKILL_BAD_SIGNAL: status = -3; break; /* No such signal */
1432 case wxKILL_ACCESS_DENIED: status = -4; break; /* Permission denied */
1433 case wxKILL_NO_PROCESS: status = -5; break; /* No such process */
1434 default: status = -6; break; /* unknown error */
1437 if (callback_result != 0)
1438 status = -3; /* Interrupt from callback */
1440 status = -2; /* User interrupt */
1451 HideProgressPanel();
1453 if (callback == DUMMY_CALLBACK) {
1455 /* Convert "\r\n" to "\n" */
1457 p = pend = membuf + strlen(membuf);
1458 while (--p >= membuf) {
1460 memmove(p, p + 1, pend - p);
1465 *((char **)callback_data) = membuf;
1468 /* if (len_total > 0)
1469 MyAppCallback_showRubyPrompt(); */
1474 static int sTimerCount = 0;
1477 MyApp::EnableTimerForDocument(MyDocument *doc)
1482 for (i = 0; i < m_CountTimerDocs; i++) {
1483 if (m_TimerDocs[i] == doc)
1486 m_TimerDocs = (MyDocument **)realloc(m_TimerDocs, sizeof(MyDocument *) * (m_CountTimerDocs + 1));
1487 m_TimerDocs[m_CountTimerDocs++] = doc;
1488 if (m_Timer == NULL)
1489 m_Timer = new wxTimer(this, -1);
1490 if (!m_Timer->IsRunning())
1491 m_Timer->Start(100, wxTIMER_CONTINUOUS);
1495 MyApp::DisableTimerForDocument(MyDocument *doc)
1500 for (i = 0; i < m_CountTimerDocs; i++) {
1501 if (m_TimerDocs[i] == doc) {
1502 // Remove this document from the array
1503 if (i < m_CountTimerDocs - 1) {
1504 memmove(&m_TimerDocs[i], &m_TimerDocs[i + 1], sizeof(MyDocument *) * (m_CountTimerDocs - 1 - i));
1507 if (m_CountTimerDocs == 0) {
1518 MyApp::TimerInvoked(wxTimerEvent &event)
1522 for (i = 0; i < m_CountTimerDocs; i++) {
1523 m_TimerDocs[i]->TimerCallback(sTimerCount);
1528 MyApp::CheckIfAllWindowsAreGoneHandler(wxCommandEvent &event)
1531 wxWindowList::iterator iter;
1532 wxTopLevelWindow *win;
1533 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1534 win = (wxTopLevelWindow *)(*iter);
1535 if (win != m_frameToBeDestroyed && win->IsShown())
1539 const char *p = MyAppCallback_getGlobalSettings(gSettingQuitOnCloseLastWindow);
1541 if (p != NULL && *p != 0)
1542 quitFlag = (atoi(p) != 0);
1543 if (quitFlag || MyAppCallback_messageBox("Do you want to quit Molby?", "Quit Molby", 3, 2)) {
1545 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1546 win = (wxTopLevelWindow *)(*iter);
1547 if (win != m_frameToBeDestroyed)
1548 win->Destroy(); // Avoid double destruction
1551 // Show console window to avoid window-less state
1552 consoleFrame->Show();
1558 MyApp::CheckIfAllWindowsAreGone(wxTopLevelWindow *frame)
1560 #if 1 || defined(__WXMSW__)
1561 /* On Windows, we should avoid the situation where all windows are hidden and
1562 still the program is running. So that we check whether all windows are gone
1563 and if so ask the user to quit the program. If user chooses not to quit, then
1564 the console window is reopened and the program continues to run. */
1565 m_frameToBeDestroyed = frame;
1566 wxCommandEvent myEvent(MyDocumentEvent, myMenuID_Internal_CheckIfAllWindowsAreGone);
1567 this->AddPendingEvent(myEvent);
1571 #pragma mark ====== MyFrame (top-level window) ======
1574 * This is the top-level window of the application.
1577 IMPLEMENT_CLASS(MyFrame, wxDocParentFrame)
1578 BEGIN_EVENT_TABLE(MyFrame, wxDocParentFrame)
1579 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
1582 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
1583 const wxPoint& pos, const wxSize& size, long type):
1584 wxDocParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
1586 editMenu = (wxMenu *) NULL;
1587 #if defined(__WXMAC__)
1588 /* Avoid this "dummy" top-level window to appear in the window menu.
1589 It should not happen because MyApp::OnActivate() tries to hide this window,
1590 but this is still here just in case. */
1592 // sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
1593 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
1597 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
1600 s = Molby_getDescription();
1601 wxString str(s, WX_DEFAULT_CONV);
1602 (void)wxMessageBox(str, _T("Molby"));
1606 MyFrame *GetMainFrame(void)
1611 #pragma mark ====== Plain-C interface ======
1614 MyAppCallback_getGUIDescriptionString(void)
1616 static char *desc = NULL;
1619 "AmberTools 1.3, http://ambermd.org/\n"
1620 " Copyright (C) Junmei Wang, Ross C. Walker, \n"
1621 " Michael F. Crowley, Scott Brozell and David A. Case\n"
1622 "wxWidgets %d.%d.%d, http://www.wxwidgets.org/\n"
1623 " Copyright (C) 1992-2013 Julian Smart, Vadim Zeitlin,\n"
1624 " Stefan Csomor, Robert Roebling,\n"
1625 " and other members of the wxWidgets team\n"
1626 " Portions (C) 1996 Artificial Intelligence Applications Institute\n",
1627 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
1633 MyAppCallback_loadGlobalSettings(void)
1635 wxGetApp().LoadDefaultSettings();
1639 MyAppCallback_saveGlobalSettings(void)
1641 wxGetApp().SaveDefaultSettings();
1644 /* Note on the global settings */
1645 /* Global settings are stored in a file in the form key="value", where
1646 the "value" is the 'inspect'-ed representation of Ruby values.
1647 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
1648 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
1649 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
1650 MyAppCallback_setGlobalSettingsWithType(). */
1652 MyAppCallback_getGlobalSettings(const char *key)
1654 wxString wxkey(key, WX_DEFAULT_CONV);
1655 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
1656 return strdup(wxvalue.mb_str(WX_DEFAULT_CONV));
1660 MyAppCallback_setGlobalSettings(const char *key, const char *value)
1662 wxString wxkey(key, WX_DEFAULT_CONV);
1663 wxString wxvalue(value, WX_DEFAULT_CONV);
1664 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
1668 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
1671 char *s = MyAppCallback_getGlobalSettings(key);
1672 char desc[] = SCRIPT_ACTION("s; ");
1673 desc[sizeof(desc) - 2] = type;
1674 retval = MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
1680 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
1682 const char *cmd = "set_global_settings";
1684 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i"), cmd, *((const Int *)ptr));
1685 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("d"), cmd, *((const Double *)ptr));
1686 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("s"), cmd, (const char *)ptr);
1687 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("v"), cmd, (const Vector *)ptr);
1688 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("t"), cmd, (const Transform *)ptr);
1690 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
1696 MyAppCallback_checkInterrupt(void)
1698 return wxGetApp().IsInterrupted();
1702 MyAppCallback_showProgressPanel(const char *msg)
1704 wxGetApp().ShowProgressPanel(msg);
1708 MyAppCallback_hideProgressPanel(void)
1710 wxGetApp().HideProgressPanel();
1714 MyAppCallback_setProgressValue(double dval)
1716 wxGetApp().SetProgressValue(dval);
1720 MyAppCallback_setProgressMessage(const char *msg)
1722 wxGetApp().SetProgressMessage(msg);
1726 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
1728 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
1729 wxStaticText *stext;
1732 wxString pstr(prompt, WX_DEFAULT_CONV);
1733 wxString defstr(buf, WX_DEFAULT_CONV);
1734 { // Vertical sizer containing [prompt, textbox, buttons]
1736 sizer1 = new wxBoxSizer(wxVERTICAL);
1737 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, wxSize(200, 22));
1738 sizer1->Add(stext, 0, wxEXPAND | wxALL, 6);
1739 tctrl = new wxTextCtrl(dialog, -1, defstr, wxDefaultPosition, wxSize(200, 22));
1740 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, 6);
1741 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
1742 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, 6);
1744 dialog->SetSizerAndFit(sizer1);
1745 dialog->Centre(wxBOTH);
1748 if (dialog->ShowModal() == wxID_OK) {
1749 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(WX_DEFAULT_CONV)), bufsize - 1);
1750 buf[bufsize - 1] = 0;
1759 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
1760 1 (information), 2 (exclamation), or 3 (stop). */
1762 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
1764 int wxflags, wxicon, retval;
1765 if (!wxGetApp().IsMainLoopRunning()) {
1766 MyAppCallback_setConsoleColor(1);
1767 MyAppCallback_showScriptMessage("*** %s ***\n%s\n", message, title);
1768 MyAppCallback_setConsoleColor(0);
1773 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
1775 case 3: wxicon = wxICON_ERROR; break;
1776 case 2: wxicon = wxICON_EXCLAMATION; break;
1777 default: wxicon = wxICON_INFORMATION; break;
1779 wxString wxmessage(message, WX_DEFAULT_CONV);
1780 wxString wxtitle(title, WX_DEFAULT_CONV);
1781 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
1782 return (retval == wxOK ? 1 : 0);
1786 MyAppCallback_errorMessageBox(const char *fmt, ...)
1792 if (strchr(fmt, '%') == 0) {
1794 } else if (strcmp(fmt, "%s") == 0) {
1795 s = va_arg(ap, char *);
1797 vasprintf(&s, fmt, ap);
1800 MyAppCallback_messageBox(s, "Error", 0, 3);
1806 MyAppCallback_getHomeDir(void)
1810 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
1811 s = getenv("USERPROFILE");
1815 return (s == NULL ? NULL : strdup(s));
1819 MyAppCallback_getDocumentHomeDir(void)
1824 s = getenv("USERPROFILE");
1825 asprintf(&ss, "%s\\My Documents", s);
1829 return (s == NULL ? NULL : strdup(s));
1834 MyAppCallback_registerScriptMenu(const char *cmd, const char *title)
1836 wxGetApp().RegisterScriptMenu(cmd, title);
1840 MyAppCallback_lookupScriptMenu(const char *title)
1842 return wxGetApp().LookupScriptMenu(title);
1846 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
1849 wxString cwd = wxFileName::GetCwd();
1850 wxString path(cpath, wxConvFile);
1851 char *p = strdup(cpath);
1852 char sep = wxFileName::GetPathSeparator();
1853 char *pp, *script = NULL;
1854 if ((pp = strrchr(p, sep)) != NULL) {
1856 wxString dirname(p, wxConvFile);
1857 wxFileName::SetCwd(dirname);
1860 /* Read the content of the file */
1861 FILE *fp = fopen(cpath, "rb");
1864 fseek(fp, 0, SEEK_END);
1866 fseek(fp, 0, SEEK_SET);
1867 script = (char *)malloc(len + 1);
1868 if (script!= NULL) {
1869 fread(script, 1, len, fp);
1875 if (script == NULL) {
1877 return (RubyValue)6; /* Cannot open file */
1880 /* Check the encoding specification, and if present convert it to default encoding */
1882 char *lp = script, *eolp;
1884 while (n < 2) { /* Check the first two lines */
1885 while (*lp && isspace(*lp))
1887 if (*lp == 0 || *lp++ != '#') /* Check only the comment line */
1891 if (*lp == '!') { /* Shebang line */
1892 while (*lp && *lp != '\n')
1893 lp++; /* Skip until end of line */
1898 for (eolp = lp; *eolp && *eolp != '\n'; eolp++);
1901 *eolp = 0; /* Limit the search area */
1902 lp = strstr(lp, "coding:");
1903 *eolp = '\n'; /* Restore original string */
1906 while (*lp && isspace(*lp))
1908 if (strncasecmp(lp, "shift-jis", 9) == 0) {
1909 wxString s(script, wxCSConv(wxT("cp932")));
1911 script = strdup(s.mb_str(WX_DEFAULT_CONV));
1912 } else if (strncasecmp(lp, "utf-8", 5) == 0) {
1913 wxString s(script, wxConvUTF8);
1915 script = strdup(s.mb_str(WX_DEFAULT_CONV));
1924 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), pp, status);
1928 wxFileName::SetCwd(cwd);
1932 void MyAppCallback_beginUndoGrouping(void)
1934 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1935 wxList::iterator iter;
1936 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1937 ((MyDocument *)(*iter))->BeginUndoGrouping();
1941 void MyAppCallback_endUndoGrouping(void)
1943 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1944 wxList::iterator iter;
1945 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1946 ((MyDocument *)(*iter))->EndUndoGrouping();
1950 int MyAppCallback_callSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *output, FILE *errout)
1952 return wxGetApp().CallSubProcess(cmdline, procname, callback, callback_data, output, errout);
1955 void MyAppCallback_showConsoleWindow(void)
1957 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
1962 void MyAppCallback_hideConsoleWindow(void)
1964 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
1968 void MyAppCallback_bell(void)
1973 int MyAppCallback_playSound(const char *filename, int flag)
1975 unsigned uflag = wxSOUND_SYNC;
1977 uflag = wxSOUND_ASYNC;
1979 uflag = wxSOUND_ASYNC | wxSOUND_LOOP;
1980 wxString fnamestr(filename, wxConvFile);
1981 bool retval = wxSound::Play(fnamestr, uflag);
1985 void MyAppCallback_stopSound(void)