Package client :: Package Viewers
[hide private]
[frames] | no frames]

Source Code for Package client.Viewers

  1  from PyQt4.QtGui import * 
  2  from PyQt4.QtCore import * 
  3   
  4  import re 
  5   
  6  import Items 
  7  import Actions 
  8   
9 -class BasinViewer (QTreeWidget):
10 """ 11 Overview 12 ======== 13 This class holds a graphical representation (in a tree format) of all the BASIN objects 14 currently accounted for by the GUI. It will only keep track of those BASIN objects that 15 were made while in %autopx mode (IPython1's auto-parallel mode). 16 17 The general way that it does this is by relying on the BASIN_ipython_shell.IPythonView 18 object for a few things. First, the IPythonView must be able to catch each time a top-level 19 region is created. Then it must stored that information on the parallel engine by appending 20 the name of this new top-level region to a variable named BASIN_TOPLEVEL_REGION_LIST. It 21 is a newline deliminated string containing the names of top-level Regions. 22 23 Since Regions are able to self-examine themselves, all 24 that needs to be stored is their variable name. From 25 that it can get the total information about objects 26 that are children to it. From their it constructs the 27 tree using the following classes: 28 - Region 29 - Grid 30 - List 31 - Attribute 32 """ 33
34 - def __init__ (self, layout, parent, bridge):
35 """ 36 37 This sets up the QTreeWidget to have 4 columns: 38 1. Data - The name of the data 39 2. Type - It's BASIN object type 40 3. Dimensions - Applicable only to BASIN Attributes 41 4. Alias - The name of the alias, if it exists 42 Aliases are actual python variables 43 that reference the represented 44 45 @param layout: The parent's layout. This will be automatically added to the layout. 46 @type layout: 47 48 @param parent: The parent object of this tree. 49 @type parent: 50 51 @param bridge: The overall connecting bridge class which gets set to self._bridge 52 @type bridge: L{Bridge<client.BASIN_bridge.Bridge>} 53 """ 54 55 QTreeWidget.__init__ (self, parent) 56 57 self._bridge = bridge 58 bridge.setRegionViewer (self) 59 60 self.setAnimated (False) 61 headers = QStringList ("Data") 62 headers.append ("Type") 63 headers.append ("Dimensions") 64 headers.append ("Alias") 65 self.setHeaderLabels (headers) 66 self.setDragEnabled (True) 67 self.setAcceptDrops (True) 68 self._copy = None 69 70 self.makeBasin () 71 72 box = QGroupBox ("BASIN Data Structure") 73 boxLayout = QHBoxLayout (box) 74 boxLayout.addWidget (self) 75 layout.addWidget (box)
76
77 - def Update (self, topRegions):
78 """ 79 Overview 80 ======== 81 This should only ever be called from the BASIN_bridge.Bridge class. 82 83 It clears out all current entries and then re-populates them based off of a (hopefully) 84 new BASIN_TOPLEVEL_REGION_LIST. 85 86 Presumably this program also uses a BASIN_variable_viewer.VariableList object. 87 In such a case, this must be updated BEFORE the VariableList is, and thus it should 88 really only be handled at one point, thus I let the bridge handle Update. 89 """ 90 91 self.clear () 92 self._copy = None 93 self.makeBasin () 94 95 for region in topRegions: 96 self.MakeTopRegion (region) 97 98 self.expandItem (self.top) 99 self.resizeColumnToContents (2) 100 self.resizeColumnToContents (1) 101 self.resizeColumnToContents (0)
102
103 - def getSingleSelectedItem (self):
104 """ 105 Overview 106 ======== 107 This will retrieve the item currently selected by the user. It is possible (although unlikely) 108 that more than one, or none, may be selected. In such a case, a False signal is returned. 109 """ 110 111 items = self.selectedItems () 112 if len (items) == 1: 113 return items[0]
114
115 - def makeBasin (self):
116 """ 117 Overview 118 ======== 119 This is called initially, and after each Update. All it doesi s create the top-most object in the 120 tree structure. It has no real value, just a place-holder for everything else to go under, much 121 like a 'root' that must exist first, regardless of anything. 122 """ 123 124 self.top = QTreeWidgetItem () 125 self.top.setText (0, "BASIN") 126 self.top.setFlags (Qt.ItemIsDropEnabled) 127 self.addTopLevelItem (self.top)
128
129 - def MakeTopRegion (self, var):
130 """ 131 Overview 132 ======== 133 This will be called by Update for as many times as there are top-level Regions. It will take the 134 name of said Region and call its `basin_kernel` method `Region::get_client_information`. This 135 generates a string containing information about all sub-objects of this Region. 136 137 All This really does is take the name of the Region, and this information string and pass 138 it to the constructor of BASIN_region_viewer.TopRegion along with the reference to 139 the top-most root in the tree, where new top-level regions will be under. 140 """ 141 142 realResult = [] 143 result = self._bridge._ipyShell.SilentCommand ("print \"\\n\" + " + var + 144 ".get_client_information ()").split ("\n")[3:] 145 146 # .index () will result in an error if the argument doesn't exist, 147 # so use count to ensure no errors occur 148 if result.count ("") > 0: 149 result = result[:result.index ("")] 150 151 regexp = re.compile (".*\[.*\].*(In|Out).*\[.*\]") 152 for line in result: 153 if not regexp.match (line): 154 realResult.append (line) 155 156 Items.TopRegion (self.top, realResult, var)
157
158 - def mouseMoveEvent (self, ev):
159 """ 160 Overview 161 ======== 162 This is used to initiate a drag sequence. Basically a drag will only start when the user 163 has pressed on an object, and moved a minimum distance. This is to prevent slight movements 164 during double-clicks as being interepreted incorrectly. 165 """ 166 167 if (ev.globalPos () - self._dragStartPosition).manhattanLength () > \ 168 QApplication.startDragDistance (): 169 object = self.getSingleSelectedItem () 170 if object != None: 171 mime = QMimeData () 172 mime.setData (QString ("text/plain"), str (object._name + "\n" + 173 object._shellAccess + "\n" + object.Type ())) 174 drag = QDrag (self) 175 drag.setMimeData (mime) 176 self._bridge._drugItem = object 177 dropAction = drag.start (Qt.LinkAction)
178
179 - def mousePressEvent (self, ev):
180 """ 181 Overview 182 ======== 183 Captures the initial position of a mouse button being pressed. The onyl real use for 184 this is in conjunction with mouseMoveEvent, which will initiate a drag sequence if the 185 mouse has moved a minimum distance from this initial point. 186 """ 187 188 QTreeWidget.mousePressEvent (self, ev) 189 self._dragStartPosition = ev.pos () 190 item = self.getSingleSelectedItem () 191 if item and item.Type () == "REGION": 192 self._bridge._actions.menuRegionSelected () 193 else: 194 self._bridge._actions.menuRegionNotSelected ()
195
196 - def mouseDoubleClickEvent (self, ev):
197 """ 198 Overview 199 ======== 200 This method merely grabs the currently selected item and sends it on its way to the 201 BASIN_dock.Dock. Presumably the Dock can handle it from there. 202 """ 203 204 self._bridge.AddToDock (self.getSingleSelectedItem ())
205
206 - def mouseReleaseEvent (self, ev):
207 """ 208 Overview 209 ======== 210 This method will check to see if the user released the right button of the mouse while 211 over the RegionTree. If so, it sends the position of the release to the appropriate 212 handling method, rightClick. 213 """ 214 215 QTreeWidget.mouseReleaseEvent (self, ev) 216 if ev.button () == Qt.RightButton: 217 self.rightClick (ev.globalPos ())
218
219 - def rightClick (self, position):
220 """ 221 Overview 222 ======== 223 This method is obviously called on a right-click and drops down a menu generated by this function. 224 225 It depends on the exact object you clicked on, for what options will appear in the menu. 226 227 Generally speaking the user will see options for: 228 - Copying / Pasting (All BASIN types) 229 - Creating an Alias (All BASIN types) 230 - Deleting (All BASIN types) 231 - Creating an appropriate blank sub-object 232 - Exporting (Regions only) 233 - Adding it to the Dock Widget (All BASIN types, 234 though there is no garauntee the dock will do 235 anything useful with it) 236 """ 237 238 if (not self._bridge._connected) or (not self._bridge._parallel): 239 return 240 item = self.getSingleSelectedItem () 241 if item == None: 242 menu = QMenu ("Right-Click", self._bridge._mainWindow) 243 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/createregion.png")), QString ("Create Region"), 244 self.CreateRegion) 245 menu.exec_ (position) 246 return 247 248 menu = QMenu ("Right-Click", self._bridge._mainWindow) 249 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/copy.png")), QString ("Copy"), item.Copy) 250 if item.Type () != "ATTRIBUTE": 251 paste = menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/paste.png")), QString ("Paste"), item.Paste) 252 if not self._copy: 253 paste.setEnabled (False) 254 else: 255 if item.Type () == "REGION" and self._copy.Type () == "ATTRIBUTE": 256 paste.setEnabled (False) 257 elif (item.Type () == "GRID" or item.Type () == "LIST") and \ 258 not self._copy.Type () == "ATTRIBUTE": 259 paste.setEnabled (False) 260 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/delete.png")), QString ("Delete"), item.Delete) 261 262 if item.Type () == "REGION": 263 menu.addSeparator () 264 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/createregion.png")), 265 QString ("Create Region"), 266 item.CreateRegion) 267 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/creategrid.png")), 268 QString ("Create Grid"), 269 item.CreateGrid) 270 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/createlist.png")), 271 QString ("Create List"), 272 item.CreateList) 273 274 menu.addSeparator () 275 276 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/alias.png")), QString ("Create Alias..."), 277 self._bridge._varViewer.createAlias) 278 279 if item.Type () == "ATTRIBUTE": 280 menu.addAction ("Convert to list...", self.AttributeToList) 281 282 menu.exec_ (position)
283
284 - def AttributeToList (self):
285 """ 286 """ 287 288 item = self.getSingleSelectedItem () 289 if item == None: 290 return 291 292 dialog = Actions.NameDialog (self._bridge._mainWindow, "Convert To List...", QIcon (Constants.ICON_DEFAULT)) 293 result = dialog.result () 294 if result == 1 and dialog.name.text () != "": # "Ok" 295 self._bridge._ipyShell.Command (str (dialog.name.text ()) + " = " + \ 296 str (item._shellAccess) + ".to_list ()", True)
297
298 - def CreateRegion (self):
299 """ 300 Overview 301 ======== 302 This method will potentially create a top-level Region. It will call a dialog which will request 303 a name from the user, or they can cancel. The given name will become the name of the new top- 304 level Region, or nothing will happen given a blank name / cancel. 305 """ 306 307 item = self.getSingleSelectedItem () 308 309 if item == None: 310 dialog = NameDialog (self._bridge._mainWindow, "Top Region", QIcon (Constants.ICON_DIR + \ 311 "/misc/createregion.png")) 312 result = dialog.result () 313 if result == 1 and dialog.name.text () != "": # "Ok" 314 commands = [] 315 commands.append (str (dialog.name.text ()) + " = Region ()") 316 commands.append (str (dialog.name.text ()) + 317 ".set_name (\"" + str (dialog.name.text ()) + "\")") 318 self._bridge._ipyShell.BatchCommands (commands, True)
319
320 - def dragEnterEvent (self, ev):
321 """ 322 Overview 323 ======== 324 This initial drag event merely checks to make sure that the source of the drag came from the 325 BASIN_variable_viewer.List object. 326 """ 327 328 if ev.source () == self._bridge._varViewer: 329 ev.accept () 330 else: 331 ev.ignore ()
332
333 - def dragMoveEvent (self, ev):
334 """ 335 Overview 336 ======== 337 This midway drag move event merely checks to make sure that the source of the drag came from the 338 BASIN_variable_viewer.List object. 339 """ 340 341 if ev.source () == self._bridge._varViewer: 342 ev.accept () 343 else: 344 ev.ignore ()
345
346 - def dropEvent (self, ev):
347 """ 348 Overview 349 ======== 350 This method will determine the type of free variable being dropped on the RegionTree, and 351 the exact object type it was dropped on. 352 """ 353 354 if ev.source () == self._bridge._varViewer: 355 # The source is the free variable 356 source = self._bridge.PopDrugItem () 357 # And the target is the region-list structure they drop it on 358 target = self.itemAt (ev.pos ()) 359 360 # There's no certainty that they actually dropped it on something... 361 if target == None: 362 ev.ignore () 363 return 364 365 if source.Type () != "VALUE" and source._alias != None: 366 self._bridge._statusBar.showTimed ("Can't add an alias, it is already " + \ 367 "coupled to another item!", 2.5) 368 return 369 370 if source.Type () == "ATTRIBUTE" or (source.Type () == "VALUE" and \ 371 source._type == "_basin.Attribute"): 372 if target.Type () == "LIST" or target.Type () == "GRID": 373 self._appendAttributeFromFreeVar (source._shellAccess, target._shellAccess) 374 else: 375 self._bridge._statusBar.showTimed ("Attributes may only be appended to Lists or Grids", 2.5) 376 elif source.Type () == "GRID" or (source.Type () == "VALUE" and \ 377 source._type == "_basin.Grid"): 378 if target.Type () == "REGION": 379 self._appendGridFromFreeVar (source._shellAccess, target._shellAccess) 380 else: 381 self._bridge._statusBar.showTimed ("Grids may only be appended to Regions", 2.5) 382 elif source.Type () == "LIST" or (source.Type () == "VALUE" and \ 383 source._type == "_basin.List"): 384 if target.Type () == "REGION": 385 self._appendListFromFreeVar (source._shellAccess, target._shellAccess) 386 else: 387 self._bridge._statusBar.showTimed ("Lists may only be appended to Regions", 2.5) 388 elif source.Type () == "REGION" or (source.Type () == "VALUE" and \ 389 source._type == "_basin.Region"): 390 if target.Type () == "REGION": 391 self._appendRegionFromFreeVar (source._shellAccess, target._shellAccess) 392 else: 393 self._bridge._statusBar.showTimed ("Regions may only be appended to Regions or BASIN", 2.5) 394 else: 395 self._bridge._statusBar.showTimed ("Only BASIN objects may be appended to the Region Viewer", 2.5) 396 397 ev.setDropAction (Qt.LinkAction) 398 ev.accept () 399 else: 400 ev.ignore ()
401
402 - def _appendAttributeFromFreeVar (self, source, target):
403 """ 404 Overview 405 ======== 406 This will occur when a user drags a free variable BASIN Attribute and drops it onto 407 a RegionTree object that is capable of being its parent, in this case Lists or Grids. 408 409 To accomplish this, it can use the internal `basin_kernel` command to add the attribute. 410 Also, the GUI will need to be updated that this has made. This is because we aren't 411 destroying the free floating attribute, but it just turns into an alias for the object 412 you are adGui ding into the RegionTree. 413 """ 414 415 commands = [] 416 commands.append (target + ".add_attribute (\"" + source + 417 "\", " + source + ")") 418 self._bridge._ipyShell.replaceFreeVariable (source, target + ".get_attribute (\"" + 419 source + "\")") 420 self._bridge._ipyShell.BatchCommands (commands, True)
421
422 - def _appendGridFromFreeVar (self, source, target):
423 """ 424 Overview 425 ======== 426 This will occur when a user drags a free variable BASIN Grid and drops it onto a 427 RegionTree object that is capable of being its parent, in this case Regions. 428 429 To accomplish this, it can use the internal `basin_kernel` command to add the Grid. 430 Also, the GUI will need to be updated that this has made. This is because we aren't 431 destroying the free floating Grid, but it just turns into an alias for the object 432 you are adding into the RegionTree. 433 """ 434 435 commands = [] 436 commands.append (target + ".add_grid (\"" + source + "\", " + 437 source + ")") 438 self._bridge._ipyShell.replaceFreeVariable (source, target + ".get_grid (\"" + 439 source + "\")") 440 self._bridge._ipyShell.BatchCommands (commands, True)
441
442 - def _appendListFromFreeVar (self, source, target):
443 """ 444 Overview 445 ======== 446 This will occur when a user drags a free variable BASIN List and drops it onto a 447 RegionTree object that is capable of being its parent, in this case Regions. 448 449 To accomplish this, it can use the internal `basin_kernel` command to add the List. 450 Also, the GUI will need to be updated that this has made. This is because we aren't 451 destroying the free floating List, but it just turns into an alias for the object you 452 are adding into the RegionTree. 453 """ 454 455 commands = [] 456 commands.append (target + ".add_list (\"" + source + 457 "\", " + source + ")") 458 self._bridge._ipyShell.replaceFreeVariable (source, target + ".get_list (\"" + 459 source + "\")") 460 self._bridge._ipyShell.BatchCommands (commands, True)
461
462 - def _appendRegionFromFreeVar (self, source, target):
463 """ 464 Overview 465 ======== 466 This will occur when a user drags a free variable BASIN Region and drops it onto a 467 RegionTree object that is capable of being its parent, in this case Regions. 468 469 To accomplish this, it can use the internal `basin_kernel` command to add the Region. 470 Also, the GUI will need to be updated that this has made. This is because we aren't 471 destroying the free floating Region, but it just turns into an alias for the object 472 you are adding into the RegionTree. 473 """ 474 475 commands = [] 476 commands.append (target + ".add_child (" + source + ")") 477 self._bridge._ipyShell.BatchCommands (commands, True)
478 479
480 -class VariableViewer (QTreeWidget):
481 """ 482 Overview 483 ======== 484 This class graphically keeps track of all free floating variables within the python session. 485 Note, it keeps track of variables in the parallel session, or commands entered while in 486 %autopx mode. There are essentially two types of free floating variables that are represented: 487 - Aliases: Variables with point to structured Basin objects. Note that not all basin objects 488 are aliases. An attribute without a list, for instance, isn't structured. 489 - Values: Self contained variables that are not references to a Basin object. 490 """
491 - def __init__ (self, layout, bridge):
492 """ 493 """ 494 QTreeWidget.__init__ (self) 495 self.setAcceptDrops (True) 496 497 self._bridge = bridge 498 bridge.setVariableViewer (self) 499 500 headers = QStringList ("Variables") 501 headers.append ("Type") 502 headers.append ("Reference") 503 self.setHeaderLabels (headers) 504 self.setDragEnabled (True) 505 self.setAcceptDrops (True) 506 507 self.makePython () 508 509 box = QGroupBox ("Free Python Variables") 510 boxLayout = QHBoxLayout (box) 511 boxLayout.addWidget (self) 512 layout.addWidget (box)
513
514 - def Update (self, freeInfo):
515 freeVars = freeInfo[0] 516 freeAccess = freeInfo[1] 517 self.clear () 518 self.makePython () 519 if len (freeVars) == 0 or len (freeAccess) == 0: 520 return 521 for index in xrange (len (freeVars)): 522 if freeVars.count (freeVars[index]) < 2: 523 result = self.findReference (freeAccess[index]) 524 if result == False: 525 Items.Value (self.top, freeVars[index]) 526 else: 527 Items.Alias (self.top, str (freeVars[index]), str (freeAccess[index])) 528 self.expandItem (self.top) 529 self.resizeColumnToContents (2) 530 self.resizeColumnToContents (1) 531 self.resizeColumnToContents (0)
532
533 - def makePython (self):
534 self.top = QTreeWidgetItem () 535 self.top.setText (0, "Python") 536 self.top.setFlags (Qt.ItemIsDropEnabled) 537 self.addTopLevelItem (self.top)
538
539 - def isBasinObject (self, name):
540 result = self._bridge._ipyShell.SilentCommand ("print \"\\n\" + str (" + name + ")") 541 if result.find ("Error") != -1: 542 self._bridge.Error ("BASIN_variable_viewer.py", "VariableViewer", 543 "isBasinObject", result) 544 return False 545 result = result.split ("\n")[3] 546 if re.compile ("<_basin.*>").match (result): 547 return True 548 return False
549
550 - def findReference (self, shellAccess):
551 iter = QTreeWidgetItemIterator (self._bridge._regionViewer) 552 iter += 1 553 while iter.value (): 554 if shellAccess.replace (" ", "") == \ 555 iter.value ()._shellAccess.replace (" ", ""): 556 return True 557 iter += 1 558 return False
559
560 - def createAlias (self, attr = None):
561 if attr == None: 562 attr = self._bridge._regionViewer.getSingleSelectedItem () 563 if attr == None: 564 return 565 dialog = QDialog () 566 dialog.setWindowTitle (QString ("Create Alias...")) 567 dialog.setWindowIcon (QIcon (QString (Constants.ICON_DIR + "/alias.png"))) 568 layout = QVBoxLayout (dialog) 569 topLayout = Constants.BQHBoxLayout (layout) 570 bottomLayout = Constants.BQHBoxLayout (layout) 571 572 name = QLineEdit (attr._name) 573 regexp = QRegExp ("[A-Za-z_][0-9A-Za-z_]*") 574 valid = QRegExpValidator (regexp, name) 575 name.setValidator (valid) 576 topLayout.addWidget (QLabel (QString ("Alias Name:"))) 577 topLayout.addWidget (name) 578 579 acceptButton = Constants.BQPushButton ("Ok", bottomLayout) 580 QObject.connect (acceptButton, SIGNAL ("clicked ()"), dialog.accept) 581 rejectButton = Constants.BQPushButton ("Cancel", bottomLayout) 582 QObject.connect (rejectButton, SIGNAL ("clicked ()"), dialog.reject) 583 584 self._bridge.CursorNorm () 585 result = dialog.exec_ () 586 587 if result == 1: # "Ok" 588 result = self._bridge._ipyShell.Command (str (name.text ()) + " = " + 589 str (attr._shellAccess)) 590 if result.find ("Error") != -1: 591 self._bridge.Error ("BASIN_variable_viewer.py", "VariableViewer", 592 "createAlias", result)
593
594 - def getSingleSelectedItem (self):
595 items = self.selectedItems () 596 if len (items) == 1: 597 return items[0] 598 return None
599
600 - def dropEvent (self, ev):
601 if ev.source () == self._bridge._regionViewer: 602 self.createAlias (self._bridge.PopDrugItem ()) 603 604 ev.setDropAction (Qt.LinkAction) 605 ev.accept () 606 else: 607 ev.ignore ()
608
609 - def dragEnterEvent (self, ev):
610 if ev.source () == self._bridge._regionViewer: 611 ev.accept () 612 else: 613 ev.ignore ()
614
615 - def dragMoveEvent (self, ev):
616 if ev.source () == self._bridge._regionViewer: 617 ev.accept () 618 else: 619 ev.ignore ()
620
621 - def mouseDoubleClickEvent (self, ev):
622 self._bridge.AddToDock (self.getSingleSelectedItem ()) 623 QTreeWidget.mouseDoubleClickEvent (self, ev)
624
625 - def mouseMoveEvent (self, ev):
626 if (ev.globalPos () - self._dragStartPosition).manhattanLength () > \ 627 QApplication.startDragDistance (): 628 object = self.getSingleSelectedItem () 629 if object != None: 630 mime = QMimeData () 631 mime.setData (QString ("text/plain"), "") 632 drag = QDrag (self) 633 drag.setMimeData (mime) 634 if object.Type () == "ALIAS": 635 self._bridge._drugItem = object 636 #self._bridge._drugItem = object._item 637 elif object.Type () == "VALUE": 638 self._bridge._drugItem = object 639 dropAction = drag.start (Qt.LinkAction)
640
641 - def mousePressEvent (self, ev):
642 QTreeWidget.mousePressEvent (self, ev) 643 self._dragStartPosition = ev.pos () 644 item = self.getSingleSelectedItem ()
645
646 - def mouseReleaseEvent (self, ev):
647 QTreeWidget.mouseReleaseEvent (self, ev) 648 if ev.button () == Qt.RightButton: 649 self.rightClick (ev.globalPos ())
650
651 - def rightClick (self, position):
652 item = self.getSingleSelectedItem () 653 if item == None: 654 return 655 656 menu = QMenu ("Right-Click", self._bridge._mainWindow) 657 if item.Type () == "ALIAS": 658 if item.Type () == "REGION": 659 menu.addAction (self._bridge._actions.fExport) 660 elif item.Type () == "VALUE": 661 item = item 662 663 menu.addAction (QIcon (QString (Constants.ICON_DIR + "/misc/delete.png")), QString ("Delete"), item.Delete) 664 665 menu.exec_ (position)
666