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 EVT_MENU(myMenuID_ImportAmberLib, MyApp::OnImportAmberLib)
85 #if defined(__WXMAC__)
86 EVT_ACTIVATE(MyApp::OnActivate)
88 EVT_END_PROCESS(-1, MyApp::OnEndProcess)
91 // Find the path of the directory where the relevant resources are to be found.
92 // Mac: the "Resources" directory in the application bundle.
93 // Windows: the directory in which the application executable is located.
96 MyApp::FindResourcePath()
98 #if defined(__WXMAC__)
99 CFBundleRef mainBundle = CFBundleGetMainBundle();
100 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(mainBundle);
103 if (CFURLGetFileSystemRepresentation(ref, true, buffer, sizeof buffer)) {
104 wxString dirname((const char *)buffer, wxConvUTF8);
110 return wxEmptyString;
111 #elif defined(__WXMSW__)
113 wxString argv0 = wxTheApp->argv[0];
114 // Fix dosish path (when invoked from MSYS console, the path may be unix-like)
115 // Note: absolute paths like /c/Molby/... (== c:\Molby\...) is not supported
117 char *p = strdup(argv0.mb_str(wxConvFile));
119 wxString argv0_fixed(p, wxConvFile);
122 // Is it an absolute path?
123 if (wxIsAbsolutePath(argv0)) {
124 return wxPathOnly(argv0);
126 // Is it a relative path?
127 wxString currentDir = wxGetCwd();
128 if (currentDir.Last() != wxFILE_SEP_PATH)
129 currentDir += wxFILE_SEP_PATH;
130 str = currentDir + argv0;
131 if (wxFileExists(str))
132 return wxPathOnly(str);
136 pathList.AddEnvList(wxT("PATH"));
137 str = pathList.FindAbsoluteValidPath(argv0);
139 return wxPathOnly(str);
140 return wxEmptyString;
142 #error "FindResourcePath is not defined for UNIXes."
149 m_progressFrame = NULL;
150 m_processTerminated = false;
151 m_processExitCode = 0;
153 scriptMenuCommands = NULL;
154 scriptMenuTitles = NULL;
155 scriptMenuModifiedEventPosted = false;
156 parameterFrame = NULL;
157 parameterFilesFrame = NULL;
161 bool MyApp::OnInit(void)
166 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
171 // Check if the same application is already running
173 asprintf(&buf, "Molby-%s", (const char *)wxGetUserId().mb_str(wxConvUTF8));
174 wxString name(buf, wxConvUTF8);
177 m_checker = new wxSingleInstanceChecker(name);
178 if (m_checker->IsAnotherRunning()) {
179 wxLogError(_T("Molby is already running."));
185 // Create a document manager
186 m_docManager = new MyDocManager;
188 // Create templates relating drawing documents to their views
189 new wxDocTemplate(m_docManager, _T("Molby Structure File"), _T("*.mbsf"), _T(""), _T("mbsf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
190 new wxDocTemplate(m_docManager, _T("Protein Structure File"), _T("*.psf"), _T(""), _T("psf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
191 new wxDocTemplate(m_docManager, _T("Protein Data Bank File"), _T("*.pdb"), _T(""), _T("pdb"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
192 new wxDocTemplate(m_docManager, _T("Gaussian Input File"), _T("*.com;*.gjf"), _T(""), _T("com"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
193 new wxDocTemplate(m_docManager, _T("Gaussian Output File"), _T("*.out"), _T(""), _T("out"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
194 new wxDocTemplate(m_docManager, _T("Gaussian Checkpoint File"), _T("*.fchk;*.fch"), _T(""), _T("fchk"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
195 new wxDocTemplate(m_docManager, _T("GAMESS Input File"), _T("*.inp"), _T(""), _T("inp"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
196 new wxDocTemplate(m_docManager, _T("GAMESS Output File"), _T("*.log"), _T(""), _T("log"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
197 new wxDocTemplate(m_docManager, _T("GAMESS DAT File"), _T("*.dat"), _T(""), _T("dat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
198 new wxDocTemplate(m_docManager, _T("ORTEP Input File"), _T("*.tep"), _T(""), _T("tep"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
199 new wxDocTemplate(m_docManager, _T("SHELX Input File"), _T("*.ins;*.res"), _T(""), _T("ins"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
200 new wxDocTemplate(m_docManager, _T("Cartesian"), _T("*.xyz"), _T(""), _T("xyz"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
201 new wxDocTemplate(m_docManager, _T("Any Molecule"), _T("*.*"), _T(""), _T(""), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
203 // Create the main frame window
204 frame = new MyFrame((wxDocManager *) m_docManager, (wxFrame *) NULL,
205 _T("Molby"), wxPoint(0, 0), wxSize(800, 600),
206 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
208 // Give it an icon (this is ignored in MDI mode: uses resources)
210 frame->SetIcon(wxIcon(_T("doc")));
213 frame->SetIcon(wxIcon(_T("doc.xbm")));
216 wxMenuBar *menu_bar = CreateMenuBar(0);
219 wxMenuBar::MacSetCommonMenuBar(menu_bar);
222 // Associate the menu bar with the frame
223 frame->SetMenuBar(menu_bar);
225 frame->Centre(wxBOTH);
227 #if defined(__WXMAC__)
228 frame->Move(-10000, -10000); // Set invisible
236 // Load default settings from the preference file
237 LoadDefaultSettings();
239 // Create a console window
240 consoleFrame = ConsoleFrame::CreateConsoleFrame(frame);
241 consoleFrame->Show(true);
243 /* Initialize Ruby interpreter with the startup script */
245 static const char fname[] = "startup.rb";
246 wxString dirname = FindResourcePath();
249 dirname += wxFILE_SEP_PATH;
250 dirname += wxT("Scripts");
251 wxString cwd = wxGetCwd();
252 wxSetWorkingDirectory(dirname);
254 /* Read atom display parameters */
255 if (ElementParameterInitialize("element.par", &wbuf) != 0) {
257 AppendConsoleMessage(wbuf);
262 /* Read default parameters */
263 ParameterReadFromFile(gBuiltinParameters, "default.par", &wbuf, NULL);
266 AppendConsoleMessage(wbuf);
271 wxString fnamestr(fname, wxConvUTF8);
272 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, (const char *)dirname.mb_str(wxConvUTF8));
274 wxSetWorkingDirectory(cwd);
275 MyAppCallback_showScriptMessage("%% ");
278 /* Open given files as MyDocument */
281 m_docManager->CreateDocument(wxEmptyString, wxDOC_NEW);
285 wxString file(argv[1]);
286 m_docManager->CreateDocument(file, wxDOC_SILENT);
296 // kind == 0: main menu
297 // kind == 1: molecule window
298 // kind == 2: console window
300 MyApp::CreateMenuBar(int kind, wxMenu **out_file_history_menu, wxMenu **out_edit_menu)
304 wxMenu *file_menu = new wxMenu;
306 file_menu->Append(wxID_NEW, _T("&New...\tCtrl-N"));
307 file_menu->Append(wxID_OPEN, _T("&Open...\tCtrl-O"));
308 if (out_file_history_menu != NULL) {
309 *out_file_history_menu = new wxMenu;
310 file_menu->AppendSubMenu(*out_file_history_menu, _T("Open Recent"));
311 m_docManager->FileHistoryAddFilesToMenu(*out_file_history_menu);
312 m_docManager->FileHistoryUseMenu(*out_file_history_menu); // Should be removed when menu is discarded
315 file_menu->AppendSeparator();
316 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
317 file_menu->Append(wxID_SAVE, _T("&Save\tCtrl-S"));
318 file_menu->Append(wxID_SAVEAS, _T("Save &As..."));
320 file_menu->AppendSeparator();
321 file_menu->Append(myMenuID_Import, _T("Import..."));
322 file_menu->Append(myMenuID_Export, _T("Export..."));
324 file_menu->AppendSeparator();
325 file_menu->Append(wxID_PRINT, _T("&Print...\tCtrl-P"));
326 file_menu->Append(wxID_PRINT_SETUP, _T("Print &Setup..."));
327 file_menu->Append(wxID_PREVIEW, _T("Print Pre&view"));
329 file_menu->AppendSeparator();
330 #if defined(__WXMAC__)
331 file_menu->Append(wxID_EXIT, _T("E&xit\tCtrl-Q"));
333 file_menu->Append(wxID_EXIT, _T("E&xit\tAlt-X"));
336 wxMenu *edit_menu = new wxMenu;
337 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
338 edit_menu->Append(wxID_REDO, _T("&Redo"));
339 edit_menu->AppendSeparator();
340 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
341 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
342 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
343 edit_menu->Append(wxID_CLEAR, _T("Clear"));
344 edit_menu->AppendSeparator();
345 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
346 edit_menu->Append(myMenuID_SelectFragment, _T("Select Fragment\tCtrl-F"));
347 edit_menu->Append(myMenuID_SelectReverse, _T("Select Reverse"));
348 edit_menu->AppendSeparator();
349 wxMenu *create_parameter_menu = new wxMenu;
350 create_parameter_menu->Append(myMenuID_CreateNewVdwParameter, _T("Vdw"));
351 create_parameter_menu->Append(myMenuID_CreateNewBondParameter, _T("Bond"));
352 create_parameter_menu->Append(myMenuID_CreateNewAngleParameter, _T("Angle"));
353 create_parameter_menu->Append(myMenuID_CreateNewDihedralParameter, _T("Dihedral"));
354 create_parameter_menu->Append(myMenuID_CreateNewImproperParameter, _T("Improper"));
355 create_parameter_menu->Append(myMenuID_CreateNewVdwPairParameter, _T("Vdw Pair"));
356 create_parameter_menu->Append(myMenuID_CreateNewVdwCutoffParameter, _T("Vdw Cutoff"));
357 edit_menu->Append(myMenuID_CreateNewAtom, _T("Create New Atom\tCtrl-I"));
358 edit_menu->Append(myMenuID_CreateNewParameter, _T("Create New Parameter"), create_parameter_menu);
359 edit_menu->AppendSeparator();
360 wxMenu *add_hydrogen_menu = new wxMenu;
361 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp3, _T("Tetrahedral sp3"));
362 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp2, _T("Trigonal sp2"));
363 add_hydrogen_menu->Append(myMenuID_AddHydrogenLinear, _T("Linear sp"));
364 add_hydrogen_menu->Append(myMenuID_AddHydrogenPyramidal, _T("Pyramidal (like NH2)"));
365 add_hydrogen_menu->Append(myMenuID_AddHydrogenBent, _T("Bent (like OH)"));
366 edit_menu->Append(myMenuID_AddHydrogen, _T("Add Hydrogen"), add_hydrogen_menu);
368 if (out_edit_menu != NULL)
369 *out_edit_menu = edit_menu; // Should be associated with the command processor if available
371 wxMenu *show_menu = new wxMenu;
372 show_menu->Append(myMenuID_FitToScreen, _T("Fit To Screen\tCtrl-T"));
373 show_menu->Append(myMenuID_CenterSelection, _T("Center Selection"));
374 show_menu->AppendSeparator();
375 show_menu->Append(myMenuID_ShowUnitCell, _T("Show Unit Cell"), _T(""), wxITEM_CHECK);
376 /* show_menu->Append(myMenuID_ShowPeriodicBox, _T("Show Periodic Box"), _T(""), wxITEM_CHECK); */
377 show_menu->Append(myMenuID_ShowHydrogens, _T("Show Hydrogen Atoms"), _T(""), wxITEM_CHECK);
378 show_menu->Append(myMenuID_ShowDummyAtoms, _T("Show Dummy Atoms"), _T(""), wxITEM_CHECK);
379 show_menu->Append(myMenuID_ShowExpandedAtoms, _T("Show Expanded Atoms"), _T(""), wxITEM_CHECK);
380 show_menu->Append(myMenuID_ShowEllipsoids, _T("Show Ellipsoids"), _T(""), wxITEM_CHECK);
381 show_menu->Append(myMenuID_ShowRotationCenter, _T("Show Rotation Center"), _T(""), wxITEM_CHECK);
382 show_menu->AppendSeparator();
383 show_menu->Append(myMenuID_HideSelected, _T("Hide Selected"), _T(""));
384 show_menu->Append(myMenuID_HideUnselected, _T("Hide Unselected"), _T(""));
385 show_menu->Append(myMenuID_HideReverse, _T("Hide Reverse"), _T(""));
386 show_menu->Append(myMenuID_ShowAllAtoms, _T("Show All Atoms"), _T(""));
387 show_menu->AppendSeparator();
388 show_menu->Append(myMenuID_ShowGraphite, _T("Show Graphite..."));
389 show_menu->AppendSeparator();
390 show_menu->Append(myMenuID_LineMode, _T("Line Mode"), _T(""), wxITEM_CHECK);
392 wxMenu *md_menu = new wxMenu;
393 md_menu->Append(myMenuID_MolecularDynamics, _T("Molecular Dynamics..."));
394 md_menu->Append(myMenuID_Minimize, _T("Minimize..."));
395 md_menu->Append(myMenuID_StopMDRun, _T("Stop\tCtrl-."));
396 md_menu->AppendSeparator();
397 // md_menu->Append(myMenuID_ReadParameters, _T("Read Parameters..."));
398 md_menu->Append(myMenuID_ViewGlobalParameters, _T("View Global Parameters..."));
399 md_menu->Append(myMenuID_ViewParameterFilesList, _T("Load/Unload Global Parameters..."));
400 md_menu->AppendSeparator();
401 md_menu->Append(myMenuID_DefinePeriodicBox, _T("Define Unit Cell..."));
402 md_menu->Append(myMenuID_ShowPeriodicImage, _T("Show Periodic Image..."));
403 md_menu->Append(myMenuID_PressureControl, _T("Pressure Control..."));
404 /* md_menu->Append(myMenuID_DefineSymmetry, _T("Define Symmetry Operations..."));
405 md_menu->Append(myMenuID_ExpandBySymmetry, _T("Expand by Symmetry...")); */
406 md_menu->AppendSeparator();
407 wxMenu *md_tools_menu = new wxMenu;
408 md_tools_menu->Append(myMenuID_RunAntechamber, _T("Antechamber/parmchk..."));
409 md_tools_menu->Append(myMenuID_RunResp, _T("GAMESS/RESP..."));
410 md_tools_menu->Append(myMenuID_CreateSanderInput, _T("Create SANDER input..."));
411 md_tools_menu->Append(myMenuID_ImportAmberLib, _T("Import AMBER Lib..."));
412 md_menu->Append(myMenuID_MDTools, _T("Tools"), md_tools_menu);
414 wxMenu *qc_menu = new wxMenu;
415 qc_menu->Append(myMenuID_CreateGamessInput, _T("Create GAMESS input..."));
416 qc_menu->Append(myMenuID_CreateMOCube, _T("Create MO cube..."));
418 wxMenu *script_menu = new wxMenu;
419 script_menu->Append(myMenuID_ExecuteScript, _T("Execute Script..."));
420 script_menu->Append(myMenuID_OpenConsoleWindow, _T("Open Console Window..."));
421 script_menu->AppendSeparator();
422 countNonCustomScriptMenu = script_menu->GetMenuItemCount();
424 wxMenu *help_menu = new wxMenu;
425 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
427 wxMenuBar *menu_bar = new wxMenuBar;
429 menu_bar->Append(file_menu, _T("&File"));
430 menu_bar->Append(edit_menu, _T("&Edit"));
431 menu_bar->Append(show_menu, _T("Show"));
432 menu_bar->Append(md_menu, _T("MM/MD"));
433 menu_bar->Append(qc_menu, _T("QChem"));
434 menu_bar->Append(script_menu, _T("&Script"));
435 menu_bar->Append(help_menu, _T("&Help"));
437 UpdateScriptMenu(menu_bar);
443 /* When the application is launched without any documents, an empty document is opened.
444 This should be implemented by overriding this special method; parsing argc/argv does
445 not work, because the list of files is passed through an Apple Event. */
449 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
453 int MyApp::OnExit(void)
455 SaveDefaultSettings();
464 MyApp::AppendConsoleMessage(const char *mes)
466 wxTextCtrl *textCtrl;
467 if (consoleFrame != NULL && (textCtrl = consoleFrame->textCtrl) != NULL) {
468 wxString string(mes, wxConvUTF8);
469 textCtrl->AppendText(string);
475 MyApp::FlushConsoleMessage()
477 wxTextCtrl *textCtrl = consoleFrame->textCtrl;
483 MyApp::SetConsoleColor(int color)
485 wxTextCtrl *textCtrl = consoleFrame->textCtrl;
486 static wxTextAttr *col[4];
487 if (col[0] == NULL) {
488 col[0] = new wxTextAttr(*wxBLACK);
489 col[1] = new wxTextAttr(*wxRED);
490 col[2] = new wxTextAttr(*wxGREEN);
491 col[3] = new wxTextAttr(*wxBLUE);
493 textCtrl->SetDefaultStyle(*(col[color % 4]));
497 MyApp::ShowProgressPanel(const char *mes)
499 wxString string((mes ? mes : ""), wxConvUTF8);
500 if (m_progressFrame == NULL) {
503 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
504 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
505 if (quitMenuItem != NULL)
506 quitMenuItem->Enable(false);
510 m_progressFrame = new ProgressFrame(_T("Progress"), string);
511 m_progressCanceled = false;
512 m_progressValue = -1;
517 MyApp::HideProgressPanel()
519 if (m_progressFrame != NULL) {
520 m_progressFrame->Hide();
521 m_progressFrame->Destroy();
522 m_progressFrame = NULL;
525 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
527 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
528 if (quitMenuItem != NULL)
529 quitMenuItem->Enable(true);
536 MyApp::SetProgressValue(double dval)
538 if (m_progressFrame != NULL) {
539 m_progressFrame->SetProgressValue(dval);
544 MyApp::SetProgressMessage(const char *mes)
546 if (m_progressFrame != NULL) {
547 wxString string((mes ? mes : ""), wxConvUTF8);
548 m_progressFrame->SetProgressMessage(string);
553 MyApp::IsInterrupted()
555 return m_progressFrame->CheckInterrupt();
558 #warning "TODO: Move this to MyDocument and 'import parameters' "
561 MyApp::OnReadParameters(wxCommandEvent& event)
563 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Parameter File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
564 if (dialog->ShowModal() == wxID_OK) {
565 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
567 ParameterReadFromFile(NULL, p, &wbuf, NULL);
570 AppendConsoleMessage(wbuf);
581 MyApp::OnOpenConsoleWindow(wxCommandEvent& event)
583 consoleFrame->Show(true);
584 consoleFrame->Raise();
588 MyApp::OnViewGlobalParameters(wxCommandEvent& event)
590 if (parameterFrame == NULL) {
591 parameterFrame = GlobalParameterFrame::CreateGlobalParameterFrame(GetMainFrame());
592 MainView_createColumnsForTableAtIndex(NULL, kMainViewParameterTableIndex);
594 MainView_refreshTable(NULL);
595 parameterFrame->Show(true);
596 parameterFrame->Raise();
600 MyApp::OnViewParameterFilesList(wxCommandEvent &event)
602 if (parameterFilesFrame == NULL) {
603 parameterFilesFrame = GlobalParameterFilesFrame::CreateGlobalParameterFilesFrame(GetMainFrame());
605 parameterFilesFrame->Show(true);
606 parameterFilesFrame->Raise();
610 MyApp::OnImportAmberLib(wxCommandEvent &event)
612 MolActionCreateAndPerform(NULL, SCRIPT_ACTION(""), "cmd_import_amberlib");
616 MyApp::RegisterScriptMenu(const char *cmd, const char *title)
619 if (cmd[0] == 0 && title[0] == 0)
620 i = countScriptMenu; /* A sepearator */
622 for (i = 0; i < countScriptMenu; i++) {
623 if (strcmp(cmd, scriptMenuCommands[i]) == 0) {
624 free(scriptMenuTitles[i]);
625 scriptMenuTitles[i] = strdup(title);
627 } else if (strcmp(title, scriptMenuTitles[i]) == 0) {
628 free(scriptMenuCommands[i]);
629 scriptMenuCommands[i] = strdup(cmd);
634 if (i >= countScriptMenu) {
635 if (countScriptMenu == 0) {
636 scriptMenuTitles = (char **)malloc(sizeof(char *));
637 scriptMenuCommands = (char **)malloc(sizeof(char *));
639 scriptMenuTitles = (char **)realloc(scriptMenuTitles, sizeof(char *) * (countScriptMenu + 1));
640 scriptMenuCommands = (char **)realloc(scriptMenuCommands, sizeof(char *) * (countScriptMenu + 1));
642 scriptMenuTitles[countScriptMenu] = strdup(title);
643 scriptMenuCommands[countScriptMenu] = strdup(cmd);
646 if (!scriptMenuModifiedEventPosted) {
647 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_scriptMenuModified);
648 wxPostEvent(this, myEvent);
649 scriptMenuModifiedEventPosted = true;
654 MyApp::UpdateScriptMenu(wxMenuBar *mbar)
658 wxMenu *smenu = mbar->GetMenu(myMenuIndex_Script);
662 // Remove all custom items
663 for (i = smenu->GetMenuItemCount() - 1; i >= countNonCustomScriptMenu; i--) {
664 wxMenuItem *item = smenu->FindItemByPosition(i);
665 if (!item->IsSeparator()) {
666 int n = item->GetId();
667 Disconnect(n, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
673 // Build script menu from internal array
674 for (i = 0; i < countScriptMenu; i++) {
675 const char *title = scriptMenuTitles[i];
676 if (title == NULL || title[0] == 0) {
677 smenu->AppendSeparator();
679 wxString stitle(scriptMenuTitles[i], wxConvUTF8);
680 wxMenuItem *item = new wxMenuItem(smenu, myMenuID_CustomScript + i, stitle);
684 Connect(myMenuID_CustomScript, myMenuID_CustomScript + countScriptMenu - 1, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
688 MyApp::OnScriptMenuModified(wxCommandEvent& event)
690 scriptMenuModifiedEventPosted = false;
691 UpdateScriptMenu(GetMainFrame()->GetMenuBar());
692 UpdateScriptMenu(consoleFrame->GetMenuBar());
697 MyApp::OnScriptMenuSelected(wxCommandEvent& event)
703 int index = event.GetId() - myMenuID_CustomScript;
704 if (index < 0 || index >= countScriptMenu)
706 cmd = scriptMenuCommands[index];
707 methodType = Ruby_methodType("Molecule", cmd);
710 mview = MainViewCallback_activeView();
713 else mol = mview->mol;
714 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
715 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), cmd);
716 else if (methodType == 2) /* Class method (with molecule as an only argument) */
717 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("M"), cmd, mol);
722 MyApp::OnUpdateUI(wxUpdateUIEvent& event)
724 int uid = event.GetId();
725 MainView *mview = MainViewCallback_activeView();
726 if (uid >= myMenuID_CustomScript && uid < myMenuID_CustomScript + countScriptMenu) {
727 // Check the script menu
731 int index = uid - myMenuID_CustomScript;
732 cmd = scriptMenuCommands[index];
733 methodType = Ruby_methodType("Molecule", cmd);
735 if (methodType != 0) {
738 else mol = mview->mol;
739 if (methodType == 1 && mol != NULL) /* Instance method (with no arguments) */
741 else if (methodType == 2) /* Class method (with molecule as an only argument) */
746 case myMenuID_ExecuteScript:
747 case myMenuID_OpenConsoleWindow:
748 case myMenuID_ViewParameterFilesList:
749 case myMenuID_ViewGlobalParameters:
750 case myMenuID_MDTools:
751 case myMenuID_ImportAmberLib:
763 MyApp::OnExecuteScript(wxCommandEvent &event)
765 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Script File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
766 if (dialog->ShowModal() == wxID_OK) {
768 wxString path = dialog->GetPath();
770 // Command line: execute_script('pathname')
771 wxString cline(path);
772 wxRegEx re(_T("[\\\\']")); // A backslash and a single-quote
773 re.Replace(&cline, _T("\\\\\\0")); // A backslash followed by "\0"
774 cline.Prepend(_T("execute_script('"));
776 MyAppCallback_setConsoleColor(3);
777 wxGetApp().AppendConsoleMessage((const char *)(cline.mb_str(wxConvFile)));
778 wxGetApp().AppendConsoleMessage("\n");
779 MyAppCallback_setConsoleColor(0);
781 MyAppCallback_executeScriptFromFile((const char *)(path.mb_str(wxConvFile)), &status);
783 Molby_showError(status);
789 MyApp::OnActivate(wxActivateEvent &event)
791 #if defined(__WXMAC__)
792 MyFrame *frame = GetMainFrame();
793 frame->Show(false); /* Sometimes this "parent" frame gets visible and screw up the menus */
799 MyApp::DefaultSettingsPath()
801 wxString name = wxStandardPaths::Get().GetUserConfigDir();
802 wxChar sep = wxFileName::GetPathSeparator();
803 if (name[name.Len() - 1] != sep)
805 name += _T("Molby.settings");
810 MyApp::LoadDefaultSettings()
812 wxString name = DefaultSettingsPath();
813 m_defaultSettings.clear();
814 wxTextFile file(name);
815 if (file.Exists() && file.Open()) {
818 for (line = file.GetFirstLine(); ; line = file.GetNextLine()) {
821 if ((pos = line.Find('=')) != wxNOT_FOUND) {
822 wxString key = line.Left(pos);
823 wxString value = line.Right(line.Length() - pos - 1);
824 SetDefaultSetting(key, value);
834 MyApp::SaveDefaultSettings()
836 wxString name = DefaultSettingsPath();
837 wxTextFile file(name);
843 MyStringHash::iterator it;
844 for (it = m_defaultSettings.begin(); it != m_defaultSettings.end(); it++) {
845 wxString key = it->first;
846 wxString value = it->second;
847 wxString line = key + _T("=") + value;
855 MyApp::SetDefaultSetting(const wxString& key, const wxString& value)
857 // TODO: The '=' and '#' characters may need to be escaped
858 m_defaultSettings[key] = value;
862 MyApp::GetDefaultSetting(const wxString& key)
864 return m_defaultSettings[key];
868 MyApp::GetGlobalParameterListCtrl()
870 if (parameterFrame != NULL)
871 return parameterFrame->GetListCtrl();
876 MyApp::OnEndProcess(wxProcessEvent &event)
878 m_processTerminated = true;
879 m_processExitCode = event.GetExitCode();
883 MyApp::CallSubProcess(const char *cmdline, const char *procname)
885 const int sEndProcessMessageID = 2;
889 size_t len, len_total;
890 wxString cmdstr(cmdline, wxConvUTF8);
891 #if defined(__WXMSW__)
892 extern int myKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
894 // Show progress panel
895 if (procname == NULL)
896 procname = "subprocess";
897 snprintf(buf, sizeof buf, "Running %s...", procname);
898 ShowProgressPanel(buf);
900 // Create log file in the current directory
901 snprintf(buf, sizeof buf, "%s.log");
902 fplog = fopen(buf, "w");
906 // Create proc object and call subprocess
907 wxProcess *proc = new wxProcess(wxGetApp().GetProgressFrame(), sEndProcessMessageID);
909 int flag = wxEXEC_ASYNC;
911 flag |= wxEXEC_MAKE_GROUP_LEADER;
913 m_processTerminated = false;
914 m_processExitCode = 0;
915 long pid = ::wxExecute(cmdstr, flag, proc);
917 MyAppCallback_errorMessageBox("Cannot start %s", procname);
924 // Wait until process ends or user interrupts
925 wxInputStream *in = proc->GetInputStream();
926 wxInputStream *err = proc->GetErrorStream();
929 if (m_processTerminated) {
930 if (m_processExitCode != 0) {
931 /* Error from subprocess */
932 MyAppCallback_errorMessageBox("%s failed with exit code %d.", procname, m_processExitCode);
933 status = m_processExitCode;
937 if (wxGetApp().IsInterrupted()) {
939 int kflag = wxKILL_CHILDREN;
943 myKillAllChildren(pid, wxSIGKILL, &rc) != 0
945 ::wxKill(pid, wxSIGTERM, &rc, kflag) != 0
950 case wxKILL_BAD_SIGNAL: emsg = "no such signal"; break;
951 case wxKILL_ACCESS_DENIED: emsg = "permission denied"; break;
952 case wxKILL_NO_PROCESS: emsg = "no such process"; break;
953 default: emsg = "unknown error"; break;
955 MyAppCallback_errorMessageBox("Cannot kill subprocess: %s", emsg);
961 while (in->CanRead()) {
962 in->Read(buf, sizeof buf - 1);
963 if ((len = in->LastRead()) > 0) {
966 fprintf(fplog, "%s", buf);
967 MyAppCallback_setConsoleColor(0);
968 MyAppCallback_showScriptMessage("%s", buf);
971 while (err->CanRead()) {
972 err->Read(buf, sizeof buf - 1);
973 if ((len = err->LastRead()) > 0) {
976 fprintf(fplog, "%s", buf);
977 MyAppCallback_setConsoleColor(1);
978 MyAppCallback_showScriptMessage("\n%s", buf);
979 MyAppCallback_setConsoleColor(0);
985 /* if (len_total > 0)
986 MyAppCallback_showRubyPrompt(); */
990 #pragma mark ====== MyFrame (top-level window) ======
993 * This is the top-level window of the application.
996 IMPLEMENT_CLASS(MyFrame, wxDocMDIParentFrame)
997 BEGIN_EVENT_TABLE(MyFrame, wxDocMDIParentFrame)
998 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
1001 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
1002 const wxPoint& pos, const wxSize& size, long type):
1003 wxDocMDIParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
1005 editMenu = (wxMenu *) NULL;
1006 #if defined(__WXMAC__)
1007 /* Avoid this "dummy" top-level window to appear in the window menu.
1008 It should not happen because MyApp::OnActivate() tries to hide this window,
1009 but this is still here just in case. */
1011 sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
1012 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
1016 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
1018 extern const char *gVersionString, *gCopyrightString;
1023 "AmberTools 1.3, http://ambermd.org/\n"
1024 " Copyright (c) Junmei Wang, Ross C. Walker, \n"
1025 " Michael F. Crowley, Scott Brozell and David A. Case\n"
1026 "wxWidgets %d.%d.%d, Copyright (c) 1992-2008 Julian Smart, \n"
1027 " Robert Roebling, Vadim Zeitlin and other members of the \n"
1029 " Portions (c) 1996 Artificial Intelligence Applications Institute\n"
1031 gVersionString, gCopyrightString,
1032 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER,
1033 gRubyVersion, gRubyCopyright);
1034 wxString str(s, wxConvUTF8);
1035 (void)wxMessageBox(str, _T("Molby"));
1038 MyFrame *GetMainFrame(void)
1043 #pragma mark ====== Plain-C interface ======
1046 MyAppCallback_loadGlobalSettings(void)
1048 wxGetApp().LoadDefaultSettings();
1052 MyAppCallback_saveGlobalSettings(void)
1054 wxGetApp().SaveDefaultSettings();
1057 /* Note on the global settings */
1058 /* Global settings are stored in a file in the form key="value", where
1059 the "value" is the 'inspect'-ed representation of Ruby values.
1060 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
1061 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
1062 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
1063 MyAppCallback_setGlobalSettingsWithType(). */
1065 MyAppCallback_getGlobalSettings(const char *key)
1067 wxString wxkey(key, wxConvUTF8);
1068 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
1069 return strdup(wxvalue.mb_str(wxConvUTF8));
1073 MyAppCallback_setGlobalSettings(const char *key, const char *value)
1075 wxString wxkey(key, wxConvUTF8);
1076 wxString wxvalue(value, wxConvUTF8);
1077 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
1081 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
1084 char *s = MyAppCallback_getGlobalSettings(key);
1085 char desc[] = SCRIPT_ACTION("s; ");
1086 desc[sizeof(desc) - 2] = type;
1087 retval = MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
1093 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
1095 const char *cmd = "set_global_settings";
1097 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i"), cmd, *((const Int *)ptr));
1098 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("d"), cmd, *((const Double *)ptr));
1099 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("s"), cmd, (const char *)ptr);
1100 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("v"), cmd, (const Vector *)ptr);
1101 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("t"), cmd, (const Transform *)ptr);
1103 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
1109 MyAppCallback_showScriptMessage(const char *fmt, ...)
1116 if (strchr(fmt, '%') == NULL) {
1117 /* No format characters */
1118 return wxGetApp().AppendConsoleMessage(fmt);
1119 } else if (strcmp(fmt, "%s") == 0) {
1120 /* Direct output of one string */
1121 p = va_arg(ap, char *);
1122 return wxGetApp().AppendConsoleMessage(p);
1125 vasprintf(&p, fmt, ap);
1127 /* Use safe wxString method */
1128 /* Not necessary any longer; vasprintf() is implemented in Missing.c */
1131 str.PrintfV(wxString::FromUTF8(fmt).GetData(), ap);
1132 p = strdup((const char *)str.mb_str(wxConvUTF8));
1136 retval = wxGetApp().AppendConsoleMessage(p);
1141 wxGetApp().FlushConsoleMessage();
1148 MyAppCallback_setConsoleColor(int color)
1150 wxGetApp().SetConsoleColor(color);
1154 MyAppCallback_showRubyPrompt(void)
1156 MyAppCallback_setConsoleColor(0);
1157 MyAppCallback_showScriptMessage("%% ");
1161 MyAppCallback_checkInterrupt(void)
1163 return wxGetApp().IsInterrupted();
1167 MyAppCallback_showProgressPanel(const char *msg)
1169 wxGetApp().ShowProgressPanel(msg);
1173 MyAppCallback_hideProgressPanel(void)
1175 wxGetApp().HideProgressPanel();
1179 MyAppCallback_setProgressValue(double dval)
1181 wxGetApp().SetProgressValue(dval);
1185 MyAppCallback_setProgressMessage(const char *msg)
1187 wxGetApp().SetProgressMessage(msg);
1191 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
1193 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
1194 wxStaticText *stext;
1197 wxString pstr(prompt, wxConvUTF8);
1198 { // Vertical sizer containing [prompt, textbox, buttons]
1200 sizer1 = new wxBoxSizer(wxVERTICAL);
1201 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, wxSize(200, 22));
1202 sizer1->Add(stext, 0, wxEXPAND | wxALL, 6);
1203 tctrl = new wxTextCtrl(dialog, -1, _T(""), wxDefaultPosition, wxSize(200, 22));
1204 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, 6);
1205 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
1206 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, 6);
1208 dialog->SetSizerAndFit(sizer1);
1209 dialog->Centre(wxBOTH);
1212 if (dialog->ShowModal() == wxID_OK) {
1213 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(wxConvUTF8)), bufsize - 1);
1214 buf[bufsize - 1] = 0;
1223 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
1224 1 (information), 2 (exclamation), or 3 (stop). */
1226 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
1228 int wxflags, wxicon, retval;
1231 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
1233 case 3: wxicon = wxICON_ERROR; break;
1234 case 2: wxicon = wxICON_EXCLAMATION; break;
1235 default: wxicon = wxICON_INFORMATION; break;
1237 wxString wxmessage(message, wxConvUTF8);
1238 wxString wxtitle(title, wxConvUTF8);
1239 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
1240 return (retval == wxOK ? 1 : 0);
1244 MyAppCallback_errorMessageBox(const char *fmt, ...)
1250 if (strchr(fmt, '%') == 0) {
1252 } else if (strcmp(fmt, "%s") == 0) {
1253 s = va_arg(ap, char *);
1255 vasprintf(&s, fmt, ap);
1258 MyAppCallback_messageBox(s, "Error", 0, 3);
1264 MyAppCallback_getHomeDir(void)
1268 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
1269 s = getenv("USERPROFILE");
1273 return (s == NULL ? NULL : strdup(s));
1277 MyAppCallback_getDocumentHomeDir(void)
1282 s = getenv("USERPROFILE");
1283 asprintf(&ss, "%s\\My Documents", s);
1287 return (s == NULL ? NULL : strdup(s));
1292 MyAppCallback_registerScriptMenu(const char *cmd, const char *title)
1294 wxGetApp().RegisterScriptMenu(cmd, title);
1299 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
1302 wxString cwd = wxFileName::GetCwd();
1303 wxString path(cpath, wxConvFile);
1304 char *p = strdup(cpath);
1305 char sep = wxFileName::GetPathSeparator();
1306 char *pp, *script = NULL;
1307 if ((pp = strrchr(p, sep)) != NULL) {
1309 wxString dirname(p, wxConvFile);
1310 wxFileName::SetCwd(dirname);
1313 /* Read the content of the file */
1315 if (file.Open((const wxChar *)path, wxFile::read)) {
1316 wxFileOffset len = file.Length();
1317 script = (char *)malloc(len + 1);
1318 if (script != NULL) {
1319 file.Read(script, len);
1325 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), status);
1328 wxFileName::SetCwd(cwd);
1332 void MyAppCallback_beginUndoGrouping(void)
1334 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1335 wxList::iterator iter;
1336 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1337 ((MyDocument *)(*iter))->BeginUndoGrouping();
1341 void MyAppCallback_endUndoGrouping(void)
1343 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1344 wxList::iterator iter;
1345 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
1346 ((MyDocument *)(*iter))->EndUndoGrouping();
1350 int MyAppCallback_callSubProcess(const char *cmdline, const char *procname)
1352 return wxGetApp().CallSubProcess(cmdline, procname);