MainFrame.py 13.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

''' 
Created on Apr 14, 2015

30
:author: Bachir Aoun, Gael Goret and Eric C. Pellegrini
31
32
'''

33
import collections
eric pellegrini's avatar
eric pellegrini committed
34
import operator
35
import os
36
37
38
39
40
import webbrowser

import wx
import wx.aui as aui

41
from MDANSE.__pkginfo__ import __version__, __revision__
42
from MDANSE import LOGGER, PLATFORM, REGISTRY
43
from MDANSE.Framework.Jobs.Converters.Converter import Converter
44
45
46
47

from MDANSE.App.GUI import DATA_CONTROLLER
from MDANSE.App.GUI.ControllerPanel import ControllerPanel
from MDANSE.App.GUI.DataTreePanel import DataTreePanel
48
from MDANSE.App.GUI.Icons import ICONS
49
from MDANSE.App.GUI.WorkingPanel import WorkingPanel
50
from MDANSE.App.GUI.PluginsTreePanel import PluginsTreePanel
51
52
53

class MainFrame(wx.Frame):

54
    def __init__(self, parent, title="MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments"):
55
56
57
58
59
        
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size = (1200,800))
  
        self.build_dialog()
        
60
        # Add some handlers to the loggers
61
        LOGGER.add_handler("console", REGISTRY['handler']['console'](self._panels["controller"].pages["logger"]), level="info")
62
        LOGGER.add_handler("dialog", REGISTRY['handler']['dialog'](), level="error")
63
64
65
66
67
68
69
70
71
        LOGGER.start()
                                
    def build_dialog(self):
        
        self.build_menu()
        
        self.build_toolbar()

        icon = wx.EmptyIcon()
72
        icon.CopyFromBitmap(ICONS["mdanse",32,32])
73
74
75
76
77
78
79
80
81
82
83
        self.SetIcon(icon) 
        
        # The main aui manager.
        self._mgr = aui.AuiManager(self)

        self._panels = {}
        self._panels["data"] = DataTreePanel(self)
        self._panels["plugins"] = PluginsTreePanel(self)
        self._panels["working"] = WorkingPanel(self)
        self._panels["controller"] = ControllerPanel(self)
        
84
85
86
87
88
89
        # Add the panes corresponding to the tree control and the notebook.
        paneInfo=aui.AuiPaneInfo()
        self._mgr.AddPane(self._panels["data"], paneInfo.Caption("Data").Name("data").Left().CloseButton(True).DestroyOnClose(False).MinSize((250,-1)))
        self._mgr.AddPane(self._panels["plugins"], paneInfo.Caption("Plugins").Name("plugins").Left().CloseButton(True).DestroyOnClose(False).MinSize((250,-1)))
        self._mgr.AddPane(self._panels["working"], paneInfo.Name("working").Center().CloseButton(False))
        self._mgr.AddPane(self._panels["controller"], paneInfo.Name("controller").Name("controller").Floatable().Right().Bottom().CloseButton(True).DestroyOnClose(False).MinSize((-1,120)))
90
91
92
93
94
95
96
97
98

        self._mgr.Update()

    def build_menu(self):
        
        self._mainMenu = wx.MenuBar()

        fileMenu = wx.Menu()
        loadDataItem = fileMenu.Append(wx.ID_ANY, 'Load data')
99
100
101
        fileMenu.AppendSeparator()
        converterMenu = wx.Menu()
        self._converters = {}
eric pellegrini's avatar
eric pellegrini committed
102
103
104
105
106
107
108

        converters = [job for job in REGISTRY["job"].values() if issubclass(job,Converter)]
        converters = sorted(converters, key = operator.attrgetter('label'))
        for job in converters:
            item = converterMenu.Append(wx.ID_ANY,job.label)
            self._converters[job.label] = job.type
            self.Bind(wx.EVT_MENU, self.on_open_converter, item)
109
110

        fileMenu.AppendMenu(wx.ID_ANY,'Trajectory converters',converterMenu)
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
        fileMenu.AppendSeparator()
        quitItem = fileMenu.Append(wx.ID_ANY, 'Quit')

        self._mainMenu.Append(fileMenu, 'File')

        viewMenu = wx.Menu()
        showDataTreeItem = viewMenu.Append(wx.ID_ANY, "Toggle data tree")
        showPluginsTreeItem = viewMenu.Append(wx.ID_ANY, "Toggle plugins tree")
        showControllerItem = viewMenu.Append(wx.ID_ANY, "Toggle controller")
        viewMenu.AppendSeparator()
        showToolbarItem = viewMenu.Append(wx.ID_ANY, "Toggle toolbar")

        self._mainMenu.Append(viewMenu, 'View')

        helpMenu = wx.Menu()
        aboutItem = helpMenu.Append(wx.ID_ANY, 'About')
        bugReportItem = helpMenu.Append(wx.ID_ANY, 'Bug report')
        self._mainMenu.Append(helpMenu, 'Help')

        self.SetMenuBar(self._mainMenu)

        self.Bind(wx.EVT_CLOSE, self.on_quit)
        
        self.Bind(wx.EVT_MENU, self.on_load_data, loadDataItem)
        self.Bind(wx.EVT_MENU, self.on_quit, quitItem)
        self.Bind(wx.EVT_MENU, self.on_about, aboutItem)
        self.Bind(wx.EVT_MENU, self.on_toggle_data_tree, showDataTreeItem)
        self.Bind(wx.EVT_MENU, self.on_toggle_plugins_tree, showPluginsTreeItem)
        self.Bind(wx.EVT_MENU, self.on_toggle_controller, showControllerItem)
        self.Bind(wx.EVT_MENU, self.on_toggle_toolbar, showToolbarItem)
        self.Bind(wx.EVT_MENU, self.on_bug_report, bugReportItem)

    def build_toolbar(self):
        
        self._toolbar = self.CreateToolBar()
                
147
148
149
        loadDataButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["load",32,32], 'Load a trajectory')
        databaseButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["periodic_table",32,32], 'Edit the MDANSE elements database')
        plotButton = self._toolbar.AddSimpleTool(wx.ID_ANY,ICONS["plot",32,32], 'Open MDANSE plotter')
150
        udButton = self._toolbar.AddSimpleTool(wx.ID_ANY,ICONS["user",32,32], 'Edit the user definitions')
151
        preferencesButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["preferences",32,32], 'Edit the preferences')
152
        registryButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["registry",32,32], 'Inspect MDANSE classes registry')
153
        apiButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["api",32,32], 'Open MDANSE API')
154
155
156
157
        websiteButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["web",32,32], 'Open MDANSE website')
        aboutButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["about",32,32], 'About MDANSE')
        bugButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["bug",32,32], 'Bug report')
        quitButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["quit",32,32], 'Quit MDANSE')
158
159
160
161
162
163
164
        
        self._toolbar.Realize()
        
        self.SetToolBar(self._toolbar)

        # The toolbar-related events handlers.
        self.Bind(wx.EVT_MENU, self.on_load_data, loadDataButton)
165
        self.Bind(wx.EVT_MENU, self.on_open_mdanse_elements_database, databaseButton)
166
167
        self.Bind(wx.EVT_MENU, self.on_start_plotter, plotButton)
        self.Bind(wx.EVT_MENU, self.on_set_preferences, preferencesButton)
168
169
        self.Bind(wx.EVT_MENU, self.on_open_user_definitions, udButton)
        self.Bind(wx.EVT_MENU, self.on_open_classes_registry, registryButton)
170
171
        self.Bind(wx.EVT_MENU, self.on_about, aboutButton)
        self.Bind(wx.EVT_MENU, self.on_quit, quitButton)
172
        self.Bind(wx.EVT_MENU, self.on_open_api, apiButton)
173
        self.Bind(wx.EVT_MENU, self.on_open_mdanse_url, websiteButton)
174
175
176
177
        self.Bind(wx.EVT_MENU, self.on_bug_report, bugButton)
                                                                    
    def load_data(self,typ,filename):
        
178
        data = REGISTRY["input_data"][typ](filename)
179
180
181
182
183

        DATA_CONTROLLER[data.filename] = data

    def on_about(self, event=None):
        
184
185
186
187
188
        if __revision__ is "undefined":
            rev=""
        else:
            rev=" (%s)" % __revision__
                        
189
        about_str = \
190
"""MDANSE version %s%s.
191

192
193
194
195
196
197
198
An interactive program for analyzing Molecular Dynamics simulations.

Authors:
\tEric C. Pellegrini
\tGael Goret
\tBachir Aoun
""" % (__version__,rev)
199
200
201
202
203
204
205
        
        d = wx.MessageDialog(self, about_str, 'About', style=wx.OK|wx.ICON_INFORMATION)
        d.ShowModal()
        d.Destroy()

    def on_bug_report(self, event=None):
        report_str = \
206
207
208
209
"""The version 1 of MDANSE is currently under testing.
In order to facilitate the integration of new features and bug fixes, please send pull request to: 

https://github.com/eurydyce/MDANSE/tree/master/MDANSE
210

211
for any other request, please send an email to:
212

213
\tpellegrini@ill.fr
214
\tgonzalezm@ill.fr
215
\tjohnson@ill.fr
216

217
or directly to the MDANSE mailing list:
218

219
220
\tmdanse@ill.fr
"""
221
222
223
224
225
        
        d = wx.MessageDialog(self, report_str, 'Bug report', style=wx.OK|wx.ICON_INFORMATION)
        d.ShowModal()
        d.Destroy()
        
226
227
228
229
230
231
232
233
    def on_open_classes_registry(self,event):
        
        from MDANSE.App.GUI.Framework.Plugins.RegistryViewerPlugin import RegistryViewerFrame
        
        f = RegistryViewerFrame(self)
        
        f.Show()

234
235
236
    def on_open_api(self, event):
        
        mainHTML = os.path.join(PLATFORM.api_path(),'MDANSE.html')
237

238
239
240
241
        if os.path.exists(mainHTML):
            webbrowser.open(mainHTML)
        else:
            LOGGER("Can not open MDANSE API. Maybe the documentation was not properly installed.", "error",['dialog'])
242
243
            
    def on_load_data(self, event=None):
244
245

        wildcards = collections.OrderedDict([kls.type, "%s (*.%s)|*.%s" % (kls.type,kls.extension,kls.extension)] for kls in REGISTRY["input_data"].values() if kls.extension is not None)
246
                
247
        dialog = wx.FileDialog ( None, message='Open data ...', wildcard="|".join(wildcards.values()), style=wx.OPEN)
248
249
250
251
252
253
        
        if dialog.ShowModal() == wx.ID_CANCEL:
            return ""
                
        idx = dialog.GetFilterIndex()
                                                
254
        dataType = wildcards.keys()[idx]
255
256
257
258
259
260
261
262
263
264
                        
        filename = dialog.GetPath()
        
        if not filename:
            return
        
        self.load_data(dataType,filename)
                
        LOGGER("Data %r successfully loaded" % filename, "info")
                                                            
265
266
267
    def on_open_user_definitions(self,event):
        
        from MDANSE.App.GUI.Framework.Plugins.UserDefinitionViewerPlugin import UserDefinitionViewerFrame
268
        
269
270
        f = UserDefinitionViewerFrame(self)
        f.Show()
271

272
    def on_open_converter(self,event):
273

274
275
276
277
278
279
280
281
282
283
284
        item = self.GetMenuBar().FindItemById(event.GetId())
        convLabel = item.GetText()
        
        from MDANSE.App.GUI.Framework.Plugins.JobPlugin import JobFrame
        
        f = JobFrame(self,self._converters[convLabel])
        f.Show()

    def on_open_mdanse_elements_database(self, event):

        from MDANSE.App.GUI.Framework.Plugins.PeriodicTablePlugin import PeriodicTableFrame
285
286
287
288
289
                
        f = PeriodicTableFrame(None)
        
        f.Show()

290
    def on_open_mdanse_url(self, event):
291

292
        webbrowser.open('https://github.com/eurydyce/MDANSE/tree/master/MDANSE')
293
294

    def on_quit(self, event=None):
295
        
296
297
298
299
300
301
        d = wx.MessageDialog(None, 'Do you really want to quit ?', 'Question', wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
        if d.ShowModal() == wx.ID_YES:
            self.Destroy()

    def on_set_preferences(self, event):

302
        from MDANSE.App.GUI.PreferencesSettingsDialog import PreferencesSettingsDialog
303
304
305
306
307
308
309
310
311
        
        d = PreferencesSettingsDialog(self)
        
        d.ShowModal()
        
        d.Destroy()
                                                                         
    def on_start_plotter(self, event = None):

312
        from MDANSE.App.GUI.Framework.Plugins.Plotter.PlotterPlugin import PlotterFrame
313
314
315
316
        
        f = PlotterFrame(None)
        
        f.Show()                                               
317
                
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    def on_toggle_controller(self, event=None):

        pane = self._mgr.GetPane("controller")        
        
        self.toggle_window(pane)

    def on_toggle_data_tree(self, event=None):

        pane = self._mgr.GetPane("data")        
        
        self.toggle_window(pane)
        
    def on_toggle_plugins_tree(self, event = None):
        
        pane = self._mgr.GetPane("plugins")
        
        self.toggle_window(pane)    

    def on_toggle_toolbar(self, event=None):

        if self.GetToolBar():
            self._toolbar.Hide()                                    
            self.SetToolBar(None)
        else:
            self.SetToolBar(self._toolbar)
            self._toolbar.Show()   
        
    @property
    def panels(self):
        return self._panels
        
    def toggle_window(self, window):
        
        if window.IsShown():
            window.Hide()
        else:
            window.Show()

        self._mgr.Update()
        
if __name__ == "__main__":
    
    app = wx.App(False)
    f = MainFrame(None)
    f.Show()
    app.MainLoop()