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"
49 #include "MyDocument.h"
50 #include "MoleculeView.h"
51 #include "ConsoleFrame.h"
52 #include "ProgressFrame.h"
53 #include "GlobalParameterFrame.h"
54 #include "GlobalParameterFilesFrame.h"
55 #include "RubyDialogFrame.h"
58 #if defined(__WXMSW__)
59 #include "MyIPCSupport.h"
62 #include "../MolLib/MolLib.h"
63 #include "../MolLib/Ruby_bind/Molby_extern.h"
64 #include "../MolLib/Missing.h"
69 #if defined(__WXMAC__)
70 #include <CoreFoundation/CoreFoundation.h>
72 #include <Carbon/Carbon.h>
73 // #include "wx/mac/carbon/private.h"
74 #include <sys/wait.h> /* for waitpid() */
77 #pragma mark ====== MyApp ======
79 const char *gSettingQuitOnCloseLastWindow = "quit_on_close_last_window";
81 MyFrame *frame = (MyFrame *) NULL;
83 bool gInitCompleted = false;
85 int gSuppressConsole = 0; // Non-zero if console output should be suppressed in non-GUI mode
90 //IMPLEMENT_CLASS(MyApp, wxApp)
92 BEGIN_EVENT_TABLE(MyApp, wxApp)
93 EVT_COMMAND(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, MyApp::OnScriptMenuModified)
94 EVT_COMMAND(MyDocumentEvent_openFilesByEvent, MyDocumentEvent, MyApp::OnOpenFilesByEvent)
95 EVT_UPDATE_UI_RANGE(myMenuID_MyFirstMenuItem, myMenuID_MyLastMenuItem, MyApp::OnUpdateUI)
96 EVT_MENU(myMenuID_ExecuteScript, MyApp::OnExecuteScript)
97 EVT_MENU(myMenuID_OpenConsoleWindow, MyApp::OnOpenConsoleWindow)
98 EVT_MENU(myMenuID_EmptyConsoleWindow, MyApp::OnEmptyConsoleWindow)
99 EVT_MENU(myMenuID_ViewGlobalParameters, MyApp::OnViewGlobalParameters)
100 EVT_MENU(myMenuID_ViewParameterFilesList, MyApp::OnViewParameterFilesList)
101 EVT_MENU(myMenuID_BringAllWindowsToFront, MyApp::OnBringAllWindowsToFront)
102 EVT_MENU(wxID_HELP, MyApp::OnHelp)
103 #if defined(__WXMAC__)
104 EVT_ACTIVATE(MyApp::OnActivate)
106 // EVT_END_PROCESS(-1, MyApp::OnEndProcess)
107 EVT_TIMER(-1, MyApp::TimerInvoked)
108 EVT_COMMAND(myMenuID_Internal_CheckIfAllWindowsAreGone, MyDocumentEvent, MyApp::CheckIfAllWindowsAreGoneHandler)
111 // Find the path of the directory where the relevant resources are to be found.
112 // Mac: the "Resources" directory in the application bundle.
113 // Windows: the directory in which the application executable is located.
116 MyApp::InitResourcePath(int& argc, wxChar **argv)
118 #if defined(__WXMAC__)
119 CFBundleRef mainBundle = CFBundleGetMainBundle();
120 CFURLRef ref = CFBundleCopyResourcesDirectoryURL(mainBundle);
123 if (CFURLGetFileSystemRepresentation(ref, true, buffer, sizeof buffer)) {
124 wxString dirname((const char *)buffer, WX_DEFAULT_CONV);
126 m_resourcePath = dirname;
131 m_resourcePath = wxEmptyString;
132 return wxEmptyString;
133 #elif defined(__WXMSW__)
135 wxString argv0 = argv[0];
136 // Fix dosish path (when invoked from MSYS console, the path may be unix-like)
137 // Note: absolute paths like /c/Molby/... (== c:\Molby\...) is not supported
139 char *p = strdup(argv0.mb_str(wxConvFile));
141 wxString argv0_fixed(p, wxConvFile);
144 // Is it an absolute path?
145 if (wxIsAbsolutePath(argv0)) {
146 m_resourcePath = wxPathOnly(argv0);
147 return m_resourcePath;
149 // Is it a relative path?
150 wxString currentDir = wxGetCwd();
151 if (currentDir.Last() != wxFILE_SEP_PATH)
152 currentDir += wxFILE_SEP_PATH;
153 str = currentDir + argv0;
154 if (wxFileExists(str)) {
155 m_resourcePath = wxPathOnly(str);
156 return m_resourcePath;
161 pathList.AddEnvList(wxT("PATH"));
162 str = pathList.FindAbsoluteValidPath(argv0);
163 if (!str.IsEmpty()) {
164 m_resourcePath = wxPathOnly(str);
165 return m_resourcePath;
167 m_resourcePath = wxEmptyString;
168 return m_resourcePath;
170 #error "FindResourcePath is not defined for UNIXes."
175 MyApp::FindResourcePath()
177 return wxGetApp().m_resourcePath;
183 m_progressDialog = NULL;
185 // m_processTerminated = false;
186 // m_processExitCode = 0;
188 scriptMenuTitles = NULL;
189 scriptMenuPositions = NULL;
190 scriptMenuModifiedEventPosted = false;
191 parameterFrame = NULL;
192 parameterFilesFrame = NULL;
194 m_CountNamedFragments = 0;
195 m_NamedFragments = (char **)(-1); /* Will be set to NULL after Ruby interpreter is initialized */
196 m_pendingFilesToOpen = NULL;
197 m_CountTimerDocs = 0;
201 #if defined(__WXMSW__)
203 m_ipcServiceName = NULL;
209 // We override Initialize() instead of OnInit, because wxAppBase::Initialize() calls OnInitGui(), which
210 // makes the program run as a GUI application.
211 // So, we intercept here, and go directly to the execution in the batch mode.
212 // Otherwise, we call the inherited version of Initialize() and the program will run as a normal application.
213 bool MyApp::Initialize(int& argc, wxChar **argv)
215 // Called with a batch mode?
216 if (argc > 1 && wcscmp(argv[1], L"-b") == 0) {
218 // Disable any wxLog functionality (otherwise ::exit() may crash)
219 wxLog::EnableLogging(false);
222 gSuppressConsole = 1;
224 if (argc > 2 && wcscmp(argv[2], L"-v") == 0)
225 gSuppressConsole = 0;
227 // We need these parameters in FindResourcePath(), so we assign them here
231 // Initialize the internal m_resourcePath member
232 InitResourcePath(argc, argv);
234 static const char fname[] = "startup.rb";
235 wxString dirname = FindResourcePath();
237 dirname += wxFILE_SEP_PATH;
238 dirname += wxT("Scripts");
239 wxString cwd = wxGetCwd();
240 wxSetWorkingDirectory(dirname);
242 wxString fnamestr(fname, wxConvFile);
243 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, (const char *)dirname.mb_str(wxConvFile));
245 wxSetWorkingDirectory(cwd);
248 int c = (gSuppressConsole ? 2 : 3);
252 if (gSuppressConsole) {
253 fprintf(stderr, "The script is not given\n");
255 } else exit(0); // Show startup message and exit
257 wxString argv_script;
258 while (i + c < argc) {
259 wxString arg(argv[i + c]);
260 arg.Replace(wxT("\'"), wxT("\\\'"));
261 argv_script += wxString::Format(wxT("ARGV[%d] = \'"), i - 1);
263 argv_script += wxT("\'\n");
266 gSuppressConsole = 0; // Console output is no longer suppressed (startup is done)
267 status = Molby_loadScript(argv_script.mb_str(wxConvFile), 0);
269 wxString arg2(argv[c]);
270 status = Molby_loadScript(arg2.mb_str(wxConvFile), 1);
273 Ruby_showError(status);
278 // Call the inherited version
279 return wxApp::Initialize(argc, argv);
283 bool MyApp::OnInit(void)
286 #if defined(__WXMAC__) || defined(__WXOSX__)
287 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
288 wxSystemOptions::SetOption(wxT("osx.openfiledialog.always-show-types"), 1);
289 wxSystemOptions::SetOption(wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1);
294 // Check if the same application is already running
296 asprintf(&buf, "Molby-%s", (const char *)wxGetUserId().mb_str(WX_DEFAULT_CONV));
297 wxString name(buf, WX_DEFAULT_CONV);
298 m_ipcServiceName = new wxString(name);
299 m_ipcServiceName->Prepend(wxT("IPC-"));
301 m_checker = new wxSingleInstanceChecker(name);
302 if (m_checker->IsAnotherRunning()) {
303 // Make a connection with the other instance and ask for opening the file(s)
306 wxConnectionBase *connection;
308 for (i = 1; i < argc; i++) {
309 files.append(argv[i]);
310 files.append(wxT("\n"));
312 m_client = new MyClient;
313 connection = m_client->MakeConnection(wxT("localhost"), *m_ipcServiceName, MOLBY_IPC_TOPIC);
314 if (connection == NULL) {
315 wxLogError(wxT("Molby is already running; please shut it down and retry"));
319 connection->Execute(files);
324 m_server = new MyServer;
325 if (m_server->Create(*m_ipcServiceName) == false) {
333 // Create a document manager
334 m_docManager = new MyDocManager;
336 // Create templates relating drawing documents to their views
337 new wxDocTemplate(m_docManager, _T("Molby Structure File"), _T("*.mbsf"), _T(""), _T("mbsf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
338 new wxDocTemplate(m_docManager, _T("Protein Structure File"), _T("*.psf"), _T(""), _T("psf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
339 new wxDocTemplate(m_docManager, _T("Protein Data Bank File"), _T("*.pdb"), _T(""), _T("pdb"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
340 new wxDocTemplate(m_docManager, _T("Gaussian Input File"), _T("*.com;*.gjf"), _T(""), _T("com"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
341 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));
342 new wxDocTemplate(m_docManager, _T("Gaussian Checkpoint File"), _T("*.fchk;*.fch"), _T(""), _T("fchk"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
343 new wxDocTemplate(m_docManager, _T("GAMESS Input File"), _T("*.inp"), _T(""), _T("inp"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
344 new wxDocTemplate(m_docManager, _T("GAMESS DAT File"), _T("*.dat"), _T(""), _T("dat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
345 new wxDocTemplate(m_docManager, _T("ORTEP Input File"), _T("*.tep"), _T(""), _T("tep"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
346 new wxDocTemplate(m_docManager, _T("SHELX Input File"), _T("*.ins;*.res"), _T(""), _T("ins"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
347 new wxDocTemplate(m_docManager, _T("Crystallographic Information File"), _T("*.cif"), _T(""), _T("cif"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
348 new wxDocTemplate(m_docManager, _T("Cartesian"), _T("*.xyz"), _T(""), _T("xyz"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
349 new wxDocTemplate(m_docManager, _T("Z Matrix"), _T("*.zmat"), _T(""), _T("zmat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
350 new wxDocTemplate(m_docManager, _T("Any Molecule"), _T("*.*"), _T(""), _T(""), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
352 // Init image handlers
353 MyAppCallback_initImageHandlers();
355 // Create the main frame window
356 frame = new MyFrame((wxDocManager *) m_docManager, (wxFrame *) NULL,
357 _T("Molby"), wxDefaultPosition, wxDefaultSize,
358 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
359 frame->SetClientSize(FromFrameDIP(frame, wxSize(800, 600)));
361 // Give it an icon (this is ignored in MDI mode: uses resources)
363 frame->SetIcon(wxIcon(_T("doc")));
366 frame->SetIcon(wxIcon(_T("doc.xbm")));
369 wxMenuBar *menu_bar = CreateMenuBar(0);
372 wxMenuBar::MacSetCommonMenuBar(menu_bar);
375 // Associate the menu bar with the frame
376 frame->SetMenuBar(menu_bar);
378 frame->Centre(wxBOTH);
380 #if defined(__WXMAC__) || defined(__WXMSW__)
381 frame->Move(-10000, -10000); // Set invisible
389 // Load default settings from the preference file
390 LoadDefaultSettings();
392 // Create a console window
393 consoleFrame = ConsoleFrame::CreateConsoleFrame(frame);
394 consoleFrame->Show(true);
396 /* Initialize Ruby interpreter with the startup script */
397 /* (Also read startup information) */
399 extern int gRevisionNumber;
400 static const char fname[] = "startup.rb";
401 InitResourcePath(argc, argv);
402 wxString dirname = FindResourcePath();
404 dirname += wxFILE_SEP_PATH;
405 dirname += wxT("Scripts");
406 /* wxString cwd = wxGetCwd(); */
407 wxSetWorkingDirectory(dirname);
409 wxString fnamestr(fname, wxConvFile);
410 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, (const char *)dirname.mb_str(wxConvFile));
413 wxString docHome(MyAppCallback_getDocumentHomeDir(), wxConvFile);
414 wxSetWorkingDirectory(docHome);
418 /* Pasteboard type strings (includes the revision number) */
419 asprintf(&gMoleculePasteboardType, "Molecule_%d", gRevisionNumber);
420 asprintf(&gParameterPasteboardType, "Parameter_%d", gRevisionNumber);
422 MyAppCallback_showScriptMessage("%% ");
424 /* Build the predefined fragments menu */
425 m_NamedFragments = NULL;
426 // UpdatePredefinedFragmentMenu(GetMainFrame()->GetMenuBar());
427 UpdatePredefinedFragmentMenu(consoleFrame->GetMenuBar());
431 /* Open given files: Ruby script is executed, other files are opened as a document */
433 #if defined(__WXMSW__)
434 m_docManager->CreateDocument(wxEmptyString, wxDOC_NEW);
439 for (i = 1; i < argc; i++) {
440 files.append(argv[i]);
441 files.append(wxT("\n"));
443 RequestOpenFilesByEvent(files);
446 gInitCompleted = true;
452 // kind == 0: main menu
453 // kind == 1: molecule window
454 // kind == 2: console window
455 // kind == 3: Ruby dialog (non-modal)
457 MyApp::CreateMenuBar(int kind, wxMenu **out_file_history_menu, wxMenu **out_edit_menu)
464 wxMenu *file_menu = new wxMenu;
465 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
467 wxMenu *edit_menu = new wxMenu;
468 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
469 edit_menu->Append(wxID_REDO, _T("&Redo"));
470 edit_menu->AppendSeparator();
471 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
472 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
473 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
474 edit_menu->Append(wxID_CLEAR, _T("Clear"));
475 edit_menu->AppendSeparator();
476 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
478 wxMenu *help_menu = new wxMenu;
479 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
480 help_menu->Append(wxID_HELP, _T("&Molby Help"));
482 wxMenuBar *menu_bar = new wxMenuBar;
484 menu_bar->Append(file_menu, _T("&File"));
485 menu_bar->Append(edit_menu, _T("&Edit"));
486 menu_bar->Append(help_menu, _T("&Help"));
492 wxMenu *file_menu = new wxMenu;
493 wxMenu *file_history_menu = NULL;
495 file_menu->Append(wxID_NEW, _T("&New...\tCtrl-N"));
496 file_menu->Append(wxID_OPEN, _T("&Open...\tCtrl-O"));
497 if (out_file_history_menu != NULL) {
498 file_history_menu = new wxMenu;
499 *out_file_history_menu = file_history_menu;
500 file_menu->AppendSubMenu(*out_file_history_menu, _T("Open Recent"));
501 m_docManager->FileHistoryAddFilesToMenu(*out_file_history_menu);
502 m_docManager->FileHistoryUseMenu(*out_file_history_menu); // Should be removed when menu is discarded
504 /* Build "Open Predefined" */
505 wxMenu *predefined_menu = new wxMenu;
506 file_menu->Append(myMenuID_PredefinedFragment, _T("Open Predefined"), predefined_menu);
508 file_menu->AppendSeparator();
509 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
510 file_menu->Append(wxID_SAVE, _T("&Save\tCtrl-S"));
511 file_menu->Append(wxID_SAVEAS, _T("Save &As..."));
512 file_menu->Append(wxID_REVERT, _T("Revert to Saved"));
514 file_menu->AppendSeparator();
515 file_menu->Append(myMenuID_Import, _T("Import..."));
516 file_menu->Append(myMenuID_Export, _T("Export..."));
517 file_menu->Append(myMenuID_ExportGraphic, _T("Export Graphic..."));
519 file_menu->AppendSeparator();
520 file_menu->Append(wxID_PRINT, _T("&Print...\tCtrl-P"));
521 file_menu->Append(wxID_PRINT_SETUP, _T("Print &Setup..."));
522 file_menu->Append(wxID_PREVIEW, _T("Print Pre&view"));
524 file_menu->AppendSeparator();
525 #if defined(__WXMAC__)
526 file_menu->Append(wxID_EXIT, _T("E&xit\tCtrl-Q"));
528 file_menu->Append(wxID_EXIT, _T("E&xit\tAlt-X"));
531 wxMenu *edit_menu = new wxMenu;
532 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
533 edit_menu->Append(wxID_REDO, _T("&Redo"));
534 edit_menu->AppendSeparator();
535 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
536 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
537 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
538 edit_menu->Append(wxID_CLEAR, _T("Clear"));
539 edit_menu->AppendSeparator();
540 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
541 edit_menu->Append(myMenuID_SelectFragment, _T("Select Fragment\tCtrl-F"));
542 edit_menu->Append(myMenuID_SelectReverse, _T("Select Reverse"));
543 edit_menu->AppendSeparator();
544 wxMenu *create_parameter_menu = new wxMenu;
545 create_parameter_menu->Append(myMenuID_CreateNewVdwParameter, _T("Vdw"));
546 create_parameter_menu->Append(myMenuID_CreateNewBondParameter, _T("Bond"));
547 create_parameter_menu->Append(myMenuID_CreateNewAngleParameter, _T("Angle"));
548 create_parameter_menu->Append(myMenuID_CreateNewDihedralParameter, _T("Dihedral"));
549 create_parameter_menu->Append(myMenuID_CreateNewImproperParameter, _T("Improper"));
550 create_parameter_menu->Append(myMenuID_CreateNewVdwPairParameter, _T("Vdw Pair"));
551 create_parameter_menu->Append(myMenuID_CreateNewVdwCutoffParameter, _T("Vdw Cutoff"));
552 edit_menu->Append(myMenuID_CreateNewAtom, _T("Create New Atom\tCtrl-I"));
553 edit_menu->Append(myMenuID_CreateNewParameter, _T("Create New Parameter"), create_parameter_menu);
554 edit_menu->Append(myMenuID_CreatePiAnchor, _T("Create Pi Anchor"));
555 edit_menu->AppendSeparator();
556 wxMenu *add_hydrogen_menu = new wxMenu;
557 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp3, _T("Tetrahedral sp3"));
558 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp2, _T("Trigonal sp2"));
559 add_hydrogen_menu->Append(myMenuID_AddHydrogenLinear, _T("Linear sp"));
560 add_hydrogen_menu->Append(myMenuID_AddHydrogenPyramidal, _T("Pyramidal (like NH2)"));
561 add_hydrogen_menu->Append(myMenuID_AddHydrogenBent, _T("Bent (like OH)"));
562 edit_menu->Append(myMenuID_AddHydrogen, _T("Add Hydrogen"), add_hydrogen_menu);
564 if (out_edit_menu != NULL)
565 *out_edit_menu = edit_menu; // Should be associated with the command processor if available
567 wxMenu *view_menu = new wxMenu;
568 view_menu->Append(myMenuID_FitToScreen, _T("Fit To Screen\tCtrl-T"));
569 view_menu->Append(myMenuID_CenterSelection, _T("Center Selection"));
570 /* view_menu->AppendSeparator();
571 view_menu->Append(myMenuID_ShowUnitCell, _T("Show Unit Cell"), _T(""), wxITEM_CHECK);
572 view_menu->Append(myMenuID_ShowHydrogens, _T("Show Hydrogen Atoms"), _T(""), wxITEM_CHECK);
573 view_menu->Append(myMenuID_ShowDummyAtoms, _T("Show Dummy Atoms"), _T(""), wxITEM_CHECK);
574 view_menu->Append(myMenuID_ShowExpandedAtoms, _T("Show Expanded Atoms"), _T(""), wxITEM_CHECK);
575 view_menu->Append(myMenuID_ShowEllipsoids, _T("Show Ellipsoids"), _T(""), wxITEM_CHECK);
576 view_menu->Append(myMenuID_ShowRotationCenter, _T("Show Rotation Center"), _T(""), wxITEM_CHECK); */
577 view_menu->AppendSeparator();
578 view_menu->Append(myMenuID_HideSelected, _T("Hide Selected"), _T(""));
579 view_menu->Append(myMenuID_HideUnselected, _T("Hide Unselected"), _T(""));
580 view_menu->Append(myMenuID_HideReverse, _T("Hide Reverse"), _T(""));
581 view_menu->Append(myMenuID_ShowAllAtoms, _T("Show All Atoms"), _T(""));
582 // view_menu->AppendSeparator();
583 // view_menu->Append(myMenuID_ShowGraphite, _T("Show Graphite..."));
584 // view_menu->AppendSeparator();
585 // view_menu->Append(myMenuID_LineMode, _T("Line Mode"), _T(""), wxITEM_CHECK);
587 wxMenu *md_menu = new wxMenu;
588 md_menu->Append(myMenuID_MolecularDynamics, _T("Molecular Dynamics..."));
589 md_menu->Append(myMenuID_Minimize, _T("Minimize..."));
590 md_menu->Append(myMenuID_StopMDRun, _T("Stop\tCtrl-."));
591 md_menu->AppendSeparator();
592 md_menu->Append(myMenuID_ViewGlobalParameters, _T("View Global Parameters..."));
593 md_menu->Append(myMenuID_ViewParameterFilesList, _T("Load/Unload Global Parameters..."));
595 wxMenu *script_menu = new wxMenu;
596 script_menu->Append(myMenuID_ExecuteScript, _T("Execute Script..."));
597 script_menu->Append(myMenuID_OpenConsoleWindow, _T("Open Console Window"));
598 script_menu->Append(myMenuID_EmptyConsoleWindow, _T("Empty Console Window"));
599 script_menu->AppendSeparator();
600 countNonCustomScriptMenu = script_menu->GetMenuItemCount();
602 wxMenu *help_menu = new wxMenu;
603 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
604 help_menu->Append(wxID_HELP, _T("&Molby Help"));
606 wxMenuBar *menu_bar = new wxMenuBar;
608 menu_bar->Append(file_menu, _T("&File"));
609 menu_bar->Append(edit_menu, _T("&Edit"));
610 menu_bar->Append(view_menu, _T("View"));
611 menu_bar->Append(md_menu, _T("MM/MD"));
612 menu_bar->Append(script_menu, _T("&Script"));
614 #if defined(__WXMAC__)
615 wxMenu *window_menu = new wxMenu;
616 window_menu->Append(myMenuID_BringAllWindowsToFront, _T("Bring All to Front"));
617 window_menu->AppendSeparator();
618 menu_bar->Append(window_menu, _T("Window"));
621 menu_bar->Append(help_menu, _T("&Help"));
623 UpdateScriptMenu(menu_bar);
624 if (m_NamedFragments != (char **)(-1))
625 UpdatePredefinedFragmentMenu(menu_bar);
630 #if defined(__WXMAC__) || defined(__WXOSX__)
631 /* When the application is launched without any documents, an empty document is opened.
632 This should be implemented by overriding this special method; parsing argc/argv does
633 not work, because the list of files is passed through an Apple Event. */
637 if (m_docManager == NULL)
638 return; // Initialization is not yet complete
639 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
643 MyApp::MacOpenFile(const wxString &fileName)
645 wxString file(fileName);
646 RequestOpenFilesByEvent(file);
650 MyApp::MacOpenFiles(const wxArrayString &fileNames)
654 n = fileNames.GetCount();
655 for (i = 0; i < n; i++) {
656 fnames = fnames + fileNames[i];
658 fnames = fnames + wxT("\n");
668 SaveDefaultSettings();
678 sModifyMenuForFilterMode(wxMenuBar *mbar)
683 idx = mbar->FindMenu(wxT("Show"));
684 if (idx != wxNOT_FOUND)
685 delete mbar->Remove(idx);
686 idx = mbar->FindMenu(wxT("MM/MD"));
687 if (idx != wxNOT_FOUND)
688 delete mbar->Remove(idx);
689 idx = mbar->FindMenu(wxT("QChem"));
690 if (idx != wxNOT_FOUND)
691 delete mbar->Remove(idx);
692 idx = mbar->FindMenu(wxT("Script"));
693 if (idx != wxNOT_FOUND) {
694 menu = mbar->GetMenu(idx);
695 n = menu->GetMenuItemCount();
696 for (i = n - 1; i >= 0; i--) {
697 item = menu->FindItemByPosition(i);
699 if (id != myMenuID_OpenConsoleWindow && id != myMenuID_EmptyConsoleWindow && id != myMenuID_ExecuteScript) {
706 idx = mbar->FindMenu(wxT("Edit"));
707 if (idx != wxNOT_FOUND) {
708 menu = mbar->GetMenu(idx);
709 n = menu->GetMenuItemCount();
710 for (i = n - 1; i >= 0; i--) {
711 item = menu->FindItemByPosition(i);
713 if (id == wxID_SELECTALL)
720 idx = mbar->FindMenu(wxT("File"));
721 if (idx != wxNOT_FOUND) {
722 menu = mbar->GetMenu(idx);
723 n = menu->GetMenuItemCount();
724 for (i = n - 1; i >= 0; i--) {
725 item = menu->FindItemByPosition(i);
727 if (id != wxID_OPEN && id != wxID_EXIT) {
737 MyApp::ShowProgressPanel(const char *mes)
739 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
740 if (m_progressDialog == NULL) {
741 m_progressDialog = new wxProgressDialog(wxT("Progress"), mes, 100, NULL, wxPD_APP_MODAL | wxPD_CAN_ABORT);
746 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
747 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
748 if (quitMenuItem != NULL)
749 quitMenuItem->Enable(false);
753 m_progressFrame = new ProgressFrame(_T("Progress"), string);
754 m_progressCanceled = false;
755 m_progressValue = -1;
760 MyApp::HideProgressPanel()
762 if (m_progressDialog != NULL) {
763 m_progressDialog->Hide();
764 m_progressDialog->Destroy();
765 m_progressDialog = NULL;
768 if (m_progressFrame != NULL) {
769 m_progressFrame->Hide();
770 m_progressFrame->Destroy();
771 m_progressFrame = NULL;
774 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
776 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
777 if (quitMenuItem != NULL)
778 quitMenuItem->Enable(true);
786 MyApp::SetProgressValue(double dval)
788 if (m_progressDialog != NULL) {
790 m_progressDialog->Update((int)(dval * 100));
792 m_progressDialog->Pulse();
797 MyApp::SetProgressMessage(const char *mes)
799 if (m_progressDialog != NULL) {
800 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
801 m_progressDialog->Update(0, string);
806 MyApp::IsInterrupted()
808 if (m_progressDialog != NULL)
809 return m_progressDialog->WasCancelled();
811 if (::wxGetKeyState(WXK_ESCAPE))
818 MyApp::OnOpenConsoleWindow(wxCommandEvent& event)
820 consoleFrame->Show(true);
821 consoleFrame->Raise();
825 MyApp::OnEmptyConsoleWindow(wxCommandEvent& event)
827 consoleFrame->EmptyBuffer();
831 MyApp::OnViewGlobalParameters(wxCommandEvent& event)
833 if (parameterFrame == NULL) {
834 parameterFrame = GlobalParameterFrame::CreateGlobalParameterFrame(GetMainFrame());
835 MainView_createColumnsForTableAtIndex(NULL, kMainViewParameterTableIndex);
837 MainView_refreshTable(NULL);
838 parameterFrame->Show(true);
839 parameterFrame->Raise();
843 MyApp::OnViewParameterFilesList(wxCommandEvent &event)
845 if (parameterFilesFrame == NULL) {
846 parameterFilesFrame = GlobalParameterFilesFrame::CreateGlobalParameterFilesFrame(GetMainFrame());
848 parameterFilesFrame->Show(true);
849 parameterFilesFrame->Raise();
853 MyApp::OnBringAllWindowsToFront(wxCommandEvent &event)
856 wxWindowList::iterator iter;
857 wxTopLevelWindow **wins;
858 size = wxTopLevelWindows.size();
860 wins = (wxTopLevelWindow **)calloc(sizeof(wxTopLevelWindow *), size);
861 for (iter = wxTopLevelWindows.begin(), n = 0; iter != wxTopLevelWindows.end(); ++iter, ++n) {
862 wins[n] = (wxTopLevelWindow *)(*iter);
864 for (n = 0; n < size; n++) {
865 if (wins[n]->IsShown())
872 MyApp::LookupScriptMenu(const char *title)
877 for (i = 0; i < countScriptMenu; i++) {
878 if (strcmp(title, scriptMenuTitles[i]) == 0)
885 MyApp::RegisterScriptMenu(const char *title)
889 // Already registered? (If it is not a separator item)
891 p = strrchr(title, '\t');
895 if (p[0] != 0 && p[0] != '-') {
896 for (i = 0; i < countScriptMenu; i++) {
897 if (strcmp(title, scriptMenuTitles[i]) == 0) {
904 if (countScriptMenu == 0) {
905 scriptMenuTitles = (char **)malloc(sizeof(char *));
906 scriptMenuPositions = (int *)malloc(sizeof(int));
908 scriptMenuTitles = (char **)realloc(scriptMenuTitles, sizeof(char *) * (countScriptMenu + 1));
909 scriptMenuPositions = (int *)realloc(scriptMenuPositions, sizeof(int) * (countScriptMenu + 1));
911 scriptMenuTitles[countScriptMenu] = strdup(title);
912 scriptMenuPositions[countScriptMenu] = -1;
915 if (!scriptMenuModifiedEventPosted) {
916 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_scriptMenuModified);
917 wxPostEvent(this, myEvent);
918 scriptMenuModifiedEventPosted = true;
921 return countScriptMenu - 1;
925 MyApp::UpdateScriptMenu(wxMenuBar *mbar)
929 for (i = 0; i < countScriptMenu; i++) {
930 // Find Menu to be inserted
931 const char *s = scriptMenuTitles[i], *p;
934 while ((p = strchr(s, '\t')) != NULL) {
935 // Find existing menu
936 wxString menuTitle(s, WX_DEFAULT_CONV, p - s);
938 mid = mbar->FindMenu(menuTitle);
939 if (mid == wxNOT_FOUND) {
940 // Create a new menu before "Script" menu
941 wxMenu *newMenu = new wxMenu;
942 int sid = mbar->FindMenu(_T("Script"));
943 if (sid == wxNOT_FOUND) {
944 mbar->Append(newMenu, menuTitle);
945 sid = mbar->GetMenuCount() - 1;
947 mbar->Insert(sid, newMenu, menuTitle);
949 menu = mbar->GetMenu(sid);
951 menu = mbar->GetMenu(mid);
954 mid = menu->FindItem(menuTitle);
955 if (mid == wxNOT_FOUND) {
956 // Create a new menu at the end
957 wxMenu *newMenu1 = new wxMenu;
958 menu->Append(myMenuID_CustomScript + i + depth * 1000, menuTitle, newMenu1);
961 menu = menu->FindItem(mid)->GetSubMenu();
968 // The new item should be under "Script" menu
969 mid = mbar->FindMenu(_T("Script"));
970 menu = mbar->GetMenu(mid);
972 if (*s == 0 || *s == '-') {
975 int count = menu->GetMenuItemCount();
976 if (scriptMenuPositions[i] >= 0 && scriptMenuPositions[i] < count) {
977 sitem = menu->FindItemByPosition(scriptMenuPositions[i]);
978 if (sitem != NULL && sitem->IsSeparator())
979 continue; // Already present
981 if (count != 0 && !menu->FindItemByPosition(count - 1)->IsSeparator()) {
982 menu->AppendSeparator();
983 scriptMenuPositions[i] = count;
991 } else checkable = false;
992 // Check if the item is already existing
993 wxString itemTitle(s, WX_DEFAULT_CONV);
996 item = mbar->FindItem(myMenuID_CustomScript + i, &omenu);
998 if (omenu == menu && item->GetItemLabel() == itemTitle) {
999 // The menu is already existing with correct position and title
1002 // The menu title does not match; remove this menu item
1003 Disconnect(myMenuID_CustomScript + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
1004 omenu->Remove(item);
1008 menu->Append(myMenuID_CustomScript + i, itemTitle, wxEmptyString, (checkable ? wxITEM_CHECK : wxITEM_NORMAL));
1009 scriptMenuPositions[i] = menu->GetMenuItemCount() - 1;
1010 Connect(myMenuID_CustomScript + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
1015 MyApp::OnScriptMenuModified(wxCommandEvent& event)
1017 scriptMenuModifiedEventPosted = false;
1018 UpdateScriptMenu(consoleFrame->GetMenuBar());
1023 MyApp::OnScriptMenuSelected(wxCommandEvent& event)
1027 int index = event.GetId() - myMenuID_CustomScript;
1028 if (index < 0 || index >= countScriptMenu)
1030 mview = MainViewCallback_activeView();
1033 else mol = mview->mol;
1034 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("iM"), "lambda { |n, m| $script_menu_commands[n].call(m) }", index, mol);
1038 MyApp::UpdatePredefinedFragmentMenu(wxMenuBar *mbar)
1041 wxMenuItem *fmenuItem = mbar->FindItem(myMenuID_PredefinedFragment);
1042 wxMenu *fmenu = (fmenuItem != NULL ? fmenuItem->GetSubMenu() : NULL);
1045 if (m_NamedFragments == (char **)(-1))
1048 /* Rebuild sNamedFragments array */
1049 if (m_NamedFragments != NULL) {
1050 for (i = 0; i < m_CountNamedFragments; i++) {
1051 free(m_NamedFragments[i * 2]);
1052 free(m_NamedFragments[i * 2 + 1]);
1054 free(m_NamedFragments);
1056 m_NamedFragments = NULL;
1057 m_CountNamedFragments = 0;
1058 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION(";i"), "lambda { $named_fragments.length }", &n) != 0 || n <= 0)
1060 m_CountNamedFragments = n;
1061 m_NamedFragments = (char **)calloc(sizeof(char *), n * 2);
1062 for (i = 0; i < n; i++) {
1063 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "lambda { |i| $named_fragments[i][0] }", i, &m_NamedFragments[i * 2]) != 0 ||
1064 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "lambda { |i| $named_fragments[i][1] }", i, &m_NamedFragments[i * 2 + 1]) != 0)
1068 for (i = 0; i < m_CountNamedFragments; i++) {
1069 if (m_NamedFragments[i * 2] != NULL)
1070 free(m_NamedFragments[i * 2]);
1071 if (m_NamedFragments[i * 2 + 1] != NULL)
1072 free(m_NamedFragments[i * 2 + 1]);
1074 free(m_NamedFragments);
1075 m_CountNamedFragments = 0;
1076 m_NamedFragments = NULL;
1080 wxMenu *predefined_submenu = NULL;
1083 for (i = sn = 0; i < m_CountNamedFragments; i++) {
1084 if (strcmp(m_NamedFragments[i * 2 + 1], "-") == 0) {
1085 if (predefined_submenu != NULL) {
1086 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
1088 predefined_submenu = new wxMenu;
1089 stitle = wxString(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
1092 wxString mtitle(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
1093 (predefined_submenu != NULL ? predefined_submenu : fmenu)->Append(myMenuID_PredefinedFragment + 1 + i, mtitle);
1096 if (predefined_submenu != NULL)
1097 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
1098 Connect(myMenuID_PredefinedFragment + 1, myMenuID_PredefinedFragment + m_CountNamedFragments, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnFragmentMenuSelected), NULL, this);
1102 MyApp::OnFragmentMenuSelected(wxCommandEvent& event)
1104 int index = event.GetId() - myMenuID_PredefinedFragment - 1;
1105 if (index < 0 || index >= m_CountNamedFragments)
1107 // Open a predefined fragment as a new file
1109 Molecule *mol = MoleculeNew();
1113 asprintf(&fullname, "%s/Scripts/mbsf/%s", (const char *)(FindResourcePath().mb_str(wxConvFile)), m_NamedFragments[index * 2 + 1]);
1114 result = MoleculeLoadMbsfFile(mol, fullname, &errbuf);
1115 if (errbuf != NULL) {
1116 MyAppCallback_showScriptMessage("On loading %s:\n%s", m_NamedFragments[index * 2 + 1], errbuf);
1120 MyAppCallback_errorMessageBox("Cannot open named fragment %s\n(See console for detailed message)", m_NamedFragments[index * 2]);
1125 MyDocument *doc = (MyDocument *)(DocManager()->CreateDocument(wxT(""), wxDOC_NEW));
1126 wxString title(m_NamedFragments[index * 2], WX_DEFAULT_CONV);
1127 title = _T("*") + title + _T("*");
1128 doc->SetMolecule(mol);
1129 if (mol->natoms > 1000)
1130 mol->mview->lineMode = 1;
1131 MainView_resizeToFit(mol->mview);
1133 // Change the window title
1134 doc->SetTitle(title);
1135 // Propagate the change of the window title
1136 wxList::compatibility_iterator node = doc->GetViews().GetFirst();
1138 wxView *view = (wxView *)node->GetData();
1139 view->OnChangeFilename();
1140 node = node->GetNext();
1145 MyApp::OnUpdateUI(wxUpdateUIEvent& event)
1147 int uid = event.GetId();
1148 MainView *mview = MainViewCallback_activeView();
1149 if (uid >= myMenuID_CustomScript && uid < myMenuID_CustomScript + countScriptMenu) {
1150 // Check the script menu
1151 // If the frontmost window is RubyDialogFrame, then disable any script menu command
1153 #if defined(__WXMAC__)
1154 void *MacGetActiveWindow(void);
1155 w = wxDynamicCast(wxNonOwnedWindow::GetFromWXWindow((WXWindow)MacGetActiveWindow()), wxWindow);
1157 w = wxGetActiveWindow();
1159 if (wxDynamicCast(w, RubyDialogFrame) != NULL) {
1160 event.Enable(false);
1164 int enabled, checked;
1166 int index = uid - myMenuID_CustomScript;
1169 else mol = mview->mol;
1172 enabled = Ruby_UpdateUI(index, mol, &checked, &title);
1174 #if wxCHECK_VERSION(3,2,0)
1175 && event.IsCheckable()
1178 event.Check(checked != 0);
1179 if (title != NULL) {
1180 wxString wtext(title, WX_DEFAULT_CONV);
1181 event.SetText(wtext);
1184 event.Enable(enabled != 0);
1185 } else if (uid >= myMenuID_PredefinedFragment && uid <= myMenuID_PredefinedFragment + m_CountNamedFragments) {
1187 #if defined(__WXMAC__)
1188 } else if (uid >= wxID_OSX_MENU_FIRST && uid <= wxID_OSX_MENU_LAST) {
1193 case myMenuID_ExecuteScript:
1194 case myMenuID_OpenConsoleWindow:
1195 case myMenuID_EmptyConsoleWindow:
1196 case myMenuID_ViewParameterFilesList:
1197 case myMenuID_ViewGlobalParameters:
1202 event.Enable(false);
1210 MyApp::OnExecuteScript(wxCommandEvent &event)
1212 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Script File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
1213 if (dialog->ShowModal() == wxID_OK) {
1216 wxString path = dialog->GetPath();
1218 // Command line: execute_script('pathname')
1219 wxString cline(path);
1220 wxRegEx re(_T("[\\\\']")); // A backslash and a single-quote
1221 re.Replace(&cline, _T("\\\\\\0")); // A backslash followed by "\0"
1222 cline.Prepend(_T("execute_script('"));
1224 MyAppCallback_setConsoleColor(3);
1225 MyAppCallback_showScriptMessage("%s", (const char *)(cline.mb_str(wxConvFile)));
1226 MyAppCallback_showScriptMessage("\n");
1227 MyAppCallback_setConsoleColor(0);
1229 retval = MyAppCallback_executeScriptFromFile((const char *)(path.mb_str(wxConvFile)), &status);
1230 if (retval == (RubyValue)6 && status == -1)
1231 MyAppCallback_errorMessageBox("Cannot open Ruby script %s", (const char *)path.mb_str(wxConvFile));
1232 else if (status != 0)
1233 Ruby_showError(status);
1239 MyApp::OnActivate(wxActivateEvent &event)
1241 #if defined(__WXMAC__) || defined(__WXMSW__)
1242 MyFrame *frame = GetMainFrame();
1244 frame->Show(false); /* Sometimes this "parent" frame gets visible and screw up the menus */
1250 MyApp::RequestOpenFilesByEvent(wxString& files)
1252 /* We do not respond to "open file" event (either via IPC [MSW] or Apple Event [Mac])
1253 while we are running something else */
1254 if (m_progressDialog != NULL || gMolbyIsCheckingInterrupt || gMolbyRunLevel > 0)
1257 if (m_pendingFilesToOpen != NULL)
1258 m_pendingFilesToOpen->Append(files);
1260 m_pendingFilesToOpen = new wxString(files);
1261 if (!m_pendingFilesToOpen->EndsWith(wxT("\n")))
1262 m_pendingFilesToOpen->Append(wxT("\n"));
1263 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openFilesByEvent);
1264 wxPostEvent(this, myEvent);
1268 MyApp::OnOpenFilesByEvent(wxCommandEvent& event)
1270 if (m_pendingFilesToOpen == NULL)
1272 if (!gInitCompleted) {
1273 // Repost this event and try again later
1274 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openFilesByEvent);
1275 wxPostEvent(this, myEvent);
1278 OnOpenFiles(*m_pendingFilesToOpen);
1279 delete m_pendingFilesToOpen;
1280 m_pendingFilesToOpen = NULL;
1284 MyApp::OnOpenFiles(const wxString &files)
1287 bool success = true;
1292 end = files.find(wxT("\n"), start);
1293 wxString file = files.Mid(start, (end == wxString::npos ? wxString::npos : end - start));
1294 if (file.Len() == 0)
1296 if (file.EndsWith(wxT(".rb")) || file.EndsWith(wxT(".mrb"))) {
1297 /* Execute the file as a Ruby script */
1298 retval = MyAppCallback_executeScriptFromFile((const char *)file.mb_str(wxConvFile), &status);
1300 if (retval == (RubyValue)6 && status == -1)
1301 MyAppCallback_errorMessageBox("Cannot open Ruby script: %s", (const char *)file.mb_str(wxConvFile));
1303 Ruby_showError(status);
1307 if (NULL == wxGetApp().DocManager()->CreateDocument(file, wxDOC_SILENT))
1310 if (end == wxString::npos)
1318 MyApp::DefaultSettingsPath()
1320 wxString name = wxStandardPaths::Get().GetUserConfigDir();
1321 wxChar sep = wxFileName::GetPathSeparator();
1322 if (name[name.Len() - 1] != sep)
1324 name += _T("Molby.settings");
1329 MyApp::LoadDefaultSettings()
1331 wxString name = DefaultSettingsPath();
1332 m_defaultSettings.clear();
1333 wxTextFile file(name);
1334 if (file.Exists() && file.Open()) {
1337 for (line = file.GetFirstLine(); ; line = file.GetNextLine()) {
1340 if ((pos = line.Find('=')) != wxNOT_FOUND) {
1341 wxString key = line.Left(pos);
1342 wxString value = line.Right(line.Length() - pos - 1);
1343 SetDefaultSetting(key, value);
1353 MyApp::SaveDefaultSettings()
1355 wxString name = DefaultSettingsPath();
1356 wxTextFile file(name);
1362 MyStringHash::iterator it;
1363 for (it = m_defaultSettings.begin(); it != m_defaultSettings.end(); it++) {
1364 wxString key = it->first;
1365 wxString value = it->second;
1366 wxString line = key + _T("=") + value;
1374 MyApp::SetDefaultSetting(const wxString& key, const wxString& value)
1376 // TODO: The '=' and '#' characters may need to be escaped
1377 m_defaultSettings[key] = value;
1381 MyApp::GetDefaultSetting(const wxString& key)
1383 return m_defaultSettings[key];
1387 MyApp::GetGlobalParameterListCtrl()
1389 if (parameterFrame != NULL)
1390 return parameterFrame->GetListCtrl();
1394 #define LOG_SUBPROCESS 0
1401 MyApp::OnEndProcess(wxProcessEvent &event)
1403 m_processTerminated = true;
1404 m_processExitCode = event.GetExitCode();
1407 fprintf(fplog, "OnEndProcess called\n");
1409 // delete m_process;
1410 // m_process = NULL;
1415 MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *fpout, FILE *fperr, int *exitstatus_p, int *pid_p)
1418 int callback_result = 0;
1419 bool progress_panel = false;
1421 wxString cmdstr(cmdline, WX_DEFAULT_CONV);
1422 wxLongLong startTime, lastTime, presentTime;
1424 if (m_process != NULL)
1425 return -1; // Another process is already running (CallSubProcess() allows only one subprocess)
1427 #if defined(__WXMSW__)
1428 extern int myKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
1430 // Show progress panel
1431 if (procname != NULL) {
1432 snprintf(buf, sizeof buf, "Running %s...", procname);
1433 ShowProgressPanel(buf);
1434 progress_panel = true;
1436 startTime = lastTime = wxGetUTCTimeMillis();
1438 // Create log file in the document home directory
1440 wxDateTime dateTime;
1441 dateTime.SetToCurrent();
1444 char *dochome = MyAppCallback_getDocumentHomeDir();
1445 snprintf(buf, sizeof buf, "%s/molby_subprocess.log", dochome);
1447 fplog = fopen(buf, "a");
1453 // Create proc object and call subprocess
1454 m_process = new wxBetterProcess(this, -1);
1455 m_process->Redirect();
1456 int flag = wxEXEC_ASYNC;
1457 flag |= wxEXEC_MAKE_GROUP_LEADER;
1458 long pid = ::wxExecute(cmdstr, flag, m_process);
1461 HideProgressPanel();
1464 fprintf(fplog, "Cannot start '%s'\n", cmdline);
1472 fprintf(fplog, "%s[DEBUG]pid = %ld\n", (const char *)(dateTime.FormatISOCombined(' ')), pid);
1476 // Wait until process ends or user interrupts
1477 wxMemoryBuffer memBuffer; // Buffer to store standard output
1478 bool interrupted = false;
1483 lastTime = wxGetUTCTimeMillis();
1484 while ((len1 = m_process->GetLine(bufstr)) > 0) {
1486 dateTime.SetToCurrent();
1487 fprintf(fplog, "%s[STDOUT]%s", (const char *)(dateTime.FormatISOCombined(' ')), (const char *)bufstr);
1490 if (callback == DUMMY_CALLBACK) {
1491 const char *p = (const char *)bufstr;
1492 memBuffer.AppendData(p, strlen(bufstr));
1493 } else if (fpout != NULL && fpout != (FILE *)1) {
1494 fputs((const char *)bufstr, fpout);
1495 } else if (fpout == (FILE *)1) {
1496 MyAppCallback_setConsoleColor(0);
1497 MyAppCallback_showScriptMessage("%s", (const char *)bufstr);
1499 presentTime = wxGetUTCTimeMillis();
1500 if (presentTime > lastTime + 25) {
1501 presentTime = lastTime;
1505 while ((len2 = m_process->GetErrorLine(buferrstr)) > 0) {
1507 dateTime.SetToCurrent();
1508 fprintf(fplog, "%s[STDERR]%s", (const char *)(dateTime.FormatISOCombined(' ')), buf);
1511 if (fperr != NULL && fperr != (FILE *)1) {
1512 fputs((const char *)buferrstr, fperr);
1513 } else if (fpout == (FILE *)1) {
1514 MyAppCallback_setConsoleColor(1);
1515 MyAppCallback_showScriptMessage("\n%s", (const char *)buferrstr);
1516 MyAppCallback_setConsoleColor(0);
1518 presentTime = wxGetUTCTimeMillis();
1519 if (presentTime > lastTime + 25) {
1520 presentTime = lastTime;
1524 if (len1 < 0 && len2 < 0) {
1525 // The standard/error outputs are exhausted; the process should have terminated
1526 // (Normally, this should be detected by wxBetterProcess::OnTerminate())
1530 if (callback != NULL && callback != DUMMY_CALLBACK) {
1531 callback_result = (*callback)(callback_data);
1532 if (callback_result != 0)
1535 ::wxSafeYield(); // This allows updating console and wxProcess status
1536 if (progress_panel) {
1537 SetProgressValue(-1);
1538 if (IsInterrupted())
1544 dateTime.SetToCurrent();
1545 fprintf(fplog, "%s[DEBUG]pid %ld exists\n", (const char *)(dateTime.FormatISOCombined(' ')), pid);
1550 if (m_process->IsTerminated() || !wxProcess::Exists(pid)) {
1551 /* The subprocess has terminated */
1552 status = m_process->GetStatus();
1554 } else if (interrupted) {
1555 /* User interrupt */
1556 int kflag = wxKILL_CHILDREN;
1560 myKillAllChildren(pid, wxSIGKILL, &rc) != 0
1562 ::wxKill(pid, wxSIGTERM, &rc, kflag) != 0
1566 case wxKILL_BAD_SIGNAL: status = -3; break; /* No such signal */
1567 case wxKILL_ACCESS_DENIED: status = -4; break; /* Permission denied */
1568 case wxKILL_NO_PROCESS: status = -5; break; /* No such process */
1569 default: status = -6; break; /* unknown error */
1572 if (callback_result != 0)
1573 status = -3; /* Interrupt from callback */
1575 status = -2; /* User interrupt */
1577 m_process->Detach();
1583 if (exitstatus_p != NULL)
1584 *exitstatus_p = status;
1586 if (progress_panel) {
1587 HideProgressPanel();
1590 if (m_process != NULL) {
1591 m_process->Detach();
1595 if (callback == DUMMY_CALLBACK) {
1596 char *membuf = NULL;
1598 memBuffer.AppendByte(0);
1599 memsize = memBuffer.GetDataLen();
1600 membuf = (char *)malloc(memsize);
1601 if (membuf != NULL) {
1602 memmove(membuf, memBuffer.GetData(), memsize);
1605 /* Convert "\r\n" to "\n" */
1607 p = pend = membuf + strlen(membuf) + 1;
1608 while (--p >= membuf) {
1610 memmove(p, p + 1, pend - p);
1616 *((char **)callback_data) = membuf;
1623 static int sTimerCount = 0;
1626 MyApp::EnableTimerForDocument(MyDocument *doc)
1631 for (i = 0; i < m_CountTimerDocs; i++) {
1632 if (m_TimerDocs[i] == doc)
1635 m_TimerDocs = (MyDocument **)realloc(m_TimerDocs, sizeof(MyDocument *) * (m_CountTimerDocs + 1));
1636 m_TimerDocs[m_CountTimerDocs++] = doc;
1637 if (m_Timer == NULL)
1638 m_Timer = new wxTimer(this, -1);
1639 if (!m_Timer->IsRunning())
1640 m_Timer->Start(100, wxTIMER_CONTINUOUS);
1644 MyApp::DisableTimerForDocument(MyDocument *doc)
1649 for (i = 0; i < m_CountTimerDocs; i++) {
1650 if (m_TimerDocs[i] == doc) {
1651 // Remove this document from the array
1652 if (i < m_CountTimerDocs - 1) {
1653 memmove(&m_TimerDocs[i], &m_TimerDocs[i + 1], sizeof(MyDocument *) * (m_CountTimerDocs - 1 - i));
1656 if (m_CountTimerDocs == 0) {
1667 MyApp::TimerInvoked(wxTimerEvent &event)
1671 for (i = 0; i < m_CountTimerDocs; i++) {
1672 m_TimerDocs[i]->TimerCallback(sTimerCount);
1677 MyApp::CheckIfAllWindowsAreGoneHandler(wxCommandEvent &event)
1680 wxWindowList::iterator iter;
1681 wxTopLevelWindow *win;
1682 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1683 win = (wxTopLevelWindow *)(*iter);
1684 if (win != m_frameToBeDestroyed && win->IsShown())
1688 const char *p = MyAppCallback_getGlobalSettings(gSettingQuitOnCloseLastWindow);
1690 if (p != NULL && *p != 0)
1691 quitFlag = (atoi(p) != 0);
1692 if (quitFlag || MyAppCallback_messageBox("Do you want to quit Molby?", "Quit Molby", 3, 2)) {
1694 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1695 win = (wxTopLevelWindow *)(*iter);
1696 if (win != m_frameToBeDestroyed)
1697 win->Destroy(); // Avoid double destruction
1700 // Show console window to avoid window-less state
1701 consoleFrame->Show();
1707 MyApp::CheckIfAllWindowsAreGone(wxTopLevelWindow *frame)
1709 /* On Windows, we should avoid the situation where all windows are hidden and
1710 still the program is running. So that we check whether all windows are gone
1711 and if so ask the user to quit the program. If user chooses not to quit, then
1712 the console window is reopened and the program continues to run. */
1713 m_frameToBeDestroyed = frame;
1714 wxCommandEvent myEvent(MyDocumentEvent, myMenuID_Internal_CheckIfAllWindowsAreGone);
1715 this->AddPendingEvent(myEvent);
1719 MyApp::OnHelp(wxCommandEvent& WXUNUSED(event) )
1721 static wxString url;
1722 if (url.IsEmpty()) {
1723 url = FindResourcePath();
1724 #if defined(__WXMSW__)
1725 if (url.SubString(0, 1) == wxT("\\\\")) {
1726 // Network drive: convert to the drive letter
1727 wxBetterProcess *process = new wxBetterProcess(this, -1);
1728 process->Redirect();
1729 long pid = ::wxExecute("net use", wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER, process);
1731 wxRegEx re(wxT("^[[:space:]]+([A-Za-z]:)[[:space:]]+(.*)$"));
1733 while (process->GetLine(bufstr) >= 0) {
1734 bufstr = bufstr.Trim();
1735 if (!bufstr.IsEmpty() && re.Matches(bufstr)) {
1736 wxString dr = re.GetMatch(bufstr, 1);
1737 wxString path = re.GetMatch(bufstr, 2);
1738 if (url.Left(path.Length()) == path) {
1739 url = dr + url.Mid(path.Length());
1748 url.Replace(wxFILE_SEP_PATH, wxT("/"));
1749 url += "/MolbyDoc/ja/index.html";
1751 wxLaunchDefaultBrowser(wxT("file:///") + url);
1755 MyApp::FilterEvent(wxEvent &event)
1758 static FILE *fp_eventlog = NULL;
1759 if (fp_eventlog == NULL) {
1763 snprintf(buf, sizeof buf, "Molby_eventlog_%d.log", i);
1764 fp_eventlog = fopen(buf, "r");
1765 if (fp_eventlog == NULL) {
1766 fp_eventlog = fopen(buf, "wt");
1769 fclose(fp_eventlog);
1774 if (fp_eventlog != NULL) {
1775 fprintf(fp_eventlog, "%d %d\n", event.GetEventType(), event.GetId());
1777 fflush(fp_eventlog);
1783 #pragma mark ====== AboutBox ======
1785 IMPLEMENT_CLASS(AboutDialog, wxDialog)
1786 BEGIN_EVENT_TABLE(AboutDialog, wxDialog)
1789 AboutDialog::AboutDialog():
1790 wxDialog(NULL, -1, wxT("About Molby"))
1792 // vsizer1 --> hsizer1 --> Molby icon
1793 // | |-> vsizer2 --> "Molby"
1794 // | |-> version strings
1796 // |-> copyright messages
1801 Molby_getDescription(&s2, &s3);
1802 wxString str1(s1, WX_DEFAULT_CONV);
1803 wxString str2(s2, WX_DEFAULT_CONV);
1804 wxString str3(s3, WX_DEFAULT_CONV);
1807 #if defined(__WXMSW__)
1808 wxFont *textFont0 = new wxFont(FromFrameDIP(this, 12), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
1809 wxFont *textFont1 = new wxFont(FromFrameDIP(this, 10), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1810 wxFont *textFont2 = new wxFont(FromFrameDIP(this, 9), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1812 wxFont *textFont0 = new wxFont(FromFrameDIP(this, 14), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
1813 wxFont *textFont1 = new wxFont(FromFrameDIP(this, 12), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1814 wxFont *textFont2 = new wxFont(FromFrameDIP(this, 11), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1816 wxBoxSizer *vsizer1 = new wxBoxSizer(wxVERTICAL);
1817 wxBoxSizer *vsizer2 = new wxBoxSizer(wxVERTICAL);
1818 wxBoxSizer *hsizer1 = new wxBoxSizer(wxHORIZONTAL);
1819 wxString tifname = wxGetApp().FindResourcePath() + wxFILE_SEP_PATH + wxT("bitmaps/molby_icon64.png");
1820 wxBitmap *molbyBitmap = new wxBitmap(tifname, wxBITMAP_TYPE_PNG);
1821 wxStaticText *stext1 = new wxStaticText(this, -1, wxT("Molby"));
1822 stext1->SetFont(*textFont0);
1823 wxStaticText *stext2 = new wxStaticText(this, -1, str2);
1824 stext2->SetFont(*textFont1);
1825 wxStaticBitmap *staticBitmap = new wxStaticBitmap(this, -1, *molbyBitmap);
1826 vsizer2->Add(stext1, 0, wxALL | wxEXPAND, FromFrameDIP(this, 2));
1827 vsizer2->Add(stext2, 0, wxALL | wxEXPAND, FromFrameDIP(this, 2));
1828 hsizer1->AddSpacer(FromFrameDIP(this, 20));
1829 hsizer1->Add(staticBitmap, 0, 0, FromFrameDIP(this, 10));
1830 hsizer1->AddSpacer(FromFrameDIP(this, 20));
1831 hsizer1->Add(vsizer2, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1832 wxStaticText *stext3 = new wxStaticText(this, -1, str3);
1833 stext3->SetFont(*textFont2);
1834 vsizer1->Add(hsizer1, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1835 vsizer1->Add(stext3, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1836 vsizer1->Add(this->CreateButtonSizer(wxOK), 0, wxALL | wxEXPAND, FromFrameDIP(this, 10));
1838 this->SetSizerAndFit(vsizer1);
1842 #pragma mark ====== MyFrame (top-level window) ======
1845 * This is the top-level window of the application.
1848 IMPLEMENT_CLASS(MyFrame, wxDocParentFrame)
1849 BEGIN_EVENT_TABLE(MyFrame, wxDocParentFrame)
1850 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
1853 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
1854 const wxPoint& pos, const wxSize& size, long type):
1855 wxDocParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
1857 editMenu = (wxMenu *) NULL;
1858 #if defined(__WXMAC__)
1859 /* Avoid this "dummy" top-level window to appear in the window menu.
1860 It should not happen because MyApp::OnActivate() tries to hide this window,
1861 but this is still here just in case. */
1863 // sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
1864 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
1868 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
1870 AboutDialog *d = new AboutDialog();
1871 if ( d->ShowModal() == wxID_OK )
1875 MyFrame *GetMainFrame(void)
1881 #pragma mark ====== Better wxProcess ======
1885 wxBetterProcess::OnTerminate(int pid, int status)
1887 m_terminated = true;
1891 wxBetterProcess::KillProcess(wxSignal sig, int flags)
1893 wxKillError retval = wxProcess::Kill(this->GetPid(), sig, flags);
1894 if (retval == wxKILL_OK)
1900 wxBetterProcess::GetLineSub(wxString &outStr, wxInputStream *stream, wxMemoryBuffer &mbuf)
1902 int err = wxSTREAM_NO_ERROR;
1908 return -3; // No stderr stream
1910 p = (char *)mbuf.GetData();
1911 len = mbuf.GetDataLen();
1913 pp = (char *)memchr(p, '\n', len);
1915 pp = (char *)memchr(p, '\r', len);
1916 if (pp == NULL && stream->GetLastError() == wxSTREAM_EOF) {
1917 // If EOF, then return all remaining data (without '\n')
1918 pp = p + mbuf.GetDataLen() - 1; // Point to the last char
1921 // Return one line and string length
1922 outStr = wxString(p, wxConvUTF8, pp - p + 1);
1923 memmove(p, pp + 1, len - (pp - p + 1));
1924 m_stdout.SetDataLen(len - (pp - p + 1));
1929 // stream->Read() is called only once
1931 if (err == wxSTREAM_EOF)
1932 return -1; // EOF and no data left
1933 return 0; // Not EOF, but no data is available at present
1936 if (stream->CanRead()) {
1937 // We need to read by one character because wxInputStream has
1938 // no way to give the available number of bytes
1939 stream->Read(buf, sizeof buf);
1940 err = stream->GetLastError();
1941 if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF)
1942 return -2; // Some read error
1943 len = stream->LastRead();
1944 } else err = stream->GetLastError();
1946 mbuf.AppendData(buf, len);
1952 wxBetterProcess::GetLine(wxString &outStr)
1954 return GetLineSub(outStr, this->GetInputStream(), m_stdout);
1958 wxBetterProcess::GetErrorLine(wxString &outStr)
1960 return GetLineSub(outStr, this->GetErrorStream(), m_stderr);
1964 wxBetterProcess::PutLine(wxString str)
1966 wxOutputStream *stream = this->GetOutputStream();
1968 return -3; // No stdin stream
1969 const char *p = str.utf8_str();
1970 long len = strlen(p);
1972 m_stdin.AppendData(p, len);
1973 char *pp = (char *)m_stdin.GetData();
1974 len = m_stdin.GetDataLen();
1977 stream->Write(pp, len);
1978 long len2 = stream->LastWrite();
1980 memmove(pp, pp + len2, len - len2);
1981 m_stdin.SetDataLen(len - len2);
1987 wxBetterProcess::CloseOutput()
1989 // We must flush the data in the internal buffer before closing the output
1990 while (PutLine("") > 0) {}
1991 wxProcess::CloseOutput(); // Call the original version
1994 #pragma mark ====== Plain-C interface ======
1997 MyAppCallback_getGUIDescriptionString(void)
1999 static char *desc = NULL;
2002 "AmberTools 1.3, http://ambermd.org/\n"
2003 " Copyright (C) Junmei Wang, Ross C. Walker, "
2004 "Michael F. Crowley, Scott Brozell and David A. Case\n"
2005 "ORTEP-III, http://web.ornl.gov/sci/ortep/\n"
2006 " Michael N. Burnett and Carroll K. Johnson, "
2007 "Oak Ridge National Laboratory Report ORNL-6895, "
2009 "wxWidgets %d.%d.%d, http://www.wxwidgets.org/\n"
2010 #if wxCHECK_VERSION(3,2,0)
2011 " Copyright (C) 1992-2022 Julian Smart, Vadim "
2013 " Copyright (C) 1992-2013 Julian Smart, Vadim "
2015 "Zeitlin, Stefan Csomor, Robert Roebling,\n"
2016 " and other members of the wxWidgets team\n"
2017 " Portions (C) 1996 Artificial Intelligence "
2018 "Applications Institute\n",
2019 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
2025 MyAppCallback_loadGlobalSettings(void)
2029 wxGetApp().LoadDefaultSettings();
2033 MyAppCallback_saveGlobalSettings(void)
2037 wxGetApp().SaveDefaultSettings();
2040 /* Note on the global settings */
2041 /* Global settings are stored in a file in the form key="value", where
2042 the "value" is the 'inspect'-ed representation of Ruby values.
2043 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
2044 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
2045 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
2046 MyAppCallback_setGlobalSettingsWithType(). */
2048 MyAppCallback_getGlobalSettings(const char *key)
2052 wxString wxkey(key, WX_DEFAULT_CONV);
2053 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
2054 return strdup(wxvalue.mb_str(WX_DEFAULT_CONV));
2058 MyAppCallback_setGlobalSettings(const char *key, const char *value)
2062 wxString wxkey(key, WX_DEFAULT_CONV);
2063 wxString wxvalue(value, WX_DEFAULT_CONV);
2064 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
2068 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
2071 char *s = MyAppCallback_getGlobalSettings(key);
2072 char desc[] = SCRIPT_ACTION("s; ");
2073 desc[sizeof(desc) - 2] = type;
2074 temp = gMolActionNoErrorDialog;
2075 gMolActionNoErrorDialog = 1;
2076 retval = MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
2078 gMolActionNoErrorDialog = temp;
2083 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
2085 const char *cmd = "set_global_settings";
2087 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("si"), cmd, key, *((const Int *)ptr));
2088 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("sd"), cmd, key, *((const Double *)ptr));
2089 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("ss"), cmd, key, (const char *)ptr);
2090 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("sv"), cmd, key, (const Vector *)ptr);
2091 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("st"), cmd, key, (const Transform *)ptr);
2093 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
2099 MyAppCallback_checkInterrupt(void)
2103 return wxGetApp().IsInterrupted();
2107 MyAppCallback_showProgressPanel(const char *msg)
2111 wxGetApp().ShowProgressPanel(msg);
2115 MyAppCallback_hideProgressPanel(void)
2119 wxGetApp().HideProgressPanel();
2123 MyAppCallback_setProgressValue(double dval)
2127 wxGetApp().SetProgressValue(dval);
2131 MyAppCallback_setProgressMessage(const char *msg)
2135 wxGetApp().SetProgressMessage(msg);
2139 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
2145 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
2146 wxStaticText *stext;
2149 wxString pstr(prompt, WX_DEFAULT_CONV);
2150 wxString defstr(buf, WX_DEFAULT_CONV);
2151 { // Vertical sizer containing [prompt, textbox, buttons]
2153 sizer1 = new wxBoxSizer(wxVERTICAL);
2154 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, FromFrameDIP(dialog, wxSize(200, 22)));
2155 sizer1->Add(stext, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2156 tctrl = new wxTextCtrl(dialog, -1, defstr, wxDefaultPosition, FromFrameDIP(dialog, wxSize(200, 22)));
2157 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2158 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
2159 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2161 dialog->SetSizerAndFit(sizer1);
2162 dialog->Centre(wxBOTH);
2166 if (dialog->ShowModal() == wxID_OK) {
2167 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(WX_DEFAULT_CONV)), bufsize - 1);
2168 buf[bufsize - 1] = 0;
2177 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
2178 1 (information), 2 (exclamation), or 3 (stop). */
2180 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
2183 printf("%s\n%s\n", title, message);
2187 int wxflags, wxicon, retval;
2188 if (!wxGetApp().IsMainLoopRunning()) {
2189 MyAppCallback_setConsoleColor(1);
2190 MyAppCallback_showScriptMessage("*** %s ***\n%s\n", message, title);
2191 MyAppCallback_setConsoleColor(0);
2196 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
2198 case 3: wxicon = wxICON_ERROR; break;
2199 case 2: wxicon = wxICON_EXCLAMATION; break;
2200 default: wxicon = wxICON_INFORMATION; break;
2202 wxString wxmessage(message, WX_DEFAULT_CONV);
2203 wxString wxtitle(title, WX_DEFAULT_CONV);
2204 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
2205 return (retval == wxOK ? 1 : 0);
2209 MyAppCallback_errorMessageBox(const char *fmt, ...)
2214 vfprintf(stderr, fmt, ap);
2221 if (strchr(fmt, '%') == 0) {
2223 } else if (strcmp(fmt, "%s") == 0) {
2224 s = va_arg(ap, char *);
2226 vasprintf(&s, fmt, ap);
2229 MyAppCallback_messageBox(s, "Error", 0, 3);
2235 MyAppCallback_getHomeDir(void)
2239 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
2240 s = getenv("USERPROFILE");
2244 return (s == NULL ? NULL : strdup(s));
2252 MyAppCallback_getDocumentHomeDir(void)
2255 char appData[MAX_PATH * 2];
2257 hResult = SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, 0, appData);
2258 if (hResult == S_OK) {
2259 return strdup(appData);
2261 return MyAppCallback_getHomeDir();
2266 return (s == NULL ? NULL : strdup(s));
2271 MyAppCallback_registerScriptMenu(const char *title)
2275 return wxGetApp().RegisterScriptMenu(title);
2279 MyAppCallback_lookupScriptMenu(const char *title)
2283 return wxGetApp().LookupScriptMenu(title);
2287 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
2294 wxString cwd = wxFileName::GetCwd();
2295 wxString path(cpath, wxConvFile);
2296 char *p = strdup(cpath);
2297 char sep = wxFileName::GetPathSeparator();
2298 char *pp, *script = NULL;
2299 if ((pp = strrchr(p, sep)) != NULL) {
2301 wxString dirname(p, wxConvFile);
2302 wxFileName::SetCwd(dirname);
2305 /* Read the content of the file */
2306 FILE *fp = fopen(cpath, "rb");
2309 fseek(fp, 0, SEEK_END);
2311 fseek(fp, 0, SEEK_SET);
2312 script = (char *)malloc(len + 1);
2313 if (script!= NULL) {
2314 fread(script, 1, len, fp);
2320 if (script == NULL) {
2322 return (RubyValue)6; /* Cannot open file */
2325 /* Check the encoding specification, and if present convert it to default encoding */
2327 char *lp = script, *eolp;
2329 while (n < 2) { /* Check the first two lines */
2330 while (*lp && isspace(*lp))
2332 if (*lp == 0 || *lp++ != '#') /* Check only the comment line */
2336 if (*lp == '!') { /* Shebang line */
2337 while (*lp && *lp != '\n')
2338 lp++; /* Skip until end of line */
2343 for (eolp = lp; *eolp && *eolp != '\n'; eolp++);
2346 *eolp = 0; /* Limit the search area */
2347 lp = strstr(lp, "coding:");
2348 *eolp = '\n'; /* Restore original string */
2351 while (*lp && isspace(*lp))
2353 if (strncasecmp(lp, "shift-jis", 9) == 0) {
2354 wxString s(script, wxCSConv(wxT("cp932")));
2356 script = strdup(s.mb_str(WX_DEFAULT_CONV));
2357 } else if (strncasecmp(lp, "utf-8", 5) == 0) {
2358 wxString s(script, wxConvUTF8);
2360 script = strdup(s.mb_str(WX_DEFAULT_CONV));
2369 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), pp, status);
2373 wxFileName::SetCwd(cwd);
2377 void MyAppCallback_beginUndoGrouping(void)
2381 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
2382 wxList::iterator iter;
2383 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
2384 ((MyDocument *)(*iter))->BeginUndoGrouping();
2388 void MyAppCallback_endUndoGrouping(void)
2392 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
2393 wxList::iterator iter;
2394 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
2395 ((MyDocument *)(*iter))->EndUndoGrouping();
2399 int MyAppCallback_callSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *output, FILE *errout, int *exitstatus_p, int *pid_p)
2402 return system(cmdline);
2403 return wxGetApp().CallSubProcess(cmdline, procname, callback, callback_data, output, errout, exitstatus_p, pid_p);
2406 void MyAppCallback_showConsoleWindow(void)
2410 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
2415 void MyAppCallback_hideConsoleWindow(void)
2419 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
2423 void MyAppCallback_bell(void)
2430 int MyAppCallback_playSound(const char *filename, int flag)
2434 unsigned uflag = wxSOUND_SYNC;
2436 uflag = wxSOUND_ASYNC;
2438 uflag = wxSOUND_ASYNC | wxSOUND_LOOP;
2439 wxString fnamestr(filename, wxConvFile);
2440 bool retval = wxSound::Play(fnamestr, uflag);
2444 void MyAppCallback_stopSound(void)
2451 void MyAppCallback_initImageHandlers(void)
2453 static bool handlers_init = false;
2454 if (!handlers_init) {
2455 wxInitAllImageHandlers();
2456 handlers_init = true;