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"
46 #include "MyDocument.h"
47 #include "MoleculeView.h"
48 #include "ConsoleFrame.h"
49 #include "ProgressFrame.h"
50 #include "GlobalParameterFrame.h"
51 #include "GlobalParameterFilesFrame.h"
53 #include "../MolLib/MolLib.h"
54 #include "../MolLib/Ruby_bind/Molby.h"
55 #include "../MolLib/Missing.h"
60 #if defined(__WXMAC__)
61 #include <CoreFoundation/CoreFoundation.h>
63 #include <Carbon/Carbon.h>
66 #pragma mark ====== MyApp ======
68 MyFrame *frame = (MyFrame *) NULL;
72 //IMPLEMENT_CLASS(MyApp, wxApp)
74 BEGIN_EVENT_TABLE(MyApp, wxApp)
75 //EVT_KEY_DOWN(MyApp::OnChar)
76 //EVT_MOUSE_EVENTS(MyApp::OnMouseEvent)
77 EVT_COMMAND(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, MyApp::OnScriptMenuModified)
78 EVT_UPDATE_UI_RANGE(myMenuID_MyFirstMenuItem, myMenuID_MyLastMenuItem, MyApp::OnUpdateUI)
79 EVT_MENU(myMenuID_ExecuteScript, MyApp::OnExecuteScript)
80 EVT_MENU(myMenuID_OpenConsoleWindow, MyApp::OnOpenConsoleWindow)
81 // EVT_MENU(myMenuID_ReadParameters, MyApp::OnReadParameters)
82 EVT_MENU(myMenuID_ViewGlobalParameters, MyApp::OnViewGlobalParameters)
83 EVT_MENU(myMenuID_ViewParameterFilesList, MyApp::OnViewParameterFilesList)
84 #if defined(__WXMAC__)
85 EVT_ACTIVATE(MyApp::OnActivate)
87 EVT_END_PROCESS(-1, MyApp::OnEndProcess)
90 // Find the path of the directory where the relevant resources are to be found.
91 // Mac: the "Resources" directory in the application bundle.
92 // Windows: the directory in which the application executable is located.
95 MyApp::FindResourcePath()
97 #if defined(__WXMAC__)
98 CFBundleRef mainBundle = CFBundleGetMainBundle();
99 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(mainBundle);
102 if (CFURLGetFileSystemRepresentation(ref, true, buffer, sizeof buffer)) {
103 wxString dirname((const char *)buffer, wxConvUTF8);
109 return wxEmptyString;
110 #elif defined(__WXMSW__)
112 wxString argv0 = wxTheApp->argv[0];
113 // Is it an absolute path?
114 if (wxIsAbsolutePath(argv0)) {
115 return wxPathOnly(argv0);
117 // Is it a relative path?
118 wxString currentDir = wxGetCwd();
119 if (currentDir.Last() != wxFILE_SEP_PATH)
120 currentDir += wxFILE_SEP_PATH;
121 str = currentDir + argv0;
122 if (wxFileExists(str))
123 return wxPathOnly(str);
127 pathList.AddEnvList(wxT("PATH"));
128 str = pathList.FindAbsoluteValidPath(argv0);
130 return wxPathOnly(str);
131 return wxEmptyString;
133 #error "FindResourcePath is not defined for UNIXes."
140 m_progressFrame = NULL;
141 m_processTerminated = false;
142 m_processExitCode = 0;
144 scriptMenuCommands = NULL;
145 scriptMenuTitles = NULL;
146 scriptMenuModifiedEventPosted = false;
147 parameterFrame = NULL;
148 parameterFilesFrame = NULL;
152 bool MyApp::OnInit(void)
157 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
162 // Check if the same application is already running
164 asprintf(&buf, "Molby-%s", wxGetUserId().c_str());
165 wxString name(buf, wxConvUTF8);
167 m_checker = new wxSingleInstanceChecker(name);
168 if (m_checker->IsAnotherRunning()) {
169 wxLogError(_T("Molby is already running."));
175 // Create a document manager
176 m_docManager = new MyDocManager;
178 // Create templates relating drawing documents to their views
179 new wxDocTemplate(m_docManager, _T("Molby Structure File"), _T("*.mbsf"), _T(""), _T("mbsf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
180 new wxDocTemplate(m_docManager, _T("Protein Structure File"), _T("*.psf"), _T(""), _T("psf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
181 new wxDocTemplate(m_docManager, _T("Protein Data Bank File"), _T("*.pdb"), _T(""), _T("pdb"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
182 new wxDocTemplate(m_docManager, _T("Gaussian Input File"), _T("*.com;*.gjf"), _T(""), _T("com"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
183 new wxDocTemplate(m_docManager, _T("Gaussian Output File"), _T("*.out"), _T(""), _T("out"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
184 new wxDocTemplate(m_docManager, _T("Gaussian Checkpoint File"), _T("*.fchk"), _T(""), _T("fchk"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
185 new wxDocTemplate(m_docManager, _T("GAMESS Input File"), _T("*.inp"), _T(""), _T("inp"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
186 new wxDocTemplate(m_docManager, _T("GAMESS Output File"), _T("*.log"), _T(""), _T("log"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
187 new wxDocTemplate(m_docManager, _T("GAMESS DAT File"), _T("*.dat"), _T(""), _T("dat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
188 new wxDocTemplate(m_docManager, _T("ORTEP Input File"), _T("*.tep"), _T(""), _T("tep"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
189 new wxDocTemplate(m_docManager, _T("SHELX Input File"), _T("*.ins;*.res"), _T(""), _T("ins"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
190 new wxDocTemplate(m_docManager, _T("Cartesian"), _T("*.xyz"), _T(""), _T("xyz"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
191 new wxDocTemplate(m_docManager, _T("Any Molecule"), _T("*.*"), _T(""), _T(""), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
193 // Create the main frame window
194 frame = new MyFrame((wxDocManager *) m_docManager, (wxFrame *) NULL,
195 _T("Molby"), wxPoint(0, 0), wxSize(800, 600),
196 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
198 // Give it an icon (this is ignored in MDI mode: uses resources)
200 frame->SetIcon(wxIcon(_T("doc")));
203 frame->SetIcon(wxIcon(_T("doc.xbm")));
206 wxMenuBar *menu_bar = CreateMenuBar(0);
209 wxMenuBar::MacSetCommonMenuBar(menu_bar);
212 // Associate the menu bar with the frame
213 frame->SetMenuBar(menu_bar);
215 frame->Centre(wxBOTH);
217 #if defined(__WXMAC__)
218 frame->Move(-10000, -10000); // Set invisible
226 // Load default settings from the preference file
227 LoadDefaultSettings();
229 // Create a console window
230 consoleFrame = ConsoleFrame::CreateConsoleFrame(frame);
231 consoleFrame->Show(true);
233 /* Initialize Ruby interpreter with the startup script */
235 static const char fname[] = "startup.rb";
236 wxString dirname = FindResourcePath();
239 dirname += wxFILE_SEP_PATH;
240 dirname += wxT("Scripts");
241 wxString cwd = wxGetCwd();
242 wxSetWorkingDirectory(dirname);
244 /* Read atom display parameters */
245 if (ElementParameterInitialize("element.par", &wbuf) != 0) {
247 AppendConsoleMessage(wbuf);
252 /* Read default parameters */
253 ParameterReadFromFile(gBuiltinParameters, "default.par", &wbuf, NULL);
256 AppendConsoleMessage(wbuf);
261 wxString fnamestr(fname, wxConvUTF8);
262 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, dirname.mb_str(wxConvUTF8));
264 wxSetWorkingDirectory(cwd);
265 MyAppCallback_showScriptMessage("%% ");
268 /* Open given files as MyDocument */
271 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
275 wxString file(argv[1]);
276 m_docManager->CreateDocument(file, wxDOC_SILENT);
286 // kind == 0: main menu
287 // kind == 1: molecule window
288 // kind == 2: console window
290 MyApp::CreateMenuBar(int kind, wxMenu **out_file_history_menu, wxMenu **out_edit_menu)
294 wxMenu *file_menu = new wxMenu;
296 file_menu->Append(wxID_NEW, _T("&New...\tCtrl-N"));
297 file_menu->Append(wxID_OPEN, _T("&Open...\tCtrl-O"));
298 if (out_file_history_menu != NULL) {
299 *out_file_history_menu = new wxMenu;
300 file_menu->AppendSubMenu(*out_file_history_menu, _T("Open Recent"));
301 m_docManager->FileHistoryAddFilesToMenu(*out_file_history_menu);
302 m_docManager->FileHistoryUseMenu(*out_file_history_menu); // Should be removed when menu is discarded
305 file_menu->AppendSeparator();
306 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
307 file_menu->Append(wxID_SAVE, _T("&Save\tCtrl-S"));
308 file_menu->Append(wxID_SAVEAS, _T("Save &As..."));
310 file_menu->AppendSeparator();
311 file_menu->Append(myMenuID_Import, _T("Import..."));
312 file_menu->Append(myMenuID_Export, _T("Export..."));
314 file_menu->AppendSeparator();
315 file_menu->Append(wxID_PRINT, _T("&Print...\tCtrl-P"));
316 file_menu->Append(wxID_PRINT_SETUP, _T("Print &Setup..."));
317 file_menu->Append(wxID_PREVIEW, _T("Print Pre&view"));
319 file_menu->AppendSeparator();
320 #if defined(__WXMAC__)
321 file_menu->Append(wxID_EXIT, _T("E&xit\tCtrl-Q"));
323 file_menu->Append(wxID_EXIT, _T("E&xit\tAlt-X"));
326 wxMenu *edit_menu = new wxMenu;
327 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
328 edit_menu->Append(wxID_REDO, _T("&Redo"));
329 edit_menu->AppendSeparator();
330 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
331 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
332 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
333 edit_menu->Append(wxID_CLEAR, _T("Clear"));
334 edit_menu->AppendSeparator();
335 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
336 edit_menu->Append(myMenuID_SelectFragment, _T("Select Fragment\tCtrl-F"));
337 edit_menu->Append(myMenuID_SelectReverse, _T("Select Reverse"));
338 edit_menu->AppendSeparator();
339 wxMenu *add_hydrogen_menu = new wxMenu;
340 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp3, _T("Tetrahedral sp3"));
341 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp2, _T("Trigonal sp2"));
342 add_hydrogen_menu->Append(myMenuID_AddHydrogenLinear, _T("Linear sp"));
343 add_hydrogen_menu->Append(myMenuID_AddHydrogenPyramidal, _T("Pyramidal (like NH2)"));
344 add_hydrogen_menu->Append(myMenuID_AddHydrogenBent, _T("Bent (like OH)"));
345 edit_menu->Append(myMenuID_AddHydrogen, _T("Add Hydrogen"), add_hydrogen_menu);
347 if (out_edit_menu != NULL)
348 *out_edit_menu = edit_menu; // Should be associated with the command processor if available
350 wxMenu *show_menu = new wxMenu;
351 show_menu->Append(myMenuID_FitToScreen, _T("Fit To Screen\tCtrl-T"));
352 show_menu->Append(myMenuID_CenterSelection, _T("Center Selection"));
353 show_menu->AppendSeparator();
354 show_menu->Append(myMenuID_ShowUnitCell, _T("Show Unit Cell"), _T(""), wxITEM_CHECK);
355 /* show_menu->Append(myMenuID_ShowPeriodicBox, _T("Show Periodic Box"), _T(""), wxITEM_CHECK); */
356 show_menu->Append(myMenuID_ShowHydrogens, _T("Show Hydrogen Atoms"), _T(""), wxITEM_CHECK);
357 show_menu->Append(myMenuID_ShowDummyAtoms, _T("Show Dummy Atoms"), _T(""), wxITEM_CHECK);
358 show_menu->Append(myMenuID_ShowExpandedAtoms, _T("Show Expanded Atoms"), _T(""), wxITEM_CHECK);
359 show_menu->Append(myMenuID_ShowEllipsoids, _T("Show Ellipsoids"), _T(""), wxITEM_CHECK);
360 show_menu->Append(myMenuID_ShowRotationCenter, _T("Show Rotation Center"), _T(""), wxITEM_CHECK);
361 show_menu->AppendSeparator();
362 show_menu->Append(myMenuID_HideSelected, _T("Hide Selected"), _T(""));
363 show_menu->Append(myMenuID_HideUnselected, _T("Hide Unselected"), _T(""));
364 show_menu->Append(myMenuID_HideReverse, _T("Hide Reverse"), _T(""));
365 show_menu->Append(myMenuID_ShowAllAtoms, _T("Show All Atoms"), _T(""));
366 show_menu->AppendSeparator();
367 show_menu->Append(myMenuID_ShowGraphite, _T("Show Graphite..."));
368 show_menu->AppendSeparator();
369 show_menu->Append(myMenuID_LineMode, _T("Line Mode"), _T(""), wxITEM_CHECK);
371 wxMenu *md_menu = new wxMenu;
372 md_menu->Append(myMenuID_MolecularDynamics, _T("Molecular Dynamics..."));
373 md_menu->Append(myMenuID_Minimize, _T("Minimize..."));
374 md_menu->Append(myMenuID_StopMDRun, _T("Stop\tCtrl-."));
375 md_menu->AppendSeparator();
376 // md_menu->Append(myMenuID_ReadParameters, _T("Read Parameters..."));
377 md_menu->Append(myMenuID_ViewGlobalParameters, _T("View Global Parameters..."));
378 md_menu->Append(myMenuID_ViewParameterFilesList, _T("Load/Unload Global Parameters..."));
379 md_menu->AppendSeparator();
380 md_menu->Append(myMenuID_DefinePeriodicBox, _T("Define Unit Cell..."));
381 md_menu->Append(myMenuID_ShowPeriodicImage, _T("Show Periodic Image..."));
382 md_menu->Append(myMenuID_PressureControl, _T("Pressure Control..."));
383 /* md_menu->Append(myMenuID_DefineSymmetry, _T("Define Symmetry Operations..."));
384 md_menu->Append(myMenuID_ExpandBySymmetry, _T("Expand by Symmetry...")); */
385 md_menu->AppendSeparator();
386 wxMenu *md_tools_menu = new wxMenu;
387 md_tools_menu->Append(myMenuID_RunAntechamber, _T("Antechamber/parmchk..."));
388 md_tools_menu->Append(myMenuID_RunResp, _T("GAMESS/RESP..."));
389 md_menu->Append(myMenuID_MDTools, _T("Tools"), md_tools_menu);
391 wxMenu *qc_menu = new wxMenu;
392 qc_menu->Append(myMenuID_CreateGamessInput, _T("Create GAMESS input..."));
393 qc_menu->Append(myMenuID_CreateMOCube, _T("Create MO cube..."));
395 wxMenu *script_menu = new wxMenu;
396 script_menu->Append(myMenuID_ExecuteScript, _T("Execute Script..."));
397 script_menu->Append(myMenuID_OpenConsoleWindow, _T("Open Console Window..."));
398 script_menu->AppendSeparator();
399 countNonCustomScriptMenu = script_menu->GetMenuItemCount();
401 wxMenu *help_menu = new wxMenu;
402 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
404 wxMenuBar *menu_bar = new wxMenuBar;
406 menu_bar->Append(file_menu, _T("&File"));
407 menu_bar->Append(edit_menu, _T("&Edit"));
408 menu_bar->Append(show_menu, _T("Show"));
409 menu_bar->Append(md_menu, _T("MM/MD"));
410 menu_bar->Append(qc_menu, _T("QChem"));
411 menu_bar->Append(script_menu, _T("&Script"));
412 menu_bar->Append(help_menu, _T("&Help"));
414 UpdateScriptMenu(menu_bar);
420 /* When the application is launched without any documents, an empty document is opened.
421 This should be implemented by overriding this special method; parsing argc/argv does
422 not work, because the list of files is passed through an Apple Event. */
426 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
430 int MyApp::OnExit(void)
432 SaveDefaultSettings();
441 MyApp::AppendConsoleMessage(const char *mes)
443 wxTextCtrl *textCtrl;
444 if (consoleFrame != NULL && (textCtrl = consoleFrame->textCtrl) != NULL) {
445 wxString string(mes, wxConvUTF8);
446 textCtrl->AppendText(string);
452 MyApp::FlushConsoleMessage()
454 wxTextCtrl *textCtrl = consoleFrame->textCtrl;
460 MyApp::SetConsoleColor(int color)
462 wxTextCtrl *textCtrl = consoleFrame->textCtrl;
463 static wxTextAttr *col[4];
464 if (col[0] == NULL) {
465 col[0] = new wxTextAttr(*wxBLACK);
466 col[1] = new wxTextAttr(*wxRED);
467 col[2] = new wxTextAttr(*wxGREEN);
468 col[3] = new wxTextAttr(*wxBLUE);
470 textCtrl->SetDefaultStyle(*(col[color % 4]));
474 MyApp::ShowProgressPanel(const char *mes)
476 wxString string((mes ? mes : ""), wxConvUTF8);
477 if (m_progressFrame == NULL) {
480 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
481 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
482 if (quitMenuItem != NULL)
483 quitMenuItem->Enable(false);
487 m_progressFrame = new ProgressFrame(_T("Progress"), string);
488 m_progressCanceled = false;
489 m_progressValue = -1;
494 MyApp::HideProgressPanel()
496 if (m_progressFrame != NULL) {
497 m_progressFrame->Hide();
498 m_progressFrame->Destroy();
499 m_progressFrame = NULL;
502 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
504 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
505 if (quitMenuItem != NULL)
506 quitMenuItem->Enable(true);
513 MyApp::SetProgressValue(double dval)
515 if (m_progressFrame != NULL) {
516 m_progressFrame->SetProgressValue(dval);
521 MyApp::SetProgressMessage(const char *mes)
523 if (m_progressFrame != NULL) {
524 wxString string((mes ? mes : ""), wxConvUTF8);
525 m_progressFrame->SetProgressMessage(string);
530 MyApp::IsInterrupted()
532 return m_progressFrame->CheckInterrupt();
535 #warning "TODO: Move this to MyDocument and 'import parameters' "
538 MyApp::OnReadParameters(wxCommandEvent& event)
540 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Parameter File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
541 if (dialog->ShowModal() == wxID_OK) {
542 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
544 ParameterReadFromFile(NULL, p, &wbuf, NULL);
547 AppendConsoleMessage(wbuf);
558 MyApp::OnOpenConsoleWindow(wxCommandEvent& event)
560 consoleFrame->Show(true);
561 consoleFrame->Raise();
565 MyApp::OnViewGlobalParameters(wxCommandEvent& event)
567 if (parameterFrame == NULL) {
568 parameterFrame = GlobalParameterFrame::CreateGlobalParameterFrame(GetMainFrame());
569 MainView_createColumnsForTableAtIndex(NULL, kMainViewParameterTableIndex);
571 MainView_refreshTable(NULL);
572 parameterFrame->Show(true);
573 parameterFrame->Raise();
577 MyApp::OnViewParameterFilesList(wxCommandEvent &event)
579 if (parameterFilesFrame == NULL) {
580 parameterFilesFrame = GlobalParameterFilesFrame::CreateGlobalParameterFilesFrame(GetMainFrame());
582 parameterFilesFrame->Show(true);
583 parameterFilesFrame->Raise();
587 MyApp::RegisterScriptMenu(const char *cmd, const char *title)
590 if (cmd[0] == 0 && title[0] == 0)
591 i = countScriptMenu; /* A sepearator */
593 for (i = 0; i < countScriptMenu; i++) {
594 if (strcmp(cmd, scriptMenuCommands[i]) == 0) {
595 free(scriptMenuTitles[i]);
596 scriptMenuTitles[i] = strdup(title);
598 } else if (strcmp(title, scriptMenuTitles[i]) == 0) {
599 free(scriptMenuCommands[i]);
600 scriptMenuCommands[i] = strdup(cmd);
605 if (i >= countScriptMenu) {
606 if (countScriptMenu == 0) {
607 scriptMenuTitles = (char **)malloc(sizeof(char *));
608 scriptMenuCommands = (char **)malloc(sizeof(char *));
610 scriptMenuTitles = (char **)realloc(scriptMenuTitles, sizeof(char *) * (countScriptMenu + 1));
611 scriptMenuCommands = (char **)realloc(scriptMenuCommands, sizeof(char *) * (countScriptMenu + 1));
613 scriptMenuTitles[countScriptMenu] = strdup(title);
614 scriptMenuCommands[countScriptMenu] = strdup(cmd);
617 if (!scriptMenuModifiedEventPosted) {
618 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_scriptMenuModified);
619 wxPostEvent(this, myEvent);
620 scriptMenuModifiedEventPosted = true;
625 MyApp::UpdateScriptMenu(wxMenuBar *mbar)
629 wxMenu *smenu = mbar->GetMenu(myMenuIndex_Script);
633 // Remove all custom items
634 for (i = smenu->GetMenuItemCount() - 1; i >= countNonCustomScriptMenu; i--) {
635 wxMenuItem *item = smenu->FindItemByPosition(i);
636 if (!item->IsSeparator()) {
637 int n = item->GetId();
638 Disconnect(n, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
644 // Build script menu from internal array
645 for (i = 0; i < countScriptMenu; i++) {
646 const char *title = scriptMenuTitles[i];
647 if (title == NULL || title[0] == 0) {
648 smenu->AppendSeparator();
650 wxString stitle(scriptMenuTitles[i], wxConvUTF8);
651 wxMenuItem *item = new wxMenuItem(smenu, myMenuID_CustomScript + i, stitle);
655 Connect(myMenuID_CustomScript, myMenuID_CustomScript + countScriptMenu - 1, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
659 MyApp::OnScriptMenuModified(wxCommandEvent& event)
661 scriptMenuModifiedEventPosted = false;
662 UpdateScriptMenu(GetMainFrame()->GetMenuBar());
663 UpdateScriptMenu(consoleFrame->GetMenuBar());
668 MyApp::OnScriptMenuSelected(wxCommandEvent& event)
674 int index = event.GetId() - myMenuID_CustomScript;
675 if (index < 0 || index >= countScriptMenu)
677 cmd = scriptMenuCommands[index];
678 methodType = Ruby_methodType("Molecule", cmd);
681 mview = MainViewCallback_activeView();
684 else mol = mview->mol;
685 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
686 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), cmd);
687 else if (methodType == 2) /* Class method (with molecule as an only argument) */
688 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("M"), cmd, mol);
693 MyApp::OnUpdateUI(wxUpdateUIEvent& event)
695 int uid = event.GetId();
696 MainView *mview = MainViewCallback_activeView();
697 if (uid >= myMenuID_CustomScript && uid < myMenuID_CustomScript + countScriptMenu) {
698 // Check the script menu
702 int index = uid - myMenuID_CustomScript;
703 cmd = scriptMenuCommands[index];
704 methodType = Ruby_methodType("Molecule", cmd);
706 if (methodType != 0) {
709 else mol = mview->mol;
710 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
712 else if (methodType == 2) /* Class method (with molecule as an only argument) */
715 } else if (uid == myMenuID_ExecuteScript || uid == myMenuID_OpenConsoleWindow || uid == myMenuID_ViewParameterFilesList || uid == myMenuID_ViewGlobalParameters) {
726 MyApp::OnExecuteScript(wxCommandEvent &event)
728 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Script File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
729 if (dialog->ShowModal() == wxID_OK) {
731 wxString path = dialog->GetPath();
733 // Command line: execute_script('pathname')
734 wxString cline(path);
735 wxRegEx re(_T("[\\\\']")); // A backslash and a single-quote
736 re.Replace(&cline, _T("\\\\\\0")); // A backslash followed by "\0"
737 cline.Prepend(_T("execute_script('"));
739 MyAppCallback_setConsoleColor(3);
740 wxGetApp().AppendConsoleMessage((const char *)(cline.mb_str(wxConvFile)));
741 wxGetApp().AppendConsoleMessage("\n");
742 MyAppCallback_setConsoleColor(0);
744 MyAppCallback_executeScriptFromFile((const char *)(path.mb_str(wxConvFile)), &status);
746 Molby_showError(status);
752 MyApp::OnActivate(wxActivateEvent &event)
754 #if defined(__WXMAC__)
755 MyFrame *frame = GetMainFrame();
756 frame->Show(false); /* Sometimes this "parent" frame gets visible and screw up the menus */
762 MyApp::DefaultSettingsPath()
764 wxString name = wxStandardPaths::Get().GetUserConfigDir();
765 wxChar sep = wxFileName::GetPathSeparator();
766 if (name[name.Len() - 1] != sep)
768 name += _T("Molby.settings");
773 MyApp::LoadDefaultSettings()
775 wxString name = DefaultSettingsPath();
776 m_defaultSettings.clear();
777 wxTextFile file(name);
778 if (file.Exists() && file.Open()) {
781 for (line = file.GetFirstLine(); ; line = file.GetNextLine()) {
784 if ((pos = line.Find('=')) != wxNOT_FOUND) {
785 wxString key = line.Left(pos);
786 wxString value = line.Right(line.Length() - pos - 1);
787 SetDefaultSetting(key, value);
797 MyApp::SaveDefaultSettings()
799 wxString name = DefaultSettingsPath();
800 wxTextFile file(name);
806 MyStringHash::iterator it;
807 for (it = m_defaultSettings.begin(); it != m_defaultSettings.end(); it++) {
808 wxString key = it->first;
809 wxString value = it->second;
810 wxString line = key + _T("=") + value;
818 MyApp::SetDefaultSetting(const wxString& key, const wxString& value)
820 // TODO: The '=' and '#' characters may need to be escaped
821 m_defaultSettings[key] = value;
825 MyApp::GetDefaultSetting(const wxString& key)
827 return m_defaultSettings[key];
831 MyApp::GetGlobalParameterListCtrl()
833 if (parameterFrame != NULL)
834 return parameterFrame->GetListCtrl();
839 MyApp::OnEndProcess(wxProcessEvent &event)
841 m_processTerminated = true;
842 m_processExitCode = event.GetExitCode();
846 MyApp::CallSubProcess(const char *cmdline, const char *procname)
848 const int sEndProcessMessageID = 2;
852 size_t len, len_total;
853 wxString cmdstr(cmdline, wxConvUTF8);
855 // Show progress panel
856 if (procname == NULL)
857 procname = "subprocess";
858 snprintf(buf, sizeof buf, "Running %s...", procname);
859 ShowProgressPanel(buf);
861 // Create log file in the current directory
862 snprintf(buf, sizeof buf, "%s.log");
863 fplog = fopen(buf, "w");
867 // Create proc object and call subprocess
868 wxProcess *proc = new wxProcess(wxGetApp().GetProgressFrame(), sEndProcessMessageID);
870 int flag = wxEXEC_ASYNC;
872 flag |= wxEXEC_MAKE_GROUP_LEADER;
874 m_processTerminated = false;
875 m_processExitCode = 0;
876 long pid = ::wxExecute(cmdstr, flag, proc);
878 MyAppCallback_errorMessageBox("Cannot start %s", procname);
885 // Wait until process ends or user interrupts
886 wxInputStream *in = proc->GetInputStream();
887 wxInputStream *err = proc->GetErrorStream();
890 if (m_processTerminated) {
891 if (m_processExitCode != 0) {
892 /* Error from subprocess */
893 MyAppCallback_errorMessageBox("%s failed with exit code %d.", procname, m_processExitCode);
894 status = m_processExitCode;
898 if (wxGetApp().IsInterrupted()) {
901 int kflag = wxKILL_NOCHILDREN;
903 int kflag = wxKILL_CHILDREN;
906 if (::wxKill(pid, wxSIGTERM, &rc, kflag) != 0) {
909 case wxKILL_BAD_SIGNAL: emsg = "no such signal"; break;
910 case wxKILL_ACCESS_DENIED: emsg = "permission denied"; break;
911 case wxKILL_NO_PROCESS: emsg = "no such process"; break;
912 default: emsg = "unknown error"; break;
914 MyAppCallback_errorMessageBox("Cannot kill subprocess: %s", emsg);
920 while (in->CanRead()) {
921 in->Read(buf, sizeof buf - 1);
922 if ((len = in->LastRead()) > 0) {
925 fprintf(fplog, "%s", buf);
926 MyAppCallback_setConsoleColor(0);
927 MyAppCallback_showScriptMessage("%s", buf);
930 while (err->CanRead()) {
931 err->Read(buf, sizeof buf - 1);
932 if ((len = err->LastRead()) > 0) {
935 fprintf(fplog, "%s", buf);
936 MyAppCallback_setConsoleColor(1);
937 MyAppCallback_showScriptMessage("\n%s", buf);
938 MyAppCallback_setConsoleColor(0);
944 /* if (len_total > 0)
945 MyAppCallback_showRubyPrompt(); */
949 #pragma mark ====== MyFrame (top-level window) ======
952 * This is the top-level window of the application.
955 IMPLEMENT_CLASS(MyFrame, wxDocMDIParentFrame)
956 BEGIN_EVENT_TABLE(MyFrame, wxDocMDIParentFrame)
957 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
960 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
961 const wxPoint& pos, const wxSize& size, long type):
962 wxDocMDIParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
964 editMenu = (wxMenu *) NULL;
965 #if defined(__WXMAC__)
966 /* Avoid this "dummy" top-level window to appear in the window menu.
967 It should not happen because MyApp::OnActivate() tries to hide this window,
968 but this is still here just in case. */
970 sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
971 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
975 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
977 extern const char *gVersionString, *gCopyrightString;
982 "AmberTools 1.3, http://ambermd.org/\n"
983 " Copyright (c) Junmei Wang, Ross C. Walker, \n"
984 " Michael F. Crowley, Scott Brozell and David A. Case\n"
985 "wxWidgets %d.%d.%d, Copyright (c) 1992-2008 Julian Smart, \n"
986 " Robert Roebling, Vadim Zeitlin and other members of the \n"
988 " Portions (c) 1996 Artificial Intelligence Applications Institute\n"
990 gVersionString, gCopyrightString,
991 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER,
992 gRubyVersion, gRubyCopyright);
993 wxString str(s, wxConvUTF8);
994 (void)wxMessageBox(str, _T("Molby"));
997 MyFrame *GetMainFrame(void)
1002 #pragma mark ====== Plain-C interface ======
1005 MyAppCallback_loadGlobalSettings(void)
1007 wxGetApp().LoadDefaultSettings();
1011 MyAppCallback_saveGlobalSettings(void)
1013 wxGetApp().SaveDefaultSettings();
1016 /* Note on the global settings */
1017 /* Global settings are stored in a file in the form key="value", where
1018 the "value" is the 'inspect'-ed representation of Ruby values.
1019 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
1020 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
1021 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
1022 MyAppCallback_setGlobalSettingsWithType(). */
1024 MyAppCallback_getGlobalSettings(const char *key)
1026 wxString wxkey(key, wxConvUTF8);
1027 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
1028 return strdup(wxvalue.mb_str(wxConvUTF8));
1032 MyAppCallback_setGlobalSettings(const char *key, const char *value)
1034 wxString wxkey(key, wxConvUTF8);
1035 wxString wxvalue(value, wxConvUTF8);
1036 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
1040 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
1042 const char *s = MyAppCallback_getGlobalSettings(key);
1043 char desc[] = SCRIPT_ACTION("s; ");
1044 desc[sizeof(desc) - 2] = type;
1045 return MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
1049 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
1051 const char *cmd = "set_global_settings";
1053 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i"), cmd, *((const Int *)ptr));
1054 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("d"), cmd, *((const Double *)ptr));
1055 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("s"), cmd, (const char *)ptr);
1056 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("v"), cmd, (const Vector *)ptr);
1057 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("t"), cmd, (const Transform *)ptr);
1059 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
1065 MyAppCallback_showScriptMessage(const char *fmt, ...)
1072 if (strchr(fmt, '%') == NULL) {
1073 /* No format characters */
1074 return wxGetApp().AppendConsoleMessage(fmt);
1075 } else if (strcmp(fmt, "%s") == 0) {
1076 /* Direct output of one string */
1077 p = va_arg(ap, char *);
1078 return wxGetApp().AppendConsoleMessage(p);
1081 vasprintf(&p, fmt, ap);
1083 /* Use safe wxString method */
1084 /* Not necessary any longer; vasprintf() is implemented in Missing.c */
1087 str.PrintfV(wxString::FromUTF8(fmt).GetData(), ap);
1088 p = strdup((const char *)str.mb_str(wxConvUTF8));
1092 retval = wxGetApp().AppendConsoleMessage(p);
1097 wxGetApp().FlushConsoleMessage();
1104 MyAppCallback_setConsoleColor(int color)
1106 wxGetApp().SetConsoleColor(color);
1110 MyAppCallback_showRubyPrompt(void)
1112 MyAppCallback_setConsoleColor(0);
1113 MyAppCallback_showScriptMessage("%% ");
1117 MyAppCallback_checkInterrupt(void)
1119 return wxGetApp().IsInterrupted();
1123 MyAppCallback_showProgressPanel(const char *msg)
1125 wxGetApp().ShowProgressPanel(msg);
1129 MyAppCallback_hideProgressPanel(void)
1131 wxGetApp().HideProgressPanel();
1135 MyAppCallback_setProgressValue(double dval)
1137 wxGetApp().SetProgressValue(dval);
1141 MyAppCallback_setProgressMessage(const char *msg)
1143 wxGetApp().SetProgressMessage(msg);
1147 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
1149 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
1150 wxStaticText *stext;
1153 wxString pstr(prompt, wxConvUTF8);
1154 { // Vertical sizer containing [prompt, textbox, buttons]
1156 sizer1 = new wxBoxSizer(wxVERTICAL);
1157 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, wxSize(200, 22));
1158 sizer1->Add(stext, 0, wxEXPAND | wxALL, 6);
1159 tctrl = new wxTextCtrl(dialog, -1, _T(""), wxDefaultPosition, wxSize(200, 22));
1160 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, 6);
1161 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
1162 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, 6);
1164 dialog->SetSizerAndFit(sizer1);
1165 dialog->Centre(wxBOTH);
1168 if (dialog->ShowModal() == wxID_OK) {
1169 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(wxConvUTF8)), bufsize - 1);
1170 buf[bufsize - 1] = 0;
1179 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
1180 1 (information), 2 (exclamation), or 3 (stop). */
1182 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
1184 int wxflags, wxicon, retval;
1187 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
1189 case 3: wxicon = wxICON_ERROR; break;
1190 case 2: wxicon = wxICON_EXCLAMATION; break;
1191 default: wxicon = wxICON_INFORMATION; break;
1193 wxString wxmessage(message, wxConvUTF8);
1194 wxString wxtitle(title, wxConvUTF8);
1195 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
1196 return (retval == wxOK ? 1 : 0);
1200 MyAppCallback_errorMessageBox(const char *fmt, ...)
1206 if (strchr(fmt, '%') == 0) {
1208 } else if (strcmp(fmt, "%s") == 0) {
1209 s = va_arg(ap, char *);
1211 vasprintf(&s, fmt, ap);
1214 MyAppCallback_messageBox(s, "Error", 0, 3);
1220 MyAppCallback_getHomeDir(void)
1224 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
1225 s = getenv("USERPROFILE");
1229 return (s == NULL ? NULL : strdup(s));
1233 MyAppCallback_getDocumentHomeDir(void)
1238 s = getenv("USERPROFILE");
1239 asprintf(&ss, "%s\\My Documents", s);
1243 return (s == NULL ? NULL : strdup(s));
1248 MyAppCallback_registerScriptMenu(const char *cmd, const char *title)
1250 wxGetApp().RegisterScriptMenu(cmd, title);
1255 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
1258 wxString cwd = wxFileName::GetCwd();
1259 wxString path(cpath, wxConvFile);
1260 char *p = strdup(cpath);
1261 char sep = wxFileName::GetPathSeparator();
1262 char *pp, *script = NULL;
1263 if ((pp = strrchr(p, sep)) != NULL) {
1265 wxString dirname(p, wxConvFile);
1266 wxFileName::SetCwd(dirname);
1269 /* Read the content of the file */
1271 if (file.Open((const wxChar *)path, wxFile::read)) {
1272 wxFileOffset len = file.Length();
1273 script = (char *)malloc(len + 1);
1274 if (script != NULL) {
1275 file.Read(script, len);
1281 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), status);
1284 wxFileName::SetCwd(cwd);
1288 void MyAppCallback_beginUndoGrouping(void)
1290 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1291 wxList::iterator iter;
1292 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1293 ((MyDocument *)(*iter))->BeginUndoGrouping();
1297 void MyAppCallback_endUndoGrouping(void)
1299 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1300 wxList::iterator iter;
1301 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1302 ((MyDocument *)(*iter))->EndUndoGrouping();
1306 int MyAppCallback_callSubProcess(const char *cmdline, const char *procname)
1308 return wxGetApp().CallSubProcess(cmdline, procname);