diff --git a/crlcore/src/cyclop/Cyclop.cpp b/crlcore/src/cyclop/Cyclop.cpp index e9b649c1..e286bbda 100644 --- a/crlcore/src/cyclop/Cyclop.cpp +++ b/crlcore/src/cyclop/Cyclop.cpp @@ -1,15 +1,9 @@ - // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC/LIP6 2008-2009, All Rights Reserved +// Copyright (c) UPMC 2008-2014, All Rights Reserved // -// =================================================================== -// -// $Id$ -// -// x-----------------------------------------------------------------x -// | | +// +-----------------------------------------------------------------+ // | C O R I O L I S | // | C y c l o p - S i m p l e V i e w e r | // | | @@ -17,25 +11,19 @@ // | E-mail : Jean-Paul.Chaput@asim.lip6.fr | // | =============================================================== | // | C++ Module : "./Cyclop.cpp" | -// | *************************************************************** | -// | U p d a t e s | -// | | -// x-----------------------------------------------------------------x +// +-----------------------------------------------------------------+ -#include -#include - -#include "hurricane/viewer/CellWidget.h" - -#include "OpenCellDialog.h" -#include "DemoGo.h" -#include "Cyclop.h" +#include +#include +#include "hurricane/viewer/CellWidget.h" +#include "OpenCellDialog.h" +#include "DemoGo.h" +#include "Cyclop.h" namespace CRL { - // ------------------------------------------------------------------- // Class : "Cyclop". diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index 97b8fcfb..4424b6da 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -1,6 +1,10 @@ +# -*- explicit-buffer-name: "CMakeLists.txt" -*- set ( pysources ${CMAKE_CURRENT_SOURCE_DIR}/placeandroute.py ${CMAKE_CURRENT_SOURCE_DIR}/ref.py ) + set ( pyplugins ${CMAKE_CURRENT_SOURCE_DIR}/ClockTree.py + ) install ( FILES ${pysources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus ) + install ( FILES ${pyplugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins ) diff --git a/cumulus/src/ClockTree.py b/cumulus/src/ClockTree.py new file mode 100755 index 00000000..ca33e59d --- /dev/null +++ b/cumulus/src/ClockTree.py @@ -0,0 +1,567 @@ +#!/usr/bin/env python + +try: + import sys + import traceback + import os.path + import optparse + import math + import Cfg + import Hurricane + from Hurricane import DbU + from Hurricane import Box + from Hurricane import Path + from Hurricane import Occurrence + from Hurricane import UpdateSession + from Hurricane import Breakpoint + from Hurricane import Net + from Hurricane import RoutingPad + from Hurricane import Contact + from Hurricane import Horizontal + from Hurricane import Vertical + from Hurricane import Instance + from Hurricane import HyperNet + import Viewer + import CRL + from CRL import RoutingLayerGauge + from helpers import ErrorMessage + import Nimbus + import Metis + import Mauka + import Katabatic + import Kite + import Unicorn +except ImportError, e: + module = str(e).split()[-1] + + print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module + print ' Please check the integrity of the package.' + sys.exit(1) +except Exception, e: + print '[ERROR] A strange exception occurred while loading the basic Coriolis/Python' + print ' modules. Something may be wrong at Python/C API level.\n' + print ' %s' % e + sys.exit(2) + + +# Will be moved away from the students eyes in the future. +def breakpoint ( editor, level, message ): + if editor: + editor.fit() + editor.refresh() + Breakpoint.stop( level, message ) + return + + +def getPlugByName ( instance, netName ): + masterCell = instance.getMasterCell() + masterNet = masterCell.getNet( netName ) + if masterNet: + return instance.getPlug( masterNet ) + return None + + +def getPlugByNet ( instance, net ): + #print 'getPlugByNet:', net, 'connected to', instance + for plug in net.getPlugs(): + #print '|', plug + if plug.getInstance() == instance: + #print '| Found.' + return plug + #print '| NOT Found' + return None + + +def showNet ( cell, netName ): + net = cell.getNet(netName) + if not net: + print ErrorMessage( 3, 'Cell %s doesn\'t have net %s' % cell.getName(), netName ) + return + + print 'Components of', netName + for component in net.getComponents(): + print '| ', component, component.getBoundingBox() + return + + +class HTree ( object ): + + HAccess = 0x0001 + + @staticmethod + def create ( cell, clockBox ): + if clockBox.isEmpty(): raise ErrorMessage( 3, 'ClockTree: The clock area is empty.' ) + + aspectRatio = DbU.toLambda( clockBox.getWidth() ) / DbU.toLambda( clockBox.getHeight() ) + if aspectRatio > 1.5 or aspectRatio < 0.5: + raise ErrorMessage( 3, 'ClockTree: aspect ratio %f is disproportionate, must be between 0.5 and 1.5.' \ + % aspectRatio ) + + ht = HTree( cell, clockBox ) + print ' o Creating Clock H-Tree for <%s>.' % cell.getName() + ht.build() + ht.place() + ht.route() + print ' - H-Tree depth: %d' % ht.getTreeDepth() + return ht + + def __init__ ( self, cell, area ): + self.minSide = DbU.fromLambda( Cfg.getParamInt('clockTree.minimumSide').asInt() ) + if self.minSide < DbU.fromLambda(100.0): + raise ErrorMessage( 3, 'ClockTree: clockTree.minimumSide (%g) is less than 100 lambda.' \ + % DbU.toLambda(self.minSide) ) + + self.framework = CRL.AllianceFramework.get() + self.cell = cell + self.area = area + self.childs = [] + self.bufferCell = self.framework.getCell( 'buf_x2', CRL.Catalog.State.Logical ) + self.cellGauge = self.framework.getCellGauge() + self.routingGauge = self.framework.getRoutingGauge() + self.topBuffer = Instance( self.cell, 'ck_htree', self.bufferCell ) + self.cloneds = [ self.cell ] + self.plugToRp = {} + self._createChildNet( self.topBuffer, 'ck_htree' ) + + topLayer = Cfg.getParamString('katabatic.topRoutingLayer').asString() + self.topLayerDepth = 0 + for layerGauge in self.routingGauge.getLayerGauges(): + if layerGauge.getLayer().getName() == topLayer: + self.topLayerDepth = layerGauge.getDepth() + break + if not self.topLayerDepth: + print '[WARNING] Gauge top layer not defined, using top of gauge (%d).' \ + % self.routingGauge.getDepth() + self.topLayerDepth = self.routingGauge.getDepth() + + self.horizontalDepth = 0 + self.verticalDepth = 0 + for depth in range(0,self.topLayerDepth+1): + if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal: + self.horizontalDepth = depth + if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical: + self.verticalDepth = depth + + self.masterClock = None + for net in cell.getNets(): + if net.isClock(): + self.masterClock = net + break + if not self.masterClock: + print '[WARNING] Cell %s has no clock net.' % cell.getName() + + return + + def _createChildNet ( self, ibuffer, tag ): + childNet = Net( self.cell, tag ) + childNet.setType( Hurricane.TypeCLOCK ) + getPlugByName(ibuffer, 'q').setNet( childNet ) + return + + def _createContact ( self, net, x, y ): + return Contact( net + , self.routingGauge.getContactLayer(self.horizontalDepth) + , x, y + , self.routingGauge.getLayerGauge(self.horizontalDepth).getViaWidth() + , self.routingGauge.getLayerGauge(self.horizontalDepth).getViaWidth() + ) + + def _createHorizontal ( self, source, target, y ): + return Horizontal( source + , target + , self.routingGauge.getRoutingLayer(self.horizontalDepth) + , y + , self.routingGauge.getLayerGauge(self.horizontalDepth).getWireWidth() + ) + + def _createVertical ( self, source, target, x ): + return Vertical( source + , target + , self.routingGauge.getRoutingLayer(self.verticalDepth) + , x + , self.routingGauge.getLayerGauge(self.verticalDepth).getWireWidth() + ) + + def _rpAccess ( self, rp, net, flags=0 ): + contact1 = Contact( rp, self.routingGauge.getContactLayer(0), 0, 0 ) + + if flags & HTree.HAccess: stopDepth = self.horizontalDepth + else: stopDepth = self.verticalDepth + + for depth in range(1,stopDepth): + contact2 = Contact( net + , self.routingGauge.getContactLayer(depth) + , contact1.getX() + , contact1.getY() + , self.routingGauge.getLayerGauge(depth).getViaWidth() + , self.routingGauge.getLayerGauge(depth).getViaWidth() + ) + if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal: + Horizontal( contact1 + , contact2 + , self.routingGauge.getRoutingLayer(depth) + , contact1.getY() + , self.routingGauge.getLayerGauge(depth).getWireWidth() + ) + else: + Vertical( contact1 + , contact2 + , self.routingGauge.getRoutingLayer(depth) + , contact1.getX() + , self.routingGauge.getLayerGauge(depth).getWireWidth() + ) + contact1 = contact2 + + return contact1 + + def _rpAccessByOccurrence ( self, occurrence, net, flags=0 ): + plug = occurrence.getEntity() + if self.plugToRp.has_key(plug): + rp = self.plugToRp[plug] + else: + rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea ) + self.plugToRp[plug] = rp + + return self._rpAccess( rp, net, flags ) + + def _rpAccessByPlug ( self, plug, net, flags=0 ): + if self.plugToRp.has_key(plug): + rp = self.plugToRp[plug] + else: + occurrence = Occurrence( plug, Path(self.cell,'') ) + rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea ) + self.plugToRp[plug] = rp + + return self._rpAccess( rp, net, flags ) + + def _rpAccessByPlugName ( self, instance, plugName, net, flags=0 ): + return self._rpAccessByPlug( getPlugByName(instance,plugName), net, flags ) + + def toXCellGrid ( self, x ): return x - (x % self.cellGauge.getSliceStep ()) + def toYCellGrid ( self, y ): return y - (y % self.cellGauge.getSliceHeight()) + + def placeInstance ( self, instance, x, y ): + xslice = self.toXCellGrid(x) + yslice = self.toYCellGrid(y) + + transformation = Hurricane.OrientationID + if (yslice / self.cellGauge.getSliceHeight()) % 2 != 0: + transformation = Hurricane.OrientationMY + yslice += self.cellGauge.getSliceHeight() + + instance.setTransformation ( Hurricane.Transformation(xslice, yslice, transformation) ) + instance.setPlacementStatus( Hurricane.PlacementStatusFIXED ) + return + + def getTreeDepth ( self ): + return self.childs[0].getTreeDepth() + + def getLeafBufferUnder ( self, point ): + return self.childs[0].getLeafBufferUnder( point ) + + def build ( self ): + self.childs.append( HTreeNode( self, self.topBuffer, self.area, '', HTreeNode.RootBranch ) ) + return + + def place ( self ): + UpdateSession.open() + center = self.area.getCenter() + self.placeInstance( self.topBuffer, center.getX(), center.getY() ) + self.childs[0].place() + UpdateSession.close() + return + + def route ( self ): + UpdateSession.open() + self.childs[0].route() + UpdateSession.close() + return + + def addDeepPlug ( self, topNet, path ): + if path.isEmpty(): return None + + tailPath = path.getTailPath() + headInstance = path.getHeadInstance() + headPlug = getPlugByNet(headInstance,topNet) + if headPlug: + if tailPath.isEmpty(): return headPlug + return self.addDeepPlug( headPlug.getMasterNet(), tailPath ) + + masterCell = headInstance.getMasterCell() + masterNet = Net( masterCell, topNet.getName() ) + masterNet.setExternal ( True ) + masterNet.setType ( Hurricane.TypeCLOCK ) + masterNet.setDirection( Hurricane.DirectionIN ) + headPlug = headInstance.getPlug( masterNet ) + if not headPlug: + raise ErrorMessage( 3, 'Plug not created for %s on instance %s of %s' \ + % (topNet.getName(),headInstance.getName(),masterCell.getName()) ) + headPlug.setNet( topNet ) + if not masterCell in self.cloneds: self.cloneds.append( masterCell ) + + if tailPath.isEmpty(): return headPlug + return self.addDeepPlug( masterNet, tailPath ) + + def connectLeaf ( self ): + UpdateSession.open() + + leafConnects = [] + hyperMasterClock = HyperNet( Occurrence(self.masterClock) ) + for plugOccurrence in hyperMasterClock.getLeafPlugOccurrences(): + position = plugOccurrence.getBoundingBox().getCenter() + leafBuffer = self.getLeafBufferUnder( position ) + leafCk = getPlugByName(leafBuffer,'q').getNet() + deepPlug = self.addDeepPlug( leafCk, plugOccurrence.getPath() ) + leafConnects.append( (deepPlug,plugOccurrence,leafCk,leafBuffer) ) + + for deepPlug, plugOccurrence, leafCk, leafBuffer in leafConnects: + plugOccurrence.getEntity().setNet( deepPlug.getMasterNet() ) + + bufferContact = self._rpAccessByPlugName( leafBuffer, 'q', leafCk , HTree.HAccess ) + registerContact = self._rpAccessByOccurrence( plugOccurrence, leafCk, 0 ) + turn = self._createContact( leafCk, registerContact.getX(), bufferContact.getY() ) + self._createVertical ( registerContact, turn, registerContact.getX() ) + self._createHorizontal( turn, bufferContact, bufferContact.getY() ) + + getPlugByName( self.topBuffer, 'i' ).setNet( self.masterClock ) + UpdateSession.close() + + return + + def _rsave ( self, cell ): + flags = CRL.Catalog.State.Physical + if cell.getName().endswith('_clocked'): + flags = flags | CRL.Catalog.State.Logical + self.framework.saveCell( cell, flags ) + + for instance in cell.getInstances(): + masterCell = instance.getMasterCell() + if not masterCell.isTerminal(): + self._rsave( masterCell ) + + def save ( self ): + for cell in self.cloneds: + cell.setName( cell.getName()+'_clocked' ) + + self._rsave( self.cell ) + return + + +class HTreeNode ( object ): + + RootBranch = 0x0001 + LeftBranch = 0x0002 + RightBranch = 0x0004 + UpBranch = 0x0008 + DownBranch = 0x0010 + + def __init__ ( self, topTree, sourceBuffer, area, prefix, flags ): + self.topTree = topTree + self.childs = [] + self.flags = flags + self.sourceBuffer = sourceBuffer + self.area = area + self.prefix = prefix + + self.blBuffer = Instance( self.topTree.cell, 'ck_htree'+self.prefix+'_bl_ins', self.topTree.bufferCell ) + self.brBuffer = Instance( self.topTree.cell, 'ck_htree'+self.prefix+'_br_ins', self.topTree.bufferCell ) + self.tlBuffer = Instance( self.topTree.cell, 'ck_htree'+self.prefix+'_tl_ins', self.topTree.bufferCell ) + self.trBuffer = Instance( self.topTree.cell, 'ck_htree'+self.prefix+'_tr_ins', self.topTree.bufferCell ) + self.ckNet = getPlugByName(self.sourceBuffer, 'q').getNet() + getPlugByName(self.blBuffer, 'i').setNet( self.ckNet ) + getPlugByName(self.brBuffer, 'i').setNet( self.ckNet ) + getPlugByName(self.tlBuffer, 'i').setNet( self.ckNet ) + getPlugByName(self.trBuffer, 'i').setNet( self.ckNet ) + + self.topTree._createChildNet( self.blBuffer, 'ck_htree'+self.prefix+'_bl' ) + self.topTree._createChildNet( self.brBuffer, 'ck_htree'+self.prefix+'_br' ) + self.topTree._createChildNet( self.tlBuffer, 'ck_htree'+self.prefix+'_tl' ) + self.topTree._createChildNet( self.trBuffer, 'ck_htree'+self.prefix+'_tr' ) + + halfWidth = self.area.getHalfWidth () + halfHeight = self.area.getHalfHeight() + if halfWidth >= self.topTree.minSide and halfHeight >= self.topTree.minSide: + # Recursive call. + self.childs.append( HTreeNode( self.topTree, self.blBuffer, self.blArea(), self.prefix+'_bl', 0 ) ) + self.childs.append( HTreeNode( self.topTree, self.brBuffer, self.brArea(), self.prefix+'_br', 0 ) ) + self.childs.append( HTreeNode( self.topTree, self.tlBuffer, self.tlArea(), self.prefix+'_tl', 0 ) ) + self.childs.append( HTreeNode( self.topTree, self.trBuffer, self.trArea(), self.prefix+'_tr', 0 ) ) + + return + + def xmin ( self ): return self.area.getXMin() + def xmax ( self ): return self.area.getXMax() + def ymin ( self ): return self.area.getYMin() + def ymax ( self ): return self.area.getYMax() + def halfWidth ( self ): return self.area.getHalfWidth() + def halfHeight( self ): return self.area.getHalfHeight() + + def blArea ( self ): + return Box( self.xmin() , self.ymin() + , self.xmin()+self.halfWidth(), self.ymin()+self.halfHeight() ) + + def brArea ( self ): + return Box( self.xmin()+self.halfWidth(), self.ymin() + , self.xmax() , self.ymin()+self.halfHeight() ) + + def tlArea ( self ): + return Box( self.xmin() , self.ymin()+self.halfHeight() + , self.xmin()+self.halfWidth(), self.ymax() ) + + def trArea ( self ): + return Box( self.xmin()+self.halfWidth(), self.ymin()+self.halfHeight() + , self.xmax() , self.ymax() ) + + def getTreeDepth ( self ): + if self.childs: return self.childs[0].getTreeDepth()+1 + return 1 + + def getLeafBufferUnder ( self, point ): + if self.childs: + if self.blArea().contains(point): return self.childs[0].getLeafBufferUnder(point) + if self.brArea().contains(point): return self.childs[1].getLeafBufferUnder(point) + if self.tlArea().contains(point): return self.childs[2].getLeafBufferUnder(point) + if self.trArea().contains(point): return self.childs[3].getLeafBufferUnder(point) + + if self.blArea().contains(point): return self.blBuffer + if self.brArea().contains(point): return self.brBuffer + if self.tlArea().contains(point): return self.tlBuffer + return self.trBuffer + + def place ( self ): + x = self.area.getXMin() + self.area.getWidth ()/4 + y = self.area.getYMin() + self.area.getHeight()/4 + halfWidth = self.area.getHalfWidth () + halfHeight = self.area.getHalfHeight() + + self.topTree.placeInstance( self.blBuffer, x , y ) + self.topTree.placeInstance( self.brBuffer, x+halfWidth, y ) + self.topTree.placeInstance( self.tlBuffer, x , y+halfHeight ) + self.topTree.placeInstance( self.trBuffer, x+halfWidth, y+halfHeight ) + + for child in self.childs: child.place() + return + + def route ( self ): + sourceContact = self.topTree._rpAccessByPlugName( self.sourceBuffer, 'q', self.ckNet , HTree.HAccess ) + blContact = self.topTree._rpAccessByPlugName( self.blBuffer , 'i', self.ckNet ) + brContact = self.topTree._rpAccessByPlugName( self.brBuffer , 'i', self.ckNet ) + tlContact = self.topTree._rpAccessByPlugName( self.tlBuffer , 'i', self.ckNet ) + trContact = self.topTree._rpAccessByPlugName( self.trBuffer , 'i', self.ckNet ) + leftContact = self.topTree._createContact( self.ckNet, blContact.getX(), sourceContact.getY() ) + rightContact = self.topTree._createContact( self.ckNet, brContact.getX(), sourceContact.getY() ) + self.topTree._createHorizontal( leftContact , sourceContact, sourceContact.getY() ) + self.topTree._createHorizontal( sourceContact, rightContact , sourceContact.getY() ) + self.topTree._createVertical ( leftContact , blContact , leftContact.getX() ) + self.topTree._createVertical ( tlContact , leftContact , leftContact.getX() ) + self.topTree._createVertical ( rightContact , brContact , rightContact.getX() ) + self.topTree._createVertical ( trContact , rightContact , rightContact.getX() ) + + for child in self.childs: child.route() + return + +def computeAbutmentBox ( cell, spaceMargin, aspectRatio, cellGauge ): + sliceHeight = DbU.toLambda( cellGauge.getSliceHeight() ) + + instancesNb = 0 + cellLength = 0 + for occurrence in cell.getLeafInstanceOccurrences(): + instance = occurrence.getEntity() + instancesNb += 1 + cellLength += int( DbU.toLambda(instance.getMasterCell().getAbutmentBox().getWidth()) ) + + # ar = x/y S = x*y = spaceMargin*SH x=S/y ar = S/y^2 + # y = sqrt(S/AR) + gcellLength = float(cellLength)*(1+spaceMargin) / sliceHeight + rows = math.sqrt( gcellLength/aspectRatio ) + if math.trunc(rows) != rows: rows = math.trunc(rows) + 1 + else: rows = math.trunc(rows) + columns = gcellLength / rows + if math.trunc(columns) != columns: columns = math.trunc(columns) + 1 + else: columns = math.trunc(columns) + + print ' o Creating abutment box (margin:%.1f%%, aspect ratio:%.1f%%, g-length:%.1fl)' \ + % (spaceMargin*100.0,aspectRatio*100.0,(cellLength/sliceHeight)) + print ' - GCell grid: [%dx%d]' % (columns,rows) + + UpdateSession.open() + abutmentBox = Box( DbU.fromLambda(0) + , DbU.fromLambda(0) + , DbU.fromLambda(columns*sliceHeight) + , DbU.fromLambda(rows *sliceHeight) + ) + cell.setAbutmentBox( abutmentBox ) + UpdateSession.close() + + return abutmentBox + + +def unicornHook ( editor ): + #print ' o Hooking up ClockTree script.' + moduleFile = sys.modules[__name__].__file__ + if moduleFile.endswith('.pyc') or moduleFile.endswith('.pyo'): + moduleFile = moduleFile[:-1] + + editor.addToMenu( 'plugins.clockTree' + , 'ClockTree' + , 'Build a buffered H-Tree for the clock' + , moduleFile + ) + #print ' <%s>' % moduleFile + return + + +def ScriptMain ( cell=None ): + try: + errorCode = 0 + + print ' o Cleaning up any previous run.' + for fileName in os.listdir('.'): + if fileName.endswith('.ap'): + print ' - <%s>' % fileName + os.unlink(fileName) + + editor = None + if globals().has_key('__editor'): + print ' o Editor detected, running in graphic mode.' + editor = __editor + if cell == None: cell = editor.getCell() + + if cell == None: + raise ErrorMessage( 3, 'ClockTree: No cell loaded yet.' ) + + framework = CRL.AllianceFramework.get() + cellGauge = framework.getCellGauge() + + if cell.getAbutmentBox().isEmpty(): + spaceMargin = Cfg.getParamPercentage('nimbus.spaceMargin').asPercentage() / 100.0 + 0.02 + aspectRatio = Cfg.getParamPercentage('nimbus.aspectRatio').asPercentage() / 100.0 + computeAbutmentBox( cell, spaceMargin, aspectRatio, cellGauge ) + if editor: editor.fit() + + ht = HTree.create( cell, cell.getAbutmentBox() ) + if editor: editor.refresh() + mauka = Mauka.MaukaEngine.create( cell ) + mauka.run() + mauka.destroy() + ht.connectLeaf() + ht.save() + + #showNet( cell, 'ck_htree_bl_bl_bl' ) + #showNet( cell, 'ck_htree_bl_bl_br' ) + #showNet( cell, 'ck_htree_bl_bl_tl' ) + #showNet( cell, 'ck_htree_bl_bl_tr' ) + + except ErrorMessage, e: + print e; errorCode = e.code + except Exception, e: + print '\n\n', e; errorCode = 1 + traceback.print_tb(sys.exc_info()[2]) + + return 0 + + +if __name__ == '__main__': + ScriptMain() + + sys.exit(0) diff --git a/etesian/src/GraphicEtesianEngine.cpp b/etesian/src/GraphicEtesianEngine.cpp index 3b562809..2c889b7f 100644 --- a/etesian/src/GraphicEtesianEngine.cpp +++ b/etesian/src/GraphicEtesianEngine.cpp @@ -94,29 +94,16 @@ namespace Etesian { } - void GraphicEtesianEngine::_resetPlacement () + void GraphicEtesianEngine::_place () { _viewer->clearToolInterrupt(); EtesianEngine* etesian = getForFramework( CreateEngine ); etesian->resetPlacement(); - } - - - void GraphicEtesianEngine::_place () - { - EtesianEngine* etesian = getForFramework( CreateEngine ); etesian->place(); } - void GraphicEtesianEngine::place () - { - ExceptionWidget::catchAllWrapper( std::bind(&GraphicEtesianEngine::_resetPlacement,this) ); - ExceptionWidget::catchAllWrapper( std::bind(&GraphicEtesianEngine::_place ,this) ); - } - - void GraphicEtesianEngine::postEvent () { static unsigned int count = 0; @@ -139,35 +126,16 @@ namespace Etesian { _viewer = viewer; - QMenu* prMenu = _viewer->findChild("viewer.menuBar.placeAndRoute"); - QMenu* stepMenu = _viewer->findChild("viewer.menuBar.placeAndRoute.stepByStep"); - if (prMenu == NULL) { - QMenuBar* menuBar = _viewer->findChild("viewer.menuBar"); - if (menuBar == NULL) { - cerr << Warning( "GraphicEtesianEngine::addToMenu() - No MenuBar in parent widget." ) << endl; - return; - } - prMenu = menuBar->addMenu( tr("P&&R") ); - prMenu->setObjectName( "viewer.menuBar.placeAndRoute" ); - - stepMenu = prMenu->addMenu( tr("&Step by Step") ); - stepMenu->setObjectName( "viewer.menuBar.placeAndRoute.stepByStep" ); - - prMenu->addSeparator(); + if (_viewer->hasMenuAction("placeAndRoute.etesianPlace")) { + cerr << Warning( "GraphicEtesianEngine::addToMenu() - Etesian placer already hooked in." ) << endl; + return; } - QAction* placeAction = _viewer->findChild("viewer.menuBar.placeAndRoute.etesianPlace"); - if (placeAction) - cerr << Warning( "GraphicEtesianEngine::addToMenu() - Etesian detailed router already hooked in." ) << endl; - else { - QAction* placeAction = new QAction ( tr("Etesian - &Place"), _viewer ); - placeAction->setObjectName( "viewer.menuBar.placeAndRoute.etesianPlace" ); - placeAction->setStatusTip ( tr("Place the design") ); - placeAction->setVisible ( true ); - prMenu->addAction( placeAction ); - - connect( placeAction , SIGNAL(triggered()), this, SLOT(place ()) ); - } + _viewer->addToMenu( "placeAndRoute.etesianPlace" + , "Etesian - Plac&e" + , "Run the Etesian placer" + , std::bind(&GraphicEtesianEngine::_place,this) + ); } diff --git a/etesian/src/etesian/GraphicEtesianEngine.h b/etesian/src/etesian/GraphicEtesianEngine.h index 7094ae05..5fdb17ae 100644 --- a/etesian/src/etesian/GraphicEtesianEngine.h +++ b/etesian/src/etesian/GraphicEtesianEngine.h @@ -61,8 +61,6 @@ namespace Etesian { virtual size_t release (); virtual void addToMenu ( CellViewer* ); void postEvent (); - public slots: - void place (); protected: static size_t _references; @@ -71,7 +69,6 @@ namespace Etesian { protected: GraphicEtesianEngine (); virtual ~GraphicEtesianEngine (); - void _resetPlacement (); void _place (); }; diff --git a/hurricane/src/isobar/PyHurricane.cpp b/hurricane/src/isobar/PyHurricane.cpp index b9b65c62..0e28b9dd 100644 --- a/hurricane/src/isobar/PyHurricane.cpp +++ b/hurricane/src/isobar/PyHurricane.cpp @@ -2,7 +2,7 @@ // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC 2008-2013, All Rights Reserved +// Copyright (c) UPMC 2008-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | diff --git a/hurricane/src/viewer/CellViewer.cpp b/hurricane/src/viewer/CellViewer.cpp index 0f441580..b6652adb 100644 --- a/hurricane/src/viewer/CellViewer.cpp +++ b/hurricane/src/viewer/CellViewer.cpp @@ -1,7 +1,7 @@ // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC/LIP6 2008-2014, All Rights Reserved +// Copyright (c) UPMC 2008-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | H U R R I C A N E | @@ -14,6 +14,7 @@ // +-----------------------------------------------------------------+ +#include #include #include #include @@ -29,10 +30,12 @@ #include #include +#include "vlsisapd/utilities/Path.h" #include "vlsisapd/configuration/Configuration.h" #include "hurricane/DataBase.h" #include "hurricane/Cell.h" //#include "MapView.h" +#include "hurricane/viewer/Script.h" #include "hurricane/viewer/Graphics.h" #include "hurricane/viewer/CellViewer.h" #include "hurricane/viewer/CellPrinter.h" @@ -41,7 +44,6 @@ #include "hurricane/viewer/ControllerWidget.h" #include "hurricane/viewer/ScriptWidget.h" #include "hurricane/viewer/ExceptionWidget.h" -//#include "hurricane/viewer/StratusWidget.h" #include "hurricane/viewer/GotoWidget.h" #include "hurricane/viewer/SelectCommand.h" @@ -69,32 +71,15 @@ namespace Hurricane { // ------------------------------------------------------------------- // Class : "CellViewer". + QString CellViewer::_prefixWPath ( "viewer.menuBar." ); + + CellViewer::CellViewer ( QWidget* parent ) : QMainWindow (parent) , _cellObserver (this) , _applicationName (tr("Viewer")) - , _toolInterruptAction (NULL) - , _openAction (NULL) - , _importAction (NULL) - , _nextAction (NULL) - , _printAction (NULL) - , _imageAction (NULL) - , _saveAction (NULL) - , _exportAction (NULL) - , _closeAction (NULL) - , _exitAction (NULL) - , _refreshAction (NULL) - , _fitToContentsAction (NULL) - , _gotoAction (NULL) , _showSelectionAction (NULL) - , _rubberChangeAction (NULL) - , _clearRulersAction (NULL) - , _controllerAction (NULL) - , _scriptAction (NULL) - , _stratusAction (NULL) - , _fileMenu (NULL) - , _viewMenu (NULL) - , _toolsMenu (NULL) , _debugMenu (NULL) + , _actionCallbacks () //, _mapView (NULL) , _mousePosition (NULL) , _controller (NULL) @@ -112,205 +97,13 @@ namespace Hurricane { , _flags (0) , _updateState (ExternalEmit) { - setObjectName("viewer"); - - createMenus (); - createLayout (); - } - - - CellViewer::~CellViewer () - { - _controller->deleteLater (); - //_script->deleteLater (); - _goto->deleteLater (); - } - - - void CellViewer::createActions () - { - if ( _openAction ) return; - - _toolInterruptAction = new QAction ( tr("Interrupt"), this ); - _toolInterruptAction->setObjectName ( "viewer.interrupt" ); - _toolInterruptAction->setShortcut ( QKeySequence(tr("CTRL+C")) ); - //_toolInterruptAction->setIcon ( QIcon(":/images/stock_open.png") ); - _toolInterruptAction->setStatusTip ( tr("Interrupt the running tool") ); - connect ( _toolInterruptAction, SIGNAL(triggered()), this, SLOT(raiseToolInterrupt()) ); - addAction ( _toolInterruptAction ); - - _openAction = new QAction ( tr("&Open Cell"), this ); - _openAction->setObjectName ( "viewer.menuBar.file.openCell" ); - _openAction->setShortcut ( QKeySequence(tr("CTRL+O")) ); - _openAction->setIcon ( QIcon(":/images/stock_open.png") ); - _openAction->setStatusTip ( tr("Open (load) a new Cell") ); - - _importAction = new QAction ( tr("&Import Cell"), this ); - _importAction->setObjectName ( "viewer.menuBar.file.importCell" ); - _importAction->setStatusTip ( tr("Import (convert) a new Cell") ); - - _nextAction = new QAction ( tr("&Next Breakpoint"), this ); - _nextAction->setObjectName ( "viewer.menuBar.file.nextBreakpoint" ); - _nextAction->setStatusTip ( tr("Proceed to the next breakpoint") ); - - for ( int i=0 ; isetObjectName ( QString("viewer.menuBar.file.cellHistory[%1]").arg(i) ); - _cellHistoryAction[i]->setVisible ( false ); - _cellHistoryAction[i]->setData ( i ); - _cellHistoryAction[i]->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); - connect ( _cellHistoryAction[i], SIGNAL(triggered()), this, SLOT(openHistoryCell())); - } - - _printAction = new QAction ( tr("&Print"), this ); - _printAction->setObjectName ( "viewer.menuBar.file.print" ); - _printAction->setStatusTip ( tr("Print the displayed area") ); - _printAction->setShortcut ( QKeySequence(tr("CTRL+P")) ); - _printAction->setVisible ( true ); - connect ( _printAction, SIGNAL(triggered()), this, SLOT(printDisplay()) ); - - _imageAction = new QAction ( tr("Save to &Image"), this ); - _imageAction->setObjectName ( "viewer.menuBar.file.image" ); - _imageAction->setStatusTip ( tr("Save the displayed area to image") ); - _imageAction->setVisible ( true ); - connect ( _imageAction, SIGNAL(triggered()), this, SLOT(imageDisplay()) ); - - _saveAction = new QAction ( tr("&Save Cell"), this ); - _saveAction->setObjectName ( "viewer.menuBar.file.saveCell" ); - _saveAction->setIcon ( QIcon(":/images/stock_save.png") ); - _saveAction->setStatusTip ( tr("Save (write) the current Cell") ); - _saveAction->setVisible ( false ); - - _exportAction = new QAction ( tr("&Export Cell"), this ); - _exportAction->setObjectName ( "viewer.menuBar.file.exportCell" ); - _exportAction->setStatusTip ( tr("Export (convert) Cell") ); - - _closeAction = new QAction ( tr("&Close"), this ); - _closeAction->setObjectName ( "viewer.menuBar.file.close" ); - _closeAction->setStatusTip ( tr("Close This Coriolis CellViewer") ); - _closeAction->setShortcut ( QKeySequence(tr("CTRL+W")) ); - connect ( _closeAction, SIGNAL(triggered()), this, SLOT(close()) ); - - _exitAction = new QAction ( tr("&Exit"), this ); - _exitAction->setObjectName ( "viewer.menuBar.file.exit" ); - _exitAction->setStatusTip ( tr("Exit All Coriolis CellViewer") ); - _exitAction->setShortcut ( QKeySequence(tr("CTRL+Q")) ); - connect ( _exitAction, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()) ); - - _refreshAction = new QAction ( tr("&Refresh"), this ); - _refreshAction->setObjectName ( "viewer.menuBar.view.refresh" ); - _refreshAction->setStatusTip ( tr("Force full redrawing of the display") ); - _refreshAction->setShortcut ( QKeySequence(tr("CTRL+L")) ); - - _fitToContentsAction = new QAction ( tr("&Fit to Contents"), this ); - _fitToContentsAction->setObjectName ( "viewer.menuBar.view.fit" ); - _fitToContentsAction->setStatusTip ( tr("Adjust zoom to fit the whole cell's contents") ); - _fitToContentsAction->setShortcut ( Qt::Key_F ); - - _gotoAction = new QAction ( tr("&Goto"), this ); - _gotoAction->setObjectName ( "viewer.menuBar.view.goto" ); - _gotoAction->setStatusTip ( tr("Center view on that point, with zoom adjustment") ); - _gotoAction->setShortcut ( Qt::Key_G ); - - _showSelectionAction = new QAction ( tr("&Show Selection"), this ); - _showSelectionAction->setObjectName ( "viewer.menuBar.view.showSelection" ); - _showSelectionAction->setStatusTip ( tr("Highlight the selected items (darken others)") ); - _showSelectionAction->setShortcut ( Qt::Key_S ); - _showSelectionAction->setCheckable ( true ); - - _rubberChangeAction = new QAction ( tr("Change Rubber Style"), this ); - _rubberChangeAction->setObjectName ( "viewer.menuBar.view.changeRubber" ); - _rubberChangeAction->setStatusTip ( tr("Cycle through all avalaibles rubber drawing styles") ); - _rubberChangeAction->setShortcut ( Qt::Key_Asterisk ); - - _clearRulersAction = new QAction ( tr("Clear Rulers"), this ); - _clearRulersAction->setObjectName ( "viewer.menuBar.view.clearRulers" ); - _clearRulersAction->setStatusTip ( tr("Remove all rulers") ); - //_clearRulersAction->setShortcut ( QKeySequence(tr("K")) ); - - _controllerAction = new QAction ( tr("Controller"), this ); - _controllerAction->setObjectName ( "viewer.menuBar.tools.controller" ); - _controllerAction->setStatusTip ( tr("Fine Tune && Inspect DataBase") ); - _controllerAction->setIcon ( QIcon(":/images/swiss-knife.png") ); - _controllerAction->setShortcut ( QKeySequence(tr("CTRL+I")) ); - - _scriptAction = new QAction ( tr("Python Script"), this ); - _scriptAction->setObjectName ( "viewer.menuBar.tools.script" ); - _scriptAction->setStatusTip ( tr("Run Python Script. Must provide a ScripMain(cell) function") ); - _scriptAction->setIcon ( QIcon(":/images/python-logo-v3.png") ); - _scriptAction->setShortcut ( QKeySequence(tr("SHIFT+P,SHIFT+S")) ); - - //_stratusAction = new QAction ( tr("Stratus"), this ); - //_stratusAction->setObjectName ( "viewer.menuBar.tools.stratusScript" ); - //_stratusAction->setStatusTip ( tr("Run Stratus Script") ); - //_stratusAction->setIcon ( QIcon(":/images/stratus-cloud.png") ); - //_stratusAction->setShortcut ( QKeySequence(tr("SHIFT+P,SHIFT+S")) ); - } - - - void CellViewer::createMenus () - { - if ( _fileMenu ) return; - if ( !_openAction ) createActions (); - - menuBar()->setObjectName ( tr("viewer.menuBar") ); - - _fileMenu = menuBar()->addMenu ( tr("File") ); - _fileMenu->setObjectName ( "viewer.menuBar.file" ); - _fileMenu->addAction ( _openAction ); - _fileMenu->addSeparator (); - for ( size_t i=0 ; iaddAction ( _cellHistoryAction[i] ); - } - _fileMenu->addSeparator (); - _fileMenu->addAction ( _saveAction ); - _fileMenu->addSeparator (); - _fileMenu->addAction ( _importAction ); - _fileMenu->addAction ( _exportAction ); - _fileMenu->addSeparator (); - _fileMenu->addAction ( _printAction ); - _fileMenu->addAction ( _imageAction ); - _fileMenu->addAction ( _nextAction ); - _fileMenu->addSeparator (); - _fileMenu->addAction ( _closeAction ); - _fileMenu->addAction ( _exitAction ); - - _viewMenu = menuBar()->addMenu ( tr("View") ); - _viewMenu->setObjectName ( "viewer.menuBar.view" ); - _viewMenu->addAction ( _refreshAction ); - _viewMenu->addAction ( _fitToContentsAction ); - _viewMenu->addAction ( _gotoAction ); - _viewMenu->addAction ( _showSelectionAction ); - _viewMenu->addAction ( _rubberChangeAction ); - _viewMenu->addAction ( _clearRulersAction ); - - _toolsMenu = menuBar()->addMenu ( tr("Tools") ); - _toolsMenu->setObjectName ( "viewer.menuBar.tools" ); - _toolsMenu->addAction ( _controllerAction ); - _toolsMenu->addAction ( _scriptAction ); - //_toolsMenu->addAction ( _stratusAction ); - } - - - QMenu* CellViewer::createDebugMenu () - { - if ( !_debugMenu ) { - _debugMenu = menuBar()->addMenu ( tr("Debug") ); - _debugMenu->setObjectName ( "viewer.menuBar.debug" ); - } - return _debugMenu; - } - - - void CellViewer::createLayout () - { - if (_cellWidget) return; + setObjectName( "viewer" ); + menuBar()->setObjectName ( _getAbsWidgetPath("") ); _cellWidget = new CellWidget (); _controller = new ControllerWidget(); _goto = new GotoWidget (); _goto->changeDbuMode( _cellWidget->getDbuMode(), _cellWidget->getUnitPower() ); - //_mapView = _cellWidget->getMapView (); _cellWidget->bindCommand( &_moveCommand ); _cellWidget->bindCommand( &_zoomCommand ); @@ -319,7 +112,7 @@ namespace Hurricane { _cellWidget->bindCommand( &_hierarchyCommand ); _controller->setCellWidget( _cellWidget ); - MousePositionWidget* _mousePosition = new MousePositionWidget(); + _mousePosition = new MousePositionWidget(); statusBar()->addPermanentWidget( _mousePosition ); setCorner( Qt::TopLeftCorner , Qt::LeftDockWidgetArea ); @@ -327,6 +120,7 @@ namespace Hurricane { setCorner( Qt::TopRightCorner , Qt::RightDockWidgetArea ); setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea ); + //_mapView = _cellWidget->getMapView (); //QDockWidget* mapViewDock = new QDockWidget ( tr("Map") ); //mapViewDock->setFeatures ( QDockWidget::DockWidgetVerticalTitleBar // | QDockWidget::DockWidgetMovable @@ -339,41 +133,385 @@ namespace Hurricane { setCentralWidget( _cellWidget ); - connect( this , SIGNAL(cellPreModificated()) , _cellWidget, SLOT(cellPreModificate()) ); - connect( this , SIGNAL(cellPostModificated()), _cellWidget, SLOT(cellPostModificate()) ); - connect( this , SIGNAL(redrawCellWidget()) , _cellWidget, SLOT(refresh()) ); - connect( _refreshAction , SIGNAL(triggered()) , _cellWidget, SLOT(refresh()) ); - connect( _fitToContentsAction , SIGNAL(triggered()) , _cellWidget, SLOT(fitToContents()) ); - connect( _showSelectionAction , SIGNAL(toggled(bool)) , this , SLOT(setShowSelection(bool)) ); - connect( _rubberChangeAction , SIGNAL(triggered()) , _cellWidget, SLOT(rubberChange()) ); - connect( _clearRulersAction , SIGNAL(triggered()) , _cellWidget, SLOT(clearRulers()) ); - connect( _controllerAction , SIGNAL(triggered()) , _controller, SLOT(toggleShow()) ); - connect( _scriptAction , SIGNAL(triggered()) , this , SLOT(runScript()) ); - //connect( _stratusAction , SIGNAL(triggered()) , this , SLOT(runStratusScript()) ); - connect( _gotoAction , SIGNAL(triggered()) , this , SLOT(doGoto()) ); + createMenus(); - connect( _cellWidget , SIGNAL(dbuModeChanged(unsigned int,DbU::UnitPower)) - , _goto , SLOT (changeDbuMode (unsigned int,DbU::UnitPower)) ); + connect( this , SIGNAL(cellPreModificated()) , _cellWidget, SLOT(cellPreModificate()) ); + connect( this , SIGNAL(cellPostModificated()), _cellWidget, SLOT(cellPostModificate()) ); + connect( this , SIGNAL(redrawCellWidget()) , _cellWidget, SLOT(refresh()) ); - connect( _cellWidget , SIGNAL(mousePositionChanged(const Point&)) - , _mousePosition , SLOT (setPosition(const Point&)) ); + connect( _cellWidget , SIGNAL(dbuModeChanged(unsigned int,DbU::UnitPower)) + , _goto , SLOT (changeDbuMode (unsigned int,DbU::UnitPower)) ); - connect( _cellWidget , SIGNAL(selectionModeChanged()) - , this , SLOT (changeSelectionMode ()) ); - //connect( &_selectCommand , SIGNAL(selectionToggled (Occurrence)) - // , _cellWidget , SLOT (toggleSelection (Occurrence)) ); - connect( &_selectCommand , SIGNAL(selectionToggled (Occurrence)) - , _cellWidget , SLOT (select (Occurrence)) ); + connect( _cellWidget , SIGNAL(mousePositionChanged(const Point&)) + , _mousePosition , SLOT (setPosition(const Point&)) ); - connect( _cellWidget , SIGNAL(stateChanged(shared_ptr&)) - , this , SLOT (setState (shared_ptr&)) ); - connect( this , SIGNAL(stateChanged(shared_ptr&)) - , _cellWidget , SLOT (setState (shared_ptr&)) ); + connect( _cellWidget , SIGNAL(selectionModeChanged()) + , this , SLOT (changeSelectionMode ()) ); + connect( &_selectCommand, SIGNAL(selectionToggled (Occurrence)) + , _cellWidget , SLOT (select (Occurrence)) ); + + connect( _cellWidget , SIGNAL(stateChanged(shared_ptr&)) + , this , SLOT (setState (shared_ptr&)) ); + connect( this , SIGNAL(stateChanged(shared_ptr&)) + , _cellWidget , SLOT (setState (shared_ptr&)) ); _cellWidget->refresh(); } + CellViewer::~CellViewer () + { + _controller->deleteLater (); + //_script->deleteLater (); + _goto->deleteLater (); + } + + + QString CellViewer::_getAbsWidgetPath ( const QString& relPath ) const + { + if (relPath.startsWith("viewer.")) return relPath; + return QString(_prefixWPath).append( relPath ); + } + + + bool CellViewer::hasMenu( const QString& relativePath ) const + { return findChild(_getAbsWidgetPath(relativePath)) != NULL; } + + + bool CellViewer::hasMenuAction( const QString& relativePath ) const + { return findChild(_getAbsWidgetPath(relativePath)) != NULL; } + + + QMenu* CellViewer::_getParentMenu( const QString& absolutePath ) const + { + QString parentPath = absolutePath.section('.',0,-2); + QMenu* parentMenu = findChild(parentPath); + if (parentMenu == NULL) { + if (parentPath != "viewer") { + cerr << Warning( "CellViewer::_getParentMenu() - Missing parent menu for %s." + , absolutePath.toStdString().c_str() ) << endl; + } + return NULL; + } + return parentMenu; + } + + + QMenu* CellViewer::addMenu ( const QString& path, string text, unsigned int flags ) + { + QString absolutePath = _getAbsWidgetPath( path ); + QMenu* menu = findChild(absolutePath); + + if (menu != NULL) return menu; + + if (flags & TopMenu) { + menu = menuBar()->addMenu( tr(text.c_str()) ); + menu->setObjectName( absolutePath ); + } else { + QMenu* parentMenu = _getParentMenu( absolutePath ); + if (parentMenu == NULL) return NULL; + + menu = parentMenu->addMenu( tr(text.c_str()) ); + menu->setObjectName( absolutePath ); + } + return menu; + } + + + bool CellViewer::addToMenu ( const QString& path ) + { + if (not path.endsWith("====")) return false; + + QMenu* menu = _getParentMenu( _getAbsWidgetPath(path) ); + if (menu == NULL) return false; + + menu->addSeparator(); + return true; + } + + + QAction* CellViewer::addToMenu ( const QString& path + , string text + , string textTip + , std::function< void() > callback + , QIcon icon ) + { + QString absolutePath = _getAbsWidgetPath( path ); + QAction* action = findChild(absolutePath); + if (action == NULL) { + QMenu* parentMenu = _getParentMenu( absolutePath ); + if (parentMenu == NULL) return NULL; + + action = new QAction( tr(text.c_str()), this ); + action->setObjectName( absolutePath ); + action->setStatusTip ( tr(textTip.c_str()) ); + action->setVisible ( true ); + if (not icon.isNull()) action->setIcon( icon ); + parentMenu->addAction( action ); + + _actionCallbacks.insert( make_pair(absolutePath,boost::any(callback)) ); + connect( action, SIGNAL(triggered()), this, SLOT(doAction()) ); + } + return action; + } + + + QAction* CellViewer::addToMenu ( const QString& path + , string text + , string textTip + , string scriptPath ) + { + QString absolutePath = _getAbsWidgetPath( path ); + QAction* action = findChild(absolutePath); + if (action == NULL) { + action = new QAction( tr(text.c_str()), this ); + action->setObjectName( absolutePath ); + action->setStatusTip ( tr(textTip.c_str()) ); + action->setVisible ( true ); + + QMenu* parentMenu = _getParentMenu( absolutePath ); + if (parentMenu != NULL) { + parentMenu->addAction( action ); + } else if (absolutePath == "viewer") { + addAction( action ); + } + + _actionCallbacks.insert( make_pair(absolutePath,boost::any(QString(scriptPath.c_str()))) ); + connect( action, SIGNAL(triggered()), this, SLOT(doAction()) ); + } + return action; + } + + + QAction* CellViewer::addToMenu ( QString path + , QString text + , QString textTip + , const QKeySequence& shortCut + , QIcon icon + //, QWidget* receiver + //, SlotMethod slotMethod + ) + { + QString absolutePath = _getAbsWidgetPath( path ); + QAction* action = findChild(absolutePath); + if (action == NULL) { + action = new QAction( text, this ); + action->setObjectName( absolutePath ); + action->setStatusTip ( textTip ); + action->setShortcut ( shortCut ); + action->setVisible ( true ); + if (not icon.isNull()) action->setIcon( icon ); + + QMenu* parentMenu = _getParentMenu( absolutePath ); + if (parentMenu != NULL) { + parentMenu->addAction( action ); + } else if (absolutePath == "viewer") { + addAction( action ); + } + + //if ((receiver != NULL) and (slotMethod != NULL)) + // connect( action, &QAction::triggered, receiver, slotMethod ); + } + return action; + } + + + void CellViewer::doAction () + { + QString path = sender()->objectName(); + ActionLut::const_iterator iaction = _actionCallbacks.find( path ); + if (iaction == _actionCallbacks.end()) { + cerr << Error( "CellViewer::doAction() - Path \"%s\" in not registered." + , path.toStdString().c_str() ) << endl; + return; + } + + const boost::any& callback = iaction->second; + if (callback.type() == typeid( std::function )) { + cerr << "Called function " << qPrintable(path) << endl; + ExceptionWidget::catchAllWrapper( boost::any_cast< std::function >(callback) ); + } else if (callback.type() == typeid( QString )) { + cerr << "Called script " << qPrintable(path) << ":" + << qPrintable(boost::any_cast(callback)) << endl; + runScript( boost::any_cast(callback) ); + } else { + cerr << Error("CellViewer::doAction(): For action \"%s\",\n" + " cannot cast the callback into QString or std::function." + , path.toStdString().c_str() ) << endl; + } + } + + + void CellViewer::createMenus () + { + addMenu ( "file" , "File" , TopMenu ); + addMenu ( "view" , "View" , TopMenu ); + addMenu ( "tools", "Tools", TopMenu ); + + // Building the "File" menu. + QAction* action = addToMenu( "viewer.interrupt" + , tr("Interrupt") + , tr("Interrupt the running tool") + , QKeySequence(tr("CTRL+C")) + ); + action->setVisible( false ); + addAction( action ); + connect( action, &QAction::triggered, this, &CellViewer::raiseToolInterrupt ); + + action = addToMenu( "file.openCell" + , tr("&Open Cell") + , tr("Open (load) a new Cell") + , QKeySequence(tr("CTRL+O")) + , QIcon(":/images/stock_open.png") + ); + addToMenu( "file.========" ); + + for ( int i=0 ; isetVisible( false ); + _cellHistoryAction[i]->setData ( i ); + _cellHistoryAction[i]->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); + connect( _cellHistoryAction[i], &QAction::triggered, this, &CellViewer::openHistoryCell ); + } + addToMenu( "file.========" ); + + action = addToMenu( "file.saveCell" + , tr("&Save Cell") + , tr("Save (write) the current Cell") + , QKeySequence() + , QIcon(":/images/stock_save.png") + ); + action->setVisible( false ); + addToMenu( "file.========" ); + + action = addToMenu( "file.importCell" + , tr("&Import Cell") + , tr("Import (convert) a new Cell") + , QKeySequence() + ); + action = addToMenu( "file.exportCell" + , tr("&Export Cell") + , tr("Export (convert) Cell") + , QKeySequence() + ); + addToMenu( "file.========" ); + + action = addToMenu( "file.print" + , tr("&Print") + , tr("Print the displayed area") + , QKeySequence(tr("CTRL+P")) + ); + connect( action, &QAction::triggered, this, &CellViewer::printDisplay ); + + action = addToMenu( "file.image" + , tr("Save to &Image") + , tr("Save the displayed area to image") + , QKeySequence() + ); + connect( action, &QAction::triggered, this, &CellViewer::imageDisplay ); + + action = addToMenu( "file.nextBreakpoint" + , tr("&Next Breakpoint") + , tr("Proceed to the next breakpoint") + , QKeySequence() + ); + addToMenu( "file.========" ); + + action = addToMenu( "file.close" + , tr("&Close") + , tr("Close This Coriolis CellViewer") + , QKeySequence(tr("CTRL+W")) + ); + connect( action, &QAction::triggered, this, &CellViewer::close ); + + action = addToMenu( "file.close" + , tr("&Close") + , tr("Close This Coriolis CellViewer") + , QKeySequence(tr("CTRL+W")) + ); + + action = addToMenu( "file.exit" + , tr("&Exit") + , tr("Exit All Coriolis CellViewer") + , QKeySequence(tr("CTRL+Q")) + ); + connect ( action, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()) ); + + // Building the "View" menu. + action = addToMenu( "view.refresh" + , tr("&Refresh") + , tr("Force full redrawing of the display") + , QKeySequence(tr("CTRL+L")) + ); + connect( action, &QAction::triggered, _cellWidget, &CellWidget::refresh ); + + action = addToMenu( "view.fit" + , tr("&Fit to Contents") + , tr("Adjust zoom to fit the whole cell's contents") + , Qt::Key_F + ); + connect( action, &QAction::triggered, _cellWidget, &CellWidget::fitToContents ); + + action = addToMenu( "view.goto" + , tr("&Goto") + , tr("Center view on that point, with zoom adjustment") + , Qt::Key_G + ); + connect( action, &QAction::triggered, this, &CellViewer::doGoto ); + + _showSelectionAction = addToMenu( "view.showSelection" + , tr("&Show Selection") + , tr("Highlight the selected items (darken others)") + , Qt::Key_S + ); + _showSelectionAction->setCheckable( true ); + connect( _showSelectionAction, &QAction::toggled, this, &CellViewer::setShowSelection ); + + action = addToMenu( "view.changeRubber" + , tr("Change Rubber Style") + , tr("Cycle through all avalaibles rubber drawing styles") + , Qt::Key_Asterisk + ); + connect( action, &QAction::triggered, _cellWidget, &CellWidget::rubberChange ); + + action = addToMenu( "view.clearRulers" + , tr("Clear Rulers") + , tr("Remove all rulers") + , QKeySequence() + ); + connect( action, &QAction::triggered, _cellWidget, &CellWidget::clearRulers ); + + // Building the "Tools" menu. + action = addToMenu( "tools.controller" + , tr("Controller") + , tr("Fine Tune && Inspect DataBase") + , QKeySequence(tr("CTRL+I")) + , QIcon(":/images/swiss-knife.png") + ); + connect( action, &QAction::triggered, _controller, &ControllerWidget::toggleShow ); + + action = addToMenu( "tools.script" + , tr("Python Script") + , tr("Run Python Script. Must provide a ScripMain(cell) function") + , QKeySequence(tr("SHIFT+P,SHIFT+S")) + , QIcon(":/images/python-logo-v3.png") + ); + connect( action, &QAction::triggered, this, &CellViewer::runScriptWidget ); + } + + + QMenu* CellViewer::createDebugMenu () + { + if (not _debugMenu) + addMenu ( "debug" , "Debug" , TopMenu ); + return _debugMenu; + } + + void CellViewer::refreshTitle () { QString cellName = "None"; @@ -619,18 +757,35 @@ namespace Hurricane { } - void CellViewer::_runScript () + void CellViewer::_runScript ( QString scriptPath ) + { + if (scriptPath.endsWith(".py",Qt::CaseInsensitive)) + scriptPath.truncate( scriptPath.size()-3 ); + + Utilities::Path userScript ( scriptPath.toStdString() ); + Utilities::Path userDirectory ( userScript.dirname() ); + + if (not userDirectory.absolute()) + userDirectory = Utilities::Path::cwd() / userDirectory; + + Isobar::Script::addPath( userDirectory.string() ); + + dbo_ptr script = Isobar::Script::create(userScript.basename().string()); + script->setEditor ( this ); + script->runFunction( "ScriptMain", getCell() ); + + Isobar::Script::removePath( userDirectory.string() ); + } + + + void CellViewer::runScript ( QString scriptPath ) + { ExceptionWidget::catchAllWrapper( std::bind( &CellViewer::_runScript, this, scriptPath ) ); } + + + void CellViewer::runScriptWidget () { ScriptWidget::runScript( this, getCell() ); } - void CellViewer::runScript () - { ExceptionWidget::catchAllWrapper( std::bind( &CellViewer::_runScript, this ) ); } - - -//void CellViewer::runStratusScript () -//{ StratusWidget::runScript ( this ); } - - string CellViewer::_getString () const { ostringstream s; diff --git a/hurricane/src/viewer/PyCellViewer.cpp b/hurricane/src/viewer/PyCellViewer.cpp index 475fc198..55a634b8 100644 --- a/hurricane/src/viewer/PyCellViewer.cpp +++ b/hurricane/src/viewer/PyCellViewer.cpp @@ -1,8 +1,7 @@ - // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC/LIP6 2010-2012, All Rights Reserved +// Copyright (c) UPMC 2010-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | @@ -41,6 +40,95 @@ extern "C" { DirectDestroyAttribute(PyCellViewer_destroy, PyCellViewer) + static PyObject* PyCellViewer_hasMenu ( PyCellViewer* self, PyObject* args ) + { + trace << "PyCellViewer_hasMenu()" << endl; + + HTRY + METHOD_HEAD("CellViewer.hasMenu()") + + char* path = NULL; + if (not PyArg_ParseTuple(args,"s:CellViewer.hasMenu()", &path)) { + PyErr_SetString ( ConstructorError, "CellViewer.hasMenu(): Takes exactly one argument." ); + return NULL; + } + + if (cw->hasMenu( path )) Py_RETURN_TRUE; + HCATCH + + Py_RETURN_FALSE; + } + + + static PyObject* PyCellViewer_hasMenuAction ( PyCellViewer* self, PyObject* args ) + { + trace << "PyCellViewer_hasMenuAction()" << endl; + + HTRY + METHOD_HEAD("CellViewer.hasMenuAction()") + + char* path = NULL; + if (not PyArg_ParseTuple(args,"s:CellViewer.hasMenuAction()", &path)) { + PyErr_SetString ( ConstructorError, "CellViewer.hasMenuAction(): Takes exactly one argument." ); + return NULL; + } + + if (cw->hasMenuAction( path )) Py_RETURN_TRUE; + HCATCH + + Py_RETURN_FALSE; + } + + + static PyObject* PyCellViewer_addMenu ( PyCellViewer* self, PyObject* args ) + { + trace << "PyCellViewer_addMenu()" << endl; + + HTRY + METHOD_HEAD("CellViewer.addMenu()") + + char* path = NULL; + char* text = NULL; + long flags = 0; + if (not PyArg_ParseTuple(args,"ssl:CellViewer.addMenu()", &path, &text, &flags)) { + PyErr_SetString ( ConstructorError, "CellViewer.addMenu(): Takes exactly three arguments." ); + return NULL; + } + + if (cw->addMenu( path, text, flags )) Py_RETURN_TRUE; + HCATCH + + Py_RETURN_FALSE; + } + + + static PyObject* PyCellViewer_addToMenu ( PyCellViewer* self, PyObject* args ) + { + trace << "PyCellViewer_addToMenu()" << endl; + + HTRY + METHOD_HEAD("CellViewer.addToMenu()") + + char* path = NULL; + char* text = NULL; + char* textTip = NULL; + char* scriptPath = NULL; + if (not PyArg_ParseTuple(args,"s|sss:CellViewer.addToMenu()", &path, &text, &textTip, &scriptPath)) { + PyErr_SetString ( ConstructorError, "CellViewer.addToMenu(): Takes one or four arguments exactly." ); + return NULL; + } + + if (text != NULL) { + if (cw->addToMenu( path, text, textTip, scriptPath )) Py_RETURN_TRUE; + } else { + if (cw->addToMenu( path )) Py_RETURN_TRUE; + } + HCATCH + + Py_RETURN_FALSE; + } + + static PyObject* PyCellViewer_getCell ( PyCellViewer* self ) { trace << "PyCellViewer_getCell ()" << endl; @@ -170,7 +258,15 @@ extern "C" { // PyCellViewer Attribute Method table. PyMethodDef PyCellViewer_Methods[] = - { { "getCell" , (PyCFunction)PyCellViewer_getCell , METH_NOARGS + { { "hasMenu" , (PyCFunction)PyCellViewer_hasMenu , METH_VARARGS + , "Return true if the menu at \"path\" exists." } + , { "hasMenuAction" , (PyCFunction)PyCellViewer_hasMenuAction , METH_VARARGS + , "Return true if the menu action at \"path\" exists." } + , { "addMenu" , (PyCFunction)PyCellViewer_addMenu , METH_VARARGS + , "Create a new menu at \"path\" and returns true if success." } + , { "addToMenu" , (PyCFunction)PyCellViewer_addToMenu , METH_VARARGS + , "Creates a new action at \"path\" and returns true if success." } + , { "getCell" , (PyCFunction)PyCellViewer_getCell , METH_NOARGS , "Return the currently edited Cell." } , { "setCell" , (PyCFunction)PyCellViewer_setCell , METH_VARARGS , "Load a Cell into the viewer." } @@ -205,6 +301,19 @@ extern "C" { PyTypeRootObjectDefinitions(CellViewer) + static void CellViewerLoadConstants ( PyObject* dictionnary ) { + PyObject* constant; + + LoadObjectConstant( dictionnary, CellViewer::NoFlags, "NoFlags" ) + LoadObjectConstant( dictionnary, CellViewer::TopMenu, "TopMenu" ) + } + + + extern void PyCellViewer_postModuleInit () + { + CellViewerLoadConstants(PyTypeCellViewer.tp_dict); + } + # endif // End of Shared Library Code Part. diff --git a/hurricane/src/viewer/PyViewer.cpp b/hurricane/src/viewer/PyViewer.cpp index 95572f7e..b593eedf 100644 --- a/hurricane/src/viewer/PyViewer.cpp +++ b/hurricane/src/viewer/PyViewer.cpp @@ -1,8 +1,7 @@ - // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC/LIP6 2010-2012, All Rights Reserved +// Copyright (c) UPMC/LIP6 2010-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | @@ -113,6 +112,7 @@ extern "C" { PyModule_AddObject ( module, "CellViewer", (PyObject*)&PyTypeCellViewer ); PyDisplayStyle_postModuleInit(); + PyCellViewer_postModuleInit(); trace << "Viewer.so loaded " << (void*)&typeid(string) << endl; } diff --git a/hurricane/src/viewer/ScriptWidget.cpp b/hurricane/src/viewer/ScriptWidget.cpp index 58648ea4..966b8cda 100644 --- a/hurricane/src/viewer/ScriptWidget.cpp +++ b/hurricane/src/viewer/ScriptWidget.cpp @@ -14,7 +14,6 @@ // +-----------------------------------------------------------------+ -#include #include #include using namespace std; @@ -27,9 +26,7 @@ using namespace std; #include #include #include -#include "vlsisapd/utilities/Path.h" #include "hurricane/Warning.h" -#include "hurricane/viewer/Script.h" #include "hurricane/viewer/Graphics.h" #include "hurricane/viewer/ScriptWidget.h" #include "hurricane/viewer/CellViewer.h" @@ -94,34 +91,21 @@ namespace Hurricane { } - bool ScriptWidget::runScript ( QWidget* parent, Cell* cell ) + void ScriptWidget::runScript ( QWidget* parent, Cell* cell ) { ScriptWidget* dialog = new ScriptWidget ( parent ); bool doRunScript = (dialog->exec() == Accepted); QString scriptName = dialog->getScriptName (); delete dialog; - if ( not doRunScript ) return false; + if (not doRunScript) return; - if ( scriptName.endsWith(".py",Qt::CaseInsensitive) ) - scriptName.truncate ( scriptName.size()-3 ); - - Utilities::Path userScript ( scriptName.toStdString() ); - Utilities::Path userDirectory ( userScript.dirname() ); - - if ( not userDirectory.absolute() ) - userDirectory = Utilities::Path::cwd() / userDirectory; - - Isobar::Script::addPath ( userDirectory.string() ); - - dbo_ptr script = Isobar::Script::create(userScript.basename().string()); - script->setEditor ( qobject_cast(parent) ); - - bool returnCode = script->runFunction ( "ScriptMain", cell ); - - Isobar::Script::removePath ( userDirectory.string() ); - - return returnCode; + CellViewer* cw = qobject_cast(parent); + if (not cw) { + cerr << Error("ScriptWidget::runScript(): The parent widget is *not* a CellViewer, cancelling.") << endl; + return; + } + cw->runScript( scriptName ); } diff --git a/hurricane/src/viewer/hurricane/viewer/CellViewer.h b/hurricane/src/viewer/hurricane/viewer/CellViewer.h index 92658f03..2efca82d 100644 --- a/hurricane/src/viewer/hurricane/viewer/CellViewer.h +++ b/hurricane/src/viewer/hurricane/viewer/CellViewer.h @@ -18,9 +18,11 @@ #define HURRICANE_CELL_VIEWER_H #include +#include #include -using namespace std; +#include +#include #include class QEvent; class QKeyEvent; @@ -76,13 +78,39 @@ namespace Hurricane { Q_OBJECT; public: - enum { CellHistorySize = 10 }; - enum Flag { InCellChange = 0x0001 }; + enum { CellHistorySize = 10 }; + enum Flag { InCellChange = 0x0001 }; + enum FunctionFlag { NoFlags = 0x0000 + , TopMenu = 0x0001 }; + private: + typedef std::map< const QString, boost::any > ActionLut; + typedef bool (QWidget::* SlotMethod)(); public: CellViewer ( QWidget* parent=NULL ); virtual ~CellViewer (); inline bool isToolInterrupted () const; QMenu* createDebugMenu (); + bool hasMenu ( const QString& path ) const; + bool hasMenuAction ( const QString& path ) const; + QMenu* addMenu ( const QString& path + , std::string text + , unsigned int flags=NoFlags + ); + bool addToMenu ( const QString& path ); + QAction* addToMenu ( const QString& path + , std::string text + , std::string textTip + , std::function< void() > + , QIcon icon=QIcon() ); + QAction* addToMenu ( const QString& path + , std::string text + , std::string textTip + , std::string scriptPath ); + QAction* addToMenu ( QString path + , QString text + , QString textTip + , const QKeySequence& shortCut + , QIcon icon =QIcon()); inline void setEnableRedrawInterrupt ( bool ); inline void setApplicationName ( const QString& ); inline CellObserver* getCellObserver (); @@ -98,9 +126,10 @@ namespace Hurricane { void unselect ( Occurrence& ); void unselectAll (); inline void setLayerVisible ( const Name& layer, bool visible ); - void _runScript (); + void runScript ( QString scriptPath ); virtual std::string _getString () const; public slots: + void doAction (); void doGoto (); void changeSelectionMode (); void setShowSelection ( bool ); @@ -111,8 +140,7 @@ namespace Hurricane { void imageDisplay (); void raiseToolInterrupt (); void clearToolInterrupt (); - void runScript (); - //void runStratusScript (); + void runScriptWidget (); inline void emitCellAboutToChange (); inline void emitCellChanged (); signals: @@ -122,56 +150,40 @@ namespace Hurricane { void cellPreModificated (); void cellPostModificated (); protected: - void createActions (); void createMenus (); - void createLayout (); void refreshTitle (); void refreshHistory (); + private: + QString _getAbsWidgetPath ( const QString& relPath ) const; + QMenu* _getParentMenu ( const QString& ) const; + void _runScript ( QString scriptPath ); protected: - CellObserver _cellObserver; - QString _applicationName; - QAction* _toolInterruptAction; - QAction* _openAction; - QAction* _importAction; - QAction* _nextAction; - QAction* _cellHistoryAction[CellHistorySize]; - QAction* _printAction; - QAction* _imageAction; - QAction* _saveAction; - QAction* _exportAction; - QAction* _closeAction; - QAction* _exitAction; - QAction* _refreshAction; - QAction* _fitToContentsAction; - QAction* _gotoAction; - QAction* _showSelectionAction; - QAction* _rubberChangeAction; - QAction* _clearRulersAction; - QAction* _controllerAction; - QAction* _scriptAction; - QAction* _stratusAction; - QMenu* _fileMenu; - QMenu* _viewMenu; - QMenu* _toolsMenu; - QMenu* _debugMenu; - //MapView* _mapView; - MousePositionWidget* _mousePosition; - ControllerWidget* _controller; - ScriptWidget* _script; - GotoWidget* _goto; - CellWidget* _cellWidget; - MoveCommand _moveCommand; - ZoomCommand _zoomCommand; - RulerCommand _rulerCommand; - SelectCommand _selectCommand; - HierarchyCommand _hierarchyCommand; - list< shared_ptr > - _cellHistory; - bool _firstShow; - bool _toolInterrupt; - unsigned int _flags; - UpdateState _updateState; + static QString _prefixWPath; + CellObserver _cellObserver; + QString _applicationName; + QAction* _openAction; + QAction* _cellHistoryAction[CellHistorySize]; + QAction* _showSelectionAction; + QMenu* _debugMenu; + ActionLut _actionCallbacks; + // MapView* _mapView; + MousePositionWidget* _mousePosition; + ControllerWidget* _controller; + ScriptWidget* _script; + GotoWidget* _goto; + CellWidget* _cellWidget; + MoveCommand _moveCommand; + ZoomCommand _zoomCommand; + RulerCommand _rulerCommand; + SelectCommand _selectCommand; + HierarchyCommand _hierarchyCommand; + list< shared_ptr > + _cellHistory; + bool _firstShow; + bool _toolInterrupt; + unsigned int _flags; + UpdateState _updateState; }; diff --git a/hurricane/src/viewer/hurricane/viewer/PyCellViewer.h b/hurricane/src/viewer/hurricane/viewer/PyCellViewer.h index 16d8b0b7..ea52e336 100644 --- a/hurricane/src/viewer/hurricane/viewer/PyCellViewer.h +++ b/hurricane/src/viewer/hurricane/viewer/PyCellViewer.h @@ -1,8 +1,7 @@ - // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC/LIP6 2010-2012, All Rights Reserved +// Copyright (c) UPMC 2010-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | @@ -15,8 +14,8 @@ // +-----------------------------------------------------------------+ -#ifndef __PY_HURRICANE_CELL_VIEWER__ -#define __PY_HURRICANE_CELL_VIEWER__ +#ifndef PY_HURRICANE_CELL_VIEWER_H +#define PY_HURRICANE_CELL_VIEWER_H #include "hurricane/isobar/PyHurricane.h" #include "hurricane/viewer/CellViewer.h" @@ -42,8 +41,9 @@ extern "C" { extern PyTypeObject PyTypeCellViewer; extern PyMethodDef PyCellViewer_Methods[]; - extern PyObject* PyCellViewer_create ( PyObject* self, PyObject* args ); - extern void PyCellViewer_LinkPyType (); + extern PyObject* PyCellViewer_create ( PyObject* self, PyObject* args ); + extern void PyCellViewer_LinkPyType (); + extern void PyCellViewer_postModuleInit (); #define IsPyCellViewer(v) ( (v)->ob_type == &PyTypeCellViewer ) @@ -57,4 +57,4 @@ extern "C" { } // End of Isobar namespace. -#endif // __PY_HURRICANE_CELL_VIEWER__ +#endif // PY_HURRICANE_CELL_VIEWER_H diff --git a/hurricane/src/viewer/hurricane/viewer/Script.h b/hurricane/src/viewer/hurricane/viewer/Script.h index 0963e440..ddc94f88 100644 --- a/hurricane/src/viewer/hurricane/viewer/Script.h +++ b/hurricane/src/viewer/hurricane/viewer/Script.h @@ -1,8 +1,7 @@ - // -*- C++ -*- // // This file is part of the Coriolis Software. -// Copyright (c) UPMC/LIP6 2008-2012, All Rights Reserved +// Copyright (c) UPMC 2008-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | H U R R I C A N E | @@ -15,8 +14,8 @@ // +-----------------------------------------------------------------+ -# ifndef __ISOBAR_SCRIPT__ -# define __ISOBAR_SCRIPT__ +# ifndef ISOBAR_SCRIPT_H +# define ISOBAR_SCRIPT_H #include @@ -78,4 +77,4 @@ namespace Isobar { } // End of Isobar namespace. -# endif // __ISOBAR_SCRIPT__ +# endif // ISOBAR_SCRIPT_H diff --git a/hurricane/src/viewer/hurricane/viewer/ScriptWidget.h b/hurricane/src/viewer/hurricane/viewer/ScriptWidget.h index 1b00afe0..b85d066d 100644 --- a/hurricane/src/viewer/hurricane/viewer/ScriptWidget.h +++ b/hurricane/src/viewer/hurricane/viewer/ScriptWidget.h @@ -30,7 +30,7 @@ namespace Hurricane { class ScriptWidget : public QDialog { Q_OBJECT; public: - static bool runScript ( QWidget* parent, Cell* ); + static void runScript ( QWidget* parent, Cell* ); const QString getScriptName () const; protected: ScriptWidget ( QWidget* parent=NULL ); diff --git a/kite/src/GraphicKiteEngine.cpp b/kite/src/GraphicKiteEngine.cpp index c48d6b0b..8f2fcdf2 100644 --- a/kite/src/GraphicKiteEngine.cpp +++ b/kite/src/GraphicKiteEngine.cpp @@ -159,7 +159,7 @@ namespace Kite { void GraphicKiteEngine::_saveGlobalSolution () { - KiteEngine* kite = KiteEngine::get( getCell() ); + KiteEngine* kite = getForFramework( NoFlags ); if (kite) kite->saveGlobalSolution (); } @@ -214,6 +214,13 @@ namespace Kite { } } + + void GraphicKiteEngine::_dumpMeasures () + { + KiteEngine* kite = getForFramework( NoFlags ); + if (kite) kite->dumpMeasures(); + } + void GraphicKiteEngine::_save () { @@ -226,53 +233,20 @@ namespace Kite { } - void GraphicKiteEngine::globalRoute () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_globalRoute,this) ); } - - - void GraphicKiteEngine::loadGlobalSolution () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_loadGlobalSolution,this) ); } - - - void GraphicKiteEngine::saveGlobalSolution () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_saveGlobalSolution,this) ); } - - - void GraphicKiteEngine::detailPreRoute () + void GraphicKiteEngine::_detailRoute () { - ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_runNegociatePreRouted,this) ); + _loadGlobalRouting (); + _balanceGlobalDensity(); + _runNegociate (); } - void GraphicKiteEngine::detailRoute () + void GraphicKiteEngine::_route () { - ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_loadGlobalRouting ,this) ); - ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_balanceGlobalDensity,this) ); - ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_runNegociate ,this) ); - } - - - void GraphicKiteEngine::finalize () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_finalize,this) ); } - - - void GraphicKiteEngine::save () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicKiteEngine::_save,this) ); } - - - void GraphicKiteEngine::route () - { - detailPreRoute(); - globalRoute (); - detailRoute (); - finalize (); - } - - - void GraphicKiteEngine::dumpMeasures () - { - KiteEngine* kite = getForFramework( NoFlags ); - if (kite) kite->dumpMeasures(); + _runNegociatePreRouted(); + _globalRoute (); + _detailRoute (); + _finalize (); } @@ -298,93 +272,58 @@ namespace Kite { _viewer = viewer; - QMenu* prMenu = _viewer->findChild("viewer.menuBar.placeAndRoute"); - QMenu* stepMenu = _viewer->findChild("viewer.menuBar.placeAndRoute.stepByStep"); - if (prMenu == NULL) { - QMenuBar* menuBar = _viewer->findChild("viewer.menuBar"); - if (menuBar == NULL) { - cerr << Warning( "GraphicKiteEngine::addToMenu() - No MenuBar in parent widget." ) << endl; - return; - } - prMenu = menuBar->addMenu( tr("P&&R") ); - prMenu->setObjectName( "viewer.menuBar.placeAndRoute" ); - - stepMenu = prMenu->addMenu( tr("&Step by Step") ); - stepMenu->setObjectName( "viewer.menuBar.placeAndRoute.stepByStep" ); - - prMenu->addSeparator(); - } - - QAction* dRouteAction = _viewer->findChild("viewer.menuBar.placeAndRoute.detailedRoute"); - if (dRouteAction) + if (_viewer->hasMenuAction("placeAndRoute.route")) { cerr << Warning( "GraphicKiteEngine::addToMenu() - Kite detailed router already hooked in." ) << endl; - else { - stepMenu->addSeparator(); - - QAction* dPreRouteAction = new QAction ( tr("Kite - Detailed Pre-Route"), _viewer ); - dPreRouteAction->setObjectName( "viewer.menuBar.placeAndPreRoute.stepBystep.detailedPreRoute" ); - dPreRouteAction->setStatusTip ( tr("Run the Kite detailed router on pre-routed nets") ); - dPreRouteAction->setVisible ( true ); - stepMenu->addAction( dPreRouteAction ); - - QAction* gRouteAction = new QAction ( tr("Kite - &Global Route"), _viewer ); - gRouteAction->setObjectName( "viewer.menuBar.placeAndRoute.stepBystep.globalRoute" ); - gRouteAction->setStatusTip ( tr("Run the Knik global router") ); - gRouteAction->setVisible ( true ); - stepMenu->addAction( gRouteAction ); - - QAction* gLoadSolutionAction = new QAction ( tr("Kite - &Load Global Routing"), _viewer ); - gLoadSolutionAction->setObjectName( "viewer.menuBar.placeAndRoute.stepByStep.loadGlobalRouting" ); - gLoadSolutionAction->setStatusTip ( tr("Load a solution for the global routing (.kgr)") ); - gLoadSolutionAction->setVisible ( true ); - stepMenu->addAction( gLoadSolutionAction ); - - QAction* gSaveSolutionAction = new QAction ( tr("Kite - &Save Global Routing"), _viewer ); - gSaveSolutionAction->setObjectName( "viewer.menuBar.placeAndRoute.stepByStep.saveGlobalRouting" ); - gSaveSolutionAction->setStatusTip ( tr("Save a global router solution (.kgr)") ); - gSaveSolutionAction->setVisible ( true ); - stepMenu->addAction( gSaveSolutionAction ); - - dRouteAction = new QAction ( tr("Kite - &Detailed Route"), _viewer ); - dRouteAction->setObjectName( "viewer.menuBar.placeAndRoute.stepBystep.detailedRoute" ); - dRouteAction->setStatusTip ( tr("Run the Kite detailed router") ); - dRouteAction->setVisible ( true ); - stepMenu->addAction( dRouteAction ); - - QAction* dFinalizeAction = new QAction( tr("Kite - &Finalize Routing"), _viewer ); - dFinalizeAction->setObjectName( "viewer.menuBar.placeAndRoute.stepBystep.finalize" ); - dFinalizeAction->setStatusTip ( tr("Closing Routing") ); - dFinalizeAction->setVisible ( true ); - stepMenu->addAction( dFinalizeAction ); - - QAction* dDumpMeasuresAction = new QAction ( tr("Kite - Dump &Measures"), _viewer ); - dDumpMeasuresAction->setObjectName( "viewer.menuBar.placeAndRoute.stepBystep.dumpMeasures" ); - dDumpMeasuresAction->setStatusTip ( tr("Dumping Measurements on the disk") ); - dDumpMeasuresAction->setVisible ( true ); - stepMenu->addAction( dDumpMeasuresAction ); - - QAction* dSaveAction = new QAction ( tr("Kite - &Save Design"), _viewer ); - dSaveAction->setObjectName( "viewer.menuBar.placeAndRoute.stepBystep.save" ); - dSaveAction->setStatusTip ( tr("Save routed design (temporary hack)") ); - dSaveAction->setVisible ( true ); - stepMenu->addAction( dSaveAction ); - - QAction* routeAction = new QAction ( tr("Kite - &Route"), _viewer ); - routeAction->setObjectName( "viewer.menuBar.placeAndRoute.route" ); - routeAction->setStatusTip ( tr("Route the design (global & detailed)") ); - routeAction->setVisible ( true ); - prMenu->addAction( routeAction ); - - connect( gLoadSolutionAction, SIGNAL(triggered()), this, SLOT(loadGlobalSolution()) ); - connect( gSaveSolutionAction, SIGNAL(triggered()), this, SLOT(saveGlobalSolution()) ); - connect( gRouteAction , SIGNAL(triggered()), this, SLOT(globalRoute ()) ); - connect( dPreRouteAction , SIGNAL(triggered()), this, SLOT(detailPreRoute ()) ); - connect( dRouteAction , SIGNAL(triggered()), this, SLOT(detailRoute ()) ); - connect( dFinalizeAction , SIGNAL(triggered()), this, SLOT(finalize ()) ); - connect( dSaveAction , SIGNAL(triggered()), this, SLOT(save ()) ); - connect( dDumpMeasuresAction, SIGNAL(triggered()), this, SLOT(dumpMeasures ()) ); - connect( routeAction , SIGNAL(triggered()), this, SLOT(route ()) ); + return; } + + _viewer->addToMenu( "placeAndRoute.route" + , "Kite - &Route" + , "Route the design (global & detailed)" + , std::bind(&GraphicKiteEngine::_route,this) + ); + + _viewer->addToMenu( "placeAndRoute.stepByStep.========" ); + _viewer->addToMenu( "placeAndRoute.stepByStep.detailedPreRoute" + , "Kite - Detailed Pre-Route" + , "Run the Kite detailed router on pre-routed nets" + , std::bind(&GraphicKiteEngine::_runNegociatePreRouted,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.globalRoute" + , "Kite - &Global Route" + , "Run the Knik global router" + , std::bind(&GraphicKiteEngine::_globalRoute,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.loadGlobalRouting" + , "Kite - &Load Global Routing" + , "Load a solution for the global routing (.kgr)" + , std::bind(&GraphicKiteEngine::_loadGlobalSolution,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.saveGlobalRouting" + , "Kite - &Save Global Routing" + , "Save a global router solution (.kgr)" + , std::bind(&GraphicKiteEngine::_saveGlobalSolution,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.detailedRoute" + , "Kite - &Detailed Route" + , "Run the Kite detailed router" + , std::bind(&GraphicKiteEngine::_detailRoute,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.finalize" + , "Kite - &Finalize Routing" + , "Closing Routing" + , std::bind(&GraphicKiteEngine::_finalize,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.dumpMeasures" + , "Kite - Dump &Measures" + , "Dumping Measurements on the disk" + , std::bind(&GraphicKiteEngine::_dumpMeasures,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.save" + , "Kite - &Save Design" + , "Save routed design (temporary hack)" + , std::bind(&GraphicKiteEngine::_save,this) + ); } diff --git a/kite/src/kite/GraphicKiteEngine.h b/kite/src/kite/GraphicKiteEngine.h index 01fc7e92..f409bfe1 100644 --- a/kite/src/kite/GraphicKiteEngine.h +++ b/kite/src/kite/GraphicKiteEngine.h @@ -76,16 +76,6 @@ namespace Kite { virtual size_t release (); virtual void addToMenu ( CellViewer* ); void postEvent (); - public slots: - void detailPreRoute (); - void loadGlobalSolution (); - void saveGlobalSolution (); - void globalRoute (); - void detailRoute (); - void finalize (); - void route (); - void save (); - void dumpMeasures (); protected: static size_t _references; @@ -94,6 +84,7 @@ namespace Kite { protected: GraphicKiteEngine (); virtual ~GraphicKiteEngine (); + void _route (); void _loadGlobalSolution (); void _saveGlobalSolution (); void _globalRoute (); @@ -101,8 +92,10 @@ namespace Kite { void _balanceGlobalDensity (); void _runNegociatePreRouted (); void _runNegociate (); + void _detailRoute (); void _finalize (); void _save (); + void _dumpMeasures (); }; diff --git a/mauka/src/GraphicMaukaEngine.cpp b/mauka/src/GraphicMaukaEngine.cpp index 432f60e0..b1f2ee53 100644 --- a/mauka/src/GraphicMaukaEngine.cpp +++ b/mauka/src/GraphicMaukaEngine.cpp @@ -206,13 +206,13 @@ namespace Mauka { void GraphicMaukaEngine::_place () { if (MetisEngine::isHMetisCapable()) { - doQuadriPart(); + _doQuadriPart(); } else { cerr << Warning("Mauka has not been compiled againts hMETIS.\n" " Quadri-partition step is disabled, simulated annealing may be *very* long." ) << endl; } - doSimulatedAnnealing(); + _doSimulatedAnnealing(); _save(); } @@ -227,85 +227,32 @@ namespace Mauka { } - void GraphicMaukaEngine::doQuadriPart () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicMaukaEngine::_doQuadriPart,this) ); } - - - void GraphicMaukaEngine::doSimulatedAnnealing () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicMaukaEngine::_doSimulatedAnnealing,this) ); } - - - void GraphicMaukaEngine::place () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicMaukaEngine::_place,this) ); } - - - void GraphicMaukaEngine::save () - { ExceptionWidget::catchAllWrapper( std::bind(&GraphicMaukaEngine::_save,this) ); } - - void GraphicMaukaEngine::addToMenu ( CellViewer* viewer ) { - assert ( _viewer == NULL ); + assert( _viewer == NULL ); _viewer = viewer; - QMenu* prMenu = _viewer->findChild("viewer.menuBar.placeAndRoute"); - QMenu* stepMenu = _viewer->findChild("viewer.menuBar.placeAndRoute.stepByStep"); - if ( prMenu == NULL ) { - QMenuBar* menuBar = _viewer->findChild("viewer.menuBar"); - if ( menuBar == NULL ) { - cerr << Warning("GraphicMaukaEngine::addToMenu() - No MenuBar in parent widget.") << endl; - return; - } - prMenu = menuBar->addMenu ( tr("P&&R") ); - prMenu->setObjectName ( "viewer.menuBar.placeAndRoute" ); - - stepMenu = prMenu->addMenu ( tr("&Step by Step") ); - stepMenu->setObjectName ( "viewer.menuBar.placeAndRoute.stepByStep" ); - - prMenu->addSeparator (); + if (_viewer->hasMenuAction("placeAndRoute.maukaPlace")) { + cerr << Warning( "GraphicMaukaEngine::addToMenu() - Mauka placer already hooked in." ) << endl; + return; } - QAction* placeAction = _viewer->findChild("viewer.menuBar.placeAndRoute.maukaPlace"); - if ( placeAction != NULL ) - cerr << Warning("GraphicMaukaEngine::addToMenu() - Mauka placer already hooked in.") << endl; - else { - QAction* quadriPartAction = new QAction ( tr("Mauka - &QuadriPartition"), _viewer ); - quadriPartAction->setObjectName ( "viewer.menuBar.placeAndRoute.quadriPartition" ); - quadriPartAction->setStatusTip ( tr("Run the hMETIS quadri-partitioner") ); - quadriPartAction->setVisible ( true ); - stepMenu->addAction ( quadriPartAction ); - - QAction* annealingAction = new QAction ( tr("Mauka - &Place"), _viewer ); - annealingAction->setObjectName ( "viewer.menuBar.placeAndRoute.maukaPlace" ); - annealingAction->setStatusTip ( tr("Run the Mauka placer") ); - annealingAction->setVisible ( true ); - stepMenu->addAction ( annealingAction ); - - QAction* placeAction = new QAction ( tr("Mauka - &Place"), _viewer ); - placeAction->setObjectName ( "viewer.menuBar.placeAndRoute.place" ); - placeAction->setStatusTip ( tr("Run the Mauka placer") ); - placeAction->setVisible ( true ); - prMenu->addAction ( placeAction ); - - connect ( quadriPartAction, SIGNAL(triggered()), this, SLOT(doQuadriPart()) ); - connect ( annealingAction , SIGNAL(triggered()), this, SLOT(doSimulatedAnnealing()) ); - connect ( placeAction , SIGNAL(triggered()), this, SLOT(place()) ); - } - - // ControllerWidget* controller = _viewer->getControllerWidget(); - // ConfigurationWidget* setting = controller->getSettings() - // ->findChild("controller.tabSettings.setting.mauka"); - - // if ( setting == NULL ) { - // setting = new ConfigurationWidget (); - // setting->setObjectName ( "controller.tabSettings.setting.mauka" ); - // setting->setConfiguration ( Nimbus::Configuration::getDefault() - // , Metis::Configuration::getDefault() - // , Configuration::getDefault() - // ); - // controller->addSetting ( setting, "Mauka" ); - // } + _viewer->addToMenu( "placeAndRoute.maukaPlace" + , "Mauka - &Place" + , "Run the Mauka placer" + , std::bind(&GraphicMaukaEngine::_place,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.quadriPartition" + , "Mauka - &QuadriPartition" + , "Run the hMETIS quadri-partitioner" + , std::bind(&GraphicMaukaEngine::_doQuadriPart,this) + ); + _viewer->addToMenu( "placeAndRoute.stepByStep.simulatedAnnealing" + , "Mauka - &Simulated Annealing" + , "Run the Mauka simulated annealing detailed placer" + , std::bind(&GraphicMaukaEngine::_doSimulatedAnnealing,this) + ); } diff --git a/mauka/src/mauka/GraphicMaukaEngine.h b/mauka/src/mauka/GraphicMaukaEngine.h index 1f3181cc..f3767bce 100644 --- a/mauka/src/mauka/GraphicMaukaEngine.h +++ b/mauka/src/mauka/GraphicMaukaEngine.h @@ -51,7 +51,6 @@ namespace Mauka { public: enum Flags { NoFlags=0x0000, CreateEngine=0x0001 }; - public: MaukaEngine* createEngine (); MaukaEngine* getForFramework ( unsigned int flags ); @@ -68,12 +67,6 @@ namespace Mauka { virtual size_t release (); virtual void addToMenu ( CellViewer* ); void refreshViewer (); - public slots: - void doQuadriPart (); - void doSimulatedAnnealing (); - void place (); - void save (); - protected: static size_t _references; static GraphicMaukaEngine* _singleton; diff --git a/unicorn/src/CMakeLists.txt b/unicorn/src/CMakeLists.txt index 16a398b5..e5468ab8 100644 --- a/unicorn/src/CMakeLists.txt +++ b/unicorn/src/CMakeLists.txt @@ -93,4 +93,6 @@ install ( FILES ${includes} ${mocincludes} ${pyIncludes} DESTINATION include/coriolis2/unicorn ) + install ( FILES init/unicornInit.py + DESTINATION ${PYTHON_SITE_PACKAGES}/unicorn ) diff --git a/unicorn/src/UnicornGui.cpp b/unicorn/src/UnicornGui.cpp index 4d051db4..8feadae5 100644 --- a/unicorn/src/UnicornGui.cpp +++ b/unicorn/src/UnicornGui.cpp @@ -14,9 +14,11 @@ // +-----------------------------------------------------------------+ +#include #include #include #include "hurricane/Warning.h" +#include "hurricane/viewer/Script.h" #include "hurricane/viewer/CellWidget.h" #include "crlcore/Catalog.h" #include "crlcore/AllianceFramework.h" @@ -32,7 +34,9 @@ namespace Unicorn { + using Hurricane::dbo_ptr; using Hurricane::Warning; + using CRL::System; using CRL::Catalog; using CRL::AllianceFramework; using CRL::DefExport; @@ -56,13 +60,40 @@ namespace Unicorn { , _tools () , _importDialog(new ImportCellDialog(this)) , _exportDialog(new ExportCellDialog(this)) - { } + { + addMenu ( "placeAndRoute" , "P&&R" , CellViewer::TopMenu ); + addMenu ( "placeAndRoute.stepByStep", "&Step by Step" ); + addToMenu( "placeAndRoute.========" ); + + _runUnicornInit(); + } UnicornGui::~UnicornGui () { } + void UnicornGui::_runUnicornInit () + { + Utilities::Path pythonSitePackages = System::getPath("pythonSitePackages"); + Utilities::Path systemConfDir = pythonSitePackages / "unicorn"; + Utilities::Path systemConfFile = systemConfDir / "unicornInit.py"; + + if (systemConfFile.exists()) { + Isobar::Script::addPath( systemConfDir.string() ); + + dbo_ptr script = Isobar::Script::create( systemConfFile.stem().string() ); + script->setEditor ( this ); + script->runFunction( "unicornConfigure", getCell() ); + + Isobar::Script::removePath( systemConfDir.string() ); + } else { + cerr << Warning("System configuration file:\n <%s> not found." + ,systemConfFile.string().c_str()) << endl; + } + } + + UnicornGui* UnicornGui::create ( QWidget* parent ) { UnicornGui* unicorn = new UnicornGui ( parent ); diff --git a/unicorn/src/init/unicornInit.py b/unicorn/src/init/unicornInit.py new file mode 100644 index 00000000..d7025ef1 --- /dev/null +++ b/unicorn/src/init/unicornInit.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +try: + import sys + import os.path + from helpers import ErrorMessage + from helpers import WarningMessage + import Viewer +except ImportError, e: + module = str(e).split()[-1] + + print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module + print ' Please check the integrity of the package.' + sys.exit(1) +except Exception, e: + print '[ERROR] A strange exception occurred while loading the basic Coriolis/Python' + print ' modules. Something may be wrong at Python/C API level.\n' + print ' %s' % e + sys.exit(2) + + +def unicornConfigure ( cell=None ): + editor = None + if globals().has_key('__editor'): + editor = __editor + else: + print ErrorMessage( 3, 'unicornConfigure.py: Must be run from a CellView derived class.' ) + return + + cumulusDir = None + for path in sys.path: + if path.endswith('/cumulus'): + cumulusDir = path + if not cumulusDir: + print ErrorMessage( 3, 'unicornConfigure.py: Cannot find in PYTHONPATH.' ) + return + + pluginsDir = os.path.join( cumulusDir, 'plugins' ) + if not os.path.isdir(pluginsDir): + print ErrorMessage( 3, 'unicornConfigure.py: Cannot find directory:' \ + , '<%s>' % pluginsDir ) + return + sys.path.append( pluginsDir ) + + if editor.hasMenu( 'plugins' ): + print WarningMessage( 'The menu has already been created.' ) + return + + editor.addMenu( 'plugins', 'Plu&gins', Viewer.CellViewer.TopMenu ) + + for pluginFile in os.listdir( pluginsDir ): + if not pluginFile.endswith('.py'): continue + + moduleName = os.path.basename(pluginFile)[:-3] + module = __import__( moduleName, globals(), locals(), moduleName ) + + if not module.__dict__.has_key('unicornHook'): + print WarningMessage( 'Module <%s> do not provides the unicornHook() method, skipped.' \ + % moduleName ) + continue + + module.__dict__['unicornHook']( editor ) + + return diff --git a/unicorn/src/unicorn/UnicornGui.h b/unicorn/src/unicorn/UnicornGui.h index e0c5807b..58d71f32 100644 --- a/unicorn/src/unicorn/UnicornGui.h +++ b/unicorn/src/unicorn/UnicornGui.h @@ -47,22 +47,23 @@ namespace Unicorn { class UnicornGui : public CellViewer { Q_OBJECT; public: - static UnicornGui* create ( QWidget* parent=NULL ); - void destroy (); - static inline Banner& getBanner (); - virtual Cell* getCellFromDb ( const char* name ); - void registerTool ( GraphicTool* ); - virtual std::string _getString () const; - public slots: - void openCell (); - void saveCell (); - void importCell (); - void exportCell (); - protected: - UnicornGui ( QWidget* parent ); - virtual ~UnicornGui (); - virtual void _postCreate (); - virtual void _preDestroy (); + static UnicornGui* create ( QWidget* parent=NULL ); + void destroy (); + static inline Banner& getBanner (); + virtual Cell* getCellFromDb ( const char* name ); + void registerTool ( GraphicTool* ); + virtual std::string _getString () const; + public slots: + void openCell (); + void saveCell (); + void importCell (); + void exportCell (); + protected: + UnicornGui ( QWidget* parent ); + virtual ~UnicornGui (); + virtual void _postCreate (); + virtual void _preDestroy (); + void _runUnicornInit (); protected: static Banner _banner; set _tools;