9 from Vispa.Main.Application
import Application
10 from Vispa.Main.Exceptions
import exception_traceback
11 from Vispa.Share.ThreadChain
import ThreadChain
12 from Vispa.Plugins.Browser.BrowserTabController
import BrowserTabController
13 from Vispa.Views.WidgetView
import WidgetView
14 from Vispa.Plugins.ConfigEditor.ConfigEditorBoxView
import ConfigEditorBoxView,ConnectionStructureView,SequenceStructureView
15 from Vispa.Gui.TextDialog
import TextDialog
18 from FWCore.GuiBrowsers.DOTExport
import DotExport
19 import_dotexport_error=
None
24 from Vispa.Plugins.EdmBrowser.EventContentDialog
import EventContentDialog
25 event_content_error=
None
30 from ToolDataAccessor
import ToolDataAccessor,ConfigToolBase,standardConfigDir
31 from ToolDialog
import ToolDialog
32 import_tools_error=
None
40 logging.debug(__name__ +
": __init__")
41 BrowserTabController.__init__(self, plugin)
48 self.setEditable(
False)
50 self.
_configMenu = self.plugin().application().createPluginMenu(
'&Config')
51 self.
_configToolBar = self.plugin().application().createPluginToolBar(
'&Config')
52 openEditorAction = self.plugin().application().createAction(
'&Open in custom editor', self.
openEditor,
"F6")
53 self._configMenu.addAction(openEditorAction)
54 chooseEditorAction = self.plugin().application().createAction(
'&Choose custom editor...', self.
chooseEditor,
"Ctrl+T")
55 self._configMenu.addAction(chooseEditorAction)
56 self._configMenu.addSeparator()
57 self.
_dumpAction = self.plugin().application().createAction(
'&Dump python config to single file...', self.
dumpPython,
"Ctrl+D")
65 self._configMenu.addSeparator()
72 """ Returns supported file type: py.
74 return [(
'py',
'Config file')]
75 staticSupportedFileTypes = staticmethod(staticSupportedFileTypes)
81 BrowserTabController.updateViewMenu(self)
86 logging.debug(__name__ +
": onCenterViewDoubleClicked()")
87 self.tab().treeView().
select(object)
88 self.onTreeViewSelected(object)
91 """ Fill the center view from an item in the TreeView and update it """
96 statusMessage = self.plugin().application().startWorking(
"Updating center view")
101 if self.
_thread !=
None and self._thread.isRunning():
102 self.dataAccessor().cancelOperations()
103 while self._thread.isRunning():
104 if not Application.NO_PROCESS_EVENTS:
105 QCoreApplication.instance().processEvents()
109 if self.currentCenterViewClassId() == self.plugin().viewClassId(ConnectionStructureView):
110 self.tab().centerView().setArrangeUsingRelations(
True)
111 if self.tab().centerView().checkNumberOfObjects():
112 if self.dataAccessor().isContainer(select):
113 self.
_thread = ThreadChain(self.dataAccessor().readConnections, [select]+self.dataAccessor().allChildren(select))
115 self.
_thread = ThreadChain(self.dataAccessor().readConnections, [select],
True)
116 while self._thread.isRunning():
117 if not Application.NO_PROCESS_EVENTS:
118 QCoreApplication.instance().processEvents()
119 self.tab().centerView().setConnections(self._thread.returnValue())
120 self.tab().centerView().setDataObjects(self.dataAccessor().nonSequenceChildren(select))
122 self.tab().centerView().setDataObjects([])
123 elif self.currentCenterViewClassId() == self.plugin().viewClassId(SequenceStructureView):
124 self.tab().centerView().setArrangeUsingRelations(
False)
125 self.tab().centerView().setDataObjects([select])
126 self.tab().centerView().setConnections({})
127 if (self.currentCenterViewClassId() == self.plugin().viewClassId(ConnectionStructureView)
or self.currentCenterViewClassId() == self.plugin().viewClassId(SequenceStructureView))
and \
129 if not self.dataAccessor().isContainer(select)
and self.currentCenterViewClassId() == self.plugin().viewClassId(ConnectionStructureView):
130 self.tab().centerView().
select(select,500)
132 self.tab().centerView().restoreSelection()
133 select = self.tab().centerView().
selection()
135 if self.tab().propertyView().dataObject() != select
and propertyView:
136 self.tab().propertyView().setDataObject(select)
138 if import_tools_error==
None and self.tab().editorSplitter():
140 self.plugin().application().stopWorking(statusMessage)
143 """ Shows plugin menus when user selects tab.
145 logging.debug(__name__ +
": activated()")
146 BrowserTabController.activated(self)
147 self.plugin().application().showPluginMenu(self.
_configMenu)
148 self.plugin().application().showPluginToolBar(self.
_configToolBar)
149 self._editorAction.setVisible(
not self.tab().editorSplitter())
150 if self.tab().editorSplitter():
151 self._applyPatToolAction.setVisible(self.dataAccessor().
process()!=
None)
152 self.tab().mainWindow().application().showZoomToolBar()
156 logging.debug(__name__ +
": openEditor")
157 selected_object = self.tab().propertyView().dataObject()
158 filename = self.dataAccessor().fullFilename(selected_object)
159 if self.
_editorName !=
"" and selected_object !=
None and os.path.exists(filename):
160 if os.path.expandvars(
"$CMSSW_RELEASE_BASE")
in filename:
161 QMessageBox.information(self.tab(),
"Opening readonly file...",
"This file is from $CMSSW_RELEASE_BASE and readonly")
163 command +=
" " + filename
168 """ Choose editor using FileDialog """
169 logging.debug(__name__ +
": chooseEditor")
170 if _editorName ==
"":
171 _editorName = str(QFileDialog.getSaveFileName(self.tab(),
"Choose editor", self.
_editorName,
"Editor (*)",
None , QFileDialog.DontConfirmOverwrite
or QFileDialog.DontResolveSymlinks))
172 if not os.path.exists(_editorName):
173 _editorName = os.path.basename(_editorName)
174 if _editorName !=
None and _editorName !=
"":
179 """ Dump python configuration to file """
180 logging.debug(__name__ +
": dumpPython")
183 logging.error(self.__class__.__name__ +
": dumpPython() - "+
"Cannot dump this config because it does not contain a 'process'.\nNote that only 'cfg' files contain a 'process'.")
184 self.plugin().application().errorMessage(
"Cannot dump this config because it does not contain a 'process'.\nNote that only 'cfg' files contain a 'process'.")
188 defaultname = os.path.splitext(self._filename)[0] +
"_dump" + os.path.splitext(self._filename)[1]
189 fileName = str(QFileDialog.getSaveFileName(self.tab(),
"Save python config...", defaultname,
"Python config (*.py)", filter))
193 if os.path.splitext(fileName)[1].upper().
strip(
".") == ext:
194 name = os.path.splitext(fileName)[0]
195 ext = os.path.splitext(fileName)[1].upper().
strip(
".")
196 text_file =
open(name +
"." + ext.lower(),
"w")
197 text_file.write(dump)
201 """ Show config history """
202 logging.debug(__name__ +
": history")
203 history = self.dataAccessor().
history()
205 logging.error(self.__class__.__name__ +
": history() - "+
"Cannot show config history because it does not contain a 'process'.\nNote that only 'cfg' files contain a 'process'.")
206 self.plugin().application().errorMessage(
"Cannot show config history because it does not contain 'process'.\nNote that only 'cfg' files contain a 'process'.")
208 dialog=TextDialog(self.tab(),
"Configuration history", history,
True,
"This window lists the parameter changes and tools applied in this configuration file before it was loaded into ConfigEditor.")
212 """ Open event content dialog """
213 logging.debug(__name__ +
": eventContent")
214 if event_content_error!=
None:
215 logging.error(__name__ +
": Could not import EventContentDialog: "+event_content_error[1])
216 self.plugin().application().errorMessage(
"Could not import EventContentDialog (see logfile for details):\n"+event_content_error[0])
218 dialog=EventContentDialog(self.tab(),
"This dialog let's you check if the input needed by your configuration file is in a dataformat or edm root file. You can compare either to a dataformat definition from a txt file (e.g. RECO_3_3_0) or any edm root file by selecting an input file.\n\nBranches that are used as input by your configuration but not present in the dataformat or file are marked in red.\nBranches that are newly created by your configuration are marked in green.")
219 dialog.setConfigDataAccessor(self.dataAccessor())
223 """ read options from ini """
224 ini = self.plugin().application().ini()
225 if ini.has_option(
"config",
"editor"):
226 self.
_editorName = str(ini.get(
"config",
"editor"))
229 if ini.has_option(
"config",
"CurrentView"):
230 proposed_view = ini.get(
"config",
"CurrentView")
232 proposed_view = self.plugin().viewClassId(ConnectionStructureView)
233 self.switchCenterView(proposed_view)
234 if ini.has_option(
"config",
"box content script")
and isinstance(self.centerView(),ConfigEditorBoxView):
235 self.centerView().setBoxContentScript(str(ini.get(
"config",
"box content script")))
236 self._boxContentDialog.setScript(str(ini.get(
"config",
"box content script")))
239 BrowserTabController.scriptChanged(self, script)
243 """ write options to ini """
244 ini = self.plugin().application().ini()
245 if not ini.has_section(
"config"):
246 ini.add_section(
"config")
248 if self.currentCenterViewClassId():
249 ini.set(
"config",
"CurrentView", self.currentCenterViewClassId())
250 if isinstance(self.centerView(),ConfigEditorBoxView):
251 ini.set(
"config",
"box content script", self.centerView().boxContentScript())
252 self.plugin().application().writeIni()
255 if import_dotexport_error!=
None:
256 logging.error(__name__ +
": Could not import DOTExport: "+import_dotexport_error[1])
257 self.plugin().application().errorMessage(
"Could not import DOTExport (see logfile for details):\n"+import_dotexport_error[0])
260 if self.currentCenterViewClassId() == self.plugin().viewClassId(ConnectionStructureView):
261 presets = {
'seqconnect':
False,
'tagconnect':
True,
'seq':
False,
'services':
False,
'es':
False,
'endpath':
True,
'source':
True,
'legend':
False}
263 presets = {
'seqconnect':
True,
'tagconnect':
False,
'seq':
True,
'services':
False,
'es':
False,
'endpath':
True,
'source':
True,
'legend':
False}
264 for opt, val
in presets.items():
265 dot.setOption(opt, val)
267 for ft
in dot.file_types:
270 types += ft.upper() +
" File (*." + ft.lower() +
")"
271 filter = QString(
"PDF File (*.pdf)")
273 defaultname = os.path.splitext(self._filename)[0] +
"_export"
274 fileName = str(QFileDialog.getSaveFileName(self.tab(),
"Export dot graphic...", defaultname, types, filter))
277 ext = str(filter).
split(
" ")[0].lower()
278 if os.path.splitext(fileName)[1].lower().
strip(
".")
in dot.file_types:
279 name = os.path.splitext(fileName)[0]
280 ext = os.path.splitext(fileName)[1].lower().
strip(
".")
282 dot.export(self.dataAccessor(), name +
"." + ext, ext)
285 dot.export(self.dataAccessor(), name +
".dot",
"dot")
286 logging.error(self.__class__.__name__ +
": exportDot() - "+
"'dot' executable not found which is needed for conversion to '*." + ext +
"'. Created '*.dot' file instead.")
287 self.plugin().application().errorMessage(
"'dot' executable not found which is needed for conversion to '*." + ext +
"'. Created '*.dot' file instead.")
289 logging.error(self.__class__.__name__ +
": exportDot() - "+
"Could not export dot graphic (see logfile for details): " + str(e))
290 self.plugin().application().errorMessage(
"Could not export dot graphic: " +
exception_traceback())
293 """ Reads in the file in a separate thread.
296 if self.dataAccessor().
open(filename):
297 self._dumpAction.setEnabled(self.dataAccessor().
process()!=
None)
298 self._historyAction.setEnabled(self.dataAccessor().
process()!=
None)
299 self._eventContentAction.setEnabled(self.dataAccessor().
process()!=
None)
300 self._editorAction.setEnabled(self.dataAccessor().
process()!=
None)
301 if self.plugin().application().commandLineOptions().saveimage:
302 self.tab().centerView().updateConnections()
303 self.saveImage(self.plugin().application().commandLineOptions().saveimage)
304 print "Saved image to", self.plugin().application().commandLineOptions().saveimage,
"."
310 logging.debug(__name__ +
': save')
313 if os.path.basename(filename) == os.path.basename(self.dataAccessor().
configFile()):
314 logging.error(self.__class__.__name__ +
": save() - "+
"Cannot use name of original configuration file: "+str(filename))
315 self.plugin().application().errorMessage(
"Cannot use name of original configuration file.")
316 elif BrowserTabController.save(self, filename):
317 self.dataAccessor().setIsReplaceConfig()
321 elif self.dataAccessor().isReplaceConfig():
322 return BrowserTabController.save(self, filename)
323 return self.tab().mainWindow().application().saveFileAsDialog()
326 """ Write replace config file.
328 logging.debug(__name__ +
': writeFile')
330 text_file =
open(filename,
"w")
332 if self.dataAccessor().
process():
333 text_file.write(self.dataAccessor().
process().dumpHistory(
False))
337 def open(self, filename=None, update=True):
338 if BrowserTabController.open(self, filename, update):
339 if self.dataAccessor().isReplaceConfig():
345 logging.debug(__name__ +
": startEditMode")
346 if import_tools_error!=
None:
347 logging.error(__name__ +
": Could not import tools for ConfigEditor: "+import_tools_error[1])
348 self.plugin().application().errorMessage(
"Could not import tools for ConfigEditor (see logfile for details):\n"+import_tools_error[0])
350 if self.tab().editorSplitter():
352 if self._filename
and not self.dataAccessor().
process():
353 logging.error(__name__ +
": Config does not contain a process and cannot be edited using ConfigEditor.")
354 self.plugin().application().errorMessage(
"Config does not contain a process and cannot be edited using ConfigEditor.")
356 if self._filename
and not self.dataAccessor().isReplaceConfig():
357 self.setFilename(
None)
359 self.tab().createEditor()
360 self.setEditable(
True)
372 self._toolDataAccessor.setConfigDataAccessor(self.dataAccessor())
374 self.connect(self.tab().editorTableView(), SIGNAL(
'importButtonClicked'), self.
importButtonClicked)
375 self.connect(self.tab().editorTableView(), SIGNAL(
'applyButtonClicked'), self.
applyButtonClicked)
376 self.connect(self.tab().editorTableView(), SIGNAL(
'removeButtonClicked'), self.
removeButtonClicked)
377 self.connect(self.tab().editorTableView(), SIGNAL(
'selected'), self.
codeSelected)
378 self.connect(self.tab().propertyView(), SIGNAL(
'valueChanged'), self.
valueChanged)
385 if self.tab().originalButton().isChecked():
387 self.tab().minimizeButton().setChecked(
True)
388 self.tab().originalButton().setChecked(
False)
389 self.tab().maximizeButton().setChecked(
False)
390 self.tab().verticalSplitter().setSizes([100, 1, 0])
393 self.tab().minimizeButton().setChecked(
False)
394 self.tab().originalButton().setChecked(
True)
395 self.tab().maximizeButton().setChecked(
False)
399 if self.tab().originalButton().isChecked():
401 self.tab().minimizeButton().setChecked(
False)
402 self.tab().originalButton().setChecked(
False)
403 self.tab().maximizeButton().setChecked(
True)
404 self.tab().verticalSplitter().setSizes([0, 1, 100])
407 logging.debug(__name__ +
": _updateCode")
408 self.tab().propertyView().setEnabled(
False)
410 self.tab().editorTableView().setDataObjects(self.
toolDataAccessor().topLevelObjects())
412 self.tab().editorTableView().restoreSelection()
414 self.tab().propertyView().setEnabled(
True)
417 logging.debug(__name__ +
": importConfig")
418 statusMessage = self.plugin().application().startWorking(
"Import python configuration in Editor")
420 good=self.
open(filename,
False)
423 self.plugin().application().errorMessage(
"Could not open configuration file (see log file for details).")
424 self.plugin().application().stopWorking(statusMessage,
"failed")
427 logging.error(__name__ +
": Could not open configuration file.")
428 self.plugin().application().errorMessage(
"Could not open configuration file.")
429 self.plugin().application().stopWorking(statusMessage,
"failed")
431 if not self.dataAccessor().
process():
432 logging.error(__name__ +
": Config does not contain a process and cannot be edited using ConfigEditor.")
433 self.plugin().application().errorMessage(
"Config does not contain a process and cannot be edited using ConfigEditor.")
434 self.plugin().application().stopWorking(statusMessage,
"failed")
436 if self._filename
and not self.dataAccessor().isReplaceConfig():
437 self.setFilename(
None)
440 self.tab().propertyView().setDataObject(
None)
442 self._applyPatToolAction.setVisible(
True)
443 self.plugin().application().stopWorking(statusMessage)
450 self.tab().centerView().highlight([])
453 logging.debug(__name__ +
": importButtonClicked")
454 filename = QFileDialog.getOpenFileName(
455 self.tab(),
'Select a configuration file',standardConfigDir,
"Python configuration (*.py)")
456 if not filename.isEmpty():
460 logging.debug(__name__ +
": applyButtonClicked")
464 if not self._toolDialog.exec_():
468 self.setModified(
True)
470 self.tab().editorTableView().
select(self.tab().editorTableView().dataObjects()[-2])
471 self.
codeSelected(self.tab().editorTableView().dataObjects()[-2])
474 logging.debug(__name__ +
": removeButtonClicked")
475 if not object
or not self.dataAccessor().
process()
or\
476 self._toolDataAccessor.label(object)
in [
"Import",
"ApplyTool"]:
479 self.plugin().application().errorMessage(
"Could not apply tool. See log file for details.")
481 self.setModified(
True)
483 self.tab().editorTableView().
select(self.tab().editorTableView().dataObjects()[-1])
484 self.
codeSelected(self.tab().editorTableView().dataObjects()[-1])
488 BrowserTabController.onSelected(self, select)
491 self.tab().propertyView().setDataObject(
None)
492 BrowserTabController.refresh(self)
495 if import_tools_error==
None and isinstance(object,ConfigToolBase):
498 self.tab().propertyView().setDataAccessor(self.dataAccessor())
499 BrowserTabController.updateContent(self, filtered, propertyView)
503 BrowserTabController.select(self, object)
506 if import_tools_error==
None and isinstance(object,ConfigToolBase):
509 self.tab().propertyView().setDataAccessor(self.dataAccessor())
512 if self.tab().propertyView().dataObject() != select:
513 statusMessage = self.plugin().application().startWorking(
"Updating property view")
515 self.tab().propertyView().setDataObject(select)
517 self.plugin().application().stopWorking(statusMessage)
521 if isinstance(self.tab().propertyView().dataObject(),ConfigToolBase):
522 if self._toolDataAccessor.label(self.tab().propertyView().dataObject())==
"Import":
523 filename=self.
toolDataAccessor().propertyValue(self.tab().propertyView().dataObject(),
"filename")
527 self.setModified(
True)
def updateConfigHighlight
def staticSupportedFileTypes
def onCenterViewDoubleClicked