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(wxID_SELECTALL, MyDocument::OnSelectAll)
80 EVT_MENU(myMenuID_SelectFragment, MyDocument::OnSelectFragment)
81 EVT_MENU(myMenuID_SelectReverse, MyDocument::OnSelectReverse)
82 EVT_MENU(myMenuID_FitToScreen, MyDocument::OnFitToScreen)
83 EVT_MENU(myMenuID_CenterSelection, MyDocument::OnCenterSelection)
84 EVT_MENU(myMenuID_ShowUnitCell, MyDocument::OnShowMenu)
85 EVT_MENU(myMenuID_ShowPeriodicBox, MyDocument::OnShowMenu)
86 EVT_MENU(myMenuID_ShowHydrogens, MyDocument::OnShowMenu)
87 EVT_MENU(myMenuID_ShowDummyAtoms, MyDocument::OnShowMenu)
88 EVT_MENU(myMenuID_ShowExpandedAtoms, MyDocument::OnShowMenu)
89 EVT_MENU(myMenuID_ShowEllipsoids, MyDocument::OnShowMenu)
90 EVT_MENU(myMenuID_ShowRotationCenter, MyDocument::OnShowMenu)
91 EVT_MENU(myMenuID_ShowGraphite, MyDocument::OnShowGraphite)
92 EVT_MENU(myMenuID_LineMode, MyDocument::OnToggleLineMode)
93 EVT_MENU_RANGE(myMenuID_AddHydrogenSp3, myMenuID_AddHydrogenBent, MyDocument::OnAddHydrogen)
94 EVT_UPDATE_UI_RANGE(myMenuID_MyFirstMenuItem, myMenuID_MyLastMenuItem, MyDocument::OnUpdateUI)
95 EVT_MENU(myMenuID_MolecularDynamics, MyDocument::OnMolecularDynamics)
96 EVT_MENU(myMenuID_Minimize, MyDocument::OnMinimize)
97 EVT_MENU(myMenuID_StopMDRun, MyDocument::OnStopMDRun)
98 EVT_MENU(myMenuID_DefinePeriodicBox, MyDocument::OnDefinePeriodicBox)
99 EVT_MENU(myMenuID_ShowPeriodicImage, MyDocument::OnShowPeriodicImage)
100 EVT_MENU(myMenuID_PressureControl, MyDocument::OnPressureControl)
101 EVT_MENU(myMenuID_DefineSymmetry, MyDocument::OnDefineSymmetry)
102 EVT_MENU(myMenuID_ExpandBySymmetry, MyDocument::OnExpandBySymmetry)
103 EVT_MENU(myMenuID_RunAntechamber, MyDocument::OnInvokeAntechamber)
104 EVT_MENU(myMenuID_RunResp, MyDocument::OnInvokeResp)
105 EVT_MENU(myMenuID_CreateSanderInput, MyDocument::OnCreateSanderInput)
106 EVT_MENU(myMenuID_ImportAmberFrcmod, MyDocument::OnImportAmberFrcmod)
107 EVT_MENU(myMenuID_CreateGamessInput, MyDocument::OnCreateGamessInput)
108 EVT_MENU(myMenuID_CreateMOCube, MyDocument::OnCreateMOCube)
109 EVT_MENU(myMenuID_ShowAllAtoms, MyDocument::OnShowAllAtoms)
110 EVT_MENU(myMenuID_HideReverse, MyDocument::OnHideReverse)
111 EVT_MENU(myMenuID_HideSelected, MyDocument::OnHideSelected)
112 EVT_MENU(myMenuID_HideUnselected, MyDocument::OnHideUnselected)
115 MyDocument::MyDocument()
119 isUndoEnabled = true;
120 isModifyNotificationSent = false;
121 currentCommand = NULL;
125 isCleanUndoStackRequested = false;
130 MyDocument::~MyDocument()
134 MoleculeRelease(mol);
135 if (undoStack != NULL) {
136 for (i = 0; i < countUndoStack; i++)
137 MolActionRelease(undoStack[i]);
144 MyDocument::GetMainView()
146 MoleculeView *view = (MoleculeView *)GetFirstView();
154 MyDocument::SetMolecule(Molecule *aMolecule)
156 if (mol == aMolecule)
159 MoleculeRelease(mol);
161 if (aMolecule != NULL)
162 MoleculeRetain(aMolecule);
164 MoleculeView *view = (MoleculeView *)GetFirstView();
166 MainView_setMolecule(view->mview, aMolecule);
167 /* if (aMolecule->natoms >= 1000)
168 view->mview->lineMode = 1; */
173 MyDocument::DoSaveDocument(const wxString& file)
176 char *p = strdup((const char *)file.mb_str(wxConvFile));
177 size_t len = strlen(p);
180 if (MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "molsave", p) != 0) {
186 if (len > 4 && strcasecmp(p + len - 4, ".psf") == 0) {
187 /* Write as a psf and a pdb file */
188 strcpy(p + len - 4, ".pdb");
189 retval = MoleculeWriteToPdbFile(mol, p, buf, sizeof buf);
194 if (mol->cell != NULL) {
195 /* Write an extended info (bounding box) */
196 p = (char *)realloc(p, len + 2);
197 strcpy(p + len - 4, ".info");
198 retval = MoleculeWriteExtendedInfo(mol, p, buf, sizeof buf);
206 GetCommandProcessor()->MarkAsSaved();
210 return (retval == 0);
214 MyDocument::DoOpenDocument(const wxString& file)
219 p = strdup((const char *)file.mb_str(wxConvFile));
220 newmol = MoleculeNew();
222 MoleculeRelease(newmol);
223 SetUndoEnabled(false);
224 if (MolActionCreateAndPerform(newmol, SCRIPT_ACTION("s"), "molload", p) != 0) {
227 SetUndoEnabled(true);
231 if ((len = strlen(p)) > 4 && strcasecmp(p + len - 4, ".psf") == 0) {
232 // Look for a ".pdb" file with the same basename
234 strcpy(p + len - 4, ".pdb");
235 // The error will be ignored
236 MoleculeReadCoordinatesFromPdbFile(newmol, p, buf, sizeof buf);
237 // Look for an ".info" file with the same basename
238 p = (char *)realloc(p, len + 2);
239 strcpy(p + len - 4, ".info");
240 MoleculeReadExtendedInfo(newmol, p, buf, sizeof buf);
244 GetCommandProcessor()->MarkAsSaved();
246 if (newmol->natoms > 1000)
247 newmol->mview->lineMode = 1;
248 if (TrackballGetModifyCount(newmol->mview->track) == 0)
249 MainView_resizeToFit(newmol->mview);
250 MoleculeCallback_notifyModification(newmol, 0);
251 SetUndoEnabled(true);
256 MyDocument::OnImport(wxCommandEvent& event)
260 wxString desc, filter, ext;
262 /* File filter is built from MyDocManager information */
263 MyDocManager *docm = wxGetApp().DocManager();
264 for (i = 0; docm->GetDocumentDescriptionAtIndex(i, &desc, &filter, &ext); i++) {
265 if (filter.Contains(_T("*.*"))) {
269 if (wildcard != _T("")) {
270 wildcard += (_T("|"));
272 wildcard += (desc + _T(" (") + filter + _T(")|") + filter);
274 /* Insert Import-only file types before "All files" */
275 wildcard += _T("|AMBER mdcrd file (*.crd;*.mdcrd)|*.crd;*.mdcrd");
276 wildcard += _T("|DCD file (*.dcd)|*.dcd");
278 wildcard += (_T("|") + desc + _T(" (") + filter + _T(")|") + filter);
281 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Choose Coordinate File"), _T(""), _T(""), wildcard, wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST);
282 if (dialog->ShowModal() == wxID_OK) {
283 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
285 // MolActionCallback_setUndoRegistrationEnabled(mol, 0);
286 MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "molload", p);
287 // MolActionCallback_setUndoRegistrationEnabled(mol, 1);
295 MyDocument::OnExport(wxCommandEvent& event)
298 wxFileName fname(GetFilename());
300 GetPrintableName(fnstr);
302 /* File filter is built from MyDocManager information */
303 wxString desc, filter, ext;
305 MyDocManager *docm = wxGetApp().DocManager();
306 if ((i = fnstr.Find('.', true)) != wxNOT_FOUND) {
307 fnstr = fnstr.Mid(0, i);
309 for (i = 0; docm->GetDocumentDescriptionAtIndex(i, &desc, &filter, &ext); i++) {
310 if (ext == _T("mbsf") || ext == _T("out") || ext == _T("log") || ext == _T("fchk"))
312 if (filter.Contains(_T("*.*"))) {
316 if (wildcard != _T("")) {
317 wildcard += (_T("|"));
319 wildcard += (desc + _T(" (") + filter + _T(")|") + filter);
321 wildcard += _T("|AMBER mdcrd file (*.crd;*.mdcrd)|*.crd;*.mdcrd");
322 wildcard += _T("|DCD file (*.dcd)|*.dcd");
324 wildcard += (_T("|") + desc + _T(" (") + filter + _T(")|") + filter);
326 wxFileDialog *dialog = new wxFileDialog(NULL, _T("Export coordinates"), fname.GetPath(), fnstr + _T(".psf"), wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxFD_CHANGE_DIR);
327 if (dialog->ShowModal() == wxID_OK) {
328 char *p = strdup((const char *)(dialog->GetPath().mb_str(wxConvFile)));
330 MolActionCallback_setUndoRegistrationEnabled(mol, 0);
331 MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "molsave", p);
332 MolActionCallback_setUndoRegistrationEnabled(mol, 1);
340 MyDocument::SetUndoEnabled(bool flag)
343 isUndoEnabled = true;
345 // Remove all registered actions
346 wxCommandProcessor *cmdProc = GetCommandProcessor();
347 currentCommand = NULL;
348 cmdProc->ClearCommands();
349 CleanUndoStack(false);
350 isUndoEnabled = false;
351 // TODO: mark the document as "edited"
356 MyDocument::PushUndoAction(MolAction *action)
358 if (countUndoStack % 8 == 0) {
359 if (undoStack == NULL)
360 undoStack = (MolAction **)malloc(sizeof(MolAction *) * 8);
362 undoStack = (MolAction **)realloc(undoStack, sizeof(MolAction *) * (countUndoStack + 8));
363 if (undoStack == NULL)
366 undoStack[countUndoStack++] = action;
367 MolActionRetain(action);
368 if (countUndoStack == 1) {
369 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_willNeedCleanUndoStack);
370 wxPostEvent(this, myEvent);
374 /* Update the modify flag to match the GetCommandProcessor isDirty flag
375 (Is this really necessary? It should be handled by wxDocument automatically. */
377 MyDocument::UpdateModifyFlag()
379 // printf("isDirty = %d\n", (GetCommandProcessor()->IsDirty()));
380 Modify(GetCommandProcessor()->IsDirty());
384 MyDocument::BeginUndoGrouping()
390 MyDocument::EndUndoGrouping()
392 if (undoGroupLevel <= 0)
393 return; /* This should not happen */
394 if (--undoGroupLevel == 0) {
395 if (isCleanUndoStackRequested) {
396 /* Resend the event so that it can be processed at the next idle time */
397 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_willNeedCleanUndoStack);
398 wxPostEvent(this, myEvent);
399 isCleanUndoStackRequested = false;
405 MyDocument::CleanUndoStack(bool shouldRegister)
407 if (undoStack != NULL) {
408 if (shouldRegister) {
409 MyCommand *cmd = (MyCommand *)currentCommand;
411 cmd = new MyCommand(mol);
413 cmd->SetRedoActions(undoStack, countUndoStack);
415 cmd->SetUndoActions(undoStack, countUndoStack);
416 if (currentCommand == NULL) {
417 if (!GetCommandProcessor()->Submit(cmd))
423 for (i = 0; i < countUndoStack; i++)
424 MolActionRelease(undoStack[i]);
431 currentCommand = NULL;
437 if (mol != NULL && mol->mutex != NULL) {
439 if (subThreadKind == 1)
441 else msg = "Some background process";
442 MyAppCallback_errorMessageBox("%s is running: please stop it before closing", msg);
445 return wxDocument::Close();
449 MyDocument::OnNeedCleanUndoStack(wxCommandEvent& event)
451 if (undoGroupLevel == 0)
452 CleanUndoStack(true);
454 /* Do not respond to this event immediately; the same event will be
455 resent when undoGroupLevel becomes 0. See EndUndoGrouping(). */
456 isCleanUndoStackRequested = true;
461 MyDocument::OnDocumentModified(wxCommandEvent& event)
463 // printf("MyDocument::OnDocumentModified invoked\n");
464 isModifyNotificationSent = false;
465 MoleculeClearModifyCount(GetMainView()->mol);
467 event.Skip(); // Also pass to other notification handlers
472 MyDocument::OnCopy(wxCommandEvent& event)
474 wxWindow *focusWindow = wxWindow::FindFocus();
475 /* printf("focus window class = %ls\n", focusWindow->GetClassInfo()->GetClassName()); */
476 if (focusWindow->IsKindOf(CLASSINFO(wxTextCtrl))) {
480 if (focusWindow == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
481 MainView_copyOrCutParameters(GetMainView(), 2);
484 MainView_copy(GetMainView());
490 MyDocument::OnCut(wxCommandEvent& event)
492 wxWindow *focusWindow = wxWindow::FindFocus();
493 if (focusWindow->IsKindOf(CLASSINFO(wxTextCtrl))) {
497 if (focusWindow == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
498 MainView_copyOrCutParameters(GetMainView(), 3);
501 MainView_cut(GetMainView());
507 MyDocument::OnPaste(wxCommandEvent& event)
509 wxWindow *focusWindow = wxWindow::FindFocus();
510 if (focusWindow->IsKindOf(CLASSINFO(wxTextCtrl))) {
514 if (focusWindow == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
515 MainView_pasteParameters(GetMainView());
518 MainView_paste(GetMainView());
524 MyDocument::OnDelete(wxCommandEvent& event)
526 if (wxWindow::FindFocus() == ((MoleculeView *)GetFirstView())->GetListCtrl() && GetMainView()->tableIndex == kMainViewParameterTableIndex) {
527 MainView_copyOrCutParameters(GetMainView(), 1);
530 MainView_delete(GetMainView());
536 MyDocument::OnCreateNewAtom(wxCommandEvent &event)
540 IntGroup *ig = MoleculeGetSelection(mol);
541 MainView *mview = GetMainView();
547 /* Make an atom name "Cxxx" */
548 for (i = 0; i < 1000; i++) {
549 sprintf(name, "C%03d", i);
550 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
551 if (strncmp(ap->aname, name, 4) == 0)
554 if (j >= mol->natoms)
557 memset(&arec, 0, sizeof(arec));
558 strncpy(arec.aname, name, 4);
559 arec.type = AtomTypeEncodeToUInt("c3");
560 arec.element[0] = 'C';
561 arec.atomicNumber = 6;
562 arec.weight = WeightForAtomicNumber(6);
563 arec.occupancy = 1.0;
565 if (ig != NULL && IntGroupGetCount(ig) > 0) {
566 idx = IntGroupGetEndPoint(ig, IntGroupGetIntervalCount(ig) - 1);
571 if (MolActionCreateAndPerform(mol, gMolActionAddAnAtom, &arec, idx, &idx) != 0)
574 /* Show the atom table and select the newly created atom */
575 MainViewCallback_selectTable(mview, kMainViewAtomTableIndex);
576 ig = IntGroupNewWithPoints(idx, 1, -1);
577 MoleculeSetSelection(mol, ig);
579 MainView_refreshTable(mview);
580 row = MainView_indexToTableRow(mview, idx);
581 /* MainViewCallback_ensureVisible(mview, row); */ /* Invoked from startEditText */
582 MainViewCallback_startEditText(mview, row, 1);
586 MyDocument::OnCreateNewParameter(wxCommandEvent &event)
588 int uid = event.GetId();
592 UInt ctype = AtomTypeEncodeToUInt("C");
593 Double cweight = WeightForAtomicNumber(6);
594 memset(&ubuf, 0, sizeof(ubuf));
595 ubuf.bond.src = -1; /* Undefined */
597 case myMenuID_CreateNewVdwParameter:
598 parType = kVdwParType;
599 ubuf.vdw.type1 = ctype;
600 ubuf.vdw.atomicNumber = 6;
601 ubuf.vdw.weight = cweight;
603 case myMenuID_CreateNewBondParameter:
604 parType = kBondParType;
605 ubuf.bond.type1 = ubuf.bond.type2 = ctype;
607 case myMenuID_CreateNewAngleParameter:
608 parType = kAngleParType;
609 ubuf.angle.type1 = ubuf.angle.type2 = ubuf.angle.type3 = ctype;
611 case myMenuID_CreateNewDihedralParameter:
612 parType = kDihedralParType;
613 ubuf.torsion.type1 = ubuf.torsion.type2 = ubuf.torsion.type3 = ubuf.torsion.type4 = ctype;
615 case myMenuID_CreateNewImproperParameter:
616 parType = kImproperParType;
617 ubuf.torsion.type1 = ubuf.torsion.type2 = ubuf.torsion.type3 = ubuf.torsion.type4 = ctype;
619 case myMenuID_CreateNewVdwPairParameter:
620 parType = kVdwPairParType;
621 ubuf.vdwp.type1 = ubuf.vdwp.type2 = ctype;
623 case myMenuID_CreateNewVdwCutoffParameter:
624 parType = kVdwCutoffParType;
625 ubuf.vdwcutoff.n1 = ubuf.vdwcutoff.n2 = ctype;
630 if (mol->par == NULL) {
632 if (MoleculePrepareMDArena(mol, 1, &errmsg) < 0) {
633 MyAppCallback_messageBox(errmsg, "MM/MD Setup Error", 1, 3);
638 n = ParameterGetCountForType(mol->par, parType);
639 ig = IntGroupNewWithPoints(n, 1, -1);
640 MolActionCreateAndPerform(mol, gMolActionAddParameters, parType, ig, 1, &ubuf);
641 if (ParameterGetCountForType(mol->par, parType) == n + 1) {
642 /* Successful creation of the parameter */
643 MainView *mview = GetMainView();
645 MainViewCallback_selectTable(mview, kMainViewParameterTableIndex);
646 MainView_refreshTable(mview);
647 row = ParameterTableGetRowFromTypeAndIndex(mol->par, parType, n);
648 MainViewCallback_startEditText(mview, row, 1);
653 MyDocument::OnSelectAll(wxCommandEvent& event)
655 if (wxWindow::FindFocus() == ((MoleculeView *)GetFirstView())->GetListCtrl() && mol->mview->tableIndex == kMainViewParameterTableIndex) {
658 MainView_selectAll(GetMainView());
664 MyDocument::OnSelectFragment(wxCommandEvent& event)
667 MainView_selectFragment(GetMainView());
672 MyDocument::OnSelectReverse(wxCommandEvent& event)
675 MainView_selectReverse(GetMainView());
680 MyDocument::OnAddHydrogen(wxCommandEvent& event)
682 int uid = event.GetId();
686 case myMenuID_AddHydrogenSp3: type = "td"; break;
687 case myMenuID_AddHydrogenSp2: type = "tr"; break;
688 case myMenuID_AddHydrogenLinear: type = "li"; break;
689 case myMenuID_AddHydrogenPyramidal: type = "py"; break;
690 case myMenuID_AddHydrogenBent: type = "be"; break;
694 ig = MoleculeGetSelection(mol);
695 MolActionCreateAndPerform(mol, SCRIPT_ACTION("Gs"), "add_hydrogen_on_group", ig, type);
700 MyDocument::OnFitToScreen(wxCommandEvent& event)
703 MainView_resizeToFit(GetMainView());
708 MyDocument::OnCenterSelection(wxCommandEvent& event)
711 MainView_centerSelection(GetMainView());
716 MyDocument::OnShowMenu(wxCommandEvent& event)
718 int uid = event.GetId();
719 if (mol == NULL || mol->mview == NULL)
722 case myMenuID_ShowUnitCell:
723 mol->mview->showUnitCell = !mol->mview->showUnitCell;
725 case myMenuID_ShowPeriodicBox:
726 mol->mview->showPeriodicBox = !mol->mview->showPeriodicBox;
728 case myMenuID_ShowHydrogens:
729 mol->mview->showHydrogens = !mol->mview->showHydrogens;
731 case myMenuID_ShowDummyAtoms:
732 mol->mview->showDummyAtoms = !mol->mview->showDummyAtoms;
734 case myMenuID_ShowExpandedAtoms:
735 mol->mview->showExpandedAtoms = !mol->mview->showExpandedAtoms;
737 case myMenuID_ShowEllipsoids:
738 mol->mview->showEllipsoids = !mol->mview->showEllipsoids;
740 case myMenuID_ShowRotationCenter:
741 mol->mview->showRotationCenter = !mol->mview->showRotationCenter;
744 MainViewCallback_setNeedsDisplay(mol->mview, 1);
748 MyDocument::OnShowAllAtoms(wxCommandEvent &event)
750 if (mol == NULL || mol->mview == NULL)
752 MoleculeShowAllAtoms(mol);
756 MyDocument::OnHideSelected(wxCommandEvent &event)
759 if (mol == NULL || mol->mview == NULL)
761 ig = MoleculeGetSelection(mol);
762 MoleculeHideAtoms(mol, ig);
766 MyDocument::OnHideUnselected(wxCommandEvent &event)
769 if (mol == NULL || mol->mview == NULL)
771 ig = MoleculeGetSelection(mol);
772 ig = IntGroupNewFromIntGroup(ig);
773 IntGroupReverse(ig, 0, mol->natoms);
774 MoleculeHideAtoms(mol, ig);
779 MyDocument::OnHideReverse(wxCommandEvent &event)
781 if (mol == NULL || mol->mview == NULL)
783 MoleculeShowReverse(mol);
787 MyDocument::OnShowGraphite(wxCommandEvent &event)
790 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_show_graphite");
795 MyDocument::OnToggleLineMode(wxCommandEvent &event)
797 mol->mview->lineMode = !mol->mview->lineMode;
798 MainViewCallback_setNeedsDisplay(mol->mview, 1);
801 /* Check whether subthread is running */
803 sCheckIsSubThreadRunning(Molecule *mol, int n)
805 if (mol->mutex != NULL) {
808 case 1: mes = "MM/MD is already running."; break;
809 default: mes = "Some subprocess is already running."; break;
811 MyAppCallback_errorMessageBox(mes);
817 /* Run MD within a subthread */
819 sDoMolecularDynamics(void *argptr, int argnum)
821 MyDocument *doc = (MyDocument *)argptr;
822 Molecule *mol = doc->GetMolecule();
823 int count, minimize, i, r;
832 mol->arena->end_step = mol->arena->start_step;
833 md_main(mol->arena, minimize);
834 } else if (count > 0) {
835 wxCommandEvent insertFrameEvent(MyDocumentEvent, MyDocumentEvent_insertFrameFromMD);
836 for (i = 0; i < count; i++) {
838 mol->arena->end_step = mol->arena->start_step + mol->arena->coord_output_freq;
839 r = md_main(mol->arena, minimize);
842 if (mol->requestAbortThread)
845 /* Copy the coordinate to the ring buffer */
846 MDRing *ring = mol->arena->ring;
847 Vector *rp = ring->buf + ring->size * ring->next;
851 for (j = 0, ap = mol->arena->mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap)) {
854 if (j < ring->size) {
855 XtalCell *cp = mol->arena->mol->cell;
857 rp[j++] = cp->axes[0];
858 rp[j++] = cp->axes[1];
859 rp[j++] = cp->axes[2];
860 rp[j++] = cp->origin;
863 ring->next = (ring->next + 1) % ring->nframes;
864 if (ring->count < ring->nframes)
868 /* Create a new frame and copy the new coordinates */
869 /* MoleculeLock(mol);
870 ig = IntGroupNewWithPoints(MoleculeGetNumberOfFrames(mol), 1, -1);
871 MolActionCreateAndPerform(mol, gMolActionInsertFrames, ig, 0, NULL);
873 md_copy_coordinates_from_internal(mol->arena);
874 MoleculeUnlock(mol); */
876 if (minimize && mol->arena->minimize_complete) {
877 r = -2; /* Minimization complete */
880 wxPostEvent(doc, insertFrameEvent);
885 if (wxThread::This()->TestDestroy())
886 return 0; /* Abnormal termination */
889 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_threadTerminated);
890 wxPostEvent(doc, myEvent);
895 MyDocument::DoMDOrMinimize(int minimize)
898 if (sCheckIsSubThreadRunning(mol, subThreadKind))
900 MolActionCreateAndPerform(mol, SCRIPT_ACTION("b;i"), "cmd_md", minimize, &n);
902 return; /* Canceled */
904 /* Check whether any bond/angle/torsion are very distant from the equilibrium values */
908 mol->mutex = new wxMutex;
911 mol->requestAbortThread = 0;
912 MyThread::DetachNewThread(sDoMolecularDynamics, NULL, (void *)this, (minimize ? -n : n));
916 MyDocument::OnMolecularDynamics(wxCommandEvent &event)
922 MyDocument::OnMinimize(wxCommandEvent &event)
928 MyDocument::OnStopMDRun(wxCommandEvent &event)
930 if (mol != NULL && mol->mutex != NULL)
931 mol->requestAbortThread = 1;
935 MyDocument::OnInsertFrameFromMD(wxCommandEvent &event)
937 Int i, j, n, old_nframes;
941 /* Create new frame(s) and copy the new coordinates from the ring buffer */
943 ring = mol->arena->ring;
948 old_nframes = MoleculeGetNumberOfFrames(mol);
949 /* It is more convenient to set cell parameter when inserting frames, whereas
950 the coordinates can be set afterwards */
951 if (ring->size > mol->natoms) {
952 rp = (Vector *)calloc(sizeof(Vector) * 4, n);
953 for (i = 0; i < n; i++) {
954 j = ((ring->next - n + i + ring->nframes) % ring->nframes) * ring->size + mol->natoms;
955 rp[i * 4] = ring->buf[j++];
956 rp[i * 4 + 1] = ring->buf[j++];
957 rp[i * 4 + 2] = ring->buf[j++];
958 rp[i * 4 + 3] = ring->buf[j++];
961 ig = IntGroupNewWithPoints(old_nframes, n, -1);
962 MolActionCreateAndPerform(mol, gMolActionInsertFrames, ig, 0, NULL, (rp != NULL ? n * 4 : 0), rp);
966 for (i = 0; i < n; i++) {
967 MoleculeSelectFrame(mol, old_nframes + i, 1);
968 rp = ring->buf + ((ring->next - n + i + ring->nframes) % ring->nframes) * ring->size;
969 for (j = 0, ap = mol->atoms; j < mol->natoms; j++, ap = ATOM_NEXT(ap))
973 mol->needsMDCopyCoordinates = 0; /* This flag needs to be negated because the coordinates come from the MD run */
979 MyDocument::OnUpdateDisplay(wxCommandEvent &event)
981 MainView *mview = GetMainView();
982 MainViewCallback_setNeedsDisplay(mview, 1);
986 MyDocument::OnSubThreadTerminated(wxCommandEvent &event)
988 if (mol != NULL && mol->mutex != NULL) {
989 delete (wxMutex *)mol->mutex;
991 mol->requestAbortThread = 0;
995 if (mol->arena != NULL && mol->arena->errmsg[0] != 0)
996 MyAppCallback_errorMessageBox("MD Error: %s", mol->arena->errmsg);
1001 MyDocument::OnDefinePeriodicBox(wxCommandEvent &event)
1004 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_define_unit_cell");
1005 MoleculeUnlock(mol);
1009 MyDocument::OnShowPeriodicImage(wxCommandEvent &event)
1011 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_show_periodic_image");
1015 MyDocument::OnPressureControl(wxCommandEvent &event)
1018 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_pressure_control");
1019 MoleculeUnlock(mol);
1023 MyDocument::OnDefineSymmetry(wxCommandEvent &event)
1028 MyDocument::OnExpandBySymmetry(wxCommandEvent &event)
1033 sCreateTemporaryLogDirectoryForAC(const wxString& filename)
1039 /* Extract the name */
1040 wxFileName fname(filename);
1041 wxString name = fname.GetName();
1043 status = MyAppCallback_getGlobalSettingsWithType("antechamber.log_dir", 's', &log_dir);
1045 char *hdir = MyAppCallback_getDocumentHomeDir();
1046 asprintf(&log_dir, "%s/antechamber", (hdir ? hdir : ""));
1050 fix_dosish_path(log_dir);
1054 /* Prepare the log directory */
1055 wxString dirname(log_dir, wxConvFile);
1056 if (!wxFileName::Mkdir(dirname, 0777, wxPATH_MKDIR_FULL)) {
1057 MyAppCallback_errorMessageBox("Cannot create log directory '%s'", log_dir);
1059 return tdir; /* empty */
1063 for (i = 0; i < 1000; i++) {
1064 tdir = dirname + wxFileName::GetPathSeparator() + name + wxString::Format(_T("_%04d"), i);
1065 if (!wxFileName::DirExists(tdir))
1068 if (i >= 1000 || !wxFileName::Mkdir(tdir)) {
1069 MyAppCallback_errorMessageBox("Cannot create temporary files. Please make sure the log directory has enough space for writing.");
1076 sRemoveDirectoryRecursively(const wxString &dir)
1078 wxString name, file;
1079 wxArrayString files;
1083 /* The GetFirst/GetNext loop should not be mixed with ::wxRemoveFile or ::wxRmdir */
1085 if (wdir.GetFirst(&name)) {
1087 file = dir + wxFileName::GetPathSeparator() + name;
1090 } while (wdir.GetNext(&name));
1093 for (i = 0; i < n; i++) {
1095 if (wxDir::Exists(file)) {
1096 if (!sRemoveDirectoryRecursively(file))
1099 if (!::wxRemoveFile(file))
1103 return ::wxRmdir(dir);
1107 sEraseLogFiles(const wxString& tdir, int status)
1109 bool success = true;
1110 Int log_keep_number, n, i, j;
1114 if (MyAppCallback_getGlobalSettingsWithType("antechamber.log_level", 's', &log_level) != 0)
1116 if (MyAppCallback_getGlobalSettingsWithType("antechamber.log_keep_number", 'i', &log_keep_number) != 0)
1117 log_keep_number = 5;
1118 if (log_level == NULL || strcmp(log_level, "none") == 0 || (strcmp(log_level, "error_only") == 0 && status == 0)) {
1119 // Erase the present log
1120 if (!sRemoveDirectoryRecursively(tdir)) {
1124 } else if (strcmp(log_level, "latest") == 0) {
1125 wxString dirname = tdir.BeforeLast(wxFileName::GetPathSeparator());
1126 wxDir wdir(dirname);
1128 wxArrayString files;
1130 if (wdir.GetFirst(&name)) {
1132 wxString fullname = dirname + wxFileName::GetPathSeparator() + name;
1133 if (wxDir::Exists(fullname)) {
1134 files.Add(fullname);
1137 } while (wdir.GetNext(&name));
1139 if (n > log_keep_number) {
1140 // Sort directories by creation date
1141 struct temp_struct { time_t tm; int idx; } *tp;
1142 tp = (struct temp_struct *)malloc(sizeof(struct temp_struct) * n);
1143 for (i = 0; i < n; i++) {
1144 wxFileName fn(files[i], wxEmptyString);
1146 j = fn.GetTimes(NULL, NULL, &dt);
1147 tp[i].tm = dt.GetTicks();
1150 for (i = 0; i < n; i++) {
1151 struct temp_struct temp;
1153 for (j = i + 1; j < n; j++) {
1154 if (tp[j].tm < tp[k].tm)
1163 // Keep last log_keep_number and delete the rest
1164 for (i = 0; i < n - log_keep_number; i++) {
1165 if (!sRemoveDirectoryRecursively(files[tp[i].idx])) {
1167 dir2 = files[tp[i].idx];
1177 MyAppCallback_errorMessageBox("Error during deleting log file '%s'", (const char *)dir2.mb_str(wxConvFile));
1183 MyDocument::OnInvokeAntechamber(wxCommandEvent &event)
1185 char *ante_dir, buf[256];
1186 Int net_charge, i, n, calc_charge, use_residue;
1189 /* Find the ambertool directory */
1190 wxString ante = MyApp::FindResourcePath() + wxFileName::GetPathSeparator() + _T("amber11") + wxFileName::GetPathSeparator() + _T("bin");
1191 ante_dir = strdup(ante.mb_str(wxConvFile));
1192 fix_dosish_path(ante_dir);
1194 /* Ask for antechamber options and log directory */
1195 MolActionCreateAndPerform(mol, SCRIPT_ACTION(";i"), "cmd_antechamber", &n);
1199 if ((status = MyAppCallback_getGlobalSettingsWithType("antechamber.nc", 'i', &net_charge))
1200 || (status = MyAppCallback_getGlobalSettingsWithType("antechamber.calc_charge", 'i', &calc_charge))
1201 || (status = MyAppCallback_getGlobalSettingsWithType("antechamber.use_residue", 'i', &use_residue))) {
1202 Molby_showError(status);
1206 /* Prepare the log directory */
1207 wxString tdir = sCreateTemporaryLogDirectoryForAC(GetFilename());
1211 /* Move to the temporary directory and export the molecule as a pdb */
1212 wxString cwd = wxFileName::GetCwd();
1213 if (!wxFileName::SetCwd(tdir)) {
1214 MyAppCallback_errorMessageBox("Cannot move to the temporary directory '%s'", (const char *)tdir.mb_str(WX_DEFAULT_CONV));
1221 resno = (Int *)calloc(sizeof(Int), mol->natoms);
1222 resnames = (char *)calloc(sizeof(char), mol->natoms * 4);
1223 if (resno == NULL || resnames == NULL) {
1224 MyAppCallback_errorMessageBox("Cannot save current residue informations (out of memory)");
1228 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
1229 resno[i] = ap->resSeq;
1230 memmove(resnames + i * 4, ap->resName, 4);
1232 memmove(resnames + i * 4, "RES", 4);
1235 n = MoleculeWriteToPdbFile(mol, "mol.pdb", buf, sizeof(buf));
1237 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
1238 ap->resSeq = resno[i];
1239 memmove(ap->resName, resnames + i * 4, 4);
1245 MyAppCallback_errorMessageBox("PDB export error: %s", buf);
1246 wxFileName::SetCwd(cwd);
1252 /* Run antechamber and parmck */
1255 /* Set AMBERHOME environment variable if necessary */
1256 n = strlen(ante_dir);
1258 p = ante_dir + n - 3;
1259 if ((p[-1] == '\\' || p[-1] == '/') && (strcmp(p, "bin") == 0 || strcmp(p, "exe") == 0)) {
1263 snprintf(buf, sizeof buf, "%.*s", n, ante_dir);
1264 p = getenv("AMBERHOME");
1265 if (p == NULL || strcmp(p, buf) != 0) {
1266 asprintf(&p, "AMBERHOME=%s", buf);
1271 snprintf(buf, sizeof buf, "-nc %d -c bcc", net_charge);
1274 asprintf(&p, "\"%s/antechamber\" -i mol.pdb -fi pdb -o mol.ac -fo ac %s", ante_dir, buf);
1276 status = MyAppCallback_callSubProcess(p, "antechamber");
1278 asprintf(&p, "\"%s/parmchk\" -i mol.ac -f ac -o frcmod", ante_dir);
1279 status = MyAppCallback_callSubProcess(p, "parmchk");
1284 wxString acfile = tdir + wxFileName::GetPathSeparator() + _T("mol.ac");
1285 status = MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "import_ac", (const char *)acfile.mb_str(wxConvFile));
1287 MyAppCallback_errorMessageBox("Cannot import antechamber output.");
1291 if (calc_charge && status == 0) {
1292 wxString sqmfile = tdir + wxFileName::GetPathSeparator() + _T("sqm.out");
1293 if (wxFileName::FileExists(sqmfile)) {
1294 status = MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "import_sqmout", (const char *)sqmfile.mb_str(wxConvFile));
1296 MyAppCallback_errorMessageBox("Cannot import sqm output.");
1302 wxString frcmodfile = tdir + wxFileName::GetPathSeparator() + _T("frcmod");
1303 status = MolActionCreateAndPerform(mol, SCRIPT_ACTION("s"), "import_frcmod", (const char *)frcmodfile.mb_str(wxConvFile));
1305 MyAppCallback_errorMessageBox("Cannot import parmchk output.");
1309 wxFileName::SetCwd(cwd);
1311 /* Erase log files */
1312 sEraseLogFiles(tdir, status);
1315 ((MoleculeView *)GetFirstView())->GetListCtrl()->Update();
1316 MyAppCallback_messageBox("Antechamber succeeded.", "Success", 0, 0);
1318 MyAppCallback_showRubyPrompt();
1322 MyDocument::OnInvokeResp(wxCommandEvent &event)
1324 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_gamess_resp");
1328 MyDocument::OnCreateSanderInput(wxCommandEvent &event)
1330 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "export_prmtop");
1334 MyDocument::OnImportAmberFrcmod(wxCommandEvent &event)
1336 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_import_frcmod");
1340 MyDocument::OnCreateGamessInput(wxCommandEvent &event)
1342 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_create_gamess_input");
1346 MyDocument::OnCreateMOCube(wxCommandEvent &event)
1348 MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), "cmd_create_cube");
1352 MyDocument::OnUpdateUI(wxUpdateUIEvent& event)
1354 int uid = event.GetId();
1355 IntGroup *ig = MoleculeGetSelection(mol);
1356 Int nselected = (ig == NULL ? 0 : IntGroupGetCount(ig));
1357 // wxMenuItem *item = (wxMenuItem *)event.GetEventObject();
1365 case myMenuID_Import:
1368 case wxID_SELECTALL:
1371 case myMenuID_SelectFragment:
1372 event.Enable(nselected > 0);
1374 case myMenuID_SelectReverse:
1377 case myMenuID_AddHydrogenSp3:
1378 case myMenuID_AddHydrogenSp2:
1379 case myMenuID_AddHydrogenLinear:
1380 case myMenuID_AddHydrogenPyramidal:
1381 case myMenuID_AddHydrogenBent:
1382 event.Enable(nselected > 0);
1384 case myMenuID_FitToScreen:
1387 case myMenuID_ShowUnitCell:
1389 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showUnitCell != 0);
1391 case myMenuID_ShowPeriodicBox:
1393 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showPeriodicBox != 0);
1395 case myMenuID_ShowHydrogens:
1397 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showHydrogens != 0);
1399 case myMenuID_ShowDummyAtoms:
1401 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showDummyAtoms != 0);
1403 case myMenuID_ShowExpandedAtoms:
1405 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showExpandedAtoms != 0);
1407 case myMenuID_ShowEllipsoids:
1409 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showEllipsoids != 0);
1411 case myMenuID_ShowRotationCenter:
1413 event.Check(mol != NULL && mol->mview != NULL && mol->mview->showRotationCenter != 0);
1415 case myMenuID_ShowAllAtoms:
1416 case myMenuID_HideReverse:
1417 event.Enable(mol->mview != NULL && mol->mview->countHidden > 0);
1419 case myMenuID_HideSelected:
1420 case myMenuID_HideUnselected:
1421 event.Enable(nselected > 0);
1423 case myMenuID_LineMode:
1425 event.Check(mol != NULL && mol->mview != NULL && mol->mview->lineMode != 0);
1427 case myMenuID_MolecularDynamics:
1428 case myMenuID_Minimize:
1429 case myMenuID_DefinePeriodicBox:
1430 case myMenuID_PressureControl:
1431 if (mol != NULL && mol->mutex == NULL)
1433 else event.Enable(false);
1435 case myMenuID_StopMDRun:
1436 if (mol != NULL && mol->mutex != NULL)
1438 else event.Enable(false);
1440 case myMenuID_ShowPeriodicImage:
1443 case myMenuID_RunAntechamber:
1444 case myMenuID_RunResp:
1445 case myMenuID_CreateSanderInput:
1446 if (mol != NULL && mol->natoms > 0)
1448 else event.Enable(false);
1450 case myMenuID_CreateGamessInput:
1451 if (mol != NULL && mol->natoms > 0)
1453 else event.Enable(false);
1455 case myMenuID_CreateMOCube:
1456 if (mol == NULL || mol->bset == NULL || mol->bset->natoms == 0)
1457 event.Enable(false);
1465 #pragma mark ====== Plain C Interface ======
1468 MyDocumentFromMolecule(Molecule *mp)
1471 if (mp != NULL && mp->mview != NULL && (ref = mp->mview->ref) != NULL)
1472 return ((MoleculeView *)ref)->MolDocument();
1477 MoleculeCallback_openNewMolecule(const char *fname)
1479 MainView *mview = MainViewCallback_newFromFile(fname);
1486 MoleculeCallback_notifyModification(Molecule *mp, int now_flag)
1488 MyDocument *doc = MyDocumentFromMolecule(mp);
1489 if (doc && !doc->isModifyNotificationSent) {
1490 doc->isModifyNotificationSent = true;
1491 wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_documentModified);
1493 doc->ProcessEvent(myEvent);
1495 wxPostEvent(doc, myEvent);
1501 sMoleculePasteboardType(const char *type)
1503 static NSMutableArray *array;
1507 array = [[NSMutableArray array] retain];
1508 str = [NSString stringWithUTF8String: type];
1509 idx = [array indexOfObject: str];
1510 if (idx == NSNotFound) {
1511 [array addObject: str];
1514 return [array objectAtIndex: idx];
1519 static wxDataObject *
1520 sMoleculePasteboardObjectOfType(const char *type, const void *data, int length)
1522 if (strcmp(type, "TEXT") == 0) {
1523 wxTextDataObject *tp = new wxTextDataObject();
1525 wxString str((const char *)data, WX_DEFAULT_CONV, length);
1530 MyClipboardData *dp = new MyClipboardData(type);
1532 dp->SetData(length, data);
1537 /* Write to pasteboard. NOTE: data must be a malloc'ed pointer and its ownership
1538 will be taken by the pasteboard. */
1540 MoleculeCallback_writeToPasteboard(const char *type, const void *data, int length)
1543 if (wxTheClipboard->Open()) {
1544 wxTheClipboard->SetData(sMoleculePasteboardObjectOfType(type, data, length));
1545 /* MyClipboardData *myData = new MyClipboardData();
1546 if (myData->SetData(length, data)) {
1547 wxTheClipboard->SetData(myData);
1551 wxTheClipboard->Close();
1558 MoleculeCallback_writeToPasteBoardInMultipleFormats(const char *type1, const void *data1, int length1, const char *type2, ...)
1564 MoleculeCallback_readFromPasteboard(const char *type, void **dptr, int *length)
1569 if (wxTheClipboard->Open()) {
1570 wxDataObject *dp = sMoleculePasteboardObjectOfType(type, NULL, 0);
1571 if (wxTheClipboard->GetData(*dp)) {
1572 if (strcmp(type, "TEXT") == 0) {
1573 wxTextDataObject *tp = (wxTextDataObject *)dp;
1574 wxString str = tp->GetText();
1575 const char *cp = str.mb_str(WX_DEFAULT_CONV);
1577 p = malloc(len + 1);
1579 strcpy((char *)p, cp);
1586 MyClipboardData *mp = (MyClipboardData *)dp;
1587 len = mp->GetDataSize();
1598 wxTheClipboard->Close();
1604 MoleculeCallback_isDataInPasteboard(const char *type)
1606 if (strcmp(type, "TEXT") == 0)
1607 return wxTheClipboard->IsSupported(wxDF_TEXT);
1609 MyClipboardData myData(type);
1610 return wxTheClipboard->IsSupported(myData.GetFormat());
1615 MoleculeCallback_currentMolecule(void)
1617 MainView *mview = MainViewCallback_activeView();
1624 MoleculeCallback_moleculeAtIndex(int idx)
1626 MainView *mview = MainViewCallback_viewWithTag(idx);
1633 MoleculeCallback_moleculeAtOrderedIndex(int idx)
1635 return MoleculeCallback_moleculeAtIndex(idx);
1639 MoleculeCallback_displayName(Molecule *mol, char *buf, int bufsize)
1641 MyDocument *doc = MyDocumentFromMolecule(mol);
1644 doc->GetPrintableName(fname);
1645 strncpy(buf, (const char*)fname.mb_str(wxConvFile), bufsize - 1);
1646 buf[bufsize - 1] = 0;
1653 MoleculeCallback_pathName(Molecule *mol, char *buf, int bufsize)
1655 MyDocument *doc = MyDocumentFromMolecule(mol);
1656 if (doc != NULL && doc->hasFile)
1657 MainViewCallback_getFilename(mol->mview, buf, bufsize);
1662 MoleculeCallback_lockMutex(void *mutex)
1664 ((wxMutex *)mutex)->Lock();
1668 MoleculeCallback_unlockMutex(void *mutex)
1670 ((wxMutex *)mutex)->Unlock();
1674 MoleculeCallback_cannotModifyMoleculeDuringMDError(Molecule *mol)
1676 MyAppCallback_errorMessageBox("Cannot modify molecule during MD");
1680 MolActionCallback_registerUndo(Molecule *mol, MolAction *action)
1682 MyDocument *doc = MyDocumentFromMolecule(mol);
1683 if (doc != NULL && doc->IsUndoEnabled())
1684 doc->PushUndoAction(action);
1688 MolActionCallback_setUndoRegistrationEnabled(Molecule *mol, int flag)
1690 MyDocument *doc = MyDocumentFromMolecule(mol);
1692 doc->SetUndoEnabled(flag);
1693 return (doc->IsUndoEnabled() ? 1 : 0);
1698 MolActionCallback_isUndoRegistrationEnabled(Molecule *mol)
1700 MyDocument *doc = MyDocumentFromMolecule(mol);
1701 if (doc != NULL && doc->IsUndoEnabled())