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_STD_IOSTREAM
34 #include "wx/ioswrap.h"
36 #include "wx/txtstrm.h"
39 #include "wx/clipbrd.h"
40 #include "wx/filename.h"
49 #include "MyDocManager.h"
50 #include "MyDocument.h"
51 #include "MoleculeView.h"
52 #include "MyCommand.h"
53 #include "MyClipboardData.h"
57 #include "../MolLib/Ruby_bind/Molby_extern.h"
58 #include "../MolLib/MD/MDCore.h"
59 #include "../MolLib/Missing.h"
61 IMPLEMENT_DYNAMIC_CLASS(MyDocument, wxDocument)
63 const wxEventType MyDocumentEvent = wxNewEventType();
65 BEGIN_EVENT_TABLE(MyDocument, wxDocument)
66 EVT_COMMAND(MyDocumentEvent_willNeedCleanUndoStack, MyDocumentEvent, MyDocument::OnNeedCleanUndoStack)
67 EVT_COMMAND(MyDocumentEvent_documentModified, MyDocumentEvent, MyDocument::OnDocumentModified)
68 EVT_COMMAND(MyDocumentEvent_insertFrameFromMD, MyDocumentEvent, MyDocument::OnInsertFrameFromMD)
69 EVT_COMMAND(MyDocumentEvent_updateDisplay, MyDocumentEvent, MyDocument::OnUpdateDisplay)
70 EVT_COMMAND(MyDocumentEvent_threadTerminated, MyDocumentEvent, MyDocument::OnSubThreadTerminated)
71 EVT_MENU(myMenuID_Import, MyDocument::OnImport)
72 EVT_MENU(myMenuID_Export, MyDocument::OnExport)
73 EVT_MENU(wxID_COPY, MyDocument::OnCopy)
74 EVT_MENU(wxID_PASTE, MyDocument::OnPaste)
75 EVT_MENU(wxID_CUT, MyDocument::OnCut)
76 EVT_MENU(wxID_DELETE, MyDocument::OnDelete)
77 EVT_MENU(myMenuID_CreateNewAtom, MyDocument::OnCreateNewAtom)
78 EVT_MENU_RANGE(myMenuID_CreateNewVdwParameter, myMenuID_CreateNewVdwCutoffParameter, MyDocument::OnCreateNewParameter)
79 EVT_MENU(myMenuID_CreatePiAnchor, MyDocument::OnCreatePiAnchor)
80 EVT_MENU(wxID_SELECTALL, MyDocument::OnSelectAll)
81 EVT_MENU(myMenuID_SelectFragment, MyDocument::OnSelectFragment)
82 EVT_MENU(myMenuID_SelectReverse, MyDocument::OnSelectReverse)
83 EVT_MENU(myMenuID_FitToScreen, MyDocument::OnFitToScreen)
84 EVT_MENU(myMenuID_CenterSelection, MyDocument::OnCenterSelection)
85 EVT_MENU(myMenuID_ShowUnitCell, MyDocument::OnShowMenu)
86 EVT_MENU(myMenuID_ShowPeriodicBox, MyDocument::OnShowMenu)
87 EVT_MENU(myMenuID_ShowHydrogens, MyDocument::OnShowMenu)
88 EVT_MENU(myMenuID_ShowDummyAtoms, MyDocument::OnShowMenu)
89 EVT_MENU(myMenuID_ShowExpandedAtoms, MyDocument::OnShowMenu)
90 EVT_MENU(myMenuID_ShowEllipsoids, MyDocument::OnShowMenu)
91 EVT_MENU(myMenuID_ShowRotationCenter, MyDocument::OnShowMenu)
92 EVT_MENU(myMenuID_ShowGraphite, MyDocument::OnShowGraphite)
93 EVT_MENU(myMenuID_LineMode, MyDocument::OnToggleLineMode)
94 EVT_MENU_RANGE(myMenuID_AddHydrogenSp3, myMenuID_AddHydrogenBent, MyDocument::OnAddHydrogen)
95 EVT_UPDATE_UI_RANGE(myMenuID_MyFirstMenuItem, myMenuID_MyLastMenuItem, MyDocument::OnUpdateUI)
96 EVT_MENU(myMenuID_MolecularDynamics, MyDocument::OnMolecularDynamics)
97 EVT_MENU(myMenuID_Minimize, MyDocument::OnMinimize)
98 EVT_MENU(myMenuID_StopMDRun, MyDocument::OnStopMDRun)
99 EVT_MENU(myMenuID_DefinePeriodicBox, MyDocument::OnDefinePeriodicBox)
100 EVT_MENU(myMenuID_ShowPeriodicImage, MyDocument::OnShowPeriodicImage)
101 EVT_MENU(myMenuID_PressureControl, MyDocument::OnPressureControl)
102 EVT_MENU(myMenuID_DefineSymmetry, MyDocument::OnDefineSymmetry)
103 EVT_MENU(myMenuID_ExpandBySymmetry, MyDocument::OnExpandBySymmetry)
104 EVT_MENU(myMenuID_RunAntechamber, MyDocument::OnInvokeAntechamber)
105 EVT_MENU(myMenuID_GuessUFFParameters, MyDocument::OnGuessUFFParameters)
106 EVT_MENU(myMenuID_RunResp, MyDocument::OnInvokeResp)
107 EVT_MENU(myMenuID_CreateSanderInput, MyDocument::OnCreateSanderInput)
108 EVT_MENU(myMenuID_ImportAmberFrcmod, MyDocument::OnImportAmberFrcmod)
109 EVT_MENU(myMenuID_CreateGamessInput, MyDocument::OnCreateGamessInput)
110 EVT_MENU(myMenuID_CreateMOCube, MyDocument::OnCreateMOCube)
111 EVT_MENU(myMenuID_ShowAllAtoms, MyDocument::OnShowAllAtoms)
112 EVT_MENU(myMenuID_HideReverse, MyDocument::OnHideReverse)
113 EVT_MENU(myMenuID_HideSelected, MyDocument::OnHideSelected)
114 EVT_MENU(myMenuID_HideUnselected, MyDocument::OnHideUnselected)
115 EVT_END_PROCESS(-1, MyDocument::OnEndSubProcess)
118 MyDocument::MyDocument()
122 isUndoEnabled = true;
123 isModifyNotificationSent = false;
124 currentCommand = NULL;
128 isCleanUndoStackRequested = false;
132 endSubProcessCallback = NULL;
133 timerSubProcessCallback = NULL;
136 MyDocument::~MyDocument()
139 Molecule *mol2 = mol;
142 if (subProcess != NULL) {
143 subProcess->Detach();
144 subProcess->Kill(subProcess->GetPid(), wxSIGTERM, wxKILL_CHILDREN);
147 /* May be unnecessary? */
148 MoleculeView *view = (MoleculeView *)GetFirstView();
150 view->OnMoleculeReplaced();
154 MoleculeRelease(mol2);
155 if (undoStack != NULL) {
156 for (i = 0; i < countUndoStack; i++)
157 MolActionRelease(undoStack[i]);
161 wxGetApp().DisableTimerForDocument(this);
166 MyDocument::GetMainView()
168 MoleculeView *view = (MoleculeView *)GetFirstView();
176 MyDocument::SetMolecule(Molecule *aMolecule)
178 Molecule *mol2 = mol;
179 if (mol == aMolecule)
182 if (aMolecule != NULL)
183 MoleculeRetain(aMolecule);
185 MoleculeView *view = (MoleculeView *)GetFirstView();
187 view->OnMoleculeReplaced();
190 MoleculeRelease(mol2);
194 MyDocument::DoSaveDocument(const wxString& file)
197 char *p = strdup((const char *)file.mb_str(wxConvFile));
198 size_t len = strlen(p);
200 if (MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "molsave", p) != 0) {
206 if (len > 4 && strcasecmp(p + len - 4, ".psf") == 0) {
207 /* Write as a psf and a pdb file */
208 char *pp = (char *)malloc(len + 2);
210 strcpy(pp + len - 4, ".pdb");
211 retval = MoleculeWriteToPdbFile(mol, pp, &buf);
216 if (mol->cell != NULL) {
217 /* Write an extended info (bounding box) */
218 strcpy(pp + len - 4, ".info");
219 retval = MoleculeWriteExtendedInfo(mol, pp, &buf);
226 GetCommandProcessor()->MarkAsSaved();
228 MoleculeSetPath(mol, p);
232 return (retval == 0);
236 MyDocument::DoOpenDocument(const wxString& file)
241 p = strdup((const char *)file.mb_str(wxConvFile));
242 newmol = MoleculeNew();
244 MoleculeRelease(newmol);
245 SetUndoEnabled(false);
246 if (MolActionCreateAndPerform(newmol, SCRIPT_ACTION("s"), "molload", p) != 0) {
249 SetUndoEnabled(true);
253 if ((len = strlen(p)) > 4 && strcasecmp(p + len - 4, ".psf") == 0) {
254 // Look for a ".pdb" file with the same basename
256 strcpy(p + len - 4, ".pdb");
257 // The error will be ignored
258 MoleculeReadCoordinatesFromPdbFile(newmol, p, &buf);
259 // Look for an ".info" file with the same basename
260 p = (char *)realloc(p, len + 2);
261 strcpy(p + len - 4, ".info");
262 MoleculeReadExtendedInfo(newmol, p, &buf);
267 GetCommandProcessor()->MarkAsSaved();
269 if (newmol->natoms > 1000)
270 newmol->mview->lineMode = 1;
271 if (TrackballGetModifyCount(newmol->mview->track) == 0)
272 MainView_resizeToFit(newmol->mview);
273 MoleculeCallback_notifyModification(newmol, 0);
274 SetUndoEnabled(true);
281 if (wxDocument::Revert()) {
282 MainViewCallback_selectTable(mol->mview, 0);
287 /* Override to intercept view creation for running script */
289 MyDocument::OnCreate(const wxString& path, long flags)
291 if (path.EndsWith(wxT(".rb")) || path.EndsWith(wxT(".mrb"))) {
292 wxGetApp().OnOpenFiles(path);
293 return false; /* This document will be deleted */
295 return wxDocument::OnCreate(path, flags);
300 MyDocument::OnImport(wxCommandEvent& event)
304 wxString desc, filter, ext;
306 /* File filter is built from MyDocManager information */
307 MyDocManager *docm = wxGetApp().DocManager();
308 for (i = 0; docm->GetDocumentDescriptionAtIndex(i, &desc, &filter, &ext); i++) {
309 if (filter.Contains(_T("*.*"))) {
313 if (wildcard != _T("")) {
314 wildcard += (_T("|"));
316 wildcard += (desc + _T(" (") + filter + _T(")|") + filter);
318 /* Insert Import-only file types before "All files" */
319 wildcard += _T("|AMBER mdcrd file (*.crd;*.mdcrd)|*.crd;*.mdcrd");
320 wildcard += _T("|DCD file (*.dcd)|*.dcd");
322 wildcard += (_T("|") + desc + _T(" (") + filter + _T(")|") + filter);
325 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Coordinate File"), _T(""), _T(""), wildcard, wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
326 if (dialog->ShowModal() == wxID_OK) {
327 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
329 MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "molload", p);
330 if (gLoadSaveErrorMessage != NULL)
331 MyAppCallback_showScriptMessage("On loading %s:\n%s\n", p, gLoadSaveErrorMessage);
339 MyDocument::OnExport(wxCommandEvent& event)
342 wxFileName fname(GetFilename());
344 GetPrintableName(fnstr);
346 /* File filter is built from MyDocManager information */
347 wxString desc, filter, ext;
349 MyDocManager *docm = wxGetApp().DocManager();
350 if ((i = fnstr.Find('.', true)) != wxNOT_FOUND) {
351 fnstr = fnstr.Mid(0, i);
353 for (i = 0; docm->GetDocumentDescriptionAtIndex(i, &desc, &filter, &ext); i++) {
354 if (ext == _T("mbsf") || ext == _T("out") || ext == _T("log") || ext == _T("fchk"))
356 if (filter.Contains(_T("*.*"))) {
360 if (wildcard != _T("")) {
361 wildcard += (_T("|"));
363 wildcard += (desc + _T(" (") + filter + _T(")|") + filter);
365 wildcard += _T("|AMBER mdcrd file (*.crd;*.mdcrd)|*.crd;*.mdcrd");
366 wildcard += _T("|DCD file (*.dcd)|*.dcd");
368 wildcard += (_T("|") + desc + _T(" (") + filter + _T(")|") + filter);
370 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Export coordinates"), fname.GetPath(), fnstr + _T(".psf"), wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxFD_CHANGE_DIR);
371 if (dialog->ShowModal() == wxID_OK) {
372 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
374 MolActionCallback_setUndoRegistrationEnabled(mol, 0);
375 MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "molsave", p);
376 MolActionCallback_setUndoRegistrationEnabled(mol, 1);
384 MyDocument::SetUndoEnabled(bool flag)
387 isUndoEnabled = true;
389 // Remove all registered actions
390 wxCommandProcessor *cmdProc = GetCommandProcessor();
391 currentCommand = NULL;
392 cmdProc->ClearCommands();
393 CleanUndoStack(false);
394 isUndoEnabled = false;
395 // TODO: mark the document as "edited"
400 MyDocument::PushUndoAction(MolAction *action)
402 if (countUndoStack % 8 == 0) {
403 if (undoStack == NULL)
404 undoStack = (MolAction **)malloc(sizeof(MolAction *) * 8);
406 undoStack = (MolAction **)realloc(undoStack, sizeof(MolAction *) * (countUndoStack + 8));
407 if (undoStack == NULL)
410 undoStack[countUndoStack++] = action;
411 MolActionRetain(action);
412 if (countUndoStack == 1) {
413 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_willNeedCleanUndoStack);
414 wxPostEvent(this, myEvent);
418 /* Update the modify flag to match the GetCommandProcessor isDirty flag
419 (Is this really necessary? It should be handled by wxDocument automatically. */
421 MyDocument::UpdateModifyFlag()
423 // printf("isDirty = %d\n", (GetCommandProcessor()->IsDirty()));
424 Modify(GetCommandProcessor()->IsDirty());
428 MyDocument::BeginUndoGrouping()
434 MyDocument::EndUndoGrouping()
436 if (undoGroupLevel <= 0)
437 return; /* This should not happen */
438 if (--undoGroupLevel == 0) {
439 if (isCleanUndoStackRequested) {
440 /* Resend the event so that it can be processed at the next idle time */
441 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_willNeedCleanUndoStack);
442 wxPostEvent(this, myEvent);
443 isCleanUndoStackRequested = false;
449 MyDocument::CleanUndoStack(bool shouldRegister)
451 if (undoStack != NULL) {
452 if (shouldRegister) {
453 MyCommand *cmd = (MyCommand *)currentCommand;
455 cmd = new MyCommand(mol);
457 cmd->SetRedoActions(undoStack, countUndoStack);
459 cmd->SetUndoActions(undoStack, countUndoStack);
460 if (currentCommand == NULL) {
461 if (!GetCommandProcessor()->Submit(cmd))
467 for (i = 0; i < countUndoStack; i++)
468 MolActionRelease(undoStack[i]);
475 currentCommand = NULL;
481 if (mol != NULL && mol->mutex != NULL) {
483 if (subThreadKind == 1)
485 else msg = "Some background process";
486 MyAppCallback_errorMessageBox("%s is running: please stop it before closing", msg);
489 if (wxDocument::Close()) {
490 /* Send a message that this document will close */
491 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_documentWillClose);
492 myEvent.SetEventObject(this);
493 ProcessEvent(myEvent);
499 MyDocument::OnNeedCleanUndoStack(wxCommandEvent& event)
501 if (undoGroupLevel == 0)
502 CleanUndoStack(true);
504 /* Do not respond to this event immediately; the same event will be
505 resent when undoGroupLevel becomes 0. See EndUndoGrouping(). */
506 isCleanUndoStackRequested = true;
511 MyDocument::OnDocumentModified(wxCommandEvent& event)
513 // printf("MyDocument::OnDocumentModified invoked\n");
514 isModifyNotificationSent = false;
515 MoleculeClearModifyCount(GetMainView()->mol);
517 event.Skip(); // Also pass to other notification handlers
522 MyDocument::OnCopy(wxCommandEvent& event)
524 wxWindow *focusWindow = wxWindow::FindFocus();
525 /* printf("focus window class = %ls\n", focusWindow->GetClassInfo()->GetClassName()); */
526 if (focusWindow->IsKindOf(CLASSINFO(wxTextCtrl))) {
530 if (focusWindow == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
531 MainView_copyOrCutParameters(GetMainView(), 2);
534 MainView_copy(GetMainView());
540 MyDocument::OnCut(wxCommandEvent& event)
542 wxWindow *focusWindow = wxWindow::FindFocus();
543 if (focusWindow->IsKindOf(CLASSINFO(wxTextCtrl))) {
547 if (focusWindow == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
548 MainView_copyOrCutParameters(GetMainView(), 3);
551 MainView_cut(GetMainView());
557 MyDocument::OnPaste(wxCommandEvent& event)
559 wxWindow *focusWindow = wxWindow::FindFocus();
560 if (focusWindow->IsKindOf(CLASSINFO(wxTextCtrl))) {
564 if (focusWindow == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
565 MainView_pasteParameters(GetMainView());
568 MainView_paste(GetMainView());
574 MyDocument::OnDelete(wxCommandEvent& event)
576 if (wxWindow::FindFocus() == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
577 MainView_copyOrCutParameters(GetMainView(), 1);
580 MainView_delete(GetMainView());
586 MyDocument::OnCreateNewAtom(wxCommandEvent &event)
590 IntGroup *ig = MoleculeGetSelection(mol);
591 MainView *mview = GetMainView();
597 /* Make an atom name "Cxxx" */
598 for (i = 0; i < 1000; i++) {
599 sprintf(name, "C%03d", i);
600 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
601 if (strncmp(ap->aname, name, 4) == 0)
604 if (j >= mol->natoms)
607 memset(&arec, 0, sizeof(arec));
608 strncpy(arec.aname, name, 4);
609 arec.type = AtomTypeEncodeToUInt("c3");
610 arec.element[0] = 'C';
611 arec.atomicNumber = 6;
612 arec.weight = WeightForAtomicNumber(6);
613 arec.occupancy = 1.0;
615 if (ig != NULL && IntGroupGetCount(ig) > 0) {
616 idx = IntGroupGetEndPoint(ig, IntGroupGetIntervalCount(ig) - 1);
621 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &arec, idx, &idx) != 0)
624 /* Show the atom table and select the newly created atom */
625 MainViewCallback_selectTable(mview, kMainViewAtomTableIndex);
626 ig = IntGroupNewWithPoints(idx, 1, -1);
627 MoleculeSetSelection(mol, ig);
629 MainView_refreshTable(mview);
630 row = MainView_indexToTableRow(mview, idx);
631 /* MainViewCallback_ensureVisible(mview, row); */ /* Invoked from startEditText */
632 MainViewCallback_startEditText(mview, row, 1);
636 MyDocument::OnCreatePiAnchor(wxCommandEvent &event)
639 MainView *mview = GetMainView();
640 IntGroup *ig = MoleculeGetSelection(mol), *ig2;
641 if (ig == NULL || IntGroupGetCount(ig) < 2)
642 return; /* Do nothing */
643 if (MolActionCreateAndPerform(mol, SCRIPT_ACTION("G;i"),
644 "proc { |g| create_pi_anchor('AN', atom_group(g) { |ap| ap.atomic_number != 1 }, nil, nil, g.max + 1).index rescue -1 }",
647 MainViewCallback_selectTable(mview, kMainViewAtomTableIndex);
648 ig2 = IntGroupNewWithPoints(idx, 1, -1);
649 MoleculeSetSelection(mol, ig2);
650 IntGroupRelease(ig2);
651 MainView_refreshTable(mview);
652 row = MainView_indexToTableRow(mview, idx);
653 MainViewCallback_ensureVisible(mview, row);
657 MyDocument::OnCreateNewParameter(wxCommandEvent &event)
659 int uid = event.GetId();
663 UInt ctype = AtomTypeEncodeToUInt("C");
664 Double cweight = WeightForAtomicNumber(6);
665 memset(&ubuf, 0, sizeof(ubuf));
666 ubuf.bond.src = -1; /* Undefined */
668 case myMenuID_CreateNewVdwParameter:
669 parType = kVdwParType;
670 ubuf.vdw.type1 = ctype;
671 ubuf.vdw.atomicNumber = 6;
672 ubuf.vdw.weight = cweight;
674 case myMenuID_CreateNewBondParameter:
675 parType = kBondParType;
676 ubuf.bond.type1 = ubuf.bond.type2 = ctype;
678 case myMenuID_CreateNewAngleParameter:
679 parType = kAngleParType;
680 ubuf.angle.type1 = ubuf.angle.type2 = ubuf.angle.type3 = ctype;
682 case myMenuID_CreateNewDihedralParameter:
683 parType = kDihedralParType;
684 ubuf.torsion.type1 = ubuf.torsion.type2 = ubuf.torsion.type3 = ubuf.torsion.type4 = ctype;
686 case myMenuID_CreateNewImproperParameter:
687 parType = kImproperParType;
688 ubuf.torsion.type1 = ubuf.torsion.type2 = ubuf.torsion.type3 = ubuf.torsion.type4 = ctype;
690 case myMenuID_CreateNewVdwPairParameter:
691 parType = kVdwPairParType;
692 ubuf.vdwp.type1 = ubuf.vdwp.type2 = ctype;
694 case myMenuID_CreateNewVdwCutoffParameter:
695 parType = kVdwCutoffParType;
696 ubuf.vdwcutoff.type1 = ubuf.vdwcutoff.type2 = ctype;
701 if (mol->par == NULL) {
703 if (MoleculePrepareMDArena(mol, 1, &errmsg) < 0) {
704 MyAppCallback_messageBox(errmsg, "MM/MD Setup Error", 1, 3);
709 n = ParameterGetCountForType(mol->par, parType);
710 ig = IntGroupNewWithPoints(n, 1, -1);
711 MolActionCreateAndPerform(mol, gMolActionAddParameters, parType, ig, 1, &ubuf);
712 if (ParameterGetCountForType(mol->par, parType) == n + 1) {
713 /* Successful creation of the parameter */
714 MainView *mview = GetMainView();
716 MainViewCallback_selectTable(mview, kMainViewParameterTableIndex);
717 MainView_refreshTable(mview);
718 row = ParameterTableGetRowFromTypeAndIndex(mol->par, parType, n);
719 MainViewCallback_startEditText(mview, row, 1);
724 MyDocument::OnSelectAll(wxCommandEvent& event)
726 if (wxWindow::FindFocus() == ((MoleculeView *)GetFirstView())->GetListCtrl() && mol->mview->tableIndex == kMainViewParameterTableIndex) {
729 MainView_selectAll(GetMainView());
735 MyDocument::OnSelectFragment(wxCommandEvent& event)
738 MainView_selectFragment(GetMainView());
743 MyDocument::OnSelectReverse(wxCommandEvent& event)
746 MainView_selectReverse(GetMainView());
751 MyDocument::OnAddHydrogen(wxCommandEvent& event)
753 int uid = event.GetId();
757 case myMenuID_AddHydrogenSp3: type = "td"; break;
758 case myMenuID_AddHydrogenSp2: type = "tr"; break;
759 case myMenuID_AddHydrogenLinear: type = "li"; break;
760 case myMenuID_AddHydrogenPyramidal: type = "py"; break;
761 case myMenuID_AddHydrogenBent: type = "be"; break;
765 ig = MoleculeGetSelection(mol);
766 MolActionCreateAndPerform(mol, SCRIPT_ACTION("Gs"), "add_hydrogen_on_group", ig, type);
771 MyDocument::OnFitToScreen(wxCommandEvent& event)
774 MainView_resizeToFit(GetMainView());
779 MyDocument::OnCenterSelection(wxCommandEvent& event)
782 MainView_centerSelection(GetMainView());
787 MyDocument::OnShowMenu(wxCommandEvent& event)
789 int uid = event.GetId();
790 if (mol == NULL || mol->mview == NULL)
793 case myMenuID_ShowUnitCell:
794 mol->mview->showUnitCell = !mol->mview->showUnitCell;
796 case myMenuID_ShowPeriodicBox:
797 mol->mview->showPeriodicBox = !mol->mview->showPeriodicBox;
799 case myMenuID_ShowHydrogens:
800 mol->mview->showHydrogens = !mol->mview->showHydrogens;
802 case myMenuID_ShowDummyAtoms:
803 mol->mview->showDummyAtoms = !mol->mview->showDummyAtoms;
805 case myMenuID_ShowExpandedAtoms:
806 mol->mview->showExpandedAtoms = !mol->mview->showExpandedAtoms;
808 case myMenuID_ShowEllipsoids:
809 mol->mview->showEllipsoids = !mol->mview->showEllipsoids;
811 case myMenuID_ShowRotationCenter:
812 mol->mview->showRotationCenter = !mol->mview->showRotationCenter;
815 MainViewCallback_setNeedsDisplay(mol->mview, 1);
819 MyDocument::OnShowAllAtoms(wxCommandEvent &event)
821 if (mol == NULL || mol->mview == NULL)
823 MoleculeShowAllAtoms(mol);
827 MyDocument::OnHideSelected(wxCommandEvent &event)
830 if (mol == NULL || mol->mview == NULL)
832 ig = MoleculeGetSelection(mol);
833 MoleculeHideAtoms(mol, ig);
837 MyDocument::OnHideUnselected(wxCommandEvent &event)
840 if (mol == NULL || mol->mview == NULL)
842 ig = MoleculeGetSelection(mol);
843 ig = IntGroupNewFromIntGroup(ig);
844 IntGroupReverse(ig, 0, mol->natoms);
845 MoleculeHideAtoms(mol, ig);
850 MyDocument::OnHideReverse(wxCommandEvent &event)
852 if (mol == NULL || mol->mview == NULL)
854 MoleculeShowReverse(mol);
858 MyDocument::OnShowGraphite(wxCommandEvent &event)
861 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_show_graphite");
866 MyDocument::OnToggleLineMode(wxCommandEvent &event)
868 mol->mview->lineMode = !mol->mview->lineMode;
869 MainViewCallback_setNeedsDisplay(mol->mview, 1);
872 /* Check whether subthread is running */
874 sCheckIsSubThreadRunning(Molecule *mol, int n)
876 if (mol->mutex != NULL) {
879 case 1: mes = "MM/MD is already running."; break;
880 case 2: mes = "Quantum chemistry calculation is already running."; break;
881 default: mes = "Some subprocess is already running."; break;
883 MyAppCallback_errorMessageBox(mes);
889 /* Run MD within a subthread */
891 sDoMolecularDynamics(void *argptr, int argnum)
893 MyDocument *doc = (MyDocument *)argptr;
894 Molecule *mol = doc->GetMolecule();
895 int count, minimize, i, r;
904 mol->arena->end_step = mol->arena->start_step;
905 md_main(mol->arena, minimize);
906 } else if (count > 0) {
907 wxCommandEvent insertFrameEvent(MyDocumentEvent, MyDocumentEvent_insertFrameFromMD);
908 for (i = 0; i < count; i++) {
910 mol->arena->end_step = mol->arena->start_step + mol->arena->coord_output_freq;
911 r = md_main(mol->arena, minimize);
914 if (mol->requestAbortThread)
917 /* Copy the coordinate to the ring buffer */
918 MDRing *ring = mol->arena->ring;
919 Vector *rp = ring->buf + ring->size * ring->next;
923 for (j = 0, ap = mol->arena->mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
926 if (j < ring->size) {
927 XtalCell *cp = mol->arena->mol->cell;
929 rp[j++] = cp->axes[0];
930 rp[j++] = cp->axes[1];
931 rp[j++] = cp->axes[2];
932 rp[j++] = cp->origin;
935 ring->next = (ring->next + 1) % ring->nframes;
936 if (ring->count < ring->nframes)
940 /* Create a new frame and copy the new coordinates */
941 /* MoleculeLock(mol);
942 ig = IntGroupNewWithPoints(MoleculeGetNumberOfFrames(mol), 1, -1);
943 MolActionCreateAndPerform(mol, gMolActionInsertFrames, ig, 0, NULL);
945 md_copy_coordinates_from_internal(mol->arena);
946 MoleculeUnlock(mol); */
948 if (minimize && mol->arena->minimize_complete) {
949 r = -2; /* Minimization complete */
952 wxPostEvent(doc, insertFrameEvent);
957 if (wxThread::This()->TestDestroy())
958 return 0; /* Abnormal termination */
961 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_threadTerminated);
962 wxPostEvent(doc, myEvent);
967 MyDocument::DoMDOrMinimize(int minimize)
971 if (sCheckIsSubThreadRunning(mol, subThreadKind))
974 /* Update the path information of the molecule before MD setup */
975 MoleculeCallback_pathName(mol, buf, sizeof buf);
976 MoleculeSetPath(mol, buf);
978 MolActionCreateAndPerform(mol, SCRIPT_ACTION("b;i"), "cmd_md", minimize, &n);
980 return; /* Canceled */
982 /* Check whether any bond/angle/torsion are very distant from the equilibrium values */
986 mol->mutex = new wxMutex;
989 mol->requestAbortThread = 0;
990 MoleculeCallback_disableModificationFromGUI(mol);
992 if (mol->mview != NULL && mol->mview->ref != NULL) {
993 ((MoleculeView *)(mol->mview->ref))->EnableProgressIndicator(true);
995 wxGetApp().EnableTimerForDocument(this);
997 MyThread::DetachNewThread(sDoMolecularDynamics, NULL, (void *)this, (minimize ? -n : n));
1001 MyDocument::OnMolecularDynamics(wxCommandEvent &event)
1007 MyDocument::OnMinimize(wxCommandEvent &event)
1013 MyDocument::OnStopMDRun(wxCommandEvent &event)
1015 if (mol != NULL && mol->mutex != NULL)
1016 mol->requestAbortThread = 1;
1020 MyDocument::OnInsertFrameFromMD(wxCommandEvent &event)
1022 Int i, j, n, old_nframes;
1026 /* Create new frame(s) and copy the new coordinates from the ring buffer */
1028 ring = mol->arena->ring;
1033 old_nframes = MoleculeGetNumberOfFrames(mol);
1034 /* It is more convenient to set cell parameter when inserting frames, whereas
1035 the coordinates can be set afterwards */
1036 if (ring->size > mol->natoms) {
1037 rp = (Vector *)calloc(sizeof(Vector) * 4, n);
1038 for (i = 0; i < n; i++) {
1039 j = ((ring->next - n + i + ring->nframes) % ring->nframes) * ring->size + mol->natoms;
1040 rp[i * 4] = ring->buf[j++];
1041 rp[i * 4 + 1] = ring->buf[j++];
1042 rp[i * 4 + 2] = ring->buf[j++];
1043 rp[i * 4 + 3] = ring->buf[j++];
1046 ig = IntGroupNewWithPoints(old_nframes, n, -1);
1047 MolActionCreateAndPerform(mol, gMolActionInsertFrames, ig, 0, NULL, (rp != NULL ? n * 4 : 0), rp);
1050 IntGroupRelease(ig);
1051 for (i = 0; i < n; i++) {
1052 MoleculeSelectFrame(mol, old_nframes + i, 1);
1053 rp = ring->buf + ((ring->next - n + i + ring->nframes) % ring->nframes) * ring->size;
1054 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap))
1058 mol->needsMDCopyCoordinates = 0; /* This flag needs to be negated because the coordinates come from the MD run */
1060 MoleculeUnlock(mol);
1064 MyDocument::OnUpdateDisplay(wxCommandEvent &event)
1066 MainView *mview = GetMainView();
1067 MainViewCallback_setNeedsDisplay(mview, 1);
1071 MyDocument::OnSubThreadTerminated(wxCommandEvent &event)
1073 if (mol != NULL && mol->mutex != NULL) {
1074 delete (wxMutex *)mol->mutex;
1076 mol->requestAbortThread = 0;
1080 if (mol->mview != NULL && mol->mview->ref != NULL) {
1081 ((MoleculeView *)(mol->mview->ref))->EnableProgressIndicator(false);
1084 wxGetApp().DisableTimerForDocument(this);
1086 if (mol->arena != NULL && mol->arena->errmsg[0] != 0)
1087 MyAppCallback_errorMessageBox("MD Error: %s", mol->arena->errmsg);
1089 MoleculeCallback_enableModificationFromGUI(mol);
1090 if (mol->mview != NULL && mol->mview->ref != NULL) {
1091 ((MoleculeView *)(mol->mview->ref))->InvalidateProgressIndicator();
1096 /* Run a subprocess asynchronically */
1098 MyDocument::RunSubProcess(const char *cmd, int (*callback)(Molecule *, int), int (*timerCallback)(Molecule *, int), FILE *output, FILE *errout)
1100 if (sCheckIsSubThreadRunning(mol, subThreadKind))
1101 return -1; /* subProcess (or MM/MD subThread) is already running */
1103 mol->mutex = new wxMutex;
1104 mol->requestAbortThread = 0;
1106 wxString cmdstr(cmd, WX_DEFAULT_CONV);
1107 subProcess = new wxProcess(this, -1);
1108 subProcess->Redirect();
1109 subProcessStdout = output;
1110 subProcessStderr = errout;
1112 subProcessPID = ::wxExecute(cmdstr, wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER, subProcess);
1113 if (subProcessPID == 0) {
1114 subProcess->Detach();
1116 delete (wxMutex *)(mol->mutex);
1119 return -2; /* Cannot start subProcess */
1122 if (mol->mview != NULL && mol->mview->ref != NULL) {
1123 ((MoleculeView *)(mol->mview->ref))->EnableProgressIndicator(true);
1126 mol->requestAbortThread = 0;
1127 MoleculeCallback_disableModificationFromGUI(mol);
1128 BeginUndoGrouping();
1129 wxGetApp().EnableTimerForDocument(this);
1130 endSubProcessCallback = callback;
1131 timerSubProcessCallback = timerCallback;
1133 return subProcessPID;
1137 MyDocument::FlushSubProcessOutput()
1139 wxInputStream *stream;
1142 if (subProcess == NULL)
1143 return; /* Do nothing */
1144 stream = subProcess->GetInputStream();
1145 if (subProcessStdout != NULL && stream != NULL && stream->CanRead()) {
1146 stream->Read(buf, sizeof buf - 1);
1147 len = stream->LastRead();
1150 if (subProcessStdout == (FILE *)1) {
1151 MyAppCallback_setConsoleColor(0);
1152 MyAppCallback_showScriptMessage("%s", buf);
1154 fwrite(buf, 1, len, subProcessStdout);
1158 stream = subProcess->GetErrorStream();
1159 if (subProcessStderr != NULL && stream != NULL && stream->CanRead()) {
1160 stream->Read(buf, sizeof buf - 1);
1161 len = stream->LastRead();
1164 if (subProcessStderr == (FILE *)1) {
1165 MyAppCallback_setConsoleColor(1);
1166 MyAppCallback_showScriptMessage("%s", buf);
1167 MyAppCallback_setConsoleColor(0);
1169 fwrite(buf, 1, len, subProcessStderr);
1176 MyDocument::OnEndSubProcess(wxProcessEvent &event)
1178 if (mol != NULL && mol->mutex != NULL) {
1180 FlushSubProcessOutput();
1181 if (subProcessStdout != NULL && subProcessStdout != (FILE *)1)
1182 fclose(subProcessStdout);
1183 if (subProcessStderr != NULL && subProcessStderr != (FILE *)1)
1184 fclose(subProcessStderr);
1185 subProcessStdout = subProcessStderr = NULL;
1187 delete (wxMutex *)mol->mutex;
1189 mol->requestAbortThread = 0;
1196 wxGetApp().DisableTimerForDocument(this);
1198 MoleculeCallback_enableModificationFromGUI(mol);
1199 if (mol->mview != NULL && mol->mview->ref != NULL) {
1200 ((MoleculeView *)(mol->mview->ref))->EnableProgressIndicator(false);
1202 if (endSubProcessCallback != NULL) {
1203 (*endSubProcessCallback)(mol, event.GetExitCode());
1204 endSubProcessCallback = NULL;
1206 timerSubProcessCallback = NULL;
1211 MyDocument::OnDefinePeriodicBox(wxCommandEvent &event)
1214 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_define_unit_cell");
1215 MoleculeUnlock(mol);
1219 MyDocument::OnShowPeriodicImage(wxCommandEvent &event)
1221 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_show_periodic_image");
1225 MyDocument::OnPressureControl(wxCommandEvent &event)
1228 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_pressure_control");
1229 MoleculeUnlock(mol);
1233 MyDocument::OnDefineSymmetry(wxCommandEvent &event)
1238 MyDocument::OnExpandBySymmetry(wxCommandEvent &event)
1243 sCreateTemporaryLogDirectoryForAC(const wxString& filename)
1249 /* Extract the name */
1250 wxFileName fname(filename);
1251 wxString name = fname.GetName();
1253 status = MyAppCallback_getGlobalSettingsWithType("antechamber.log_dir", 's', &log_dir);
1255 char *hdir = MyAppCallback_getDocumentHomeDir();
1256 asprintf(&log_dir, "%s/antechamber", (hdir ? hdir : ""));
1260 fix_dosish_path(log_dir);
1264 /* Prepare the log directory */
1265 wxString dirname(log_dir, wxConvFile);
1266 if (!wxFileName::Mkdir(dirname, 0777, wxPATH_MKDIR_FULL)) {
1267 MyAppCallback_errorMessageBox("Cannot create log directory '%s'", log_dir);
1269 return tdir; /* empty */
1273 for (i = 0; i < 1000; i++) {
1274 tdir = dirname + wxFileName::GetPathSeparator() + name + wxString::Format(_T("_%04d"), i);
1275 if (!wxFileName::DirExists(tdir))
1278 if (i >= 1000 || !wxFileName::Mkdir(tdir)) {
1279 MyAppCallback_errorMessageBox("Cannot create temporary files. Please make sure the log directory has enough space for writing.");
1286 sRemoveDirectoryRecursively(const wxString &dir)
1288 wxString name, file;
1289 wxArrayString files;
1293 /* The GetFirst/GetNext loop should not be mixed with ::wxRemoveFile or ::wxRmdir */
1295 if (wdir.GetFirst(&name)) {
1297 file = dir + wxFileName::GetPathSeparator() + name;
1300 } while (wdir.GetNext(&name));
1303 for (i = 0; i < n; i++) {
1305 if (wxDir::Exists(file)) {
1306 if (!sRemoveDirectoryRecursively(file))
1309 if (!::wxRemoveFile(file))
1313 return ::wxRmdir(dir);
1317 sEraseLogFiles(const wxString& tdir, int status)
1319 bool success = true;
1320 Int log_keep_number, n, i, j;
1324 if (MyAppCallback_getGlobalSettingsWithType("antechamber.log_level", 's', &log_level) != 0)
1326 if (MyAppCallback_getGlobalSettingsWithType("antechamber.log_keep_number", 'i', &log_keep_number) != 0)
1327 log_keep_number = 5;
1328 if (log_level == NULL || strcmp(log_level, "none") == 0 || (strcmp(log_level, "error_only") == 0 && status == 0)) {
1329 // Erase the present log
1330 if (!sRemoveDirectoryRecursively(tdir)) {
1334 } else if (strcmp(log_level, "latest") == 0) {
1335 wxString dirname = tdir.BeforeLast(wxFileName::GetPathSeparator());
1336 wxDir wdir(dirname);
1338 wxArrayString files;
1340 if (wdir.GetFirst(&name)) {
1342 wxString fullname = dirname + wxFileName::GetPathSeparator() + name;
1343 if (wxDir::Exists(fullname)) {
1344 files.Add(fullname);
1347 } while (wdir.GetNext(&name));
1349 if (n > log_keep_number) {
1350 // Sort directories by creation date
1351 struct temp_struct { time_t tm; int idx; } *tp;
1352 tp = (struct temp_struct *)malloc(sizeof(struct temp_struct) * n);
1353 for (i = 0; i < n; i++) {
1354 wxFileName fn(files[i], wxEmptyString);
1356 j = fn.GetTimes(NULL, NULL, &dt);
1357 tp[i].tm = dt.GetTicks();
1360 for (i = 0; i < n; i++) {
1361 struct temp_struct temp;
1363 for (j = i + 1; j < n; j++) {
1364 if (tp[j].tm < tp[k].tm)
1373 // Keep last log_keep_number and delete the rest
1374 for (i = 0; i < n - log_keep_number; i++) {
1375 if (!sRemoveDirectoryRecursively(files[tp[i].idx])) {
1377 dir2 = files[tp[i].idx];
1387 MyAppCallback_errorMessageBox("Error during deleting log file '%s'", (const char *)dir2.mb_str(wxConvFile));
1393 MyDocument::OnGuessUFFParameters(wxCommandEvent &event)
1395 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "guess_uff_parameters");
1399 MyDocument::OnInvokeAntechamber(wxCommandEvent &event)
1401 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_antechamber");
1402 MyAppCallback_showRubyPrompt();
1406 MyDocument::OnInvokeResp(wxCommandEvent &event)
1408 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_gamess_resp");
1412 MyDocument::OnCreateSanderInput(wxCommandEvent &event)
1414 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "export_prmtop");
1418 MyDocument::OnImportAmberFrcmod(wxCommandEvent &event)
1420 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_import_frcmod");
1424 MyDocument::OnCreateGamessInput(wxCommandEvent &event)
1426 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_create_gamess_input");
1430 MyDocument::OnCreateMOCube(wxCommandEvent &event)
1432 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_create_cube");
1436 MyDocument::OnUpdateUI(wxUpdateUIEvent& event)
1438 int uid = event.GetId();
1439 IntGroup *ig = MoleculeGetSelection(mol);
1440 Int nselected = (ig == NULL ? 0 : IntGroupGetCount(ig));
1441 // wxMenuItem *item = (wxMenuItem *)event.GetEventObject();
1449 case myMenuID_Import:
1452 case wxID_SELECTALL:
1455 case myMenuID_SelectFragment:
1456 event.Enable(nselected > 0);
1458 case myMenuID_SelectReverse:
1461 case myMenuID_CreatePiAnchor:
1462 event.Enable(nselected > 0);
1464 case myMenuID_AddHydrogenSp3:
1465 case myMenuID_AddHydrogenSp2:
1466 case myMenuID_AddHydrogenLinear:
1467 case myMenuID_AddHydrogenPyramidal:
1468 case myMenuID_AddHydrogenBent:
1469 event.Enable(nselected > 0);
1471 case myMenuID_FitToScreen:
1474 case myMenuID_ShowUnitCell:
1476 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showUnitCell != 0);
1478 case myMenuID_ShowPeriodicBox:
1480 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showPeriodicBox != 0);
1482 case myMenuID_ShowHydrogens:
1484 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showHydrogens != 0);
1486 case myMenuID_ShowDummyAtoms:
1488 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showDummyAtoms != 0);
1490 case myMenuID_ShowExpandedAtoms:
1492 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showExpandedAtoms != 0);
1494 case myMenuID_ShowEllipsoids:
1496 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showEllipsoids != 0);
1498 case myMenuID_ShowRotationCenter:
1500 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showRotationCenter != 0);
1502 case myMenuID_ShowAllAtoms:
1503 case myMenuID_HideReverse:
1504 event.Enable(mol->mview != NULL && mol->mview->countHidden > 0);
1506 case myMenuID_HideSelected:
1507 case myMenuID_HideUnselected:
1508 event.Enable(nselected > 0);
1510 case myMenuID_LineMode:
1512 event.Check(mol != NULL && mol->mview != NULL && mol->mview->lineMode != 0);
1514 case myMenuID_MolecularDynamics:
1515 case myMenuID_Minimize:
1516 case myMenuID_DefinePeriodicBox:
1517 case myMenuID_PressureControl:
1518 if (mol != NULL && mol->mutex == NULL)
1520 else event.Enable(false);
1522 case myMenuID_StopMDRun:
1523 if (mol != NULL && mol->mutex != NULL)
1525 else event.Enable(false);
1527 case myMenuID_ShowPeriodicImage:
1530 case myMenuID_RunAntechamber:
1531 case myMenuID_RunResp:
1532 case myMenuID_CreateSanderInput:
1533 case myMenuID_GuessUFFParameters:
1534 if (mol != NULL && mol->natoms > 0)
1536 else event.Enable(false);
1538 case myMenuID_CreateGamessInput:
1539 if (mol != NULL && mol->natoms > 0)
1541 else event.Enable(false);
1543 case myMenuID_CreateMOCube:
1544 if (mol == NULL || mol->bset == NULL || mol->bset->natoms == 0)
1545 event.Enable(false);
1554 MyDocument::TimerCallback(int timerCount)
1556 if (mol != NULL && mol->mview != NULL && mol->mview->ref != NULL) {
1557 ((MoleculeView *)(mol->mview->ref))->ProceedProgressIndicator();
1558 if (subProcess != NULL) {
1559 FlushSubProcessOutput();
1560 if (timerSubProcessCallback != NULL) {
1561 if ((*timerSubProcessCallback)(mol, timerCount) != 0)
1562 mol->requestAbortThread = 1;
1564 if (mol->requestAbortThread) {
1565 /* Try to terminate the subprocess gently */
1566 wxProcess::Kill(subProcessPID, wxSIGTERM, wxKILL_CHILDREN);
1572 #pragma mark ====== Plain C Interface ======
1575 MyDocumentFromMolecule(Molecule *mp)
1578 if (mp != NULL && mp->mview != NULL && (ref = mp->mview->ref) != NULL)
1579 return ((MoleculeView *)ref)->MolDocument();
1584 MoleculeCallback_openNewMolecule(const char *fname)
1587 MyDocManager *manager = wxGetApp().DocManager();
1588 if (fname == NULL || *fname == 0) {
1589 doc = manager->CreateDocument(wxT(""), wxDOC_NEW);
1591 wxString fnamestr(fname, wxConvFile);
1592 doc = manager->CreateDocument(fnamestr, wxDOC_SILENT);
1596 else return ((MyDocument *)doc)->GetMolecule();
1600 MoleculeCallback_notifyModification(Molecule *mp, int now_flag)
1602 MyDocument *doc = MyDocumentFromMolecule(mp);
1603 if (doc && !doc->isModifyNotificationSent) {
1604 doc->isModifyNotificationSent = true;
1605 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_documentModified);
1606 myEvent.SetEventObject(doc);
1608 doc->ProcessEvent(myEvent);
1610 wxPostEvent(doc, myEvent);
1616 sMoleculePasteboardType(const char *type)
1618 static NSMutableArray *array;
1622 array = [[NSMutableArray array] retain];
1623 str = [NSString stringWithUTF8String: type];
1624 idx = [array indexOfObject: str];
1625 if (idx == NSNotFound) {
1626 [array addObject: str];
1629 return [array objectAtIndex: idx];
1634 static wxDataObject *
1635 sMoleculePasteboardObjectOfType(const char *type, const void *data, int length)
1637 if (strcmp(type, "TEXT") == 0) {
1638 wxTextDataObject *tp = new wxTextDataObject();
1640 wxString str((const char *)data, WX_DEFAULT_CONV, length);
1645 MyClipboardData *dp = new MyClipboardData(type);
1647 dp->SetData(length, data);
1652 /* Write to pasteboard. NOTE: data must be a malloc'ed pointer and its ownership
1653 will be taken by the pasteboard. */
1655 MoleculeCallback_writeToPasteboard(const char *type, const void *data, int length)
1658 if (wxTheClipboard->Open()) {
1659 wxTheClipboard->SetData(sMoleculePasteboardObjectOfType(type, data, length));
1660 /* MyClipboardData *myData = new MyClipboardData();
1661 if (myData->SetData(length, data)) {
1662 wxTheClipboard->SetData(myData);
1666 wxTheClipboard->Close();
1673 MoleculeCallback_writeToPasteBoardInMultipleFormats(const char *type1, const void *data1, int length1, const char *type2, ...)
1679 MoleculeCallback_readFromPasteboard(const char *type, void **dptr, int *length)
1684 if (wxTheClipboard->Open()) {
1685 wxDataObject *dp = sMoleculePasteboardObjectOfType(type, NULL, 0);
1686 if (wxTheClipboard->GetData(*dp)) {
1687 if (strcmp(type, "TEXT") == 0) {
1688 wxTextDataObject *tp = (wxTextDataObject *)dp;
1689 wxString str = tp->GetText();
1690 const char *cp = str.mb_str(WX_DEFAULT_CONV);
1692 p = malloc(len + 1);
1694 strcpy((char *)p, cp);
1701 MyClipboardData *mp = (MyClipboardData *)dp;
1702 len = mp->GetDataSize();
1713 wxTheClipboard->Close();
1719 MoleculeCallback_isDataInPasteboard(const char *type)
1721 if (strcmp(type, "TEXT") == 0)
1722 return wxTheClipboard->IsSupported(wxDF_TEXT);
1724 MyClipboardData myData(type);
1725 return wxTheClipboard->IsSupported(myData.GetFormat());
1730 MoleculeCallback_currentMolecule(void)
1732 MainView *mview = MainViewCallback_activeView();
1739 MoleculeCallback_moleculeAtIndex(int idx)
1741 MainView *mview = MainViewCallback_viewWithTag(idx);
1748 MoleculeCallback_moleculeAtOrderedIndex(int idx)
1750 return MoleculeCallback_moleculeAtIndex(idx);
1754 MoleculeCallback_displayName(Molecule *mol, char *buf, int bufsize)
1756 MyDocument *doc = MyDocumentFromMolecule(mol);
1759 doc->GetPrintableName(fname);
1760 strncpy(buf, (const char*)fname.mb_str(wxConvFile), bufsize - 1);
1761 buf[bufsize - 1] = 0;
1768 MoleculeCallback_pathName(Molecule *mol, char *buf, int bufsize)
1770 MyDocument *doc = MyDocumentFromMolecule(mol);
1771 if (doc != NULL && doc->hasFile)
1772 MainViewCallback_getFilename(mol->mview, buf, bufsize);
1777 MoleculeCallback_setDisplayName(Molecule *mol, const char *name)
1779 MyDocument *doc = MyDocumentFromMolecule(mol);
1780 if (doc == NULL || doc->hasFile)
1781 return 1; /* Cannot change file-associated window title */
1782 wxString fname(name, wxConvFile);
1783 doc->SetTitle(fname);
1784 doc->GetFirstView()->OnChangeFilename();
1789 MoleculeCallback_lockMutex(void *mutex)
1791 ((wxMutex *)mutex)->Lock();
1795 MoleculeCallback_unlockMutex(void *mutex)
1797 ((wxMutex *)mutex)->Unlock();
1801 MoleculeCallback_disableModificationFromGUI(Molecule *mol)
1803 mol->dontModifyFromGUI = 1;
1804 if (mol->mview != NULL) {
1805 if (mol->mview->mode == kTrackballCreateMode || mol->mview->mode == kTrackballEraseMode) {
1806 MainView_setMode(mol->mview, kTrackballSelectionMode);
1807 MainViewCallback_selectMatrixCellForMode(mol->mview, kTrackballSelectionMode);
1809 MainViewCallback_enableToggleButton(mol->mview, kTrackballCreateMode, false);
1810 MainViewCallback_enableToggleButton(mol->mview, kTrackballEraseMode, false);
1815 MoleculeCallback_enableModificationFromGUI(Molecule *mol)
1817 mol->dontModifyFromGUI = 0;
1818 if (mol->mview != NULL) {
1819 MainViewCallback_enableToggleButton(mol->mview, kTrackballCreateMode, true);
1820 MainViewCallback_enableToggleButton(mol->mview, kTrackballEraseMode, true);
1825 MoleculeCallback_cannotModifyMoleculeDuringMDError(Molecule *mol)
1827 MyAppCallback_errorMessageBox("Cannot modify molecule during MD");
1831 MoleculeCallback_callSubProcessAsync(Molecule *mol, const char *cmd, int (*callback)(Molecule *, int), int (*timerCallback)(Molecule *, int), FILE *output, FILE *errout)
1833 MyDocument *doc = MyDocumentFromMolecule(mol);
1835 return doc->RunSubProcess(cmd, callback, timerCallback, output, errout);
1840 MolActionCallback_registerUndo(Molecule *mol, MolAction *action)
1842 MyDocument *doc = MyDocumentFromMolecule(mol);
1843 if (doc != NULL && doc->IsUndoEnabled())
1844 doc->PushUndoAction(action);
1848 MolActionCallback_setUndoRegistrationEnabled(Molecule *mol, int flag)
1850 MyDocument *doc = MyDocumentFromMolecule(mol);
1852 doc->SetUndoEnabled(flag);
1853 return (doc->IsUndoEnabled() ? 1 : 0);
1858 MolActionCallback_isUndoRegistrationEnabled(Molecule *mol)
1860 MyDocument *doc = MyDocumentFromMolecule(mol);
1861 if (doc != NULL && doc->IsUndoEnabled())