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;
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 = 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;
1482 int len1 = m_process->GetLine(bufstr);
1485 dateTime.SetToCurrent();
1486 fprintf(fplog, "%s[STDOUT]%s", (const char *)(dateTime.FormatISOCombined(' ')), (const char *)bufstr);
1489 if (callback == DUMMY_CALLBACK) {
1490 const char *p = (const char *)bufstr;
1491 memBuffer.AppendData(p, strlen(bufstr));
1492 } else if (fpout != NULL && fpout != (FILE *)1) {
1493 fputs((const char *)bufstr, fpout);
1494 } else if (fpout == (FILE *)1) {
1495 MyAppCallback_setConsoleColor(0);
1496 MyAppCallback_showScriptMessage("%s", (const char *)bufstr);
1499 int len2 = m_process->GetErrorLine(buferrstr);
1502 dateTime.SetToCurrent();
1503 fprintf(fplog, "%s[STDERR]%s", (const char *)(dateTime.FormatISOCombined(' ')), buf);
1506 if (fperr != NULL && fperr != (FILE *)1) {
1507 fputs((const char *)buferrstr, fperr);
1508 } else if (fpout == (FILE *)1) {
1509 MyAppCallback_setConsoleColor(1);
1510 MyAppCallback_showScriptMessage("\n%s", (const char *)buferrstr);
1511 MyAppCallback_setConsoleColor(0);
1515 if (len1 < 0 && len2 < 0) {
1516 // The standard/error outputs are exhausted; the process should have terminated
1517 // (Normally, this should be detected by wxBetterProcess::OnTerminate())
1521 if (callback != NULL && callback != DUMMY_CALLBACK) {
1522 callback_result = (*callback)(callback_data);
1523 if (callback_result != 0)
1526 if (progress_panel) {
1527 SetProgressValue(-1);
1528 if (IsInterrupted())
1531 ::wxSafeYield(); // This allows updating console and wxProcess status
1536 dateTime.SetToCurrent();
1537 fprintf(fplog, "%s[DEBUG]pid %ld exists\n", (const char *)(dateTime.FormatISOCombined(' ')), pid);
1542 if (m_process->IsTerminated() || !wxProcess::Exists(pid)) {
1543 /* The subprocess has terminated */
1544 status = m_process->GetStatus();
1546 } else if (interrupted) {
1547 /* User interrupt */
1548 int kflag = wxKILL_CHILDREN;
1552 myKillAllChildren(pid, wxSIGKILL, &rc) != 0
1554 ::wxKill(pid, wxSIGTERM, &rc, kflag) != 0
1558 case wxKILL_BAD_SIGNAL: status = -3; break; /* No such signal */
1559 case wxKILL_ACCESS_DENIED: status = -4; break; /* Permission denied */
1560 case wxKILL_NO_PROCESS: status = -5; break; /* No such process */
1561 default: status = -6; break; /* unknown error */
1564 if (callback_result != 0)
1565 status = -3; /* Interrupt from callback */
1567 status = -2; /* User interrupt */
1569 m_process->Detach();
1575 if (exitstatus_p != NULL)
1576 *exitstatus_p = status;
1578 if (progress_panel) {
1579 HideProgressPanel();
1582 if (m_process != NULL) {
1583 m_process->Detach();
1587 if (callback == DUMMY_CALLBACK) {
1588 char *membuf = NULL;
1590 memBuffer.AppendByte(0);
1591 memsize = memBuffer.GetDataLen();
1592 membuf = (char *)malloc(memsize);
1593 if (membuf != NULL) {
1594 memmove(membuf, memBuffer.GetData(), memsize);
1597 /* Convert "\r\n" to "\n" */
1599 p = pend = membuf + strlen(membuf) + 1;
1600 while (--p >= membuf) {
1602 memmove(p, p + 1, pend - p);
1608 *((char **)callback_data) = membuf;
1615 static int sTimerCount = 0;
1618 MyApp::EnableTimerForDocument(MyDocument *doc)
1623 for (i = 0; i < m_CountTimerDocs; i++) {
1624 if (m_TimerDocs[i] == doc)
1627 m_TimerDocs = (MyDocument **)realloc(m_TimerDocs, sizeof(MyDocument *) * (m_CountTimerDocs + 1));
1628 m_TimerDocs[m_CountTimerDocs++] = doc;
1629 if (m_Timer == NULL)
1630 m_Timer = new wxTimer(this, -1);
1631 if (!m_Timer->IsRunning())
1632 m_Timer->Start(100, wxTIMER_CONTINUOUS);
1636 MyApp::DisableTimerForDocument(MyDocument *doc)
1641 for (i = 0; i < m_CountTimerDocs; i++) {
1642 if (m_TimerDocs[i] == doc) {
1643 // Remove this document from the array
1644 if (i < m_CountTimerDocs - 1) {
1645 memmove(&m_TimerDocs[i], &m_TimerDocs[i + 1], sizeof(MyDocument *) * (m_CountTimerDocs - 1 - i));
1648 if (m_CountTimerDocs == 0) {
1659 MyApp::TimerInvoked(wxTimerEvent &event)
1663 for (i = 0; i < m_CountTimerDocs; i++) {
1664 m_TimerDocs[i]->TimerCallback(sTimerCount);
1669 MyApp::CheckIfAllWindowsAreGoneHandler(wxCommandEvent &event)
1672 wxWindowList::iterator iter;
1673 wxTopLevelWindow *win;
1674 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1675 win = (wxTopLevelWindow *)(*iter);
1676 if (win != m_frameToBeDestroyed && win->IsShown())
1680 const char *p = MyAppCallback_getGlobalSettings(gSettingQuitOnCloseLastWindow);
1682 if (p != NULL && *p != 0)
1683 quitFlag = (atoi(p) != 0);
1684 if (quitFlag || MyAppCallback_messageBox("Do you want to quit Molby?", "Quit Molby", 3, 2)) {
1686 for (iter = wxTopLevelWindows.begin(); iter != wxTopLevelWindows.end(); ++iter) {
1687 win = (wxTopLevelWindow *)(*iter);
1688 if (win != m_frameToBeDestroyed)
1689 win->Destroy(); // Avoid double destruction
1692 // Show console window to avoid window-less state
1693 consoleFrame->Show();
1699 MyApp::CheckIfAllWindowsAreGone(wxTopLevelWindow *frame)
1701 /* On Windows, we should avoid the situation where all windows are hidden and
1702 still the program is running. So that we check whether all windows are gone
1703 and if so ask the user to quit the program. If user chooses not to quit, then
1704 the console window is reopened and the program continues to run. */
1705 m_frameToBeDestroyed = frame;
1706 wxCommandEvent myEvent(MyDocumentEvent, myMenuID_Internal_CheckIfAllWindowsAreGone);
1707 this->AddPendingEvent(myEvent);
1711 MyApp::OnHelp(wxCommandEvent& WXUNUSED(event) )
1713 static wxString url;
1714 if (url.IsEmpty()) {
1715 url = FindResourcePath();
1716 #if defined(__WXMSW__)
1717 if (url.SubString(0, 1) == wxT("\\\\")) {
1718 // Network drive: convert to the drive letter
1719 wxBetterProcess *process = new wxBetterProcess(this, -1);
1720 process->Redirect();
1721 long pid = ::wxExecute("net use", wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER, process);
1723 wxRegEx re(wxT("^[[:space:]]+([A-Za-z]:)[[:space:]]+(.*)$"));
1725 while (process->GetLine(bufstr) >= 0) {
1726 bufstr = bufstr.Trim();
1727 if (!bufstr.IsEmpty() && re.Matches(bufstr)) {
1728 wxString dr = re.GetMatch(bufstr, 1);
1729 wxString path = re.GetMatch(bufstr, 2);
1730 if (url.Left(path.Length()) == path) {
1731 url = dr + url.Mid(path.Length());
1740 url.Replace(wxFILE_SEP_PATH, wxT("/"));
1741 url += "/MolbyDoc/ja/index.html";
1743 wxLaunchDefaultBrowser(wxT("file:///") + url);
1747 MyApp::FilterEvent(wxEvent &event)
1750 static FILE *fp_eventlog = NULL;
1751 if (fp_eventlog == NULL) {
1755 snprintf(buf, sizeof buf, "Molby_eventlog_%d.log", i);
1756 fp_eventlog = fopen(buf, "r");
1757 if (fp_eventlog == NULL) {
1758 fp_eventlog = fopen(buf, "wt");
1761 fclose(fp_eventlog);
1766 if (fp_eventlog != NULL) {
1767 fprintf(fp_eventlog, "%d %d\n", event.GetEventType(), event.GetId());
1769 fflush(fp_eventlog);
1775 #pragma mark ====== AboutBox ======
1777 IMPLEMENT_CLASS(AboutDialog, wxDialog)
1778 BEGIN_EVENT_TABLE(AboutDialog, wxDialog)
1781 AboutDialog::AboutDialog():
1782 wxDialog(NULL, -1, wxT("About Molby"))
1784 // vsizer1 --> hsizer1 --> Molby icon
1785 // | |-> vsizer2 --> "Molby"
1786 // | |-> version strings
1788 // |-> copyright messages
1793 Molby_getDescription(&s2, &s3);
1794 wxString str1(s1, WX_DEFAULT_CONV);
1795 wxString str2(s2, WX_DEFAULT_CONV);
1796 wxString str3(s3, WX_DEFAULT_CONV);
1799 #if defined(__WXMSW__)
1800 wxFont *textFont0 = new wxFont(FromFrameDIP(this, 12), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
1801 wxFont *textFont1 = new wxFont(FromFrameDIP(this, 10), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1802 wxFont *textFont2 = new wxFont(FromFrameDIP(this, 9), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1804 wxFont *textFont0 = new wxFont(FromFrameDIP(this, 14), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
1805 wxFont *textFont1 = new wxFont(FromFrameDIP(this, 12), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1806 wxFont *textFont2 = new wxFont(FromFrameDIP(this, 11), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1808 wxBoxSizer *vsizer1 = new wxBoxSizer(wxVERTICAL);
1809 wxBoxSizer *vsizer2 = new wxBoxSizer(wxVERTICAL);
1810 wxBoxSizer *hsizer1 = new wxBoxSizer(wxHORIZONTAL);
1811 wxString tifname = wxGetApp().FindResourcePath() + wxFILE_SEP_PATH + wxT("bitmaps/molby_icon64.png");
1812 wxBitmap *molbyBitmap = new wxBitmap(tifname, wxBITMAP_TYPE_PNG);
1813 wxStaticText *stext1 = new wxStaticText(this, -1, wxT("Molby"));
1814 stext1->SetFont(*textFont0);
1815 wxStaticText *stext2 = new wxStaticText(this, -1, str2);
1816 stext2->SetFont(*textFont1);
1817 wxStaticBitmap *staticBitmap = new wxStaticBitmap(this, -1, *molbyBitmap);
1818 vsizer2->Add(stext1, 0, wxALL | wxEXPAND, FromFrameDIP(this, 2));
1819 vsizer2->Add(stext2, 0, wxALL | wxEXPAND, FromFrameDIP(this, 2));
1820 hsizer1->AddSpacer(FromFrameDIP(this, 20));
1821 hsizer1->Add(staticBitmap, 0, 0, FromFrameDIP(this, 10));
1822 hsizer1->AddSpacer(FromFrameDIP(this, 20));
1823 hsizer1->Add(vsizer2, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1824 wxStaticText *stext3 = new wxStaticText(this, -1, str3);
1825 stext3->SetFont(*textFont2);
1826 vsizer1->Add(hsizer1, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1827 vsizer1->Add(stext3, 0, wxALL | wxEXPAND, FromFrameDIP(this, 5));
1828 vsizer1->Add(this->CreateButtonSizer(wxOK), 0, wxALL | wxEXPAND, FromFrameDIP(this, 10));
1830 this->SetSizerAndFit(vsizer1);
1834 #pragma mark ====== MyFrame (top-level window) ======
1837 * This is the top-level window of the application.
1840 IMPLEMENT_CLASS(MyFrame, wxDocParentFrame)
1841 BEGIN_EVENT_TABLE(MyFrame, wxDocParentFrame)
1842 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
1845 MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
1846 const wxPoint& pos, const wxSize& size, long type):
1847 wxDocParentFrame(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
1849 editMenu = (wxMenu *) NULL;
1850 #if defined(__WXMAC__)
1851 /* Avoid this "dummy" top-level window to appear in the window menu.
1852 It should not happen because MyApp::OnActivate() tries to hide this window,
1853 but this is still here just in case. */
1855 // sts = ChangeWindowAttributes((WindowRef)m_macWindow, 0, kWindowInWindowMenuAttribute);
1856 /* printf("m_macWindow = %p, status = %d\n", m_macWindow, (int)sts); */
1860 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
1862 AboutDialog *d = new AboutDialog();
1863 if ( d->ShowModal() == wxID_OK )
1867 MyFrame *GetMainFrame(void)
1873 #pragma mark ====== Better wxProcess ======
1877 wxBetterProcess::OnTerminate(int pid, int status)
1879 m_terminated = true;
1883 wxBetterProcess::KillProcess(wxSignal sig, int flags)
1885 wxKillError retval = wxProcess::Kill(this->GetPid(), sig, flags);
1886 if (retval == wxKILL_OK)
1892 wxBetterProcess::GetLineSub(wxString &outStr, wxInputStream *stream, wxMemoryBuffer &mbuf)
1894 int err = wxSTREAM_NO_ERROR;
1900 return -3; // No stderr stream
1902 p = (char *)mbuf.GetData();
1903 len = mbuf.GetDataLen();
1905 pp = (char *)memchr(p, '\n', len);
1907 pp = (char *)memchr(p, '\r', len);
1908 if (pp == NULL && stream->GetLastError() == wxSTREAM_EOF) {
1909 // If EOF, then return all remaining data (without '\n')
1910 pp = p + mbuf.GetDataLen() - 1; // Point to the last char
1913 // Return one line and string length
1914 outStr = wxString(p, wxConvUTF8, pp - p + 1);
1915 memmove(p, pp + 1, len - (pp - p + 1));
1916 m_stdout.SetDataLen(len - (pp - p + 1));
1921 // stream->Read() is called only once
1923 if (err == wxSTREAM_EOF)
1924 return -1; // EOF and no data left
1925 return 0; // Not EOF, but no data is available at present
1928 if (stream->CanRead()) {
1929 // We need to read by one character because wxInputStream has
1930 // no way to give the available number of bytes
1931 stream->Read(buf, sizeof buf);
1932 err = stream->GetLastError();
1933 if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF)
1934 return -2; // Some read error
1935 len = stream->LastRead();
1936 } else err = stream->GetLastError();
1938 mbuf.AppendData(buf, len);
1944 wxBetterProcess::GetLine(wxString &outStr)
1946 return GetLineSub(outStr, this->GetInputStream(), m_stdout);
1950 wxBetterProcess::GetErrorLine(wxString &outStr)
1952 return GetLineSub(outStr, this->GetErrorStream(), m_stderr);
1956 wxBetterProcess::PutLine(wxString str)
1958 wxOutputStream *stream = this->GetOutputStream();
1960 return -3; // No stdin stream
1961 const char *p = str.utf8_str();
1962 long len = strlen(p);
1964 m_stdin.AppendData(p, len);
1965 char *pp = (char *)m_stdin.GetData();
1966 len = m_stdin.GetDataLen();
1969 stream->Write(pp, len);
1970 long len2 = stream->LastWrite();
1972 memmove(pp, pp + len2, len - len2);
1973 m_stdin.SetDataLen(len - len2);
1979 wxBetterProcess::CloseOutput()
1981 // We must flush the data in the internal buffer before closing the output
1982 while (PutLine("") > 0) {}
1983 wxProcess::CloseOutput(); // Call the original version
1986 #pragma mark ====== Plain-C interface ======
1989 MyAppCallback_getGUIDescriptionString(void)
1991 static char *desc = NULL;
1994 "AmberTools 1.3, http://ambermd.org/\n"
1995 " Copyright (C) Junmei Wang, Ross C. Walker, "
1996 "Michael F. Crowley, Scott Brozell and David A. Case\n"
1997 "ORTEP-III, http://web.ornl.gov/sci/ortep/\n"
1998 " Michael N. Burnett and Carroll K. Johnson, "
1999 "Oak Ridge National Laboratory Report ORNL-6895, "
2001 "wxWidgets %d.%d.%d, http://www.wxwidgets.org/\n"
2002 #if wxCHECK_VERSION(3,2,0)
2003 " Copyright (C) 1992-2022 Julian Smart, Vadim "
2005 " Copyright (C) 1992-2013 Julian Smart, Vadim "
2007 "Zeitlin, Stefan Csomor, Robert Roebling,\n"
2008 " and other members of the wxWidgets team\n"
2009 " Portions (C) 1996 Artificial Intelligence "
2010 "Applications Institute\n",
2011 wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
2017 MyAppCallback_loadGlobalSettings(void)
2021 wxGetApp().LoadDefaultSettings();
2025 MyAppCallback_saveGlobalSettings(void)
2029 wxGetApp().SaveDefaultSettings();
2032 /* Note on the global settings */
2033 /* Global settings are stored in a file in the form key="value", where
2034 the "value" is the 'inspect'-ed representation of Ruby values.
2035 So that, if the value is a string like 'aaaa', the stored value is "aaaa" (with quotes),
2036 not aaaa (without quotes). This is convenient for access from Ruby scripts, but it needs
2037 care for access from C. For C-level access, use MyAppCallback_getGlobalSettingsWithType() and
2038 MyAppCallback_setGlobalSettingsWithType(). */
2040 MyAppCallback_getGlobalSettings(const char *key)
2044 wxString wxkey(key, WX_DEFAULT_CONV);
2045 wxString wxvalue = wxGetApp().GetDefaultSetting(wxkey);
2046 return strdup(wxvalue.mb_str(WX_DEFAULT_CONV));
2050 MyAppCallback_setGlobalSettings(const char *key, const char *value)
2054 wxString wxkey(key, WX_DEFAULT_CONV);
2055 wxString wxvalue(value, WX_DEFAULT_CONV);
2056 wxGetApp().SetDefaultSetting(wxkey, wxvalue);
2060 MyAppCallback_getGlobalSettingsWithType(const char *key, int type, void *ptr)
2063 char *s = MyAppCallback_getGlobalSettings(key);
2064 char desc[] = SCRIPT_ACTION("s; ");
2065 desc[sizeof(desc) - 2] = type;
2066 temp = gMolActionNoErrorDialog;
2067 gMolActionNoErrorDialog = 1;
2068 retval = MolActionCreateAndPerform(NULL, desc, "eval", s, ptr);
2070 gMolActionNoErrorDialog = temp;
2075 MyAppCallback_setGlobalSettingsWithType(const char *key, int type, const void *ptr)
2077 const char *cmd = "set_global_settings";
2079 case 'i': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("si"), cmd, key, *((const Int *)ptr));
2080 case 'd': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("sd"), cmd, key, *((const Double *)ptr));
2081 case 's': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("ss"), cmd, key, (const char *)ptr);
2082 case 'v': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("sv"), cmd, key, (const Vector *)ptr);
2083 case 't': return MolActionCreateAndPerform(NULL, SCRIPT_ACTION("st"), cmd, key, (const Transform *)ptr);
2085 MyAppCallback_errorMessageBox("Internal error: unsupported format '%c' at line %d, file %s", type, __LINE__, __FILE__);
2091 MyAppCallback_checkInterrupt(void)
2095 return wxGetApp().IsInterrupted();
2099 MyAppCallback_showProgressPanel(const char *msg)
2103 wxGetApp().ShowProgressPanel(msg);
2107 MyAppCallback_hideProgressPanel(void)
2111 wxGetApp().HideProgressPanel();
2115 MyAppCallback_setProgressValue(double dval)
2119 wxGetApp().SetProgressValue(dval);
2123 MyAppCallback_setProgressMessage(const char *msg)
2127 wxGetApp().SetProgressMessage(msg);
2131 MyAppCallback_getTextWithPrompt(const char *prompt, char *buf, int bufsize)
2137 wxDialog *dialog = new wxDialog(NULL, -1, _T("Input request"), wxDefaultPosition);
2138 wxStaticText *stext;
2141 wxString pstr(prompt, WX_DEFAULT_CONV);
2142 wxString defstr(buf, WX_DEFAULT_CONV);
2143 { // Vertical sizer containing [prompt, textbox, buttons]
2145 sizer1 = new wxBoxSizer(wxVERTICAL);
2146 stext = new wxStaticText(dialog, -1, pstr, wxDefaultPosition, FromFrameDIP(dialog, wxSize(200, 22)));
2147 sizer1->Add(stext, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2148 tctrl = new wxTextCtrl(dialog, -1, defstr, wxDefaultPosition, FromFrameDIP(dialog, wxSize(200, 22)));
2149 sizer1->Add(tctrl, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2150 wxSizer *bsizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
2151 sizer1->Add(bsizer, 0, wxEXPAND | wxALL, FromFrameDIP(dialog, 6));
2153 dialog->SetSizerAndFit(sizer1);
2154 dialog->Centre(wxBOTH);
2158 if (dialog->ShowModal() == wxID_OK) {
2159 strncpy(buf, (const char *)(tctrl->GetValue().mb_str(WX_DEFAULT_CONV)), bufsize - 1);
2160 buf[bufsize - 1] = 0;
2169 /* Generic message box. Flags is a bitwise OR of 1 (OK) and 2 (Cancel). Icon is either
2170 1 (information), 2 (exclamation), or 3 (stop). */
2172 MyAppCallback_messageBox(const char *message, const char *title, int flags, int icon)
2175 printf("%s\n%s\n", title, message);
2179 int wxflags, wxicon, retval;
2180 if (!wxGetApp().IsMainLoopRunning()) {
2181 MyAppCallback_setConsoleColor(1);
2182 MyAppCallback_showScriptMessage("*** %s ***\n%s\n", message, title);
2183 MyAppCallback_setConsoleColor(0);
2188 wxflags = ((flags & 1) ? wxOK : 0) | ((flags & 2) ? wxCANCEL : 0);
2190 case 3: wxicon = wxICON_ERROR; break;
2191 case 2: wxicon = wxICON_EXCLAMATION; break;
2192 default: wxicon = wxICON_INFORMATION; break;
2194 wxString wxmessage(message, WX_DEFAULT_CONV);
2195 wxString wxtitle(title, WX_DEFAULT_CONV);
2196 retval = ::wxMessageBox(wxmessage, wxtitle, wxflags | wxicon);
2197 return (retval == wxOK ? 1 : 0);
2201 MyAppCallback_errorMessageBox(const char *fmt, ...)
2206 vfprintf(stderr, fmt, ap);
2213 if (strchr(fmt, '%') == 0) {
2215 } else if (strcmp(fmt, "%s") == 0) {
2216 s = va_arg(ap, char *);
2218 vasprintf(&s, fmt, ap);
2221 MyAppCallback_messageBox(s, "Error", 0, 3);
2227 MyAppCallback_getHomeDir(void)
2231 /* wxFileName::GetHomeDir() may return unexpected value under MSYS */
2232 s = getenv("USERPROFILE");
2236 return (s == NULL ? NULL : strdup(s));
2244 MyAppCallback_getDocumentHomeDir(void)
2247 char appData[MAX_PATH * 2];
2249 hResult = SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, 0, appData);
2250 if (hResult == S_OK) {
2251 return strdup(appData);
2253 return MyAppCallback_getHomeDir();
2258 return (s == NULL ? NULL : strdup(s));
2263 MyAppCallback_registerScriptMenu(const char *title)
2267 return wxGetApp().RegisterScriptMenu(title);
2271 MyAppCallback_lookupScriptMenu(const char *title)
2275 return wxGetApp().LookupScriptMenu(title);
2279 MyAppCallback_executeScriptFromFile(const char *cpath, int *status)
2286 wxString cwd = wxFileName::GetCwd();
2287 wxString path(cpath, wxConvFile);
2288 char *p = strdup(cpath);
2289 char sep = wxFileName::GetPathSeparator();
2290 char *pp, *script = NULL;
2291 if ((pp = strrchr(p, sep)) != NULL) {
2293 wxString dirname(p, wxConvFile);
2294 wxFileName::SetCwd(dirname);
2297 /* Read the content of the file */
2298 FILE *fp = fopen(cpath, "rb");
2301 fseek(fp, 0, SEEK_END);
2303 fseek(fp, 0, SEEK_SET);
2304 script = (char *)malloc(len + 1);
2305 if (script!= NULL) {
2306 fread(script, 1, len, fp);
2312 if (script == NULL) {
2314 return (RubyValue)6; /* Cannot open file */
2317 /* Check the encoding specification, and if present convert it to default encoding */
2319 char *lp = script, *eolp;
2321 while (n < 2) { /* Check the first two lines */
2322 while (*lp && isspace(*lp))
2324 if (*lp == 0 || *lp++ != '#') /* Check only the comment line */
2328 if (*lp == '!') { /* Shebang line */
2329 while (*lp && *lp != '\n')
2330 lp++; /* Skip until end of line */
2335 for (eolp = lp; *eolp && *eolp != '\n'; eolp++);
2338 *eolp = 0; /* Limit the search area */
2339 lp = strstr(lp, "coding:");
2340 *eolp = '\n'; /* Restore original string */
2343 while (*lp && isspace(*lp))
2345 if (strncasecmp(lp, "shift-jis", 9) == 0) {
2346 wxString s(script, wxCSConv(wxT("cp932")));
2348 script = strdup(s.mb_str(WX_DEFAULT_CONV));
2349 } else if (strncasecmp(lp, "utf-8", 5) == 0) {
2350 wxString s(script, wxConvUTF8);
2352 script = strdup(s.mb_str(WX_DEFAULT_CONV));
2361 retval = Molby_evalRubyScriptOnMolecule(script, MoleculeCallback_currentMolecule(), pp, status);
2365 wxFileName::SetCwd(cwd);
2369 void MyAppCallback_beginUndoGrouping(void)
2373 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
2374 wxList::iterator iter;
2375 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
2376 ((MyDocument *)(*iter))->BeginUndoGrouping();
2380 void MyAppCallback_endUndoGrouping(void)
2384 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
2385 wxList::iterator iter;
2386 for (iter = doclist.begin(); iter != doclist.end(); ++iter) {
2387 ((MyDocument *)(*iter))->EndUndoGrouping();
2391 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)
2394 return system(cmdline);
2395 return wxGetApp().CallSubProcess(cmdline, procname, callback, callback_data, output, errout, exitstatus_p, pid_p);
2398 void MyAppCallback_showConsoleWindow(void)
2402 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
2407 void MyAppCallback_hideConsoleWindow(void)
2411 ConsoleFrame *frame = wxGetApp().GetConsoleFrame();
2415 void MyAppCallback_bell(void)
2422 int MyAppCallback_playSound(const char *filename, int flag)
2426 unsigned uflag = wxSOUND_SYNC;
2428 uflag = wxSOUND_ASYNC;
2430 uflag = wxSOUND_ASYNC | wxSOUND_LOOP;
2431 wxString fnamestr(filename, wxConvFile);
2432 bool retval = wxSound::Play(fnamestr, uflag);
2436 void MyAppCallback_stopSound(void)
2443 void MyAppCallback_initImageHandlers(void)
2445 static bool handlers_init = false;
2446 if (!handlers_init) {
2447 wxInitAllImageHandlers();
2448 handlers_init = true;