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)
287 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
288 wxSystemOptions::SetOption(wxT("osx.openfiledialog.always-show-types"), 1);
293 // Check if the same application is already running
295 asprintf(&buf, "Molby-%s", (const char *)wxGetUserId().mb_str(WX_DEFAULT_CONV));
296 wxString name(buf, WX_DEFAULT_CONV);
297 m_ipcServiceName = new wxString(name);
298 m_ipcServiceName->Prepend(wxT("IPC-"));
300 m_checker = new wxSingleInstanceChecker(name);
301 if (m_checker->IsAnotherRunning()) {
302 // Make a connection with the other instance and ask for opening the file(s)
305 wxConnectionBase *connection;
307 for (i = 1; i < argc; i++) {
308 files.append(argv[i]);
309 files.append(wxT("\n"));
311 m_client = new MyClient;
312 connection = m_client->MakeConnection(wxT("localhost"), *m_ipcServiceName, MOLBY_IPC_TOPIC);
313 if (connection == NULL) {
314 wxLogError(wxT("Molby is already running; please shut it down and retry"));
318 connection->Execute(files);
323 m_server = new MyServer;
324 if (m_server->Create(*m_ipcServiceName) == false) {
332 // Create a document manager
333 m_docManager = new MyDocManager;
335 // Create templates relating drawing documents to their views
336 new wxDocTemplate(m_docManager, _T("Molby Structure File"), _T("*.mbsf"), _T(""), _T("mbsf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
337 new wxDocTemplate(m_docManager, _T("Protein Structure File"), _T("*.psf"), _T(""), _T("psf"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
338 new wxDocTemplate(m_docManager, _T("Protein Data Bank File"), _T("*.pdb"), _T(""), _T("pdb"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
339 new wxDocTemplate(m_docManager, _T("Gaussian Input File"), _T("*.com;*.gjf"), _T(""), _T("com"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
340 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));
341 new wxDocTemplate(m_docManager, _T("Gaussian Checkpoint File"), _T("*.fchk;*.fch"), _T(""), _T("fchk"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
342 new wxDocTemplate(m_docManager, _T("GAMESS Input File"), _T("*.inp"), _T(""), _T("inp"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
343 new wxDocTemplate(m_docManager, _T("GAMESS DAT File"), _T("*.dat"), _T(""), _T("dat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
344 new wxDocTemplate(m_docManager, _T("ORTEP Input File"), _T("*.tep"), _T(""), _T("tep"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
345 new wxDocTemplate(m_docManager, _T("SHELX Input File"), _T("*.ins;*.res"), _T(""), _T("ins"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
346 new wxDocTemplate(m_docManager, _T("Crystallographic Information File"), _T("*.cif"), _T(""), _T("cif"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
347 new wxDocTemplate(m_docManager, _T("Cartesian"), _T("*.xyz"), _T(""), _T("xyz"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
348 new wxDocTemplate(m_docManager, _T("Z Matrix"), _T("*.zmat"), _T(""), _T("zmat"), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
349 new wxDocTemplate(m_docManager, _T("Any Molecule"), _T("*.*"), _T(""), _T(""), _T("Molecule Doc"), _T("Molecule View"), CLASSINFO(MyDocument), CLASSINFO(MoleculeView));
351 // Init image handlers
352 MyAppCallback_initImageHandlers();
354 // Create the main frame window
355 frame = new MyFrame((wxDocManager *) m_docManager, (wxFrame *) NULL,
356 _T("Molby"), wxDefaultPosition, wxDefaultSize,
357 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
358 frame->SetClientSize(FromFrameDIP(frame, wxSize(800, 600)));
360 // Give it an icon (this is ignored in MDI mode: uses resources)
362 frame->SetIcon(wxIcon(_T("doc")));
365 frame->SetIcon(wxIcon(_T("doc.xbm")));
368 wxMenuBar *menu_bar = CreateMenuBar(0);
371 wxMenuBar::MacSetCommonMenuBar(menu_bar);
374 // Associate the menu bar with the frame
375 frame->SetMenuBar(menu_bar);
377 frame->Centre(wxBOTH);
379 #if defined(__WXMAC__) || defined(__WXMSW__)
380 frame->Move(-10000, -10000); // Set invisible
388 // Load default settings from the preference file
389 LoadDefaultSettings();
391 // Create a console window
392 consoleFrame = ConsoleFrame::CreateConsoleFrame(frame);
393 consoleFrame->Show(true);
395 /* Initialize Ruby interpreter with the startup script */
396 /* (Also read startup information) */
398 extern int gRevisionNumber;
399 static const char fname[] = "startup.rb";
400 InitResourcePath(argc, argv);
401 wxString dirname = FindResourcePath();
403 dirname += wxFILE_SEP_PATH;
404 dirname += wxT("Scripts");
405 /* wxString cwd = wxGetCwd(); */
406 wxSetWorkingDirectory(dirname);
408 wxString fnamestr(fname, wxConvFile);
409 Molby_startup(wxFileExists(fnamestr) ? fname : NULL, (const char *)dirname.mb_str(wxConvFile));
412 wxString docHome(MyAppCallback_getDocumentHomeDir(), wxConvFile);
413 wxSetWorkingDirectory(docHome);
417 /* Pasteboard type strings (includes the revision number) */
418 asprintf(&gMoleculePasteboardType, "Molecule_%d", gRevisionNumber);
419 asprintf(&gParameterPasteboardType, "Parameter_%d", gRevisionNumber);
421 MyAppCallback_showScriptMessage("%% ");
423 /* Build the predefined fragments menu */
424 m_NamedFragments = NULL;
425 // UpdatePredefinedFragmentMenu(GetMainFrame()->GetMenuBar());
426 UpdatePredefinedFragmentMenu(consoleFrame->GetMenuBar());
430 /* Open given files: Ruby script is executed, other files are opened as a document */
432 #if defined(__WXMSW__)
433 m_docManager->CreateDocument(wxEmptyString, wxDOC_NEW);
438 for (i = 1; i < argc; i++) {
439 files.append(argv[i]);
440 files.append(wxT("\n"));
442 RequestOpenFilesByEvent(files);
445 gInitCompleted = true;
451 // kind == 0: main menu
452 // kind == 1: molecule window
453 // kind == 2: console window
454 // kind == 3: Ruby dialog (non-modal)
456 MyApp::CreateMenuBar(int kind, wxMenu **out_file_history_menu, wxMenu **out_edit_menu)
463 wxMenu *file_menu = new wxMenu;
464 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
466 wxMenu *edit_menu = new wxMenu;
467 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
468 edit_menu->Append(wxID_REDO, _T("&Redo"));
469 edit_menu->AppendSeparator();
470 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
471 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
472 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
473 edit_menu->Append(wxID_CLEAR, _T("Clear"));
474 edit_menu->AppendSeparator();
475 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
477 wxMenu *help_menu = new wxMenu;
478 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
479 help_menu->Append(wxID_HELP, _T("&Molby Help"));
481 wxMenuBar *menu_bar = new wxMenuBar;
483 menu_bar->Append(file_menu, _T("&File"));
484 menu_bar->Append(edit_menu, _T("&Edit"));
485 menu_bar->Append(help_menu, _T("&Help"));
491 wxMenu *file_menu = new wxMenu;
492 wxMenu *file_history_menu = NULL;
494 file_menu->Append(wxID_NEW, _T("&New...\tCtrl-N"));
495 file_menu->Append(wxID_OPEN, _T("&Open...\tCtrl-O"));
496 if (out_file_history_menu != NULL) {
497 file_history_menu = new wxMenu;
498 *out_file_history_menu = file_history_menu;
499 file_menu->AppendSubMenu(*out_file_history_menu, _T("Open Recent"));
500 m_docManager->FileHistoryAddFilesToMenu(*out_file_history_menu);
501 m_docManager->FileHistoryUseMenu(*out_file_history_menu); // Should be removed when menu is discarded
503 /* Build "Open Predefined" */
504 wxMenu *predefined_menu = new wxMenu;
505 file_menu->Append(myMenuID_PredefinedFragment, _T("Open Predefined"), predefined_menu);
507 file_menu->AppendSeparator();
508 file_menu->Append(wxID_CLOSE, _T("&Close\tCtrl-W"));
509 file_menu->Append(wxID_SAVE, _T("&Save\tCtrl-S"));
510 file_menu->Append(wxID_SAVEAS, _T("Save &As..."));
511 file_menu->Append(wxID_REVERT, _T("Revert to Saved"));
513 file_menu->AppendSeparator();
514 file_menu->Append(myMenuID_Import, _T("Import..."));
515 file_menu->Append(myMenuID_Export, _T("Export..."));
516 file_menu->Append(myMenuID_ExportGraphic, _T("Export Graphic..."));
518 file_menu->AppendSeparator();
519 file_menu->Append(wxID_PRINT, _T("&Print...\tCtrl-P"));
520 file_menu->Append(wxID_PRINT_SETUP, _T("Print &Setup..."));
521 file_menu->Append(wxID_PREVIEW, _T("Print Pre&view"));
523 file_menu->AppendSeparator();
524 #if defined(__WXMAC__)
525 file_menu->Append(wxID_EXIT, _T("E&xit\tCtrl-Q"));
527 file_menu->Append(wxID_EXIT, _T("E&xit\tAlt-X"));
530 wxMenu *edit_menu = new wxMenu;
531 edit_menu->Append(wxID_UNDO, _T("&Undo\tCtrl-Z"));
532 edit_menu->Append(wxID_REDO, _T("&Redo"));
533 edit_menu->AppendSeparator();
534 edit_menu->Append(wxID_CUT, _T("Cut\tCtrl-X"));
535 edit_menu->Append(wxID_COPY, _T("Copy\tCtrl-C"));
536 edit_menu->Append(wxID_PASTE, _T("Paste\tCtrl-V"));
537 edit_menu->Append(wxID_CLEAR, _T("Clear"));
538 edit_menu->AppendSeparator();
539 edit_menu->Append(wxID_SELECTALL, _T("Select All\tCtrl-A"));
540 edit_menu->Append(myMenuID_SelectFragment, _T("Select Fragment\tCtrl-F"));
541 edit_menu->Append(myMenuID_SelectReverse, _T("Select Reverse"));
542 edit_menu->AppendSeparator();
543 wxMenu *create_parameter_menu = new wxMenu;
544 create_parameter_menu->Append(myMenuID_CreateNewVdwParameter, _T("Vdw"));
545 create_parameter_menu->Append(myMenuID_CreateNewBondParameter, _T("Bond"));
546 create_parameter_menu->Append(myMenuID_CreateNewAngleParameter, _T("Angle"));
547 create_parameter_menu->Append(myMenuID_CreateNewDihedralParameter, _T("Dihedral"));
548 create_parameter_menu->Append(myMenuID_CreateNewImproperParameter, _T("Improper"));
549 create_parameter_menu->Append(myMenuID_CreateNewVdwPairParameter, _T("Vdw Pair"));
550 create_parameter_menu->Append(myMenuID_CreateNewVdwCutoffParameter, _T("Vdw Cutoff"));
551 edit_menu->Append(myMenuID_CreateNewAtom, _T("Create New Atom\tCtrl-I"));
552 edit_menu->Append(myMenuID_CreateNewParameter, _T("Create New Parameter"), create_parameter_menu);
553 edit_menu->Append(myMenuID_CreatePiAnchor, _T("Create Pi Anchor"));
554 edit_menu->AppendSeparator();
555 wxMenu *add_hydrogen_menu = new wxMenu;
556 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp3, _T("Tetrahedral sp3"));
557 add_hydrogen_menu->Append(myMenuID_AddHydrogenSp2, _T("Trigonal sp2"));
558 add_hydrogen_menu->Append(myMenuID_AddHydrogenLinear, _T("Linear sp"));
559 add_hydrogen_menu->Append(myMenuID_AddHydrogenPyramidal, _T("Pyramidal (like NH2)"));
560 add_hydrogen_menu->Append(myMenuID_AddHydrogenBent, _T("Bent (like OH)"));
561 edit_menu->Append(myMenuID_AddHydrogen, _T("Add Hydrogen"), add_hydrogen_menu);
563 if (out_edit_menu != NULL)
564 *out_edit_menu = edit_menu; // Should be associated with the command processor if available
566 wxMenu *view_menu = new wxMenu;
567 view_menu->Append(myMenuID_FitToScreen, _T("Fit To Screen\tCtrl-T"));
568 view_menu->Append(myMenuID_CenterSelection, _T("Center Selection"));
569 /* view_menu->AppendSeparator();
570 view_menu->Append(myMenuID_ShowUnitCell, _T("Show Unit Cell"), _T(""), wxITEM_CHECK);
571 view_menu->Append(myMenuID_ShowHydrogens, _T("Show Hydrogen Atoms"), _T(""), wxITEM_CHECK);
572 view_menu->Append(myMenuID_ShowDummyAtoms, _T("Show Dummy Atoms"), _T(""), wxITEM_CHECK);
573 view_menu->Append(myMenuID_ShowExpandedAtoms, _T("Show Expanded Atoms"), _T(""), wxITEM_CHECK);
574 view_menu->Append(myMenuID_ShowEllipsoids, _T("Show Ellipsoids"), _T(""), wxITEM_CHECK);
575 view_menu->Append(myMenuID_ShowRotationCenter, _T("Show Rotation Center"), _T(""), wxITEM_CHECK); */
576 view_menu->AppendSeparator();
577 view_menu->Append(myMenuID_HideSelected, _T("Hide Selected"), _T(""));
578 view_menu->Append(myMenuID_HideUnselected, _T("Hide Unselected"), _T(""));
579 view_menu->Append(myMenuID_HideReverse, _T("Hide Reverse"), _T(""));
580 view_menu->Append(myMenuID_ShowAllAtoms, _T("Show All Atoms"), _T(""));
581 // view_menu->AppendSeparator();
582 // view_menu->Append(myMenuID_ShowGraphite, _T("Show Graphite..."));
583 // view_menu->AppendSeparator();
584 // view_menu->Append(myMenuID_LineMode, _T("Line Mode"), _T(""), wxITEM_CHECK);
586 wxMenu *md_menu = new wxMenu;
587 md_menu->Append(myMenuID_MolecularDynamics, _T("Molecular Dynamics..."));
588 md_menu->Append(myMenuID_Minimize, _T("Minimize..."));
589 md_menu->Append(myMenuID_StopMDRun, _T("Stop\tCtrl-."));
590 md_menu->AppendSeparator();
591 md_menu->Append(myMenuID_ViewGlobalParameters, _T("View Global Parameters..."));
592 md_menu->Append(myMenuID_ViewParameterFilesList, _T("Load/Unload Global Parameters..."));
594 wxMenu *script_menu = new wxMenu;
595 script_menu->Append(myMenuID_ExecuteScript, _T("Execute Script..."));
596 script_menu->Append(myMenuID_OpenConsoleWindow, _T("Open Console Window"));
597 script_menu->Append(myMenuID_EmptyConsoleWindow, _T("Empty Console Window"));
598 script_menu->AppendSeparator();
599 countNonCustomScriptMenu = script_menu->GetMenuItemCount();
601 wxMenu *help_menu = new wxMenu;
602 help_menu->Append(wxID_ABOUT, _T("&About...\tF1"));
603 help_menu->Append(wxID_HELP, _T("&Molby Help"));
605 wxMenuBar *menu_bar = new wxMenuBar;
607 menu_bar->Append(file_menu, _T("&File"));
608 menu_bar->Append(edit_menu, _T("&Edit"));
609 menu_bar->Append(view_menu, _T("View"));
610 menu_bar->Append(md_menu, _T("MM/MD"));
611 menu_bar->Append(script_menu, _T("&Script"));
613 #if defined(__WXMAC__)
614 wxMenu *window_menu = new wxMenu;
615 window_menu->Append(myMenuID_BringAllWindowsToFront, _T("Bring All to Front"));
616 window_menu->AppendSeparator();
617 menu_bar->Append(window_menu, _T("Window"));
620 menu_bar->Append(help_menu, _T("&Help"));
622 UpdateScriptMenu(menu_bar);
623 if (m_NamedFragments != (char **)(-1))
624 UpdatePredefinedFragmentMenu(menu_bar);
630 /* When the application is launched without any documents, an empty document is opened.
631 This should be implemented by overriding this special method; parsing argc/argv does
632 not work, because the list of files is passed through an Apple Event. */
636 if (m_docManager == NULL)
637 return; // Initialization is not yet complete
638 m_docManager->CreateDocument(_T(""), wxDOC_NEW);
642 MyApp::MacOpenFile(const wxString &fileName)
644 wxString file(fileName);
645 RequestOpenFilesByEvent(file);
648 /* Open given files: instead of calling MacOpenFile() for each entry, build a file list
649 and call MyApp::OnOpenFiles() */
651 MyApp::MacHandleAEODoc(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply))
655 DescType returnedType;
661 return noErr; /* TODO: handle open Apple event */
663 err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList, &docList);
667 err = AECountItems(&docList, &itemsInList);
671 ProcessSerialNumber PSN ;
672 PSN.highLongOfPSN = 0 ;
673 PSN.lowLongOfPSN = kCurrentProcess ;
674 SetFrontProcess( &PSN ) ;
676 wxString fName, fNameList;
679 for (i = 1; i <= itemsInList; i++)
682 &docList, i, typeFSRef, &keywd, &returnedType,
683 (Ptr)&theRef, sizeof(theRef), &actualSize);
684 // fName = wxMacFSRefToPath( &theRef ) ;
685 fNameList.append(fName);
686 fNameList.append(wxT("\n"));
689 OnOpenFiles(fNameList);
699 SaveDefaultSettings();
709 sModifyMenuForFilterMode(wxMenuBar *mbar)
714 idx = mbar->FindMenu(wxT("Show"));
715 if (idx != wxNOT_FOUND)
716 delete mbar->Remove(idx);
717 idx = mbar->FindMenu(wxT("MM/MD"));
718 if (idx != wxNOT_FOUND)
719 delete mbar->Remove(idx);
720 idx = mbar->FindMenu(wxT("QChem"));
721 if (idx != wxNOT_FOUND)
722 delete mbar->Remove(idx);
723 idx = mbar->FindMenu(wxT("Script"));
724 if (idx != wxNOT_FOUND) {
725 menu = mbar->GetMenu(idx);
726 n = menu->GetMenuItemCount();
727 for (i = n - 1; i >= 0; i--) {
728 item = menu->FindItemByPosition(i);
730 if (id != myMenuID_OpenConsoleWindow && id != myMenuID_EmptyConsoleWindow && id != myMenuID_ExecuteScript) {
737 idx = mbar->FindMenu(wxT("Edit"));
738 if (idx != wxNOT_FOUND) {
739 menu = mbar->GetMenu(idx);
740 n = menu->GetMenuItemCount();
741 for (i = n - 1; i >= 0; i--) {
742 item = menu->FindItemByPosition(i);
744 if (id == wxID_SELECTALL)
751 idx = mbar->FindMenu(wxT("File"));
752 if (idx != wxNOT_FOUND) {
753 menu = mbar->GetMenu(idx);
754 n = menu->GetMenuItemCount();
755 for (i = n - 1; i >= 0; i--) {
756 item = menu->FindItemByPosition(i);
758 if (id != wxID_OPEN && id != wxID_EXIT) {
768 MyApp::ShowProgressPanel(const char *mes)
770 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
771 if (m_progressDialog == NULL) {
772 m_progressDialog = new wxProgressDialog(wxT("Progress"), mes, 100, NULL, wxPD_APP_MODAL | wxPD_CAN_ABORT);
777 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
778 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
779 if (quitMenuItem != NULL)
780 quitMenuItem->Enable(false);
784 m_progressFrame = new ProgressFrame(_T("Progress"), string);
785 m_progressCanceled = false;
786 m_progressValue = -1;
791 MyApp::HideProgressPanel()
793 if (m_progressDialog != NULL) {
794 m_progressDialog->Hide();
795 m_progressDialog->Destroy();
796 m_progressDialog = NULL;
799 if (m_progressFrame != NULL) {
800 m_progressFrame->Hide();
801 m_progressFrame->Destroy();
802 m_progressFrame = NULL;
805 wxMenuBar *mbar = ((wxFrame *)GetTopWindow())->GetMenuBar();
807 wxMenuItem *quitMenuItem = mbar->FindItem(wxID_EXIT);
808 if (quitMenuItem != NULL)
809 quitMenuItem->Enable(true);
817 MyApp::SetProgressValue(double dval)
819 if (m_progressDialog != NULL) {
821 m_progressDialog->Update((int)(dval * 100));
823 m_progressDialog->Pulse();
828 MyApp::SetProgressMessage(const char *mes)
830 if (m_progressDialog != NULL) {
831 wxString string((mes ? mes : ""), WX_DEFAULT_CONV);
832 m_progressDialog->Update(0, string);
837 MyApp::IsInterrupted()
839 if (m_progressDialog != NULL)
840 return m_progressDialog->WasCancelled();
842 if (::wxGetKeyState(WXK_ESCAPE))
849 MyApp::OnOpenConsoleWindow(wxCommandEvent& event)
851 consoleFrame->Show(true);
852 consoleFrame->Raise();
856 MyApp::OnEmptyConsoleWindow(wxCommandEvent& event)
858 consoleFrame->EmptyBuffer();
862 MyApp::OnViewGlobalParameters(wxCommandEvent& event)
864 if (parameterFrame == NULL) {
865 parameterFrame = GlobalParameterFrame::CreateGlobalParameterFrame(GetMainFrame());
866 MainView_createColumnsForTableAtIndex(NULL, kMainViewParameterTableIndex);
868 MainView_refreshTable(NULL);
869 parameterFrame->Show(true);
870 parameterFrame->Raise();
874 MyApp::OnViewParameterFilesList(wxCommandEvent &event)
876 if (parameterFilesFrame == NULL) {
877 parameterFilesFrame = GlobalParameterFilesFrame::CreateGlobalParameterFilesFrame(GetMainFrame());
879 parameterFilesFrame->Show(true);
880 parameterFilesFrame->Raise();
884 MyApp::OnBringAllWindowsToFront(wxCommandEvent &event)
887 wxWindowList::iterator iter;
888 wxTopLevelWindow **wins;
889 size = wxTopLevelWindows.size();
891 wins = (wxTopLevelWindow **)calloc(sizeof(wxTopLevelWindow *), size);
892 for (iter = wxTopLevelWindows.begin(), n = 0; iter != wxTopLevelWindows.end(); ++iter, ++n) {
893 wins[n] = (wxTopLevelWindow *)(*iter);
895 for (n = 0; n < size; n++) {
896 if (wins[n]->IsShown())
903 MyApp::LookupScriptMenu(const char *title)
908 for (i = 0; i < countScriptMenu; i++) {
909 if (strcmp(title, scriptMenuTitles[i]) == 0)
916 MyApp::RegisterScriptMenu(const char *title)
920 // Already registered? (If it is not a separator item)
922 p = strrchr(title, '\t');
926 if (p[0] != 0 && p[0] != '-') {
927 for (i = 0; i < countScriptMenu; i++) {
928 if (strcmp(title, scriptMenuTitles[i]) == 0) {
935 if (countScriptMenu == 0) {
936 scriptMenuTitles = (char **)malloc(sizeof(char *));
937 scriptMenuPositions = (int *)malloc(sizeof(int));
939 scriptMenuTitles = (char **)realloc(scriptMenuTitles, sizeof(char *) * (countScriptMenu + 1));
940 scriptMenuPositions = (int *)realloc(scriptMenuPositions, sizeof(int) * (countScriptMenu + 1));
942 scriptMenuTitles[countScriptMenu] = strdup(title);
943 scriptMenuPositions[countScriptMenu] = -1;
946 if (!scriptMenuModifiedEventPosted) {
947 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_scriptMenuModified);
948 wxPostEvent(this, myEvent);
949 scriptMenuModifiedEventPosted = true;
952 return countScriptMenu - 1;
956 MyApp::UpdateScriptMenu(wxMenuBar *mbar)
960 for (i = 0; i < countScriptMenu; i++) {
961 // Find Menu to be inserted
962 const char *s = scriptMenuTitles[i], *p;
965 while ((p = strchr(s, '\t')) != NULL) {
966 // Find existing menu
967 wxString menuTitle(s, WX_DEFAULT_CONV, p - s);
969 mid = mbar->FindMenu(menuTitle);
970 if (mid == wxNOT_FOUND) {
971 // Create a new menu before "Script" menu
972 wxMenu *newMenu = new wxMenu;
973 int sid = mbar->FindMenu(_T("Script"));
974 if (sid == wxNOT_FOUND) {
975 mbar->Append(newMenu, menuTitle);
976 sid = mbar->GetMenuCount() - 1;
978 mbar->Insert(sid, newMenu, menuTitle);
980 menu = mbar->GetMenu(sid);
982 menu = mbar->GetMenu(mid);
985 mid = menu->FindItem(menuTitle);
986 if (mid == wxNOT_FOUND) {
987 // Create a new menu at the end
988 wxMenu *newMenu1 = new wxMenu;
989 menu->Append(myMenuID_CustomScript + i + depth * 1000, menuTitle, newMenu1);
992 menu = menu->FindItem(mid)->GetSubMenu();
999 // The new item should be under "Script" menu
1000 mid = mbar->FindMenu(_T("Script"));
1001 menu = mbar->GetMenu(mid);
1003 if (*s == 0 || *s == '-') {
1006 int count = menu->GetMenuItemCount();
1007 if (scriptMenuPositions[i] >= 0 && scriptMenuPositions[i] < count) {
1008 sitem = menu->FindItemByPosition(scriptMenuPositions[i]);
1009 if (sitem != NULL && sitem->IsSeparator())
1010 continue; // Already present
1012 if (count != 0 && !menu->FindItemByPosition(count - 1)->IsSeparator()) {
1013 menu->AppendSeparator();
1014 scriptMenuPositions[i] = count;
1022 } else checkable = false;
1023 // Check if the item is already existing
1024 wxString itemTitle(s, WX_DEFAULT_CONV);
1027 item = mbar->FindItem(myMenuID_CustomScript + i, &omenu);
1029 if (omenu == menu && item->GetItemLabel() == itemTitle) {
1030 // The menu is already existing with correct position and title
1033 // The menu title does not match; remove this menu item
1034 Disconnect(myMenuID_CustomScript + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
1035 omenu->Remove(item);
1039 menu->Append(myMenuID_CustomScript + i, itemTitle, wxEmptyString, (checkable ? wxITEM_CHECK : wxITEM_NORMAL));
1040 scriptMenuPositions[i] = menu->GetMenuItemCount() - 1;
1041 Connect(myMenuID_CustomScript + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnScriptMenuSelected), NULL, this);
1046 MyApp::OnScriptMenuModified(wxCommandEvent& event)
1048 scriptMenuModifiedEventPosted = false;
1049 UpdateScriptMenu(consoleFrame->GetMenuBar());
1054 MyApp::OnScriptMenuSelected(wxCommandEvent& event)
1058 int index = event.GetId() - myMenuID_CustomScript;
1059 if (index < 0 || index >= countScriptMenu)
1061 mview = MainViewCallback_activeView();
1064 else mol = mview->mol;
1065 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("iM"), "lambda { |n, m| $script_menu_commands[n].call(m) }", index, mol);
1069 MyApp::UpdatePredefinedFragmentMenu(wxMenuBar *mbar)
1072 wxMenuItem *fmenuItem = mbar->FindItem(myMenuID_PredefinedFragment);
1073 wxMenu *fmenu = (fmenuItem != NULL ? fmenuItem->GetSubMenu() : NULL);
1076 if (m_NamedFragments == (char **)(-1))
1079 /* Rebuild sNamedFragments array */
1080 if (m_NamedFragments != NULL) {
1081 for (i = 0; i < m_CountNamedFragments; i++) {
1082 free(m_NamedFragments[i * 2]);
1083 free(m_NamedFragments[i * 2 + 1]);
1085 free(m_NamedFragments);
1087 m_NamedFragments = NULL;
1088 m_CountNamedFragments = 0;
1089 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION(";i"), "lambda { $named_fragments.length }", &n) != 0 || n <= 0)
1091 m_CountNamedFragments = n;
1092 m_NamedFragments = (char **)calloc(sizeof(char *), n * 2);
1093 for (i = 0; i < n; i++) {
1094 if (MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "lambda { |i| $named_fragments[i][0] }", i, &m_NamedFragments[i * 2]) != 0 ||
1095 MolActionCreateAndPerform(NULL, SCRIPT_ACTION("i;s"), "lambda { |i| $named_fragments[i][1] }", i, &m_NamedFragments[i * 2 + 1]) != 0)
1099 for (i = 0; i < m_CountNamedFragments; i++) {
1100 if (m_NamedFragments[i * 2] != NULL)
1101 free(m_NamedFragments[i * 2]);
1102 if (m_NamedFragments[i * 2 + 1] != NULL)
1103 free(m_NamedFragments[i * 2 + 1]);
1105 free(m_NamedFragments);
1106 m_CountNamedFragments = 0;
1107 m_NamedFragments = NULL;
1111 wxMenu *predefined_submenu = NULL;
1114 for (i = sn = 0; i < m_CountNamedFragments; i++) {
1115 if (strcmp(m_NamedFragments[i * 2 + 1], "-") == 0) {
1116 if (predefined_submenu != NULL) {
1117 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
1119 predefined_submenu = new wxMenu;
1120 stitle = wxString(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
1123 wxString mtitle(m_NamedFragments[i * 2], WX_DEFAULT_CONV);
1124 (predefined_submenu != NULL ? predefined_submenu : fmenu)->Append(myMenuID_PredefinedFragment + 1 + i, mtitle);
1127 if (predefined_submenu != NULL)
1128 fmenu->Append(myMenuID_PredefinedFragment + 1 + sn, stitle, predefined_submenu);
1129 Connect(myMenuID_PredefinedFragment + 1, myMenuID_PredefinedFragment + m_CountNamedFragments, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyApp::OnFragmentMenuSelected), NULL, this);
1133 MyApp::OnFragmentMenuSelected(wxCommandEvent& event)
1135 int index = event.GetId() - myMenuID_PredefinedFragment - 1;
1136 if (index < 0 || index >= m_CountNamedFragments)
1138 // Open a predefined fragment as a new file
1140 Molecule *mol = MoleculeNew();
1144 asprintf(&fullname, "%s/Scripts/mbsf/%s", (const char *)(FindResourcePath().mb_str(wxConvFile)), m_NamedFragments[index * 2 + 1]);
1145 result = MoleculeLoadMbsfFile(mol, fullname, &errbuf);
1146 if (errbuf != NULL) {
1147 MyAppCallback_showScriptMessage("On loading %s:\n%s", m_NamedFragments[index * 2 + 1], errbuf);
1151 MyAppCallback_errorMessageBox("Cannot open named fragment %s\n(See console for detailed message)", m_NamedFragments[index * 2]);
1156 MyDocument *doc = (MyDocument *)(DocManager()->CreateDocument(wxT(""), wxDOC_NEW));
1157 wxString title(m_NamedFragments[index * 2], WX_DEFAULT_CONV);
1158 title = _T("*") + title + _T("*");
1159 doc->SetMolecule(mol);
1160 if (mol->natoms > 1000)
1161 mol->mview->lineMode = 1;
1162 MainView_resizeToFit(mol->mview);
1164 // Change the window title
1165 doc->SetTitle(title);
1166 // Propagate the change of the window title
1167 wxList::compatibility_iterator node = doc->GetViews().GetFirst();
1169 wxView *view = (wxView *)node->GetData();
1170 view->OnChangeFilename();
1171 node = node->GetNext();
1176 MyApp::OnUpdateUI(wxUpdateUIEvent& event)
1178 int uid = event.GetId();
1179 MainView *mview = MainViewCallback_activeView();
1180 if (uid >= myMenuID_CustomScript && uid < myMenuID_CustomScript + countScriptMenu) {
1181 // Check the script menu
1182 // If the frontmost window is RubyDialogFrame, then disable any script menu command
1184 #if defined(__WXMAC__)
1185 void *MacGetActiveWindow(void);
1186 w = wxDynamicCast(wxNonOwnedWindow::GetFromWXWindow((WXWindow)MacGetActiveWindow()), wxWindow);
1188 w = wxGetActiveWindow();
1190 if (wxDynamicCast(w, RubyDialogFrame) != NULL) {
1191 event.Enable(false);
1195 int enabled, checked;
1197 int index = uid - myMenuID_CustomScript;
1200 else mol = mview->mol;
1203 enabled = Ruby_UpdateUI(index, mol, &checked, &title);
1205 event.Check(checked != 0);
1206 if (title != NULL) {
1207 wxString wtext(title, WX_DEFAULT_CONV);
1208 event.SetText(wtext);
1211 event.Enable(enabled != 0);
1212 } else if (uid >= myMenuID_PredefinedFragment && uid <= myMenuID_PredefinedFragment + m_CountNamedFragments) {
1214 #if defined(__WXMAC__)
1215 } else if (uid >= wxID_OSX_MENU_FIRST && uid <= wxID_OSX_MENU_LAST) {
1220 case myMenuID_ExecuteScript:
1221 case myMenuID_OpenConsoleWindow:
1222 case myMenuID_EmptyConsoleWindow:
1223 case myMenuID_ViewParameterFilesList:
1224 case myMenuID_ViewGlobalParameters:
1229 event.Enable(false);
1237 MyApp::OnExecuteScript(wxCommandEvent &event)
1239 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Script File"), _T(""), _T(""), _T("All files (*.*)|*.*"), wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
1240 if (dialog->ShowModal() == wxID_OK) {
1243 wxString path = dialog->GetPath();
1245 // Command line: execute_script('pathname')
1246 wxString cline(path);
1247 wxRegEx re(_T("[\\\\']")); // A backslash and a single-quote
1248 re.Replace(&cline, _T("\\\\\\0")); // A backslash followed by "\0"
1249 cline.Prepend(_T("execute_script('"));
1251 MyAppCallback_setConsoleColor(3);
1252 MyAppCallback_showScriptMessage("%s", (const char *)(cline.mb_str(wxConvFile)));
1253 MyAppCallback_showScriptMessage("\n");
1254 MyAppCallback_setConsoleColor(0);
1256 retval = MyAppCallback_executeScriptFromFile((const char *)(path.mb_str(wxConvFile)), &status);
1257 if (retval == (RubyValue)6 && status == -1)
1258 MyAppCallback_errorMessageBox("Cannot open Ruby script %s", (const char *)path.mb_str(wxConvFile));
1259 else if (status != 0)
1260 Ruby_showError(status);
1266 MyApp::OnActivate(wxActivateEvent &event)
1268 #if defined(__WXMAC__) || defined(__WXMSW__)
1269 MyFrame *frame = GetMainFrame();
1271 frame->Show(false); /* Sometimes this "parent" frame gets visible and screw up the menus */
1277 MyApp::RequestOpenFilesByEvent(wxString& files)
1279 /* We do not respond to "open file" event (either via IPC [MSW] or Apple Event [Mac])
1280 while we are running something else */
1281 if (m_progressDialog != NULL || gMolbyIsCheckingInterrupt || gMolbyRunLevel > 0)
1284 if (m_pendingFilesToOpen != NULL)
1285 m_pendingFilesToOpen->Append(files);
1287 m_pendingFilesToOpen = new wxString(files);
1288 if (!m_pendingFilesToOpen->EndsWith(wxT("\n")))
1289 m_pendingFilesToOpen->Append(wxT("\n"));
1290 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openFilesByEvent);
1291 wxPostEvent(this, myEvent);
1295 MyApp::OnOpenFilesByEvent(wxCommandEvent& event)
1297 if (m_pendingFilesToOpen == NULL)
1299 if (!gInitCompleted) {
1300 // Repost this event and try again later
1301 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openFilesByEvent);
1302 wxPostEvent(this, myEvent);
1305 OnOpenFiles(*m_pendingFilesToOpen);
1306 delete m_pendingFilesToOpen;
1307 m_pendingFilesToOpen = NULL;
1311 MyApp::OnOpenFiles(const wxString &files)
1314 bool success = true;
1319 end = files.find(wxT("\n"), start);
1320 wxString file = files.Mid(start, (end == wxString::npos ? wxString::npos : end - start));
1321 if (file.Len() == 0)
1323 if (file.EndsWith(wxT(".rb")) || file.EndsWith(wxT(".mrb"))) {
1324 /* Execute the file as a Ruby script */
1325 retval = MyAppCallback_executeScriptFromFile((const char *)file.mb_str(wxConvFile), &status);
1327 if (retval == (RubyValue)6 && status == -1)
1328 MyAppCallback_errorMessageBox("Cannot open Ruby script: %s", (const char *)file.mb_str(wxConvFile));
1330 Ruby_showError(status);
1334 if (NULL == wxGetApp().DocManager()->CreateDocument(file, wxDOC_SILENT))
1337 if (end == wxString::npos)
1345 MyApp::DefaultSettingsPath()
1347 wxString name = wxStandardPaths::Get().GetUserConfigDir();
1348 wxChar sep = wxFileName::GetPathSeparator();
1349 if (name[name.Len() - 1] != sep)
1351 name += _T("Molby.settings");
1356 MyApp::LoadDefaultSettings()
1358 wxString name = DefaultSettingsPath();
1359 m_defaultSettings.clear();
1360 wxTextFile file(name);
1361 if (file.Exists() && file.Open()) {
1364 for (line = file.GetFirstLine(); ; line = file.GetNextLine()) {
1367 if ((pos = line.Find('=')) != wxNOT_FOUND) {
1368 wxString key = line.Left(pos);
1369 wxString value = line.Right(line.Length() - pos - 1);
1370 SetDefaultSetting(key, value);
1380 MyApp::SaveDefaultSettings()
1382 wxString name = DefaultSettingsPath();
1383 wxTextFile file(name);
1389 MyStringHash::iterator it;
1390 for (it = m_defaultSettings.begin(); it != m_defaultSettings.end(); it++) {
1391 wxString key = it->first;
1392 wxString value = it->second;
1393 wxString line = key + _T("=") + value;
1401 MyApp::SetDefaultSetting(const wxString& key, const wxString& value)
1403 // TODO: The '=' and '#' characters may need to be escaped
1404 m_defaultSettings[key] = value;
1408 MyApp::GetDefaultSetting(const wxString& key)
1410 return m_defaultSettings[key];
1414 MyApp::GetGlobalParameterListCtrl()
1416 if (parameterFrame != NULL)
1417 return parameterFrame->GetListCtrl();
1421 #define LOG_SUBPROCESS 0
1428 MyApp::OnEndProcess(wxProcessEvent &event)
1430 m_processTerminated = true;
1431 m_processExitCode = event.GetExitCode();
1434 fprintf(fplog, "OnEndProcess called\n");
1436 // delete m_process;
1437 // m_process = NULL;
1442 MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback)(void *), void *callback_data, FILE *fpout, FILE *fperr, int *exitstatus_p, int *pid_p)
1445 int callback_result = 0;
1447 bool progress_panel = false;
1449 size_t len, len_total;
1450 wxString cmdstr(cmdline, WX_DEFAULT_CONV);
1451 wxLongLong startTime;
1453 if (m_process != NULL)
1454 return -1; // Another process is already running (CallSubProcess() allows only one subprocess)
1456 #if defined(__WXMSW__)
1457 extern int myKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
1459 // Show progress panel
1460 if (procname != NULL) {
1461 snprintf(buf, sizeof buf, "Running %s...", procname);
1462 ShowProgressPanel(buf);
1463 progress_panel = true;
1465 startTime = wxGetUTCTimeMillis();
1467 // Create log file in the document home directory
1469 wxDateTime dateTime;
1470 dateTime.SetToCurrent();
1473 char *dochome = MyAppCallback_getDocumentHomeDir();
1474 snprintf(buf, sizeof buf, "%s/molby_subprocess.log", dochome);
1476 fplog = fopen(buf, "a");
1482 // Create proc object and call subprocess
1483 m_process = new wxBetterProcess(this, -1);
1484 m_process->Redirect();
1485 int flag = wxEXEC_ASYNC;
1486 flag |= wxEXEC_MAKE_GROUP_LEADER;
1487 long pid = ::wxExecute(cmdstr, flag, m_process);
1490 HideProgressPanel();
1493 fprintf(fplog, "Cannot start '%s'\n", cmdline);
1501 fprintf(fplog, "%s[DEBUG]pid = %ld\n", (const char *)(dateTime.FormatISOCombined(' ')), pid);
1505 // Wait until process ends or user interrupts
1506 wxMemoryBuffer memBuffer; // Buffer to store standard output
1507 bool interrupted = false;
1511 int len1 = m_process->GetLine(bufstr);
1514 dateTime.SetToCurrent();
1515 fprintf(fplog, "%s[STDOUT]%s", (const char *)(dateTime.FormatISOCombined(' ')), (const char *)bufstr);
1518 if (callback == DUMMY_CALLBACK) {
1519 const char *p = (const char *)bufstr;
1520 memBuffer.AppendData(p, strlen(bufstr));
1521 } else if (fpout != NULL && fpout != (FILE *)1) {
1522 fputs((const char *)bufstr, fpout);
1523 } else if (fpout == (FILE *)1) {
1524 MyAppCallback_setConsoleColor(0);
1525 MyAppCallback_showScriptMessage("%s", (const char *)bufstr);
1528 int len2 = m_process->GetErrorLine(buferrstr);
1531 dateTime.SetToCurrent();
1532 fprintf(fplog, "%s[STDERR]%s", (const char *)(dateTime.FormatISOCombined(' ')), buf);
1535 if (fperr != NULL && fperr != (FILE *)1) {
1536 fputs((const char *)buferrstr, fperr);
1537 } else if (fpout == (FILE *)1) {
1538 MyAppCallback_setConsoleColor(1);
1539 MyAppCallback_showScriptMessage("\n%s", (const char *)buferrstr);
1540 MyAppCallback_setConsoleColor(0);
1544 if (len1 < 0 && len2 < 0) {
1545 // The standard/error outputs are exhausted; the process should have terminated
1546 // (Normally, this should be detected by wxBetterProcess::OnTerminate())
1550 if (callback != NULL && callback != DUMMY_CALLBACK) {
1551 callback_result = (*callback)(callback_data);
1552 if (callback_result != 0)
1555 if (progress_panel) {
1556 SetProgressValue(-1);
1557 if (IsInterrupted())
1560 ::wxSafeYield(); // This allows updating console and wxProcess status
1565 dateTime.SetToCurrent();
1566 fprintf(fplog, "%s[DEBUG]pid %ld exists\n", (const char *)(dateTime.FormatISOCombined(' ')), pid);
1571 if (m_process->IsTerminated() || !wxProcess::Exists(pid)) {
1572 /* The subprocess has terminated */
1573 status = m_process->GetStatus();
1575 } else if (interrupted) {
1576 /* User interrupt */
1577 int kflag = wxKILL_CHILDREN;
1581 myKillAllChildren(pid, wxSIGKILL, &rc) != 0
1583 ::wxKill(pid, wxSIGTERM, &rc, kflag) != 0
1587 case wxKILL_BAD_SIGNAL: status = -3; break; /* No such signal */
1588 case wxKILL_ACCESS_DENIED: status = -4; break; /* Permission denied */
1589 case wxKILL_NO_PROCESS: status = -5; break; /* No such process */
1590 default: status = -6; break; /* unknown error */
1593 if (callback_result != 0)
1594 status = -3; /* Interrupt from callback */
1596 status = -2; /* User interrupt */
1598 m_process->Detach();
1604 if (exitstatus_p != NULL)
1605 *exitstatus_p = status;
1607 if (progress_panel) {
1608 HideProgressPanel();
1611 if (m_process != NULL) {
1612 m_process->Detach();
1616 if (callback == DUMMY_CALLBACK) {
1617 char *membuf = NULL;
1619 memBuffer.AppendByte(0);
1620 memsize = memBuffer.GetDataLen();
1621 membuf = (char *)malloc(memsize);
1622 if (membuf != NULL) {
1623 memmove(membuf, memBuffer.GetData(), memsize);
1626 /* Convert "\r\n" to "\n" */
1628 p = pend = membuf + strlen(membuf) + 1;
1629 while (--p >= membuf) {
1631 memmove(p, p + 1, pend - p);
1637 *((char **)callback_data) = membuf;
1644 static int sTimerCount = 0;
1647 MyApp::EnableTimerForDocument(MyDocument *doc)
1652 for (i = 0; i < m_CountTimerDocs; i++) {
1653 if (m_TimerDocs[i] == doc)
1656 m_TimerDocs = (MyDocument **)realloc(m_TimerDocs, sizeof(MyDocument *) * (m_CountTimerDocs + 1));
1657 m_TimerDocs[m_CountTimerDocs++] = doc;
1658 if (m_Timer == NULL)
1659 m_Timer = new wxTimer(this, -1);
1660 if (!m_Timer->IsRunning())
1661 m_Timer->Start(100, wxTIMER_CONTINUOUS);
1665 MyApp::DisableTimerForDocument(MyDocument *doc)
1670 for (i = 0; i < m_CountTimerDocs; i++) {
1671 if (m_TimerDocs[i] == doc) {
1672 // Remove this document from the array
1673 if (i < m_CountTimerDocs - 1) {
1674 memmove(&m_TimerDocs[i], &m_TimerDocs[i + 1], sizeof(MyDocument *) * (m_CountTimerDocs - 1 - i));
1677 if (m_CountTimerDocs == 0) {
1688 MyApp::TimerInvoked(wxTimerEvent &event)
1692 for (i = 0; i < m_CountTimerDocs; i++) {
1693 m_TimerDocs[i]->TimerCallback(sTimerCount);
1698 MyApp::CheckIfAllWindowsAreGoneHandler(wxCommandEvent &event)
1701 wxWindowList::iterator iter;
1702 wxTopLevelWindow *win;
1703 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1704 win = (wxTopLevelWindow *)(*iter);
1705 if (win != m_frameToBeDestroyed && win->IsShown())
1709 const char *p = MyAppCallback_getGlobalSettings(gSettingQuitOnCloseLastWindow);
1711 if (p != NULL && *p != 0)
1712 quitFlag = (atoi(p) != 0);
1713 if (quitFlag || MyAppCallback_messageBox("Do you want to quit Molby?", "Quit Molby", 3, 2)) {
1715 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1716 win = (wxTopLevelWindow *)(*iter);
1717 if (win != m_frameToBeDestroyed)
1718 win->Destroy(); // Avoid double destruction
1721 // Show console window to avoid window-less state
1722 consoleFrame->Show();
1728 MyApp::CheckIfAllWindowsAreGone(wxTopLevelWindow *frame)
1730 /* On Windows, we should avoid the situation where all windows are hidden and
1731 still the program is running. So that we check whether all windows are gone
1732 and if so ask the user to quit the program. If user chooses not to quit, then
1733 the console window is reopened and the program continues to run. */
1734 m_frameToBeDestroyed = frame;
1735 wxCommandEvent myEvent(MyDocumentEvent, myMenuID_Internal_CheckIfAllWindowsAreGone);
1736 this->AddPendingEvent(myEvent);
1740 MyApp::OnHelp(wxCommandEvent& WXUNUSED(event) )
1742 static wxString url;
1743 if (url.IsEmpty()) {
1744 url = FindResourcePath();
1745 #if defined(__WXMSW__)
1746 if (url.SubString(0, 1) == wxT("\\\\")) {
1747 // Network drive: convert to the drive letter
1748 wxBetterProcess *process = new wxBetterProcess(this, -1);
1749 process->Redirect();
1750 long pid = ::wxExecute("net use", wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER, process);
1752 wxRegEx re(wxT("^[[:space:]]+([A-Za-z]:)[[:space:]]+(.*)$"));
1754 while (process->GetLine(bufstr) >= 0) {
1755 bufstr = bufstr.Trim();
1756 if (!bufstr.IsEmpty() && re.Matches(bufstr)) {
1757 wxString dr = re.GetMatch(bufstr, 1);
1758 wxString path = re.GetMatch(bufstr, 2);
1759 if (url.Left(path.Length()) == path) {
1760 url = dr + url.Mid(path.Length());
1769 url.Replace(wxFILE_SEP_PATH, wxT("/"));
1770 url += "/MolbyDoc/ja/index.html";
1772 wxLaunchDefaultBrowser(wxT("file:///") + url);
1776 MyApp::FilterEvent(wxEvent &event)
1779 static FILE *fp_eventlog = NULL;
1780 if (fp_eventlog == NULL) {
1784 snprintf(buf, sizeof buf, "Molby_eventlog_%d.log", i);
1785 fp_eventlog = fopen(buf, "r");
1786 if (fp_eventlog == NULL) {
1787 fp_eventlog = fopen(buf, "wt");
1790 fclose(fp_eventlog);
1795 if (fp_eventlog != NULL) {
1796 fprintf(fp_eventlog, "%d %d\n", event.GetEventType(), event.GetId());
1798 fflush(fp_eventlog);
1804 #pragma mark ====== AboutBox ======
1806 IMPLEMENT_CLASS(AboutDialog, wxDialog)
1807 BEGIN_EVENT_TABLE(AboutDialog, wxDialog)
1810 AboutDialog::AboutDialog():
1811 wxDialog(NULL, -1, wxT("About Molby"))
1813 // vsizer1 --> hsizer1 --> Molby icon
1814 // | |-> vsizer2 --> "Molby"
1815 // | |-> version strings
1817 // |-> copyright messages
1821 Molby_getDescription(&s2, &s3);
1822 wxString str1(s1, WX_DEFAULT_CONV);
1823 wxString str2(s2, WX_DEFAULT_CONV);
1824 wxString str3(s3, WX_DEFAULT_CONV);
1827 #if defined(__WXMSW__)
1828 wxFont *textFont0 = new wxFont(FromFrameDIP(this, 12), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
1829 wxFont *textFont1 = new wxFont(FromFrameDIP(this, 10), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1830 wxFont *textFont2 = new wxFont(FromFrameDIP(this, 9), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1832 wxFont *textFont0 = new wxFont(FromFrameDIP(this, 14), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
1833 wxFont *textFont1 = new wxFont(FromFrameDIP(this, 12), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1834 wxFont *textFont2 = new wxFont(FromFrameDIP(this, 11), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1836 wxBoxSizer *vsizer1 = new wxBoxSizer(wxVERTICAL);
1837 wxBoxSizer *vsizer2 = new wxBoxSizer(wxVERTICAL);
1838 wxBoxSizer *hsizer1 = new wxBoxSizer(wxHORIZONTAL);
1839 wxString tifname = wxGetApp().FindResourcePath() + wxFILE_SEP_PATH + wxT("bitmaps/molby_icon64.png");
1840 wxBitmap *molbyBitmap = new wxBitmap(tifname, wxBITMAP_TYPE_PNG);
1841 wxStaticText *stext1 = new wxStaticText(this, -1, wxT("Molby"));
1842 stext1->SetFont(*textFont0);
1843 wxStaticText *stext2 = new wxStaticText(this, -1, str2);
1844 stext2->SetFont(*textFont1);
1845 wxStaticBitmap *staticBitmap = new wxStaticBitmap(this, -1, *molbyBitmap);
1846 vsizer2->Add(stext1, 0, wxALL | wxEXPAND, FromFrameDIP(this, 2));
1847 vsizer2->Add(stext2, 0, wxALL | wxEXPAND, FromFrameDIP(this, 2));
1848 hsizer1->AddSpacer(FromFrameDIP(this, 20));
1849 hsizer1->Add(staticBitmap, 0, 0, FromFrameDIP(this, 10));
1850 hsizer1->AddSpacer(FromFrameDIP(this, 20));
1851 hsizer1->Add(vsizer2, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1852 wxStaticText *stext3 = new wxStaticText(this, -1, str3);
1853 stext3->SetFont(*textFont2);
1854 vsizer1->Add(hsizer1, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1855 vsizer1->Add(stext3, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1856 vsizer1->Add(this->CreateButtonSizer(wxOK), 0, wxALL | wxEXPAND, FromFrameDIP(this, 10));
1858 this->SetSizerAndFit(vsizer1);
1862 #pragma mark ====== MyFrame (top-level window) ======
1865 * This is the top-level window of the application.
1868 IMPLEMENT_CLASS(MyFrame, wxDocParentFrame)
1869 BEGIN_EVENT_TABLE(MyFrame, wxDocParentFrame)
1870 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
1873 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
1874 const wxPoint& pos, const wxSize& size, long type):
1875 wxDocParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
1877 editMenu = (wxMenu *) NULL;
1878 #if defined(__WXMAC__)
1879 /* Avoid this "dummy" top-level window to appear in the window menu.
1880 It should not happen because MyApp::OnActivate() tries to hide this window,
1881 but this is still here just in case. */
1883 // sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
1884 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
1888 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
1890 AboutDialog *d = new AboutDialog();
1891 if ( d->ShowModal() == wxID_OK )
1895 MyFrame *GetMainFrame(void)
1901 #pragma mark ====== Better wxProcess ======
1905 wxBetterProcess::OnTerminate(int pid, int status)
1907 m_terminated = true;
1911 wxBetterProcess::KillProcess(wxSignal sig, int flags)
1913 wxKillError retval = wxProcess::Kill(this->GetPid(), sig, flags);
1914 if (retval == wxKILL_OK)
1920 wxBetterProcess::GetLineSub(wxString &outStr, wxInputStream *stream, wxMemoryBuffer &mbuf)
1922 int err = wxSTREAM_NO_ERROR;
1928 return -3; // No stderr stream
1930 p = (char *)mbuf.GetData();
1931 len = mbuf.GetDataLen();
1933 pp = (char *)memchr(p, '\n', len);
1935 pp = (char *)memchr(p, '\r', len);
1936 if (pp == NULL && stream->GetLastError() == wxSTREAM_EOF) {
1937 // If EOF, then return all remaining data (without '\n')
1938 pp = p + mbuf.GetDataLen() - 1; // Point to the last char
1941 // Return one line and string length
1942 outStr = wxString(p, wxConvUTF8, pp - p + 1);
1943 memmove(p, pp + 1, len - (pp - p + 1));
1944 m_stdout.SetDataLen(len - (pp - p + 1));
1949 // stream->Read() is called only once
1951 if (err == wxSTREAM_EOF)
1952 return -1; // EOF and no data left
1953 return 0; // Not EOF, but no data is available at present
1956 if (stream->CanRead()) {
1957 // We need to read by one character because wxInputStream has
1958 // no way to give the available number of bytes
1959 stream->Read(buf, sizeof buf);
1960 err = stream->GetLastError();
1961 if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF)
1962 return -2; // Some read error
1963 len = stream->LastRead();
1964 } else err = stream->GetLastError();
1966 mbuf.AppendData(buf, len);
1972 wxBetterProcess::GetLine(wxString &outStr)
1974 return GetLineSub(outStr, this->GetInputStream(), m_stdout);
1978 wxBetterProcess::GetErrorLine(wxString &outStr)
1980 return GetLineSub(outStr, this->GetErrorStream(), m_stderr);
1984 wxBetterProcess::PutLine(wxString str)
1986 wxOutputStream *stream = this->GetOutputStream();
1988 return -3; // No stdin stream
1989 const char *p = str.utf8_str();
1990 long len = strlen(p);
1992 m_stdin.AppendData(p, len);
1993 char *pp = (char *)m_stdin.GetData();
1994 len = m_stdin.GetDataLen();
1997 stream->Write(pp, len);
1998 long len2 = stream->LastWrite();
2000 memmove(pp, pp + len2, len - len2);
2001 m_stdin.SetDataLen(len - len2);
2007 wxBetterProcess::CloseOutput()
2009 // We must flush the data in the internal buffer before closing the output
2010 while (PutLine("") > 0) {}
2011 wxProcess::CloseOutput(); // Call the original version
2014 #pragma mark ====== Plain-C interface ======
2017 MyAppCallback_getGUIDescriptionString(void)
2019 static char *desc = NULL;
2022 "AmberTools 1.3, http://ambermd.org/\n"
2023 " Copyright (C) Junmei Wang, Ross C. Walker, "
2024 "Michael F. Crowley, Scott Brozell and David A. Case\n"
2025 "ORTEP-III, http://web.ornl.gov/sci/ortep/\n"
2026 " Michael N. Burnett and Carroll K. Johnson, "
2027 "Oak Ridge National Laboratory Report ORNL-6895, "
2029 "wxWidgets %d.%d.%d, http://www.wxwidgets.org/\n"
2030 " Copyright (C) 1992-2013 Julian Smart, Vadim "
2031 "Zeitlin, Stefan Csomor, Robert Roebling,\n"
2032 " and other members of the wxWidgets team\n"
2033 " Portions (C) 1996 Artificial Intelligence "
2034 "Applications Institute\n",
2035 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
2041 MyAppCallback_loadGlobalSettings(void)
2045 wxGetApp().LoadDefaultSettings();
2049 MyAppCallback_saveGlobalSettings(void)
2053 wxGetApp().SaveDefaultSettings();
2056 /* Note on the global settings */
2057 /* Global settings are stored in a file in the form key="value", where
2058 the "value" is the 'inspect'-ed representation of Ruby values.
2059 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
2060 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
2061 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
2062 MyAppCallback_setGlobalSettingsWithType(). */
2064 MyAppCallback_getGlobalSettings(const char *key)
2068 wxString wxkey(key, WX_DEFAULT_CONV);
2069 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
2070 return strdup(wxvalue.mb_str(WX_DEFAULT_CONV));
2074 MyAppCallback_setGlobalSettings(const char *key, const char *value)
2078 wxString wxkey(key, WX_DEFAULT_CONV);
2079 wxString wxvalue(value, WX_DEFAULT_CONV);
2080 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
2084 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
2087 char *s = MyAppCallback_getGlobalSettings(key);
2088 char desc[] = SCRIPT_ACTION("s; ");
2089 desc[sizeof(desc) - 2] = type;
2090 temp = gMolActionNoErrorDialog;
2091 gMolActionNoErrorDialog = 1;
2092 retval = MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
2094 gMolActionNoErrorDialog = temp;
2099 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
2101 const char *cmd = "set_global_settings";
2103 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("si"), cmd, key, *((const Int *)ptr));
2104 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("sd"), cmd, key, *((const Double *)ptr));
2105 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("ss"), cmd, key, (const char *)ptr);
2106 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("sv"), cmd, key, (const Vector *)ptr);
2107 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("st"), cmd, key, (const Transform *)ptr);
2109 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
2115 MyAppCallback_checkInterrupt(void)
2119 return wxGetApp().IsInterrupted();
2123 MyAppCallback_showProgressPanel(const char *msg)
2127 wxGetApp().ShowProgressPanel(msg);
2131 MyAppCallback_hideProgressPanel(void)
2135 wxGetApp().HideProgressPanel();
2139 MyAppCallback_setProgressValue(double dval)
2143 wxGetApp().SetProgressValue(dval);
2147 MyAppCallback_setProgressMessage(const char *msg)
2151 wxGetApp().SetProgressMessage(msg);
2155 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
2161 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
2162 wxStaticText *stext;
2165 wxString pstr(prompt, WX_DEFAULT_CONV);
2166 wxString defstr(buf, WX_DEFAULT_CONV);
2167 { // Vertical sizer containing [prompt, textbox, buttons]
2169 sizer1 = new wxBoxSizer(wxVERTICAL);
2170 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, FromFrameDIP(dialog, wxSize(200, 22)));
2171 sizer1->Add(stext, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2172 tctrl = new wxTextCtrl(dialog, -1, defstr, wxDefaultPosition, FromFrameDIP(dialog, wxSize(200, 22)));
2173 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2174 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
2175 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2177 dialog->SetSizerAndFit(sizer1);
2178 dialog->Centre(wxBOTH);
2182 if (dialog->ShowModal() == wxID_OK) {
2183 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(WX_DEFAULT_CONV)), bufsize - 1);
2184 buf[bufsize - 1] = 0;
2193 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
2194 1 (information), 2 (exclamation), or 3 (stop). */
2196 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
2199 printf("%s\n%s\n", title, message);
2203 int wxflags, wxicon, retval;
2204 if (!wxGetApp().IsMainLoopRunning()) {
2205 MyAppCallback_setConsoleColor(1);
2206 MyAppCallback_showScriptMessage("*** %s ***\n%s\n", message, title);
2207 MyAppCallback_setConsoleColor(0);
2212 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
2214 case 3: wxicon = wxICON_ERROR; break;
2215 case 2: wxicon = wxICON_EXCLAMATION; break;
2216 default: wxicon = wxICON_INFORMATION; break;
2218 wxString wxmessage(message, WX_DEFAULT_CONV);
2219 wxString wxtitle(title, WX_DEFAULT_CONV);
2220 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
2221 return (retval == wxOK ? 1 : 0);
2225 MyAppCallback_errorMessageBox(const char *fmt, ...)
2230 vfprintf(stderr, fmt, ap);
2237 if (strchr(fmt, '%') == 0) {
2239 } else if (strcmp(fmt, "%s") == 0) {
2240 s = va_arg(ap, char *);
2242 vasprintf(&s, fmt, ap);
2245 MyAppCallback_messageBox(s, "Error", 0, 3);
2251 MyAppCallback_getHomeDir(void)
2255 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
2256 s = getenv("USERPROFILE");
2260 return (s == NULL ? NULL : strdup(s));
2268 MyAppCallback_getDocumentHomeDir(void)
2271 char appData[MAX_PATH * 2];
2273 hResult = SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, 0, appData);
2274 if (hResult == S_OK) {
2275 return strdup(appData);
2277 return MyAppCallback_getHomeDir();
2282 return (s == NULL ? NULL : strdup(s));
2287 MyAppCallback_registerScriptMenu(const char *title)
2291 return wxGetApp().RegisterScriptMenu(title);
2295 MyAppCallback_lookupScriptMenu(const char *title)
2299 return wxGetApp().LookupScriptMenu(title);
2303 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
2310 wxString cwd = wxFileName::GetCwd();
2311 wxString path(cpath, wxConvFile);
2312 char *p = strdup(cpath);
2313 char sep = wxFileName::GetPathSeparator();
2314 char *pp, *script = NULL;
2315 if ((pp = strrchr(p, sep)) != NULL) {
2317 wxString dirname(p, wxConvFile);
2318 wxFileName::SetCwd(dirname);
2321 /* Read the content of the file */
2322 FILE *fp = fopen(cpath, "rb");
2325 fseek(fp, 0, SEEK_END);
2327 fseek(fp, 0, SEEK_SET);
2328 script = (char *)malloc(len + 1);
2329 if (script!= NULL) {
2330 fread(script, 1, len, fp);
2336 if (script == NULL) {
2338 return (RubyValue)6; /* Cannot open file */
2341 /* Check the encoding specification, and if present convert it to default encoding */
2343 char *lp = script, *eolp;
2345 while (n < 2) { /* Check the first two lines */
2346 while (*lp && isspace(*lp))
2348 if (*lp == 0 || *lp++ != '#') /* Check only the comment line */
2352 if (*lp == '!') { /* Shebang line */
2353 while (*lp && *lp != '\n')
2354 lp++; /* Skip until end of line */
2359 for (eolp = lp; *eolp && *eolp != '\n'; eolp++);
2362 *eolp = 0; /* Limit the search area */
2363 lp = strstr(lp, "coding:");
2364 *eolp = '\n'; /* Restore original string */
2367 while (*lp && isspace(*lp))
2369 if (strncasecmp(lp, "shift-jis", 9) == 0) {
2370 wxString s(script, wxCSConv(wxT("cp932")));
2372 script = strdup(s.mb_str(WX_DEFAULT_CONV));
2373 } else if (strncasecmp(lp, "utf-8", 5) == 0) {
2374 wxString s(script, wxConvUTF8);
2376 script = strdup(s.mb_str(WX_DEFAULT_CONV));
2385 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), pp, status);
2389 wxFileName::SetCwd(cwd);
2393 void MyAppCallback_beginUndoGrouping(void)
2397 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
2398 wxList::iterator iter;
2399 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
2400 ((MyDocument *)(*iter))->BeginUndoGrouping();
2404 void MyAppCallback_endUndoGrouping(void)
2408 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
2409 wxList::iterator iter;
2410 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
2411 ((MyDocument *)(*iter))->EndUndoGrouping();
2415 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)
2418 return system(cmdline);
2419 return wxGetApp().CallSubProcess(cmdline, procname, callback, callback_data, output, errout, exitstatus_p, pid_p);
2422 void MyAppCallback_showConsoleWindow(void)
2426 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
2431 void MyAppCallback_hideConsoleWindow(void)
2435 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
2439 void MyAppCallback_bell(void)
2446 int MyAppCallback_playSound(const char *filename, int flag)
2450 unsigned uflag = wxSOUND_SYNC;
2452 uflag = wxSOUND_ASYNC;
2454 uflag = wxSOUND_ASYNC | wxSOUND_LOOP;
2455 wxString fnamestr(filename, wxConvFile);
2456 bool retval = wxSound::Play(fnamestr, uflag);
2460 void MyAppCallback_stopSound(void)
2467 void MyAppCallback_initImageHandlers(void)
2469 static bool handlers_init = false;
2470 if (!handlers_init) {
2471 wxInitAllImageHandlers();
2472 handlers_init = true;