// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | H U R R I C A N E | // | V L S I B a c k e n d D a t a - B a s e | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@asim.lip6.fr | // | =============================================================== | // | C++ Module : "./CellViewer.cpp" | // +-----------------------------------------------------------------+ #include #include #include #include #include #include #include #include #include #include #include #include #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/isobar/PyCell.h" #include "hurricane/viewer/Script.h" #include "hurricane/viewer/Graphics.h" #include "hurricane/viewer/CellViewer.h" #include "hurricane/viewer/CellPrinter.h" #include "hurricane/viewer/CellImage.h" #include "hurricane/viewer/MousePositionWidget.h" #include "hurricane/viewer/ControllerWidget.h" #include "hurricane/viewer/ScriptWidget.h" #include "hurricane/viewer/ExceptionWidget.h" #include "hurricane/viewer/GotoWidget.h" #include "hurricane/viewer/SelectCommand.h" #include "hurricane/viewer/PyCellViewer.h" namespace Hurricane { using Isobar::PyCell_Link; // ------------------------------------------------------------------- // Class : "CellObserver". void CellObserver::notify ( unsigned int flags ) { CellViewer* viewer = getOwner(); switch ( flags & (Cell::CellAboutToChange|Cell::CellChanged) ) { case Cell::CellAboutToChange: viewer->emitCellAboutToChange(); break; case Cell::CellChanged: viewer->emitCellChanged(); break; } } // ------------------------------------------------------------------- // Class : "CellViewer". QString CellViewer::_prefixWPath ( "viewer.menuBar." ); CellViewer::CellViewer ( QWidget* parent ) : QMainWindow (parent) , _cellObserver (this) , _applicationName (tr("Viewer")) , _showSelectionAction (NULL) , _debugMenu (NULL) , _actionCallbacks () //, _mapView (NULL) , _mousePosition (NULL) , _controller (NULL) , _script (NULL) , _goto (NULL) , _cellWidget (NULL) , _moveCommand () , _zoomCommand () , _rulerCommand () , _selectCommand () , _hierarchyCommand () , _cellHistory () , _firstShow (false) , _toolInterrupt (false) , _flags (0) , _updateState (ExternalEmit) { setObjectName( "viewer" ); menuBar()->setObjectName ( _getAbsWidgetPath("") ); _cellWidget = new CellWidget (); _controller = new ControllerWidget(); _goto = new GotoWidget (); _goto->changeDbuMode( _cellWidget->getDbuMode(), _cellWidget->getUnitPower() ); _cellWidget->bindCommand( &_moveCommand ); _cellWidget->bindCommand( &_zoomCommand ); _cellWidget->bindCommand( &_rulerCommand ); _cellWidget->bindCommand( &_selectCommand ); _cellWidget->bindCommand( &_hierarchyCommand ); _controller->setCellWidget( _cellWidget ); _mousePosition = new MousePositionWidget(); statusBar()->addPermanentWidget( _mousePosition ); setCorner( Qt::TopLeftCorner , Qt::LeftDockWidgetArea ); setCorner( Qt::BottomLeftCorner , Qt::LeftDockWidgetArea ); 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 // | QDockWidget::DockWidgetFloatable // ); //mapViewDock->setObjectName ( "viewer.menuBar.dock.mapView" ); //mapViewDock->setWidget ( _mapView ); //mapViewDock->setAllowedAreas ( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea ); //addDockWidget( Qt::RightDockWidgetArea, mapViewDock ); setCentralWidget( _cellWidget ); createMenus(); connect( this , SIGNAL(cellPreModificated()) , _cellWidget, SLOT(cellPreModificate()) ); connect( this , SIGNAL(cellPostModificated()), _cellWidget, SLOT(cellPostModificate()) ); connect( this , SIGNAL(redrawCellWidget()) , _cellWidget, SLOT(refresh()) ); connect( _cellWidget , SIGNAL(dbuModeChanged(unsigned int,DbU::UnitPower)) , _goto , SLOT (changeDbuMode (unsigned int,DbU::UnitPower)) ); connect( _cellWidget , SIGNAL(mousePositionChanged(const Point&)) , _mousePosition , SLOT (setPosition(const Point&)) ); 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 )) { ExceptionWidget::catchAllWrapper( boost::any_cast< std::function >(callback) ); } else if (callback.type() == typeid( QString )) { 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, SIGNAL(triggered()), this, SLOT(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], SIGNAL(triggered()), this, SLOT(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, SIGNAL(triggered()), this, SLOT(printDisplay()) ); action = addToMenu( "file.image" , tr("Save to &Image") , tr("Save the displayed area to image") , QKeySequence() ); connect( action, SIGNAL(triggered()), this, SLOT(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, SIGNAL(triggered()), this, SLOT(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, SIGNAL(triggered()), _cellWidget, SLOT(refresh()) ); action = addToMenu( "view.fit" , tr("&Fit to Contents") , tr("Adjust zoom to fit the whole cell's contents") , Qt::Key_F ); connect( action, SIGNAL(triggered()), _cellWidget, SLOT(fitToContents()) ); action = addToMenu( "view.goto" , tr("&Goto") , tr("Center view on that point, with zoom adjustment") , Qt::Key_G ); connect( action, SIGNAL(triggered()), this, SLOT(doGoto()) ); _showSelectionAction = addToMenu( "view.showSelection" , tr("&Show Selection") , tr("Highlight the selected items (darken others)") , Qt::Key_S ); _showSelectionAction->setCheckable( true ); connect( _showSelectionAction, SIGNAL(toggled(bool)), this, SLOT(setShowSelection(bool)) ); action = addToMenu( "view.changeRubber" , tr("Change Rubber Style") , tr("Cycle through all avalaibles rubber drawing styles") , Qt::Key_Asterisk ); connect( action, SIGNAL(triggered()), _cellWidget, SLOT(rubberChange()) ); action = addToMenu( "view.clearRulers" , tr("Clear Rulers") , tr("Remove all rulers") , QKeySequence() ); connect( action, SIGNAL(triggered()), _cellWidget, SLOT(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, SIGNAL(triggered()), _controller, SLOT(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, SIGNAL(triggered()), this, SLOT(runScriptWidget()) ); } QMenu* CellViewer::createDebugMenu () { if (not _debugMenu) addMenu ( "debug" , "Debug" , TopMenu ); return _debugMenu; } void CellViewer::refreshTitle () { QString cellName = "None"; if ( getCell() ) cellName = getString(getCell()->getName()).c_str(); QString title = QString("%1:<%2>").arg(_applicationName).arg(cellName); setWindowTitle ( title ); } void CellViewer::refreshHistory () { if ( getCell() == NULL ) return; shared_ptr activeState = _cellWidget->getState(); _cellHistory.remove ( activeState ); if ( _cellHistory.size() > CellHistorySize-1 ) _cellHistory.pop_front (); _cellHistory.push_back ( activeState ); list< shared_ptr >::iterator istate = _cellHistory.begin(); for ( size_t i=0 ; igetName()).c_str() ); _cellHistoryAction[i]->setText ( entry ); _cellHistoryAction[i]->setVisible ( true ); istate++; } else { _cellHistoryAction[i]->setVisible ( false ); } } } void CellViewer::setState ( shared_ptr& state ) { static bool isEmitter = false; if ( sender() == this ) { isEmitter = true; emit stateChanged ( state ); } else { if ( !isEmitter ) { blockSignals ( true ); refreshTitle (); refreshHistory (); blockSignals ( false ); } else isEmitter = false; } } void CellViewer::setCell ( Cell* cell ) { if (cell == getCell()) return; if (getCell()) getCell()->removeObserver( getCellObserver() ); Name cellName = (cell) ? cell->getName() : "empty"; list< shared_ptr >::iterator istate = find_if( _cellHistory.begin(), _cellHistory.end(), CellWidget::FindStateName(cellName) ); if (istate != _cellHistory.end()) { (*istate)->getCell()->addObserver( getCellObserver() ); emit stateChanged ( *istate ); return; } cell->addObserver( getCellObserver() ); _cellWidget->setCell( cell ); } Cell* CellViewer::getCell () const { return getCellWidget()->getCell(); } Cell* CellViewer::getCellFromDb ( const char* name ) { cerr << "[ERROR] virtual function CellViewer::getCellFromDb() has not been overloaded.\n" << " (this will prevent \"Open Cell\" to work)" << endl; return NULL; } void CellViewer::renameCell ( const char* name ) { Cell* cell = getCell(); if ( cell == NULL ) return; cell->setName ( name ); refreshTitle (); refreshHistory (); } void CellViewer::doGoto () { if ( _goto->exec() == QDialog::Accepted ) { if ( not _goto->hasXy() ) return; Box gotoArea ( _goto->getX(), _goto->getY() ); DbU::Unit width; DbU::Unit height; if ( _goto->hasAperture() ) { width = height = _goto->getAperture() / 2; } else { Box visibleArea = _cellWidget->getVisibleArea (); width = visibleArea.getWidth ()/2; height = visibleArea.getHeight()/2; } gotoArea.inflate ( width, height ); _cellWidget->reframe ( gotoArea ); } } void CellViewer::setAnonNetSelectable ( bool state ) { SelectCommand* command = static_cast( getCellWidget()->getCommand(SelectCommand::getStaticName()) ); unsigned int mode = (state) ? SelectCommand::NetMode : SelectCommand::NoAnonNetMode; if (command) command->setSelectMode( mode ); } void CellViewer::changeSelectionMode () { if ( _updateState != InternalEmit ) { _showSelectionAction->blockSignals ( true ); _showSelectionAction->setChecked ( _cellWidget->getState()->cumulativeSelection() ); _showSelectionAction->blockSignals ( false ); } _updateState = ExternalEmit; } void CellViewer::setShowSelection ( bool state ) { _updateState = InternalEmit; _cellWidget->setShowSelection ( state ); } void CellViewer::raiseToolInterrupt () { _toolInterrupt = true; } void CellViewer::clearToolInterrupt () { _toolInterrupt = false; } void CellViewer::openHistoryCell () { QAction* historyAction = qobject_cast ( sender() ); if ( historyAction ) { list< shared_ptr >::iterator istate = _cellHistory.begin(); size_t index = historyAction->data().toUInt(); for ( ; index>0 ; index--, istate++ ); //cerr << "History: " << (*istate)->getName() << endl; emit stateChanged ( *istate ); } } void CellViewer::select ( Occurrence& occurrence ) { if ( _cellWidget ) _cellWidget->select ( occurrence ); } void CellViewer::unselect ( Occurrence& occurrence ) { if ( _cellWidget ) _cellWidget->unselect ( occurrence ); } void CellViewer::unselectAll () { if ( _cellWidget ) _cellWidget->unselectAll(); } void CellViewer::printDisplay () { if ( !_cellWidget ) return; if ( !_cellWidget->getCell() ) { cerr << Warning("Unable to print, no cell loaded yet.") << endl; return; } QPrinter printer ( QPrinter::ScreenResolution ); printer.setPaperSize ( (QPrinter::PaperSize)Cfg::getParamEnumerate("viewer.printer.paper",0)->asInt() ); printer.setOutputFileName ( "unicorn-snapshot.pdf" ); QPrintDialog dialog ( &printer ); if ( dialog.exec() == QDialog::Accepted ) print ( &printer ); } void CellViewer::print ( QPrinter* printer ) { CellPrinter* cellPrinter = new CellPrinter(); cellPrinter->setScreenCellWidget( _cellWidget ); cellPrinter->toPdf ( printer, false ); delete cellPrinter; } void CellViewer::imageDisplay () { if ( !_cellWidget ) return; if ( !_cellWidget->getCell() ) { cerr << Warning("Unable to save to image, no cell loaded yet.") << endl; return; } CellImage* cellImage = new CellImage(); cellImage->setScreenCellWidget( _cellWidget ); QImage* image = cellImage->toImage(0); delete cellImage; char workingDirectory [1024]; getcwd ( workingDirectory, 1024 ); QString filePath = QFileDialog::getSaveFileName ( this , tr("Save Image as ...") , workingDirectory , tr("Image (*.png)") ); image->save ( filePath, "png" ); delete image; } 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->addKwArgument( "cell" , (PyObject*)PyCell_Link(getCell()) ); script->addKwArgument( "editor" , (PyObject*)PyCellViewer_Link(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() ); } string CellViewer::_getString () const { ostringstream s; s << "getName()); else s << "No_Cell_Loaded"; s << ">"; return s.str(); } } // End of Hurricane namespace.