Package pyffi :: Package qskope
[hide private]
[frames] | no frames]

Source Code for Package pyffi.qskope

  1  """Class definition for the main QSkope window.""" 
  2   
  3  # ***** BEGIN LICENSE BLOCK ***** 
  4  # 
  5  # Copyright (c) 2007-2011, Python File Format Interface 
  6  # All rights reserved. 
  7  # 
  8  # Redistribution and use in source and binary forms, with or without 
  9  # modification, are permitted provided that the following conditions 
 10  # are met: 
 11  # 
 12  #    * Redistributions of source code must retain the above copyright 
 13  #      notice, this list of conditions and the following disclaimer. 
 14  # 
 15  #    * Redistributions in binary form must reproduce the above 
 16  #      copyright notice, this list of conditions and the following 
 17  #      disclaimer in the documentation and/or other materials provided 
 18  #      with the distribution. 
 19  # 
 20  #    * Neither the name of the Python File Format Interface 
 21  #      project nor the names of its contributors may be used to endorse 
 22  #      or promote products derived from this software without specific 
 23  #      prior written permission. 
 24  # 
 25  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 26  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 27  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 28  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 29  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 30  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 31  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 32  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 33  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 34  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 35  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 36  # POSSIBILITY OF SUCH DAMAGE. 
 37  # 
 38  # ***** END LICENSE BLOCK ***** 
 39   
 40  from PyQt4 import QtGui, QtCore 
 41   
 42  import pyffi.qskope.global_model 
 43  import pyffi.qskope.detail_model 
 44  import pyffi.qskope.detail_delegate 
 45   
 46  import pyffi 
 47  from pyffi.formats.nif import NifFormat 
 48  from pyffi.formats.cgf import CgfFormat 
 49  from pyffi.formats.kfm import KfmFormat 
 50  from pyffi.formats.dds import DdsFormat 
 51  from pyffi.formats.tga import TgaFormat 
 52  from pyffi.formats.egm import EgmFormat 
 53  from pyffi.formats.egt import EgtFormat 
 54  from pyffi.formats.esp import EspFormat 
 55  from pyffi.formats.tri import TriFormat 
 56  from pyffi.formats.bsa import BsaFormat 
 57  from pyffi.formats.rockstar.dir_ import DirFormat 
 58   
 59  from pyffi.object_models import FileFormat 
60 61 # implementation details: 62 # http://doc.trolltech.com/4.3/qmainwindow.html#details 63 -class QSkope(QtGui.QMainWindow):
64 """Main QSkope window."""
65 - def __init__(self, parent = None):
66 """Initialize the main window.""" 67 QtGui.QMainWindow.__init__(self, parent) 68 69 # set up the menu bar 70 self.createActions() 71 self.createMenus() 72 73 # set up the global model view 74 self.globalWidget = QtGui.QTreeView() 75 self.globalWidget.setAlternatingRowColors(True) 76 77 # set up the detail model view 78 self.detailWidget = QtGui.QTreeView() 79 self.detailDelegate = pyffi.qskope.detail_delegate.DetailDelegate() 80 self.detailWidget.setItemDelegate(self.detailDelegate) 81 self.detailWidget.setAlternatingRowColors(True) 82 83 # connect global with detail: 84 # if object is selected in global view, then show its details in the 85 # detail view 86 QtCore.QObject.connect(self.globalWidget, 87 QtCore.SIGNAL("clicked(const QModelIndex &)"), 88 self.setDetailModel) 89 90 # set up the central widget 91 self.splitter = QtGui.QSplitter() 92 self.splitter.addWidget(self.globalWidget) 93 self.splitter.addWidget(self.detailWidget) 94 self.setCentralWidget(self.splitter) 95 96 # activate status bar 97 self.statusBar().clearMessage() 98 99 # window title 100 self.setWindowTitle("QSkope") 101 102 # set the main application data 103 self.data = None 104 105 # restore geometry 106 settings = self.getSettings(versioned = True) 107 self.restoreGeometry( 108 settings.value("MainWindow/geometry").toByteArray())
109
110 - def createActions(self):
111 """Create the menu actions.""" 112 # open a file 113 self.openAct = QtGui.QAction("&Open", self) 114 self.openAct.setShortcut("Ctrl+O") 115 QtCore.QObject.connect(self.openAct, 116 QtCore.SIGNAL("triggered()"), 117 self.openAction) 118 119 # save a file 120 self.saveAct = QtGui.QAction("&Save", self) 121 self.saveAct.setShortcut("Ctrl+S") 122 QtCore.QObject.connect(self.saveAct, 123 QtCore.SIGNAL("triggered()"), 124 self.saveAction) 125 126 # save a file as ... 127 self.saveAsAct = QtGui.QAction("Save As...", self) 128 self.saveAsAct.setShortcut("Ctrl+Shift+S") 129 QtCore.QObject.connect(self.saveAsAct, 130 QtCore.SIGNAL("triggered()"), 131 self.saveAsAction) 132 133 # exit 134 self.exitAct = QtGui.QAction("E&xit", self) 135 self.exitAct.setShortcut("Ctrl+Q") 136 QtCore.QObject.connect(self.exitAct, 137 QtCore.SIGNAL("triggered()"), 138 QtGui.qApp.quit) 139 140 # tell something about QSkope 141 self.aboutQSkopeAct = QtGui.QAction("About QSkope", self) 142 QtCore.QObject.connect(self.aboutQSkopeAct, 143 QtCore.SIGNAL("triggered()"), 144 self.aboutQSkopeAction) 145 146 # tell something about Qt 147 self.aboutQtAct = QtGui.QAction("About Qt", self) 148 QtCore.QObject.connect(self.aboutQtAct, 149 QtCore.SIGNAL("triggered()"), 150 QtGui.qApp.aboutQt)
151 152 # implementation details: 153 # http://doc.trolltech.com/4.3/mainwindows-menus.html
154 - def createMenus(self):
155 """Create the menu bar.""" 156 # the file menu: open, save, save as 157 fileMenu = self.menuBar().addMenu("&File") 158 fileMenu.addAction(self.openAct) 159 fileMenu.addAction(self.saveAct) 160 fileMenu.addAction(self.saveAsAct) 161 fileMenu.addSeparator() 162 fileMenu.addAction(self.exitAct) 163 164 # the help menu: 165 helpMenu = self.menuBar().addMenu("&Help") 166 helpMenu.addAction(self.aboutQSkopeAct) 167 helpMenu.addAction(self.aboutQtAct)
168
169 - def closeEvent(self, event):
170 """Called when the application is closed. Saves the settings.""" 171 settings = self.getSettings(versioned = True) 172 settings.setValue("MainWindow/geometry", 173 QtCore.QVariant(self.saveGeometry())) 174 QtGui.QMainWindow.closeEvent(self, event)
175 176 177 # 178 # various helper functions 179 # 180
181 - def openFile(self, filename = None):
182 """Open a file, and set up the view.""" 183 # inform user about file being read 184 self.statusBar().showMessage("Reading %s ..." % filename) 185 186 # open the file and check type and version 187 # then read the file 188 try: 189 stream = open(filename, "rb") 190 # try reading as a nif file 191 for Format in (NifFormat, CgfFormat, KfmFormat, DdsFormat, 192 TgaFormat, EgmFormat, EspFormat, TriFormat, 193 EgtFormat, BsaFormat, DirFormat): 194 self.data = Format.Data() 195 try: 196 self.data.read(stream) 197 except ValueError as err: #ValueError: 198 # failed, try next format 199 print(str(err)) 200 continue 201 else: 202 break 203 else: 204 # all failed: inform user that format 205 # is not recognized 206 self.statusBar().showMessage( 207 'File format of %s not recognized' 208 % filename) 209 return 210 211 except (ValueError, IOError): 212 # update status bar message 213 self.statusBar().showMessage("Failed reading %s (see console)" 214 % filename) 215 raise 216 217 else: 218 # update current file name 219 self.fileName = filename 220 221 # update the status bar 222 self.statusBar().showMessage("Finished reading %s" % filename) 223 224 # set up the models and update the views 225 self.globalModel = pyffi.qskope.global_model.GlobalModel( 226 globalnode=self.data) 227 self.globalWidget.setModel(self.globalModel) 228 self.setDetailModel( 229 self.globalModel.index(0, 0, QtCore.QModelIndex())) 230 231 # update window title 232 self.setWindowTitle("QSkope - %s" % self.fileName) 233 finally: 234 try: 235 stream.close() 236 except UnboundLocalError: 237 pass
238
239 - def saveFile(self, filename = None):
240 """Save changes to disk.""" 241 # TODO support dds saving as well 242 # TODO support tga saving as well 243 if self.data is None: 244 self.statusBar().showMessage("Saving this format not supported") 245 return 246 247 # tell user we are saving the file 248 self.statusBar().showMessage("Saving %s ..." % filename) 249 try: 250 # open stream for writing 251 stream = open(filename, "wb") 252 # check type of file 253 self.data.write(stream) 254 255 except ValueError: 256 # update status bar message 257 self.statusBar().showMessage("Failed saving %s (see console)" 258 % filename) 259 raise 260 else: 261 # update status bar message 262 self.statusBar().showMessage("Finished saving %s" % filename) 263 finally: 264 stream.close()
265 266 @staticmethod
267 - def getSettings(versioned = False):
268 """Return the QSkope settings.""" 269 if not versioned: 270 return QtCore.QSettings("PyFFI", "QSkope") 271 else: 272 return QtCore.QSettings("PyFFI-%s" % pyffi.__version__, "QSkope")
273 274 # 275 # slots 276 # 277
278 - def setDetailModel(self, index):
279 """Set the detail model given an index from the global model.""" 280 # if the index is valid, then get the block from its internal pointer 281 # and set up the model 282 if index.isValid(): 283 globalnode = index.internalPointer().data.node 284 self.detailModel = pyffi.qskope.detail_model.DetailModel( 285 globalnode=globalnode, 286 globalmodel=self.globalModel) 287 else: 288 self.detailModel = pyffi.qskope.detail_model.DetailModel() 289 # set the widget's model 290 self.detailWidget.setModel(self.detailModel)
291
292 - def openAction(self):
293 """Open a file.""" 294 # wrapper around openFile 295 # (displays an extra file dialog) 296 filename = QtGui.QFileDialog.getOpenFileName(self, "Open File") 297 if filename: 298 self.openFile(filename = filename)
299
300 - def saveAsAction(self):
301 """Save a file.""" 302 # wrapper around saveAction 303 # (displays an extra file dialog) 304 filename = QtGui.QFileDialog.getSaveFileName(self, "Save File") 305 if filename: 306 self.fileName = filename 307 self.saveAction()
308
309 - def saveAction(self):
310 """Save a file.""" 311 # wrapper around saveFile 312 # (gets file name automatically from stored file name) 313 if self.fileName: 314 self.saveFile(filename = self.fileName)
315
316 - def aboutQSkopeAction(self):
317 """Display an information window about QSkope.""" 318 # create the box 319 mbox = QtGui.QMessageBox(self) 320 # set window title and window text 321 mbox.setWindowTitle("About QSkope") 322 mbox.setText(""" 323 <p>QSkope is a tool bundled with PyFFI for analyzing and editing files whose 324 format is supported by pyffi. QSkope is written in Python.</p> 325 <p>The Python File Format Interface, or briefly PyFFI, is a general purpose 326 library to read and write block structured file formats.</p> 327 <p>For more informations visit 328 <a href="http://pyffi.sourceforge.net">http://pyffi.sourceforge.net</a>.</p> 329 <p>PyFFI is free software and comes under a BSD license. The source is 330 available via 331 <a href="http://pyffi.svn.sourceforge.net/viewvc/pyffi/trunk/">svn</a> 332 on <a href="http://sourceforge.net">SourceForge</a>.</p> 333 <p>You are running PyFFI %s. 334 The most recent version of PyFFI can always be downloaded from the 335 <a href="http://sourceforge.net/projects/pyffi/files/"> 336 PyFFI SourceForge Project page</a>.""" % pyffi.__version__) 337 # display the window 338 mbox.exec_()
339