From 642cc0c19c61be7fde4b0574db044d6551d139e9 Mon Sep 17 00:00:00 2001 From: nds Date: Thu, 3 Nov 2005 07:23:45 +0000 Subject: [PATCH] Has functionality from SalomeApp without dependency from CORBA --- src/LightApp/LightApp.h | 28 + src/LightApp/LightApp_AboutDlg.cxx | 130 ++ src/LightApp/LightApp_AboutDlg.h | 36 + src/LightApp/LightApp_Application.cxx | 1811 ++++++++++++++++++++ src/LightApp/LightApp_Application.h | 188 ++ src/LightApp/LightApp_DataModel.cxx | 122 ++ src/LightApp/LightApp_DataModel.h | 53 + src/LightApp/LightApp_DataObject.cxx | 163 ++ src/LightApp/LightApp_DataObject.h | 51 + src/LightApp/LightApp_DataOwner.cxx | 56 + src/LightApp/LightApp_DataOwner.h | 30 + src/LightApp/LightApp_DataSubOwner.cxx | 33 + src/LightApp/LightApp_DataSubOwner.h | 24 + src/LightApp/LightApp_Dialog.cxx | 860 ++++++++++ src/LightApp/LightApp_Dialog.h | 267 +++ src/LightApp/LightApp_Displayer.cxx | 145 ++ src/LightApp/LightApp_Displayer.h | 28 + src/LightApp/LightApp_Driver.cxx | 486 ++++++ src/LightApp/LightApp_Driver.h | 49 + src/LightApp/LightApp_GLSelector.cxx | 99 ++ src/LightApp/LightApp_GLSelector.h | 33 + src/LightApp/LightApp_Module.cxx | 412 +++++ src/LightApp/LightApp_Module.h | 119 ++ src/LightApp/LightApp_ModuleDlg.cxx | 198 +++ src/LightApp/LightApp_ModuleDlg.h | 45 + src/LightApp/LightApp_NameDlg.cxx | 128 ++ src/LightApp/LightApp_NameDlg.h | 47 + src/LightApp/LightApp_OBFilter.cxx | 29 + src/LightApp/LightApp_OBFilter.h | 22 + src/LightApp/LightApp_OBSelector.cxx | 101 ++ src/LightApp/LightApp_OBSelector.h | 38 + src/LightApp/LightApp_OCCSelector.cxx | 103 ++ src/LightApp/LightApp_OCCSelector.h | 37 + src/LightApp/LightApp_Operation.cxx | 290 ++++ src/LightApp/LightApp_Operation.h | 91 + src/LightApp/LightApp_Preferences.cxx | 87 + src/LightApp/LightApp_Preferences.h | 49 + src/LightApp/LightApp_PreferencesDlg.cxx | 84 + src/LightApp/LightApp_PreferencesDlg.h | 33 + src/LightApp/LightApp_RootObject.h | 33 + src/LightApp/LightApp_Selection.cxx | 177 ++ src/LightApp/LightApp_Selection.h | 70 + src/LightApp/LightApp_SelectionMgr.cxx | 271 +++ src/LightApp/LightApp_SelectionMgr.h | 57 + src/LightApp/LightApp_ShowHideOp.cxx | 80 + src/LightApp/LightApp_ShowHideOp.h | 26 + src/LightApp/LightApp_Study.cxx | 393 +++++ src/LightApp/LightApp_Study.h | 70 + src/LightApp/LightApp_SwitchOp.cxx | 164 ++ src/LightApp/LightApp_SwitchOp.h | 72 + src/LightApp/LightApp_UpdateFlags.h | 37 + src/LightApp/LightApp_VTKSelector.cxx | 187 ++ src/LightApp/LightApp_VTKSelector.h | 78 + src/LightApp/LightApp_WidgetContainer.cxx | 133 ++ src/LightApp/LightApp_WidgetContainer.h | 42 + src/LightApp/Makefile.in | 114 ++ src/LightApp/resources/LightApp.ini | 21 + src/LightApp/resources/LightApp.xml | 70 + src/LightApp/resources/LightApp_images.po | 33 + src/LightApp/resources/LightApp_msg_en.po | 252 +++ src/LightApp/resources/icon_about.png | Bin 0 -> 195122 bytes src/LightApp/resources/icon_applogo.png | Bin 0 -> 2383 bytes src/LightApp/resources/icon_default.png | Bin 0 -> 684 bytes src/LightApp/resources/icon_module.png | Bin 0 -> 1385 bytes src/LightApp/resources/icon_module_big.png | Bin 0 -> 3630 bytes src/LightApp/resources/icon_select.png | Bin 0 -> 976 bytes 66 files changed, 8985 insertions(+) create mode 100644 src/LightApp/LightApp.h create mode 100644 src/LightApp/LightApp_AboutDlg.cxx create mode 100644 src/LightApp/LightApp_AboutDlg.h create mode 100644 src/LightApp/LightApp_Application.cxx create mode 100644 src/LightApp/LightApp_Application.h create mode 100644 src/LightApp/LightApp_DataModel.cxx create mode 100644 src/LightApp/LightApp_DataModel.h create mode 100644 src/LightApp/LightApp_DataObject.cxx create mode 100644 src/LightApp/LightApp_DataObject.h create mode 100644 src/LightApp/LightApp_DataOwner.cxx create mode 100644 src/LightApp/LightApp_DataOwner.h create mode 100644 src/LightApp/LightApp_DataSubOwner.cxx create mode 100644 src/LightApp/LightApp_DataSubOwner.h create mode 100644 src/LightApp/LightApp_Dialog.cxx create mode 100644 src/LightApp/LightApp_Dialog.h create mode 100644 src/LightApp/LightApp_Displayer.cxx create mode 100644 src/LightApp/LightApp_Displayer.h create mode 100644 src/LightApp/LightApp_Driver.cxx create mode 100644 src/LightApp/LightApp_Driver.h create mode 100644 src/LightApp/LightApp_GLSelector.cxx create mode 100644 src/LightApp/LightApp_GLSelector.h create mode 100644 src/LightApp/LightApp_Module.cxx create mode 100644 src/LightApp/LightApp_Module.h create mode 100644 src/LightApp/LightApp_ModuleDlg.cxx create mode 100644 src/LightApp/LightApp_ModuleDlg.h create mode 100644 src/LightApp/LightApp_NameDlg.cxx create mode 100644 src/LightApp/LightApp_NameDlg.h create mode 100644 src/LightApp/LightApp_OBFilter.cxx create mode 100644 src/LightApp/LightApp_OBFilter.h create mode 100644 src/LightApp/LightApp_OBSelector.cxx create mode 100644 src/LightApp/LightApp_OBSelector.h create mode 100644 src/LightApp/LightApp_OCCSelector.cxx create mode 100644 src/LightApp/LightApp_OCCSelector.h create mode 100755 src/LightApp/LightApp_Operation.cxx create mode 100755 src/LightApp/LightApp_Operation.h create mode 100644 src/LightApp/LightApp_Preferences.cxx create mode 100644 src/LightApp/LightApp_Preferences.h create mode 100644 src/LightApp/LightApp_PreferencesDlg.cxx create mode 100644 src/LightApp/LightApp_PreferencesDlg.h create mode 100644 src/LightApp/LightApp_RootObject.h create mode 100644 src/LightApp/LightApp_Selection.cxx create mode 100644 src/LightApp/LightApp_Selection.h create mode 100644 src/LightApp/LightApp_SelectionMgr.cxx create mode 100644 src/LightApp/LightApp_SelectionMgr.h create mode 100644 src/LightApp/LightApp_ShowHideOp.cxx create mode 100644 src/LightApp/LightApp_ShowHideOp.h create mode 100644 src/LightApp/LightApp_Study.cxx create mode 100644 src/LightApp/LightApp_Study.h create mode 100755 src/LightApp/LightApp_SwitchOp.cxx create mode 100755 src/LightApp/LightApp_SwitchOp.h create mode 100755 src/LightApp/LightApp_UpdateFlags.h create mode 100644 src/LightApp/LightApp_VTKSelector.cxx create mode 100644 src/LightApp/LightApp_VTKSelector.h create mode 100644 src/LightApp/LightApp_WidgetContainer.cxx create mode 100644 src/LightApp/LightApp_WidgetContainer.h create mode 100755 src/LightApp/Makefile.in create mode 100755 src/LightApp/resources/LightApp.ini create mode 100644 src/LightApp/resources/LightApp.xml create mode 100644 src/LightApp/resources/LightApp_images.po create mode 100644 src/LightApp/resources/LightApp_msg_en.po create mode 100755 src/LightApp/resources/icon_about.png create mode 100755 src/LightApp/resources/icon_applogo.png create mode 100644 src/LightApp/resources/icon_default.png create mode 100644 src/LightApp/resources/icon_module.png create mode 100755 src/LightApp/resources/icon_module_big.png create mode 100644 src/LightApp/resources/icon_select.png diff --git a/src/LightApp/LightApp.h b/src/LightApp/LightApp.h new file mode 100644 index 000000000..bfbe7e24a --- /dev/null +++ b/src/LightApp/LightApp.h @@ -0,0 +1,28 @@ +// File: LightApp.h +// Created: June, 2005 +// Author: OCC team +// Copyright (C) CEA 2005 + + +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the LightApp_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// LightApp_API functions as being imported from a DLL, wheras this DLL sees symbols +// defined with this macro as being exported. +#ifdef WNT + +#ifdef LIGHTAPP_EXPORTS +#define LIGHTAPP_EXPORT __declspec(dllexport) +#else +#define LIGHTAPP_EXPORT __declspec(dllimport) +#endif + +#else +#define LIGHTAPP_EXPORT +#endif //WNT + +#define APP_VERSION "0.1" + +#pragma warning ( disable:4251 ) +#pragma warning ( disable:4786 ) diff --git a/src/LightApp/LightApp_AboutDlg.cxx b/src/LightApp/LightApp_AboutDlg.cxx new file mode 100644 index 000000000..689d4165c --- /dev/null +++ b/src/LightApp/LightApp_AboutDlg.cxx @@ -0,0 +1,130 @@ +// File: LightApp_AboutDlg.cxx +// Created: 03.06.2005 13:52:45 +// Author: Sergey TELKOV +// Copyright (C) CEA 2005 + +#include "LightApp_AboutDlg.h" + +#include +#include + +#include +#include +#include +#include + +/*!Constructor.*/ +LightApp_AboutDlg::LightApp_AboutDlg( const QString& defName, const QString& defVer, QWidget* parent ) +: QtxDialog( parent, "salome_about_dialog", true, false, None ) +{ + SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); + + QPixmap ico = resMgr->loadPixmap( "LightApp", tr( "ICO_ABOUT" ), false ); + if ( !ico.isNull() ) + setIcon( ico ); + + QPalette pal = palette(); + QColorGroup cg = pal.active(); + cg.setColor( QColorGroup::Foreground, Qt::darkBlue ); + cg.setColor( QColorGroup::Background, Qt::white ); + pal.setActive( cg ); pal.setInactive( cg ); pal.setDisabled( cg ); + setPalette(pal); + + QVBoxLayout* main = new QVBoxLayout( mainFrame() ); + QGroupBox* base = new QGroupBox( 1, Qt::Horizontal, "", mainFrame() ); + base->setFrameStyle( QFrame::NoFrame ); + base->setInsideMargin( 0 ); + main->addWidget( base ); + + QLabel* screen = new QLabel( base ); + screen->setScaledContents( true ); + screen->setAlignment( Qt::AlignCenter ); + screen->setFrameStyle( QFrame::Box | QFrame::Plain ); + + QLabel* title = new QLabel( base ); + title->setAlignment( Qt::AlignCenter ); + changeFont( title, true, false, false, 5 ); + + QLabel* version = new QLabel( base ); + version->setAlignment( Qt::AlignCenter ); + changeFont( version, false, true, false, 2 ); + + QLabel* copyright = new QLabel( base ); + copyright->setAlignment( Qt::AlignCenter ); + changeFont( copyright, false, false, false, 1 ); + + QLabel* license = new QLabel( base ); + license->setAlignment( Qt::AlignCenter ); + changeFont( license, false, false, false, 1 ); + + screen->setPixmap( resMgr->loadPixmap( "LightApp", tr( "ABOUT" ), false ) ); + checkLabel( screen ); + + QString titleText = tr( "ABOUT_TITLE" ); + if ( titleText == "ABOUT_TITLE" ) + titleText = defName; + title->setText( titleText ); + checkLabel( title ); + + QString verText = tr( "ABOUT_VERSION" ); + if ( verText.contains( "%1" ) ) + verText = verText.arg( defVer ); + version->setText( verText ); + checkLabel( version ); + + copyright->setText( tr( "ABOUT_COPYRIGHT" ) ); + checkLabel( copyright ); + + license->setText( tr( "ABOUT_LICENSE" ) ); + checkLabel( license ); + + QString capText = tr( "ABOUT_CAPTION" ); + if ( capText.contains( "%1" ) ) + capText = capText.arg( defName ); + setCaption( capText ); + + setSizeGripEnabled( false ); +} + +/*!Destructor.*/ +LightApp_AboutDlg::~LightApp_AboutDlg() +{ + //! Do nothing. +} + +/*!On mouse press event.*/ +void LightApp_AboutDlg::mousePressEvent( QMouseEvent* ) +{ + accept(); +} + +/*!Change font of widget \a wid. + *\param wid - QWidget + *\param bold - boolean value + *\param italic - boolean value + *\param underline - boolean value + *\param inc - integer increment for font point size. + */ +void LightApp_AboutDlg::changeFont( QWidget* wid, const bool bold, const bool italic, + const bool underline, const int inc ) const +{ + if ( !wid ) + return; + + QFont widFont = wid->font(); + widFont.setBold( bold ); + widFont.setItalic( italic ); + widFont.setUnderline( underline ); + widFont.setPointSize( widFont.pointSize() + inc ); +} + +/*!Check lable \a lab.*/ +void LightApp_AboutDlg::checkLabel( QLabel* lab ) const +{ + if ( !lab ) + return; + + bool vis = !lab->text().stripWhiteSpace().isEmpty() || + ( lab->pixmap() && !lab->pixmap()->isNull() ); + vis ? lab->show() : lab->hide(); +} diff --git a/src/LightApp/LightApp_AboutDlg.h b/src/LightApp/LightApp_AboutDlg.h new file mode 100644 index 000000000..c59cc938b --- /dev/null +++ b/src/LightApp/LightApp_AboutDlg.h @@ -0,0 +1,36 @@ +// File: LightApp_AboutDlg.h +// Created: 03.06.2005 13:49:25 +// Author: Sergey TELKOV +// Copyright (C) CEA 2005 + +#ifndef LIGHTAPP_ABOUTDLG_H +#define LIGHTAPP_ABOUTDLG_H + +#include "LightApp.h" + +#include + +/*! + Descr: LightApp help about dialog +*/ + +class QLabel; + +class LIGHTAPP_EXPORT LightApp_AboutDlg : public QtxDialog +{ + Q_OBJECT + +public: + LightApp_AboutDlg( const QString&, const QString&, QWidget* = 0 ); + virtual ~LightApp_AboutDlg(); + +protected: + virtual void mousePressEvent( QMouseEvent* ); + +private: + void checkLabel( QLabel* ) const; + void changeFont( QWidget*, const bool = false, const bool = false, + const bool = false, const int = 0 ) const; +}; + +#endif diff --git a/src/LightApp/LightApp_Application.cxx b/src/LightApp/LightApp_Application.cxx new file mode 100644 index 000000000..2a7cce67f --- /dev/null +++ b/src/LightApp/LightApp_Application.cxx @@ -0,0 +1,1811 @@ +// File: LightApp_Application.cxx +// Created: 6/20/2005 18:39:45 PM +// Author: Natalia Donis +// Copyright (C) CEA 2005 + +#include "PythonConsole_PyInterp.h" // WARNING! This include must be the first! + +#include "LightApp_Application.h" +#include "LightApp_WidgetContainer.h" +#include "LightApp_Module.h" +#include "LightApp_DataModel.h" +#include "LightApp_Study.h" +#include "LightApp_Preferences.h" +#include "LightApp_PreferencesDlg.h" +#include "LightApp_ModuleDlg.h" +#include "LightApp_AboutDlg.h" + +#include "LightApp_OBFilter.h" + +#include "LightApp_GLSelector.h" +#include "LightApp_OBSelector.h" +#include "LightApp_OCCSelector.h" +#include "LightApp_VTKSelector.h" +#include "LightApp_SelectionMgr.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OBJECT_BROWSER_WIDTH 300 +#define OBJECT_COLUMN_WIDTH 150 + +#define DEFAULT_BROWSER "mozilla" + +#define FIRST_HELP_ID 1000000 + +#include "SALOME_InteractiveObject.hxx" +#include "SALOME_ListIO.hxx" + +static const char* imageEmptyIcon[] = { +"20 20 1 1", +". c None", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"....................", +"...................."}; + +/*!Create new instance of LightApp_Application.*/ +extern "C" LIGHTAPP_EXPORT SUIT_Application* createApplication() +{ + return new LightApp_Application(); +} + +LightApp_Preferences* LightApp_Application::_prefs_ = 0; + +/* + Class : LightApp_Application + Description : Application containing LightApp module +*/ + +/*!Constructor.*/ +LightApp_Application::LightApp_Application() +: CAM_Application( false ), +myPrefs( 0 ) +{ + STD_TabDesktop* desk = new STD_TabDesktop(); + + setDesktop( desk ); + + SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr(); + QPixmap aLogo = aResMgr->loadPixmap( "LightApp", tr( "APP_DEFAULT_ICO" ), false ); + + desktop()->setIcon( aLogo ); + desktop()->setDockableMenuBar( true ); + desktop()->setDockableStatusBar( false ); + + // base logo (salome itself) + desktop()->addLogo( "_app_base", aResMgr->loadPixmap( "LightApp", tr( "APP_BASE_LOGO" ), false ) ); + // extra logo (salome-based application) + desktop()->addLogo( "_app_extra", aResMgr->loadPixmap( "LightApp", tr( "APP_EXTRA_LOGO" ), false ) ); + + clearViewManagers(); + + mySelMgr = new LightApp_SelectionMgr( this ); + + myAccel = new SUIT_Accel( desktop() ); + myAccel->setActionKey( SUIT_Accel::PanLeft, CTRL+Key_Left, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanRight, CTRL+Key_Right, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanUp, CTRL+Key_Up, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanDown, CTRL+Key_Down, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::ZoomIn, CTRL+Key_Plus, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::ZoomOut, CTRL+Key_Minus, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::ZoomFit, CTRL+Key_Asterisk, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateLeft, ALT+Key_Left, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateRight, ALT+Key_Right, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateUp, ALT+Key_Up, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateDown, ALT+Key_Down, OCCViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanLeft, CTRL+Key_Left, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanRight, CTRL+Key_Right, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanUp, CTRL+Key_Up, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::PanDown, CTRL+Key_Down, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::ZoomIn, CTRL+Key_Plus, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::ZoomOut, CTRL+Key_Minus, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::ZoomFit, CTRL+Key_Asterisk, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateLeft, ALT+Key_Left, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateRight, ALT+Key_Right, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateUp, ALT+Key_Up, VTKViewer_Viewer::Type() ); + myAccel->setActionKey( SUIT_Accel::RotateDown, ALT+Key_Down, VTKViewer_Viewer::Type() ); + + connect( mySelMgr, SIGNAL( selectionChanged() ), this, SLOT( onSelection() ) ); +} + +/*!Destructor. + *\li Save window geometry. + *\li Save desktop geometry. + *\li Save resource maneger. + *\li Delete selection manager. + */ +LightApp_Application::~LightApp_Application() +{ + saveWindowsGeometry(); + + if ( resourceMgr() ) + { + if ( desktop() ) + desktop()->saveGeometry( resourceMgr(), "desktop" ); + resourceMgr()->save(); + } + delete mySelMgr; +} + +/*!Start application.*/ +void LightApp_Application::start() +{ + if ( desktop() ) + desktop()->loadGeometry( resourceMgr(), "desktop" ); + + CAM_Application::start(); + + QAction* a = action( ViewWindowsId ); + if ( a && a->inherits( "QtxDockAction" ) ) + ((QtxDockAction*)a)->setAutoPlace( true ); + + updateWindows(); + updateViewManagers(); + + putInfo( "" ); + desktop()->statusBar()->message( "" ); +} + +/*!Gets application name.*/ +QString LightApp_Application::applicationName() const +{ + return tr( "APP_NAME" ); +} + +/*!Gets application version.*/ +QString LightApp_Application::applicationVersion() const +{ + static QString _app_version; + + if ( _app_version.isEmpty() ) + { + QString resVersion = tr( "APP_VERSION" ); + if ( resVersion != "APP_VERSION" ) + { + _app_version = resVersion; + } + else + { + QString path( ::getenv( "GUI_ROOT_DIR" ) ); + if ( !path.isEmpty() ) + path += QDir::separator(); + path += QString( "bin/salome/VERSION" ); + + QFile vf( path ); + if ( vf.open( IO_ReadOnly ) ) + { + QString line; + vf.readLine( line, 1024 ); + vf.close(); + + if ( !line.isEmpty() ) + { + while ( !line.isEmpty() && line.at( line.length() - 1 ) == QChar( '\n' ) ) + line.remove( line.length() - 1, 1 ); + + int idx = line.findRev( ":" ); + if ( idx != -1 ) + _app_version = line.mid( idx + 1 ).stripWhiteSpace(); + } + } + } + } + return _app_version; +} + +/*!Load module by \a name.*/ +CAM_Module* LightApp_Application::loadModule( const QString& name ) +{ + CAM_Module* mod = CAM_Application::loadModule( name ); + if ( mod ) + { + connect( this, SIGNAL( studyOpened() ), mod, SLOT( onModelOpened() ) ); + connect( this, SIGNAL( studySaved() ), mod, SLOT( onModelSaved() ) ); + connect( this, SIGNAL( studyClosed() ), mod, SLOT( onModelClosed() ) ); + } + return mod; +} + +/*!Activate module by \a modName*/ +bool LightApp_Application::activateModule( const QString& modName ) +{ + QString actName; + CAM_Module* prevMod = activeModule(); + + if ( prevMod ) + actName = prevMod->moduleName(); + + if ( actName == modName ) + return true; + + putInfo( tr( "ACTIVATING_MODULE" ).arg( modName ) ); + + saveWindowsGeometry(); + + bool status = CAM_Application::activateModule( modName ); + + updateModuleActions(); + + putInfo( "" ); + + if ( !status ) + return false; + + updateWindows(); + updateViewManagers(); + + return true; +} + +bool LightApp_Application::useStudy(const QString& theName) +{ + createEmptyStudy(); + LightApp_Study* aStudy = dynamic_cast(activeStudy()); + bool res = false; + if (aStudy) + res = aStudy->loadDocument( theName ); + updateDesktopTitle(); + updateCommandsStatus(); + return res; +} + +/*!Gets selection manager.*/ +LightApp_SelectionMgr* LightApp_Application::selectionMgr() const +{ + return mySelMgr; +} + +/*!Create actions:*/ +void LightApp_Application::createActions() +{ + STD_Application::createActions(); + + SUIT_Desktop* desk = desktop(); + SUIT_ResourceMgr* resMgr = resourceMgr(); + + //! Preferences + createAction( PreferencesId, tr( "TOT_DESK_PREFERENCES" ), QIconSet(), + tr( "MEN_DESK_PREFERENCES" ), tr( "PRP_DESK_PREFERENCES" ), + CTRL+Key_P, desk, false, this, SLOT( onPreferences() ) ); + + //! Help for modules + int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, -1, 1000 ); + int helpModuleMenu = createMenu( tr( "MEN_DESK_MODULE_HELP" ), helpMenu, -1, 0 ); + createMenu( separator(), helpMenu, -1, 1 ); + + QStringList aModuleList; + modules( aModuleList, false ); + + int id = LightApp_Application::UserID + FIRST_HELP_ID; + // help for KERNEL and GUI + QCString dir; + QAction* a; + if (dir = getenv("GUI_ROOT_DIR")) { + a = createAction( id, tr( QString("Kernel & GUI Help") ), QIconSet(), + tr( QString("Kernel && GUI Help") ), + tr( QString("Kernel & GUI Help") ), + 0, desk, false, this, SLOT( onHelpContentsModule() ) ); + a->setName( QString("GUI") ); + createMenu( a, helpModuleMenu, -1 ); + id++; + } + // help for other existing modules + for ( QStringList::Iterator it = aModuleList.begin(); it != aModuleList.end(); ++it ) + { + if ( (*it).isEmpty() ) + continue; + + QString modName = moduleName( *it ); + if ( modName.compare("GEOM") == 0 ) { // to be removed when documentation for other modules will be done + QAction* a = createAction( id, tr( moduleTitle(modName) + QString(" Help") ), QIconSet(), + tr( moduleTitle(modName) + QString(" Help") ), + tr( moduleTitle(modName) + QString(" Help") ), + 0, desk, false, this, SLOT( onHelpContentsModule() ) ); + a->setName( modName ); + createMenu( a, helpModuleMenu, -1 ); + id++; + } + } + + //! MRU + QtxMRUAction* mru = new QtxMRUAction( tr( "TOT_DESK_MRU" ), tr( "MEN_DESK_MRU" ), desk ); + connect( mru, SIGNAL( activated( QString ) ), this, SLOT( onMRUActivated( QString ) ) ); + registerAction( MRUId, mru ); + + // default icon for neutral point ('SALOME' module) + QPixmap defIcon = resMgr->loadPixmap( "LightApp", tr( "APP_DEFAULT_ICO" ), false ); + if ( defIcon.isNull() ) + defIcon = QPixmap( imageEmptyIcon ); + + //! default icon for any module + QPixmap modIcon = resMgr->loadPixmap( "LightApp", tr( "APP_MODULE_ICO" ), false ); + if ( modIcon.isNull() ) + modIcon = QPixmap( imageEmptyIcon ); + + QToolBar* modTBar = new QtxToolBar( true, desk ); + modTBar->setLabel( tr( "INF_TOOLBAR_MODULES" ) ); + + QActionGroup* modGroup = new QActionGroup( this ); + modGroup->setExclusive( true ); + modGroup->setUsesDropDown( true ); + + a = createAction( -1, tr( "APP_NAME" ), defIcon, tr( "APP_NAME" ), + tr( "PRP_APP_MODULE" ), 0, desk, true ); + modGroup->add( a ); + myActions.insert( QString(), a ); + + QMap iconMap; + moduleIconNames( iconMap ); + + const int iconSize = 20; + + modGroup->addTo( modTBar ); + modTBar->addSeparator(); + + QStringList modList; + modules( modList, false ); + + for ( QStringList::Iterator it = modList.begin(); it != modList.end(); ++it ) + { + if ( (*it).isEmpty() ) + continue; + + QString iconName; + if ( iconMap.contains( *it ) ) + iconName = iconMap[*it]; + + QString modName = moduleName( *it ); + + QPixmap icon = resMgr->loadPixmap( modName, iconName, false ); + if ( icon.isNull() ) + icon = modIcon; + + icon.convertFromImage( icon.convertToImage().smoothScale( iconSize, iconSize, QImage::ScaleMin ) ); + + QAction* a = createAction( -1, *it, icon, *it, tr( "PRP_MODULE" ).arg( *it ), 0, desk, true ); + a->addTo( modTBar ); + modGroup->add( a ); + + myActions.insert( *it, a ); + } + + SUIT_Tools::simplifySeparators( modTBar ); + + // New window + int windowMenu = createMenu( tr( "MEN_DESK_WINDOW" ), -1, 100 ); + int newWinMenu = createMenu( tr( "MEN_DESK_NEWWINDOW" ), windowMenu, -1, 0 ); + createMenu( separator(), windowMenu, -1, 1 ); + + QMap accelMap; + accelMap[NewGLViewId] = ALT+Key_G; + accelMap[NewPlot2dId] = ALT+Key_P; + accelMap[NewOCCViewId] = ALT+Key_O; + accelMap[NewVTKViewId] = ALT+Key_K; + + for ( int id = NewGLViewId; id <= NewVTKViewId; id++ ) + { + QAction* a = createAction( id, tr( QString( "NEW_WINDOW_%1" ).arg( id - NewGLViewId ) ), QIconSet(), + tr( QString( "NEW_WINDOW_%1" ).arg( id - NewGLViewId ) ), + tr( QString( "NEW_WINDOW_%1" ).arg( id - NewGLViewId ) ), + accelMap.contains( id ) ? accelMap[id] : 0, desk, false, this, SLOT( onNewWindow() ) ); + createMenu( a, newWinMenu, -1 ); + } + + connect( modGroup, SIGNAL( selected( QAction* ) ), this, SLOT( onModuleActivation( QAction* ) ) ); + + int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 ); + createMenu( PreferencesId, fileMenu, 15, -1 ); + createMenu( separator(), fileMenu, -1, 15, -1 ); + + /* + createMenu( separator(), fileMenu, -1, 100, -1 ); + createMenu( MRUId, fileMenu, 100, -1 ); + createMenu( separator(), fileMenu, -1, 100, -1 ); + */ +} + +/*!On module activation action.*/ +void LightApp_Application::onModuleActivation( QAction* a ) +{ + if ( !a ) + return; + + QString modName = a->menuText(); + if ( modName == tr( "APP_NAME" ) ) + modName = QString::null; + + // Force user to create/open a study before module activation + QMap iconMap; + moduleIconNames( iconMap ); + QPixmap icon = resourceMgr()->loadPixmap( moduleName( modName ), iconMap[ modName ], false ); + if ( icon.isNull() ) + icon = resourceMgr()->loadPixmap( "LightApp", tr( "APP_MODULE_BIG_ICO" ), false ); // default icon for any module + + bool cancelled = false; + while ( !modName.isEmpty() && !activeStudy() && !cancelled ){ + LightApp_ModuleDlg aDlg( desktop(), modName, icon ); + int res = aDlg.exec(); + + switch ( res ){ + case 1: + onNewDoc(); + break; + case 2: + onOpenDoc(); + break; + case 3: + //onLoadStudy(); + //break; + case 0: + default: + putInfo( tr("INF_CANCELLED") ); + myActions[QString()]->setOn( true ); + cancelled = true; + } + } + + if ( !cancelled ) + activateModule( modName ); +} + +/*!Default module activation.*/ +QString LightApp_Application::defaultModule() const +{ + QStringList aModuleNames; + modules( aModuleNames, false ); // obtain a complete list of module names for the current configuration + //! If there's the one and only module --> activate it automatically + //! TODO: Possible improvement - default module can be taken from preferences + return aModuleNames.count() > 1 ? "" : ( aModuleNames.count() ? aModuleNames.first() : "" ); +} + +/*!On new window slot.*/ +void LightApp_Application::onNewWindow() +{ + const QObject* obj = sender(); + if ( !obj || !obj->inherits( "QAction" ) ) + return; + + QString type; + int id = actionId( (QAction*)obj ); + switch ( id ) + { + case NewGLViewId: + type = GLViewer_Viewer::Type(); + break; + case NewPlot2dId: + type = Plot2d_Viewer::Type(); + break; + case NewOCCViewId: + type = OCCViewer_Viewer::Type(); + break; + case NewVTKViewId: + type = VTKViewer_Viewer::Type(); + break; + } + + if ( !type.isEmpty() ) + createViewManager( type ); +} + +//======================================================================= +// name : onNewDoc +/*! Purpose : SLOT. Create new document*/ +//======================================================================= +void LightApp_Application::onNewDoc() +{ + SUIT_Study* study = activeStudy(); + + saveWindowsGeometry(); + + CAM_Application::onNewDoc(); + + if ( !study ) // new study will be create in THIS application + { + updateWindows(); + updateViewManagers(); + } +} + +//======================================================================= +// name : onOpenDoc +/*! Purpose : SLOT. Open new document*/ +//======================================================================= +void LightApp_Application::onOpenDoc() +{ + SUIT_Study* study = activeStudy(); + saveWindowsGeometry(); + + CAM_Application::onOpenDoc(); + + if ( !study ) // new study will be create in THIS application + { + updateWindows(); + updateViewManagers(); + } +} + +#include "SUIT_MessageBox.h" +/*! Purpose : SLOT. Open new document with \a aName.*/ +bool LightApp_Application::onOpenDoc( const QString& aName ) +{ + bool isAlreadyOpen = false; + + // Look among opened studies + if (activeStudy()) { // at least one study is opened + SUIT_Session* aSession = SUIT_Session::session(); + QPtrList aAppList = aSession->applications(); + QPtrListIterator it (aAppList); + SUIT_Application* aApp = 0; + // iterate on all applications + for (; (aApp = it.current()) && !isAlreadyOpen; ++it) { + if (aApp->activeStudy()->studyName() == aName) { + isAlreadyOpen = true; // Already opened, ask user what to do + + // The document ... is already open. + // Do you want to reload it? + int aAnswer = SUIT_MessageBox::warn2(desktop(), tr("WRN_WARNING"), + tr("QUE_DOC_ALREADYOPEN").arg(aName), + tr("BUT_YES"), tr("BUT_NO"), 1, 2, 2); + if (aAnswer == 1) { // reload + if (activeStudy()->studyName() == aName && aAppList.count() > 1) { + // Opened in THIS (active) application. + STD_Application* app1 = (STD_Application*)aAppList.at(0); + STD_Application* app2 = (STD_Application*)aAppList.at(1); + if (!app1 || !app2) { + // Error + return false; + } + if (app1->activeStudy()->studyName() == aName) { + // app1 is this application, we need another one + app1 = app2; + } + // Close document of this application. This application will be destroyed. + onCloseDoc(/*ask = */false); + // Open the file with another application, as this one will be destroyed. + return app1->onOpenDoc(aName); + } else { + // Opened in another application. + STD_Application* app = (STD_Application*)aApp; + if (app) + app->onCloseDoc(/*ask = */false); + } + } else { // do not reload + // OK, the study will not be reloaded, but we call + // CAM_Application::onOpenDoc( aName ) all the same. + // It will activate a desktop of the study . + } + } + } + } + + bool res = CAM_Application::onOpenDoc( aName ); + + QAction* a = action( MRUId ); + if ( a && a->inherits( "QtxMRUAction" ) ) + { + QtxMRUAction* mru = (QtxMRUAction*)a; + if ( res ) + mru->insert( aName ); + else + mru->remove( aName ); + } + return res; +} + +//======================================================================= +// name : onHelpAbout +/*! Purpose : SLOT. Display "About" message box*/ +//======================================================================= +void LightApp_Application::onHelpAbout() +{ + LightApp_AboutDlg* dlg = new LightApp_AboutDlg( applicationName(), applicationVersion(), desktop() ); + dlg->exec(); + delete dlg; +} + +/*!SLOT. Load document with \a aName.*/ +bool LightApp_Application::onLoadDoc( const QString& aName ) +{ + bool res = CAM_Application::onLoadDoc( aName ); + + /*jfa tmp:QAction* a = action( MRUId ); + if ( a && a->inherits( "QtxMRUAction" ) ) + { + QtxMRUAction* mru = (QtxMRUAction*)a; + if ( res ) + mru->insert( aName ); + else + mru->remove( aName ); + }*/ + return res; +} + +/*!Private SLOT. Selection.*/ +void LightApp_Application::onSelection() +{ + onSelectionChanged(); + + if ( activeModule() && activeModule()->inherits( "LightApp_Module" ) ) + ((LightApp_Module*)activeModule())->selectionChanged(); +} + +/*!Set active study. + *\param study - SUIT_Study. + */ +void LightApp_Application::setActiveStudy( SUIT_Study* study ) +{ + CAM_Application::setActiveStudy( study ); + + activateWindows(); +} + +//======================================================================= +// name : updateCommandsStatus +/*! Purpose : Enable/Disable menu items and toolbar buttons. Rebuild menu*/ +//======================================================================= +void LightApp_Application::updateCommandsStatus() +{ + CAM_Application::updateCommandsStatus(); + + for ( int id = NewGLViewId; id <= NewVTKViewId; id++ ) + { + QAction* a = action( id ); + if ( a ) + a->setEnabled( activeStudy() ); + } +} + +// Helps to execute command +class RunBrowser: public QThread { +public: + + RunBrowser(QString theApp, QString theParams, QString theHelpFile, QString theContext=NULL): + myApp(theApp), myParams(theParams), myHelpFile("file:" + theHelpFile + theContext), myStatus(0) {}; + + virtual void run() + { + QString aCommand; + + if ( !myApp.isEmpty()) + { + aCommand.sprintf("%s %s %s",myApp.latin1(),myParams.latin1(),myHelpFile.latin1()); + myStatus = system(aCommand); + if(myStatus != 0) + { + QCustomEvent* ce2000 = new QCustomEvent (2000); + postEvent (qApp, ce2000); + } + } + + if( myStatus != 0 || myApp.isEmpty()) + { + myParams = ""; + aCommand.sprintf("%s %s %s", QString(DEFAULT_BROWSER).latin1(),myParams.latin1(), myHelpFile.latin1()); + myStatus = system(aCommand); + if(myStatus != 0) + { + QCustomEvent* ce2001 = new QCustomEvent (2001); + postEvent (qApp, ce2001); + } + } + } + +private: + QString myApp; + QString myParams; + QString myHelpFile; + int myStatus; + +}; + +//======================================================================= +// name : onHelpContentsModule +/*! Purpose : SLOT. Display help contents for choosen module*/ +//======================================================================= +void LightApp_Application::onHelpContentsModule() +{ + const QAction* obj = (QAction*) sender(); + + QString aComponentName = obj->name(); + QString aFileName = aComponentName.lower() + ".htm"; + + QCString dir; + QString root; + QString homeDir; + if (dir = getenv( aComponentName + "_ROOT_DIR")) { + root = Qtx::addSlash( Qtx::addSlash(dir) + Qtx::addSlash("doc") + Qtx::addSlash("salome") + Qtx::addSlash(aComponentName)); + if ( QFileInfo( root + aFileName ).exists() ) { + homeDir = root; + } else { + SUIT_MessageBox::warn1( desktop(), tr("WRN_WARNING"), + QString( "%1"+ aFileName + " doesn't exist." ).arg(root), tr ("BUT_OK") ); + return; + } + } + + QString helpFile = QFileInfo( homeDir + aFileName ).absFilePath(); + SUIT_ResourceMgr* resMgr = resourceMgr(); + QString anApp = resMgr->stringValue("ExternalBrowser", "application"); + QString aParams = resMgr->stringValue("ExternalBrowser", "parameters"); + + RunBrowser* rs = new RunBrowser(anApp, aParams, helpFile); + rs->start(); +} + +/*!Sets enable or disable some actions on selection changed.*/ +void LightApp_Application::onSelectionChanged() +{ +} + +/*!Return window. + *\param flag - key for window + *\param studyId - study id + * Flag used how identificator of window in windows list. + */ +QWidget* LightApp_Application::window( const int flag, const int studyId ) const +{ + QWidget* wid = 0; + + int sId = studyId; + if ( sId < 0 ) + { + if ( !activeStudy() ) + return 0; + else + sId = activeStudy()->id(); + } + + if ( myWindows.contains( flag ) ) + wid = myWindows[flag]->widget( sId ); + + return wid; +} + +/*!Adds window to application. + *\param wid - QWidget + *\param flag - key wor window + *\param studyId - study id + * Flag used how identificator of window in windows list. + */ +void LightApp_Application::addWindow( QWidget* wid, const int flag, const int studyId ) +{ + if ( !wid ) + return; + + int sId = studyId; + if ( sId < 0 ) + { + if ( !activeStudy() ) + return; + else + sId = activeStudy()->id(); + } + + if ( !myWindows.contains( flag ) ) + { + QMap winMap; + currentWindows( winMap ); + + myWindows.insert( flag, new LightApp_WidgetContainer( flag, desktop() ) ); + if ( winMap.contains( flag ) ) + desktop()->moveDockWindow( myWindows[flag], (Dock)winMap[flag] ); + + myWindows[flag]->setResizeEnabled( true ); + myWindows[flag]->setCloseMode( QDockWindow::Always ); + myWindows[flag]->setName( QString( "dock_window_%1" ).arg( flag ) ); + } + + QFont f; + if( wid->inherits( "PythonConsole" ) ) + f = ( ( PythonConsole* )wid )->font(); + else + f = wid->font(); + + myWindows[flag]->insert( sId, wid ); + wid->setFont(f); + + setWindowShown( flag, !myWindows[flag]->isEmpty() ); +} + +/*!Remove window from application. + *\param flag - key wor window + *\param studyId - study id + * Flag used how identificator of window in windows list. + */ +void LightApp_Application::removeWindow( const int flag, const int studyId ) +{ + if ( !myWindows.contains( flag ) ) + return; + + int sId = studyId; + if ( sId < 0 ) + { + if ( !activeStudy() ) + return; + else + sId = activeStudy()->id(); + } + + QWidget* wid = myWindows[flag]->widget( sId ); + myWindows[flag]->remove( sId ); + delete wid; + + setWindowShown( flag, !myWindows[flag]->isEmpty() ); +} + +/*!Gets window. + *\param flag - key wor window + *\param studyId - study id + * Flag used how identificator of window in windows list. + */ +QWidget* LightApp_Application::getWindow( const int flag, const int studyId ) +{ + QWidget* wid = window( flag, studyId ); + if ( !wid ) + addWindow( wid = createWindow( flag ), flag, studyId ); + + return wid; +} + +/*!Check is window visible?(with identificator \a type)*/ +bool LightApp_Application::isWindowVisible( const int type ) const +{ + bool res = false; + if ( myWindows.contains( type ) ) + { + SUIT_Desktop* desk = ((LightApp_Application*)this)->desktop(); + res = desk && desk->appropriate( myWindows[type] ); + } + return res; +} + +/*!Sets window show or hide. + *\param type - window identificator. + *\param on - true/false (window show/hide) + */ +void LightApp_Application::setWindowShown( const int type, const bool on ) +{ + if ( !desktop() || !myWindows.contains( type ) ) + return; + + QDockWindow* dw = myWindows[type]; + desktop()->setAppropriate( dw, on ); + on ? dw->show() : dw->hide(); +} + +/*!Gets "ObjectBrowser".*/ +OB_Browser* LightApp_Application::objectBrowser() +{ + OB_Browser* ob = 0; + QWidget* wid = getWindow( WT_ObjectBrowser ); + if ( wid->inherits( "OB_Browser" ) ) + ob = (OB_Browser*)wid; + return ob; +} + +/*!Gets "LogWindow".*/ +LogWindow* LightApp_Application::logWindow() +{ + LogWindow* lw = 0; + QWidget* wid = getWindow( WT_LogWindow ); + if ( wid->inherits( "LogWindow" ) ) + lw = (LogWindow*)wid; + return lw; +} + +/*!Get "PythonConsole"*/ +PythonConsole* LightApp_Application::pythonConsole() +{ + PythonConsole* console = 0; + QWidget* wid = getWindow( WT_PyConsole ); + if ( wid->inherits( "PythonConsole" ) ) + console = (PythonConsole*)wid; + return console; +} + +/*!Update obect browser*/ +void LightApp_Application::updateObjectBrowser( const bool updateModels ) +{ + // update existing data models + if ( updateModels ) + { + LightApp_Study* study = dynamic_cast(activeStudy()); + if ( study ) { + CAM_Study::ModelList dm_list; + study->dataModels( dm_list ); + for ( CAM_Study::ModelListIterator it( dm_list ); it.current(); ++it ) { + CAM_DataModel* camDM = it.current(); + if ( camDM && camDM->inherits( "LightApp_DataModel" ) ) + ((LightApp_DataModel*)camDM)->update(); + } + } + } + if ( objectBrowser() ) + { + objectBrowser()->updateGeometry(); + objectBrowser()->updateTree(); + } +} + +/*!Gets preferences.*/ +LightApp_Preferences* LightApp_Application::preferences() const +{ + return preferences( false ); +} + +/*!Gets view manager*/ +SUIT_ViewManager* LightApp_Application::getViewManager( const QString& vmType, const bool create ) +{ + SUIT_ViewManager* aVM = viewManager( vmType ); + SUIT_ViewManager* anActiveVM = CAM_Application::activeViewManager(); + + if ( anActiveVM && anActiveVM->getType() == vmType ) + aVM = anActiveVM; + + if ( aVM && create ) + { + if ( !aVM->getActiveView() ) + aVM->createView(); + else + aVM->getActiveView()->setFocus(); + } + else if ( create ) + aVM = createViewManager( vmType ); + + return aVM; +} + +/*!Create view manager.*/ +SUIT_ViewManager* LightApp_Application::createViewManager( const QString& vmType ) +{ + SUIT_ResourceMgr* resMgr = resourceMgr(); + + SUIT_ViewManager* viewMgr = 0; + if ( vmType == GLViewer_Viewer::Type() ) + { + viewMgr = new GLViewer_ViewManager( activeStudy(), desktop() ); + new LightApp_GLSelector( (GLViewer_Viewer2d*)viewMgr->getViewModel(), mySelMgr ); + } + else if ( vmType == Plot2d_Viewer::Type() ) + { + viewMgr = new Plot2d_ViewManager( activeStudy(), desktop() ); + viewMgr->setViewModel( new SPlot2d_Viewer() );// custom view model, which extends SALOME_View interface + } + else if ( vmType == OCCViewer_Viewer::Type() ) + { + viewMgr = new OCCViewer_ViewManager( activeStudy(), desktop() ); + SOCC_Viewer* vm = new SOCC_Viewer(); + vm->setBackgroundColor( resMgr->colorValue( "OCCViewer", "background", vm->backgroundColor() ) ); + vm->setTrihedronSize( resMgr->integerValue( "OCCViewer", "trihedron_size", vm->trihedronSize() ) ); + int u( 1 ), v( 1 ); + vm->isos( u, v ); + u = resMgr->integerValue( "OCCViewer", "iso_number_u", u ); + v = resMgr->integerValue( "OCCViewer", "iso_number_v", v ); + vm->setIsos( u, v ); + viewMgr->setViewModel( vm );// custom view model, which extends SALOME_View interface + new LightApp_OCCSelector( (OCCViewer_Viewer*)viewMgr->getViewModel(), mySelMgr ); + } + else if ( vmType == SVTK_Viewer::Type() ) + { + viewMgr = new SVTK_ViewManager( activeStudy(), desktop() ); + SVTK_Viewer* vm = dynamic_cast( viewMgr->getViewModel() ); + if( vm ) + { + vm->setBackgroundColor( resMgr->colorValue( "VTKViewer", "background", vm->backgroundColor() ) ); + vm->setTrihedronSize( resMgr->integerValue( "VTKViewer", "trihedron_size", vm->trihedronSize() ) ); + new LightApp_VTKSelector( vm, mySelMgr ); + } + } + + if ( !viewMgr ) + return 0; + + addViewManager( viewMgr ); + SUIT_ViewWindow* viewWin = viewMgr->createViewWindow(); + + if ( viewWin && desktop() ) + viewWin->resize( (int)( desktop()->width() * 0.6 ), (int)( desktop()->height() * 0.6 ) ); + + connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ), + this, SLOT( onCloseView( SUIT_ViewManager* ) ) ); + + return viewMgr; +} + +//======================================================================= +// name : onCloseView +/*! Purpose : SLOT. Remove view manager from application*/ +//======================================================================= +void LightApp_Application::onCloseView( SUIT_ViewManager* theVM ) +{ + removeViewManager( theVM ); +} + +/*!Protected SLOT. On study created.*/ +void LightApp_Application::onStudyCreated( SUIT_Study* theStudy ) +{ + SUIT_DataObject* aRoot = 0; + if ( theStudy && theStudy->root() ) + { + aRoot = theStudy->root(); + //aRoot->setName( tr( "DATA_MODELS" ) ); + } + if ( objectBrowser() != 0 ) + objectBrowser()->setRootObject( aRoot ); + + activateModule( defaultModule() ); + + activateWindows(); +} + +/*!Protected SLOT. On study opened.*/ +void LightApp_Application::onStudyOpened( SUIT_Study* theStudy ) +{ + SUIT_DataObject* aRoot = 0; + if ( theStudy && theStudy->root() ) + { + aRoot = theStudy->root(); + //aRoot->dump(); + } + if ( objectBrowser() != 0 ) { + objectBrowser()->setRootObject( aRoot ); + } + + activateModule( defaultModule() ); + + activateWindows(); + + emit studyOpened(); +} + +/*!Protected SLOT. On study saved.*/ +void LightApp_Application::onStudySaved( SUIT_Study* ) +{ + emit studySaved(); +} + +/*!Protected SLOT. On study closed.*/ +void LightApp_Application::onStudyClosed( SUIT_Study* ) +{ + emit studyClosed(); + + activateModule( "" ); + + // Bug 10396: remove all selectors + delete mySelMgr; + mySelMgr = new LightApp_SelectionMgr( this ); + + saveWindowsGeometry(); +} + +/*!Protected SLOT.On desktop activated.*/ +void LightApp_Application::onDesktopActivated() +{ + CAM_Application::onDesktopActivated(); + LightApp_Module* aModule = dynamic_cast(activeModule()); + if(aModule) + aModule->studyActivated(); +} + +/*!Gets file filter. + *\retval QString "(*.bin)" + */ +QString LightApp_Application::getFileFilter() const +{ + return "(*.bin)"; +} + +/*! Gets file name*/ +QString LightApp_Application::getFileName( bool open, const QString& initial, const QString& filters, + const QString& caption, QWidget* parent ) +{ + if ( !parent ) + parent = desktop(); + QStringList fls = QStringList::split( ";;", filters, false ); + return SUIT_FileDlg::getFileName( parent, initial, fls, caption, open, true ); +} + +/*! Gets directory*/ +QString LightApp_Application::getDirectory( const QString& initial, const QString& caption, QWidget* parent ) +{ + if ( !parent ) + parent = desktop(); + return SUIT_FileDlg::getExistingDirectory( parent, initial, caption, true ); +} + +/*! Get open file names*/ +QStringList LightApp_Application::getOpenFileNames( const QString& initial, const QString& filters, + const QString& caption, QWidget* parent ) +{ + if ( !parent ) + parent = desktop(); + QStringList fls = QStringList::split( ";;", filters, false ); + return SUIT_FileDlg::getOpenFileNames( parent, initial, fls, caption, true ); +} + +/*!Private SLOT. Update object browser.*/ +void LightApp_Application::onRefresh() +{ + updateObjectBrowser( true ); +} + +/*!Private SLOT. On preferences.*/ +void LightApp_Application::onPreferences() +{ + QApplication::setOverrideCursor( Qt::waitCursor ); + + LightApp_PreferencesDlg* prefDlg = new LightApp_PreferencesDlg( preferences( true ), desktop()); + + QApplication::restoreOverrideCursor(); + + if ( !prefDlg ) + return; + + prefDlg->exec(); + + delete prefDlg; +} + +/*!Protected SLOT. On preferences changed.*/ +void LightApp_Application::onPreferenceChanged( QString& modName, QString& section, QString& param ) +{ + LightApp_Module* sMod = 0; + CAM_Module* mod = module( modName ); + if ( mod && mod->inherits( "LightApp_Module" ) ) + sMod = (LightApp_Module*)mod; + + if ( sMod ) + sMod->preferencesChanged( section, param ); + else + preferencesChanged( section, param ); +} + +/*!Private SLOT. On open document with name \a aName.*/ +void LightApp_Application::onMRUActivated( QString aName ) +{ + onOpenDoc( aName ); +} + +/*!Remove all windows from study.*/ +void LightApp_Application::beforeCloseDoc( SUIT_Study* s ) +{ + CAM_Application::beforeCloseDoc( s ); + + for ( WindowMap::ConstIterator itr = myWindows.begin(); s && itr != myWindows.end(); ++itr ) + removeWindow( itr.key(), s->id() ); +} + +/*!Update actions.*/ +void LightApp_Application::updateActions() +{ + updateCommandsStatus(); +} + +//======================================================================= +// name : createNewStudy +/*! Purpose : Create new study*/ +//======================================================================= +SUIT_Study* LightApp_Application::createNewStudy() +{ + LightApp_Study* aStudy = new LightApp_Study( this ); + + // Set up processing of major study-related events + connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) ); + connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) ); + connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) ); + connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) ); + + return aStudy; +} + +/*!Create window.*/ +QWidget* LightApp_Application::createWindow( const int flag ) +{ + QWidget* wid = 0; + if ( flag == WT_ObjectBrowser ) + { + OB_Browser* ob = new OB_Browser( desktop() ); + ob->setAutoUpdate( true ); + ob->setAutoOpenLevel( 1 ); + ob->setCaption( tr( "OBJECT_BROWSER" ) ); + ob->listView()->setColumnWidth( 0, OBJECT_COLUMN_WIDTH ); + ob->resize( OBJECT_BROWSER_WIDTH, ob->height() ); + ob->setFilter( new LightApp_OBFilter( selectionMgr() ) ); + + ob->setNameTitle( tr( "OBJ_BROWSER_NAME" ) ); + + // Create OBSelector + new LightApp_OBSelector( ob, mySelMgr ); + + wid = ob; + + ob->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) ); + } + else if ( flag == WT_PyConsole ) + { + PythonConsole* pyCons = new PythonConsole( desktop() ); + pyCons->setCaption( tr( "PYTHON_CONSOLE" ) ); + wid = pyCons; + // pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) ); + } + else if ( flag == WT_LogWindow ) + { + LogWindow* logWin = new LogWindow( desktop() ); + logWin->setCaption( tr( "LOG_WINDOW" ) ); + wid = logWin; + logWin->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) ); + } + return wid; +} + +/*!Default windows(Object Browser, Python Console). + * Adds to map \a aMap. + */ +void LightApp_Application::defaultWindows( QMap& aMap ) const +{ + aMap.insert( WT_ObjectBrowser, Qt::DockLeft ); + aMap.insert( WT_PyConsole, Qt::DockBottom ); + // aMap.insert( WT_LogWindow, Qt::DockBottom ); +} + +/*!Default view manager.*/ +void LightApp_Application::defaultViewManagers( QStringList& ) const +{ + /*!Do nothing.*/ +} + +/*!Gets preferences. + * Create preferences, if \a crt = true. + */ +LightApp_Preferences* LightApp_Application::preferences( const bool crt ) const +{ + if ( myPrefs ) + return myPrefs; + + LightApp_Application* that = (LightApp_Application*)this; + + if ( !_prefs_ && crt ) + { + _prefs_ = new LightApp_Preferences( resourceMgr() ); + that->createPreferences( _prefs_ ); + } + + that->myPrefs = _prefs_; + + QPtrList appList = SUIT_Session::session()->applications(); + for ( QPtrListIterator appIt ( appList ); appIt.current(); ++appIt ) + { + if ( !appIt.current()->inherits( "LightApp_Application" ) ) + continue; + + LightApp_Application* app = (LightApp_Application*)appIt.current(); + + QStringList modNameList; + app->modules( modNameList, false ); + for ( QStringList::const_iterator it = modNameList.begin(); it != modNameList.end(); ++it ) + { + int id = _prefs_->addPreference( *it ); + _prefs_->setItemProperty( id, "info", tr( "PREFERENCES_NOT_LOADED" ).arg( *it ) ); + } + + ModuleList modList; + app->modules( modList ); + for ( ModuleListIterator itr( modList ); itr.current(); ++itr ) + { + LightApp_Module* mod = 0; + if ( itr.current()->inherits( "LightApp_Module" ) ) + mod = (LightApp_Module*)itr.current(); + + if ( mod && !_prefs_->hasModule( mod->moduleName() ) ) + { + int modCat = _prefs_->addPreference( mod->moduleName() ); + _prefs_->setItemProperty( modCat, "info", QString::null ); + mod->createPreferences(); + } + } + } + + connect( myPrefs, SIGNAL( preferenceChanged( QString&, QString&, QString& ) ), + this, SLOT( onPreferenceChanged( QString&, QString&, QString& ) ) ); + + return myPrefs; +} + +/*!Add new module to application.*/ +void LightApp_Application::moduleAdded( CAM_Module* mod ) +{ + CAM_Application::moduleAdded( mod ); + + LightApp_Module* lightMod = 0; + if ( mod && mod->inherits( "LightApp_Module" ) ) + lightMod = (LightApp_Module*)mod; + + if ( myPrefs && lightMod && !myPrefs->hasModule( lightMod->moduleName() )) + { + int modCat = myPrefs->addPreference( mod->moduleName() ); + myPrefs->setItemProperty( modCat, "info", QString::null ); + lightMod->createPreferences(); + } +} + +/*!Create preferences.*/ +void LightApp_Application::createPreferences( LightApp_Preferences* pref ) +{ + if ( !pref ) + return; + + int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) ); + + int genTab = pref->addPreference( tr( "PREF_TAB_GENERAL" ), salomeCat ); + int studyGroup = pref->addPreference( tr( "PREF_GROUP_STUDY" ), genTab ); + pref->setItemProperty( studyGroup, "columns", 1 ); + + pref->addPreference( tr( "PREF_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file" ); + pref->addPreference( tr( "PREF_ASCII_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "ascii_file" ); + int undoPref = pref->addPreference( tr( "PREF_UNDO_LEVEL" ), studyGroup, LightApp_Preferences::IntSpin, "Study", "undo_level" ); + pref->setItemProperty( undoPref, "min", 1 ); + pref->setItemProperty( undoPref, "max", 100 ); + + int extgroup = pref->addPreference( tr( "PREF_GROUP_EXT_BROWSER" ), genTab ); + pref->setItemProperty( extgroup, "columns", 1 ); + int apppref = pref->addPreference( tr( "PREF_APP" ), extgroup, LightApp_Preferences::File, "ExternalBrowser", "application" ); + pref->setItemProperty( apppref, "existing", true ); + pref->setItemProperty( apppref, "flags", QFileInfo::ExeUser ); + + pref->addPreference( tr( "PREF_PARAM" ), extgroup, LightApp_Preferences::String, "ExternalBrowser", "parameters" ); + + int pythonConsoleGroup = pref->addPreference( tr( "PREF_GROUP_PY_CONSOLE" ), genTab ); + pref->setItemProperty( pythonConsoleGroup, "columns", 1 ); + pref->addPreference( tr( "PREF_FONT" ), pythonConsoleGroup, LightApp_Preferences::Font, "PyConsole", "font" ); + + int viewTab = pref->addPreference( tr( "PREF_TAB_VIEWERS" ), salomeCat ); + + int occGroup = pref->addPreference( tr( "PREF_GROUP_OCCVIEWER" ), viewTab ); + + int vtkGroup = pref->addPreference( tr( "PREF_GROUP_VTKVIEWER" ), viewTab ); + + int plot2dGroup = pref->addPreference( tr( "PREF_GROUP_PLOT2DVIEWER" ), viewTab ); + + pref->setItemProperty( occGroup, "columns", 1 ); + pref->setItemProperty( vtkGroup, "columns", 1 ); + pref->setItemProperty( plot2dGroup, "columns", 1 ); + + int occTS = pref->addPreference( tr( "PREF_TRIHEDRON_SIZE" ), occGroup, + LightApp_Preferences::IntSpin, "OCCViewer", "trihedron_size" ); + pref->addPreference( tr( "PREF_VIEWER_BACKGROUND" ), occGroup, + LightApp_Preferences::Color, "OCCViewer", "background" ); + + pref->setItemProperty( occTS, "min", 1 ); + pref->setItemProperty( occTS, "max", 150 ); + + int isoU = pref->addPreference( tr( "PREF_ISOS_U" ), occGroup, + LightApp_Preferences::IntSpin, "OCCViewer", "iso_number_u" ); + int isoV = pref->addPreference( tr( "PREF_ISOS_V" ), occGroup, + LightApp_Preferences::IntSpin, "OCCViewer", "iso_number_v" ); + + pref->setItemProperty( isoU, "min", 0 ); + pref->setItemProperty( isoU, "max", 100000 ); + + pref->setItemProperty( isoV, "min", 0 ); + pref->setItemProperty( isoV, "max", 100000 ); + + int vtkTS = pref->addPreference( tr( "PREF_TRIHEDRON_SIZE" ), vtkGroup, + LightApp_Preferences::IntSpin, "VTKViewer", "trihedron_size" ); + pref->addPreference( tr( "PREF_VIEWER_BACKGROUND" ), vtkGroup, + LightApp_Preferences::Color, "VTKViewer", "background" ); + + pref->setItemProperty( vtkTS, "min", 1 ); + pref->setItemProperty( vtkTS, "max", 150 ); + + pref->addPreference( tr( "PREF_SHOW_LEGEND" ), plot2dGroup, + LightApp_Preferences::Bool, "Plot2d", "ShowLegend" ); + + int legendPosition = pref->addPreference( tr( "PREF_LEGEND_POSITION" ), plot2dGroup, + LightApp_Preferences::Selector, "Plot2d", "LegendPos" ); + QStringList aLegendPosList; + aLegendPosList.append( tr("PREF_LEFT") ); + aLegendPosList.append( tr("PREF_RIGHT") ); + aLegendPosList.append( tr("PREF_TOP") ); + aLegendPosList.append( tr("PREF_BOTTOM") ); + + QValueList anIndexesList; + anIndexesList.append(0); + anIndexesList.append(1); + anIndexesList.append(2); + anIndexesList.append(3); + + pref->setItemProperty( legendPosition, "strings", aLegendPosList ); + pref->setItemProperty( legendPosition, "indexes", anIndexesList ); + + int curveType = pref->addPreference( tr( "PREF_CURVE_TYPE" ), plot2dGroup, + LightApp_Preferences::Selector, "Plot2d", "CurveType" ); + QStringList aCurveTypesList; + aCurveTypesList.append( tr("PREF_POINTS") ); + aCurveTypesList.append( tr("PREF_LINES") ); + aCurveTypesList.append( tr("PREF_SPLINE") ); + + anIndexesList.clear(); + anIndexesList.append(0); + anIndexesList.append(1); + anIndexesList.append(2); + + pref->setItemProperty( curveType, "strings", aCurveTypesList ); + pref->setItemProperty( curveType, "indexes", anIndexesList ); + + int markerSize = pref->addPreference( tr( "PREF_MARKER_SIZE" ), plot2dGroup, + LightApp_Preferences::IntSpin, "Plot2d", "MarkerSize" ); + + pref->setItemProperty( markerSize, "min", 0 ); + pref->setItemProperty( markerSize, "max", 100 ); + + QStringList aScaleModesList; + aScaleModesList.append( tr("PREF_LINEAR") ); + aScaleModesList.append( tr("PREF_LOGARITHMIC") ); + + anIndexesList.clear(); + anIndexesList.append(0); + anIndexesList.append(1); + + int horScale = pref->addPreference( tr( "PREF_HOR_AXIS_SCALE" ), plot2dGroup, + LightApp_Preferences::Selector, "Plot2d", "HorScaleMode" ); + + pref->setItemProperty( horScale, "strings", aScaleModesList ); + pref->setItemProperty( horScale, "indexes", anIndexesList ); + + int verScale = pref->addPreference( tr( "PREF_VERT_AXIS_SCALE" ), plot2dGroup, + LightApp_Preferences::Selector, "Plot2d", "VerScaleMode" ); + + pref->setItemProperty( verScale, "strings", aScaleModesList ); + pref->setItemProperty( verScale, "indexes", anIndexesList ); + + pref->addPreference( tr( "PREF_VIEWER_BACKGROUND" ), plot2dGroup, + LightApp_Preferences::Color, "Plot2d", "Background" ); + + int dirTab = pref->addPreference( tr( "PREF_TAB_DIRECTORIES" ), salomeCat ); + int dirGroup = pref->addPreference( tr( "PREF_GROUP_DIRECTORIES" ), dirTab ); + pref->setItemProperty( dirGroup, "columns", 1 ); + pref->addPreference( tr( "" ), dirGroup, + LightApp_Preferences::DirList, "FileDlg", "QuickDirList" ); +} + +/*!Changed preferences */ +void LightApp_Application::preferencesChanged( const QString& sec, const QString& param ) +{ + SUIT_ResourceMgr* resMgr = resourceMgr(); + if ( !resMgr ) + return; + + if ( sec == QString( "OCCViewer" ) && param == QString( "trihedron_size" ) ) + { + int sz = resMgr->integerValue( sec, param, -1 ); + QPtrList lst; + viewManagers( OCCViewer_Viewer::Type(), lst ); + for ( QPtrListIterator it( lst ); it.current() && sz >= 0; ++it ) + { + SUIT_ViewModel* vm = it.current()->getViewModel(); + if ( !vm || !vm->inherits( "OCCViewer_Viewer" ) ) + continue; + + OCCViewer_Viewer* occVM = (OCCViewer_Viewer*)vm; + occVM->setTrihedronSize( sz ); + occVM->getAISContext()->UpdateCurrentViewer(); + } + } + + if ( sec == QString( "VTKViewer" ) && param == QString( "trihedron_size" ) ) + { + int sz = resMgr->integerValue( sec, param, -1 ); + QPtrList lst; + viewManagers( SVTK_Viewer::Type(), lst ); + for ( QPtrListIterator it( lst ); it.current() && sz >= 0; ++it ) + { + SUIT_ViewModel* vm = it.current()->getViewModel(); + if ( !vm || !vm->inherits( "SVTK_Viewer" ) ) + continue; + + SVTK_Viewer* vtkVM = dynamic_cast( vm ); + if( vtkVM ) + { + vtkVM->setTrihedronSize( sz ); + vtkVM->Repaint(); + } + } + } + + if ( sec == QString( "OCCViewer" ) && ( param == QString( "iso_number_u" ) || param == QString( "iso_number_v" ) ) ) + { + QPtrList lst; + viewManagers( OCCViewer_Viewer::Type(), lst ); + int u = resMgr->integerValue( sec, "iso_number_u" ); + int v = resMgr->integerValue( sec, "iso_number_v" ); + for ( QPtrListIterator it( lst ); it.current(); ++it ) + ((OCCViewer_Viewer*)it.current())->setIsos( u, v ); + } + + if( sec=="ObjectBrowser" ) + { + if( param=="auto_size" ) + { + OB_Browser* ob = objectBrowser(); + if( !ob ) + return; + + bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false ); + ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual ); + + updateObjectBrowser( false ); + } + } + + if( sec=="PyConsole" ) + { + if( param=="font" ) + if( pythonConsole() ) + pythonConsole()->setFont( resMgr->fontValue( "PyConsole", "font" ) ); + } +} + +/*!Update desktop title.*/ +void LightApp_Application::updateDesktopTitle() { + QString aTitle = applicationName(); + QString aVer = applicationVersion(); + if ( !aVer.isEmpty() ) + aTitle += QString( " " ) + aVer; + + desktop()->setCaption( aTitle ); +} + +/*!Update windows after close document.*/ +void LightApp_Application::afterCloseDoc() +{ + updateWindows(); + + CAM_Application::afterCloseDoc(); +} + +/*!Update module action.*/ +void LightApp_Application::updateModuleActions() +{ + QString modName; + if ( activeModule() ) + modName = activeModule()->moduleName(); + + if ( myActions.contains( modName ) ) + myActions[modName]->setOn( true ); +} + +/*!Gets current windows. + *\param winMap - output current windows map. + */ +void LightApp_Application::currentWindows( QMap& winMap ) const +{ + winMap.clear(); + if ( !activeStudy() ) + return; + + if ( activeModule() && activeModule()->inherits( "LightApp_Module" ) ) + ((LightApp_Module*)activeModule())->windows( winMap ); + else + defaultWindows( winMap ); +} + +/*!Gets current view managers. + *\param lst - output current view managers list. + */ +void LightApp_Application::currentViewManagers( QStringList& lst ) const +{ + lst.clear(); + if ( !activeStudy() ) + return; + + if ( activeModule() && activeModule()->inherits( "LightApp_Module" ) ) + ((LightApp_Module*)activeModule())->viewManagers( lst ); + else + defaultViewManagers( lst ); +} + +/*!Update windows.*/ +void LightApp_Application::updateWindows() +{ + QMap winMap; + currentWindows( winMap ); + + for ( QMap::ConstIterator it = winMap.begin(); it != winMap.end(); ++it ) + getWindow( it.key() ); + + loadWindowsGeometry(); + + for ( WindowMap::ConstIterator itr = myWindows.begin(); itr != myWindows.end(); ++itr ) + setWindowShown( itr.key(), !itr.data()->isEmpty() && winMap.contains( itr.key() ) ); +} + +/*!Update view managers.*/ +void LightApp_Application::updateViewManagers() +{ + QStringList lst; + currentViewManagers( lst ); + + for ( QStringList::const_iterator it = lst.begin(); it != lst.end(); ++it ) + getViewManager( *it, true ); +} + +/*!Load windows geometry.*/ +void LightApp_Application::loadWindowsGeometry() +{ + QtxDockAction* dockMgr = 0; + + QAction* a = action( ViewWindowsId ); + if ( a && a->inherits( "QtxDockAction" ) ) + dockMgr = (QtxDockAction*)a; + + if ( !dockMgr ) + return; + + QString modName; + if ( activeModule() ) + modName = activeModule()->name(""); + + QString section = QString( "windows_geometry" ); + if ( !modName.isEmpty() ) + section += QString( "." ) + modName; + + dockMgr->loadGeometry( resourceMgr(), section, false ); + dockMgr->restoreGeometry(); +} + +/*!Save windows geometry.*/ +void LightApp_Application::saveWindowsGeometry() +{ + QtxDockAction* dockMgr = 0; + + QAction* a = action( ViewWindowsId ); + if ( a && a->inherits( "QtxDockAction" ) ) + dockMgr = (QtxDockAction*)a; + + if ( !dockMgr ) + return; + + QString modName; + if ( activeModule() ) + modName = activeModule()->name(""); + + QString section = QString( "windows_geometry" ); + if ( !modName.isEmpty() ) + section += QString( "." ) + modName; + + dockMgr->storeGeometry(); + dockMgr->saveGeometry( resourceMgr(), section, false ); +} + +/*!Activate windows.*/ +void LightApp_Application::activateWindows() +{ + if ( activeStudy() ) + { + for ( WindowMap::Iterator itr = myWindows.begin(); itr != myWindows.end(); ++itr ) + itr.data()->activate( activeStudy()->id() ); + } +} + +/*!Adds icon names for modules.*/ +void LightApp_Application::moduleIconNames( QMap& iconMap ) const +{ + iconMap.clear(); + + SUIT_ResourceMgr* resMgr = resourceMgr(); + if ( !resMgr ) + return; + + QStringList modList; + modules( modList, false ); + + for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it ) + { + QString modName = *it; + QString modIntr = moduleName( modName ); + QString modIcon = resMgr->stringValue( modIntr, "icon", QString::null ); + + if ( modIcon.isEmpty() ) + continue; + + if ( SUIT_Tools::extension( modIcon ).isEmpty() ) + modIcon += QString( ".png" ); + + iconMap.insert( modName, modIcon ); + } +} + +/*!Insert items in popup, which necessary for current application*/ +void LightApp_Application::contextMenuPopup( const QString& type, QPopupMenu* thePopup, QString& title ) +{ + CAM_Application::contextMenuPopup( type, thePopup, title ); + + OB_Browser* ob = objectBrowser(); + if ( !ob || type != ob->popupClientType() ) + return; + + thePopup->insertSeparator(); + thePopup->insertItem( tr( "MEN_REFRESH" ), this, SLOT( onRefresh() ) ); +} + +/*!Create empty study.*/ +void LightApp_Application::createEmptyStudy() +{ + CAM_Application::createEmptyStudy(); + if ( objectBrowser() ) + objectBrowser()->updateTree(); +} + +/*!Activate module \a mod.*/ +bool LightApp_Application::activateModule( CAM_Module* mod ) +{ + bool res = CAM_Application::activateModule( mod ); + if ( objectBrowser() ) + objectBrowser()->updateTree(); + return res; +} + +/*!return keyborad accelerators manager object */ +SUIT_Accel* LightApp_Application::accel() const +{ + return myAccel; +} diff --git a/src/LightApp/LightApp_Application.h b/src/LightApp/LightApp_Application.h new file mode 100644 index 000000000..cfb459fba --- /dev/null +++ b/src/LightApp/LightApp_Application.h @@ -0,0 +1,188 @@ +// File: LightApp_Application.h +// Created: 6/20/2005 18:39:25 PM +// Author: OCC team +// Copyright (C) CEA 2005 + +#ifndef LIGHTAPP_APPLICATION_H +#define LIGHTAPP_APPLICATION_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "LightApp.h" +#include + +class LogWindow; +class OB_Browser; +class PythonConsole; +class STD_Application; +class LightApp_WidgetContainer; +class LightApp_Preferences; +class LightApp_SelectionMgr; +class SUIT_Study; +class SUIT_Accel; +class CAM_Module; + +class QString; +class QWidget; +class QStringList; +class QPixmap; + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +/*! + Description : Application containing only LightApp module +*/ + +class LIGHTAPP_EXPORT LightApp_Application : public CAM_Application +{ + Q_OBJECT + +public: + typedef enum { WT_ObjectBrowser, WT_PyConsole, WT_LogWindow, WT_User } WindowTypes; + + enum { NewGLViewId = STD_Application::UserID, NewPlot2dId, NewOCCViewId, NewVTKViewId, + PreferencesId, MRUId, UserID }; +public: + LightApp_Application(); + virtual ~LightApp_Application(); + + virtual QString applicationName() const; + virtual QString applicationVersion() const; + + virtual CAM_Module* loadModule( const QString& ); + virtual bool activateModule( const QString& ); + + virtual bool useStudy( const QString& ); + + LightApp_SelectionMgr* selectionMgr() const; + + LogWindow* logWindow(); + OB_Browser* objectBrowser(); + PythonConsole* pythonConsole(); + + virtual void updateObjectBrowser( const bool = true ); + + LightApp_Preferences* preferences() const; + + virtual QString getFileFilter() const; + + virtual QString getFileName( bool open, const QString& initial, const QString& filters, + const QString& caption, QWidget* parent ); + virtual QString getDirectory( const QString& initial, const QString& caption, QWidget* parent ); + virtual QStringList getOpenFileNames( const QString& initial, const QString& filters, + const QString& caption, QWidget* parent ); + + void updateActions(); + + SUIT_ViewManager* getViewManager( const QString&, const bool ); + QWidget* getWindow( const int, const int = -1 ); + QWidget* window( const int, const int = -1 ) const; + void addWindow( QWidget*, const int, const int = -1 ); + void removeWindow( const int, const int = -1 ); + + bool isWindowVisible( const int ) const; + void setWindowShown( const int, const bool ); + + virtual void start(); + + virtual void contextMenuPopup( const QString&, QPopupMenu*, QString& ); + + virtual void createEmptyStudy(); + + SUIT_Accel* accel() const; + +signals: + void studyOpened(); + void studySaved(); + void studyClosed(); + +public slots: + virtual void onHelpContentsModule(); + virtual void onNewDoc(); + virtual void onOpenDoc(); + virtual void onHelpAbout(); + virtual bool onOpenDoc( const QString& ); + virtual bool onLoadDoc( const QString& ); + +protected: + virtual void createActions(); + virtual SUIT_Study* createNewStudy(); + virtual QWidget* createWindow( const int ); + virtual void defaultWindows( QMap& ) const; + void defaultViewManagers( QStringList& ) const; + + virtual void setActiveStudy( SUIT_Study* ); + virtual void updateCommandsStatus(); + virtual void onSelectionChanged(); + + virtual void beforeCloseDoc( SUIT_Study* ); + virtual void afterCloseDoc(); + virtual void moduleAdded( CAM_Module* ); + virtual bool activateModule( CAM_Module* = 0 ); + + LightApp_Preferences* preferences( const bool ) const; + virtual void createPreferences( LightApp_Preferences* ); + virtual void preferencesChanged( const QString&, const QString& ); + virtual void updateDesktopTitle(); + +protected slots: + virtual void onDesktopActivated(); + + void onNewWindow(); + void onModuleActivation( QAction* ); + void onCloseView( SUIT_ViewManager* ); + + void onStudyCreated( SUIT_Study* ); + void onStudyOpened( SUIT_Study* ); + void onStudySaved( SUIT_Study* ); + void onStudyClosed( SUIT_Study* ); + +private slots: + void onSelection(); + void onRefresh(); + void onPreferences(); + void onMRUActivated( QString ); + void onPreferenceChanged( QString&, QString&, QString& ); + +protected: + void updateWindows(); + void updateViewManagers(); + void updateModuleActions(); + + void loadWindowsGeometry(); + void saveWindowsGeometry(); + + void updatePreference( const QString&, const QString&, const QString& ); + + QString defaultModule() const; + void currentWindows( QMap& ) const; + void currentViewManagers( QStringList& ) const; + virtual SUIT_ViewManager* createViewManager( const QString& vmType ); + void moduleIconNames( QMap& ) const; + + void activateWindows(); + +protected: + typedef QMap ActionMap; + typedef QMap WindowMap; + +protected: + LightApp_Preferences* myPrefs; + LightApp_SelectionMgr* mySelMgr; + ActionMap myActions; + WindowMap myWindows; + + SUIT_Accel* myAccel; + + static LightApp_Preferences* _prefs_; +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/LightApp/LightApp_DataModel.cxx b/src/LightApp/LightApp_DataModel.cxx new file mode 100644 index 000000000..6ccba618b --- /dev/null +++ b/src/LightApp/LightApp_DataModel.cxx @@ -0,0 +1,122 @@ +// File: LightApp_DataModel.cxx +// Created: 10/25/2004 10:36:06 AM +// Author: Sergey LITONIN +// Copyright (C) CEA 2004 + +#include "LightApp_DataModel.h" +#include "LightApp_Study.h" +#include "LightApp_RootObject.h" +#include "LightApp_Module.h" +#include "LightApp_Application.h" + +#include + +#include +#include +#include +#include + +//======================================================================= +// name : LightApp_DataModel::LightApp_DataModel +/*!Purpose : Constructor*/ +//======================================================================= +LightApp_DataModel::LightApp_DataModel( CAM_Module* theModule ) +: CAM_DataModel( theModule ) +{ +} + +//======================================================================= +// name : LightApp_DataModel::~LightApp_DataModel +/*! Purpose : Destructor*/ +//======================================================================= +LightApp_DataModel::~LightApp_DataModel() +{ +} + +//================================================================ +// Function : open +/*! Purpose : Emit opened()*/ +//================================================================ +bool LightApp_DataModel::open( const QString&, CAM_Study* study, QStringList ) +{ + emit opened(); //TODO: is it really needed? to be removed maybe... + return true; +} + +//================================================================ +// Function : save +/*! Purpose : Emit saved()*/ +//================================================================ +bool LightApp_DataModel::save( QStringList& ) +{ + emit saved(); + return true; +} + +//================================================================ +// Function : saveAs +/*! Purpose : Emit saved()*/ +//================================================================ +bool LightApp_DataModel::saveAs( const QString&, CAM_Study*, QStringList& ) +{ + emit saved(); + return true; +} + +//================================================================ +// Function : close +/*! Purpose : Emit closed()*/ +//================================================================ +bool LightApp_DataModel::close() +{ + emit closed(); + return true; +} + +//================================================================ +// Function : update +/*! Purpose : Update application (empty virtual function).*/ +//================================================================ +void LightApp_DataModel::update( LightApp_DataObject*, LightApp_Study* study ) +{ +} + +//================================================================ +// Function : getModule +/*! Purpose : gets module*/ +//================================================================ + +LightApp_Module* LightApp_DataModel::getModule() const +{ + return dynamic_cast( module() ); +} + +//================================================================ +// Function : getStudy +/*! Purpose : gets study */ +//================================================================ +LightApp_Study* LightApp_DataModel::getStudy() const +{ + LightApp_RootObject* aRoot = dynamic_cast( root()->root() ); + if ( !aRoot ) + return 0; + return aRoot->study(); +} + +//================================================================ +// Function : isModified +/*! Purpose : default implementation, always returns false so as not to mask study's isModified()*/ +//================================================================ +bool LightApp_DataModel::isModified() const +{ + return false; +} + +//================================================================ +// Function : isSaved +/*! Purpose : default implementation, always returns true so as not to mask study's isSaved()*/ +//================================================================ +bool LightApp_DataModel::isSaved() const +{ + return true; +} diff --git a/src/LightApp/LightApp_DataModel.h b/src/LightApp/LightApp_DataModel.h new file mode 100644 index 000000000..7b1f92d6c --- /dev/null +++ b/src/LightApp/LightApp_DataModel.h @@ -0,0 +1,53 @@ +// File: LightApp_DataModel.h +// Created: 10/25/2004 10:32:33 AM +// Author: Sergey LITONIN +// Copyright (C) CEA 2004 + +#ifndef LIGHTAPP_DATAMODEL_H +#define LIGHTAPP_DATAMODEL_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "LightApp.h" +#include "CAM_DataModel.h" + +class LightApp_Module; +class LightApp_Study; +class LightApp_DataObject; + +/*! + Description : Base class of data model +*/ +class LIGHTAPP_EXPORT LightApp_DataModel : public CAM_DataModel +{ + Q_OBJECT + +public: + LightApp_DataModel ( CAM_Module* theModule ); + virtual ~LightApp_DataModel(); + + virtual bool open( const QString&, CAM_Study*, QStringList ); + virtual bool save( QStringList& ); + virtual bool saveAs( const QString&, CAM_Study*, QStringList& ); + virtual bool close(); + + virtual void update( LightApp_DataObject* = 0, LightApp_Study* = 0 ); + + virtual bool isModified() const; + virtual bool isSaved() const; + + LightApp_Module* getModule() const; + +signals: + void opened(); + void saved(); + void closed(); + +protected: + LightApp_Study* getStudy() const; + +}; + +#endif diff --git a/src/LightApp/LightApp_DataObject.cxx b/src/LightApp/LightApp_DataObject.cxx new file mode 100644 index 000000000..9320c256d --- /dev/null +++ b/src/LightApp/LightApp_DataObject.cxx @@ -0,0 +1,163 @@ +#include "LightApp_DataObject.h" + +#include "LightApp_Study.h" +#include "LightApp_RootObject.h" + +#include "CAM_DataModel.h" +#include "CAM_Module.h" + +#include +#include +#include + +#include + +/*! + Class: LightApp_DataObject::Key + Level: Internal +*/ +class LightApp_DataObject::Key : public SUIT_DataObjectKey +{ +public: + Key( const QString& ); + virtual ~Key(); + + virtual bool isLess( const SUIT_DataObjectKey* ) const; + virtual bool isEqual( const SUIT_DataObjectKey* ) const; + +private: + QString myEntry; +}; + +/*!Constructor. Initialize by \a entry.*/ +LightApp_DataObject::Key::Key( const QString& entry ) +: SUIT_DataObjectKey(), + myEntry( entry ) +{ +} + +/*!Destructor. Do nothing.*/ +LightApp_DataObject::Key::~Key() +{ +} + +/*!Checks: Is current key less than \a other.*/ +bool LightApp_DataObject::Key::isLess( const SUIT_DataObjectKey* other ) const +{ + Key* that = (Key*)other; + return myEntry < that->myEntry; +} + +/*!Checks: Is current key equal with \a other.*/ +bool LightApp_DataObject::Key::isEqual( const SUIT_DataObjectKey* other ) const +{ + Key* that = (Key*)other; + return myEntry == that->myEntry; +} + +/* + Class: LightApp_DataObject + Level: Public +*/ +/*!Constructor. Initialize by \a parent*/ +LightApp_DataObject::LightApp_DataObject( SUIT_DataObject* parent ) +: CAM_DataObject( parent ) +{ +} + +/*!Destructor. Do nothing.*/ +LightApp_DataObject::~LightApp_DataObject() +{ +} + +/*!Gets object ID. + *\retval QString + */ +QString LightApp_DataObject::entry() const +{ + return QString::null; +} + +/*!Create and return new key object.*/ +SUIT_DataObjectKey* LightApp_DataObject::key() const +{ + QString str = entry(); + return new Key( str ); +} + +/*!Gets component object. + *\retval SUIT_DataObject. + */ +SUIT_DataObject* LightApp_DataObject::componentObject() const +{ + SUIT_DataObject* compObj = 0; // for root object + + if ( parent() && parent() == root() ) + compObj = (SUIT_DataObject*)this; // for component-level objects + else + { + compObj = parent(); // for lower level objects + while ( compObj && compObj->parent() != root() ) + compObj = compObj->parent(); + } + return compObj; +} + +/*!Get component type.*/ +QString LightApp_DataObject::componentDataType() const +{ + SUIT_DataObject* aCompObj = componentObject(); + LightApp_ModuleObject* anObj = dynamic_cast( aCompObj ); + if ( anObj ) { + CAM_DataModel* aModel = anObj->dataModel(); + if ( aModel ) + return aModel->module()->name(); + } + return ""; +} + +/* + Class: LightApp_ModuleObject + Level: Public +*/ + +/*!Constructor.Initialize by \a parent.*/ +LightApp_ModuleObject::LightApp_ModuleObject( SUIT_DataObject* parent ) +: CAM_RootObject( parent ), + CAM_DataObject( parent ) +{ +} + +/*!Constructor.Initialize by \a module and parent.*/ +LightApp_ModuleObject::LightApp_ModuleObject( CAM_DataModel* dm, SUIT_DataObject* parent ) +: CAM_RootObject( dm, parent ), + CAM_DataObject( parent ) +{ +} + +/*!Destructor. Do nothing.*/ +LightApp_ModuleObject::~LightApp_ModuleObject() +{ +} + +/*!Returns module name */ +QString LightApp_ModuleObject::name() const +{ + return CAM_RootObject::name(); +} + +/*!Insert new child object to the children list at specified position + *\add component in Study for this module object if it necessary*/ +void LightApp_ModuleObject::insertChild( SUIT_DataObject* theObj, int thePosition ) +{ + CAM_RootObject::insertChild(theObj, thePosition); + + CAM_DataModel* aModel = dataModel(); + + LightApp_RootObject* aRoot = dynamic_cast(parent()); + + if (aRoot) + aRoot->study()->addComponent(aModel); + + +} diff --git a/src/LightApp/LightApp_DataObject.h b/src/LightApp/LightApp_DataObject.h new file mode 100644 index 000000000..e338a218f --- /dev/null +++ b/src/LightApp/LightApp_DataObject.h @@ -0,0 +1,51 @@ +#ifndef LIGHTAPP_DATAOBJECT_H +#define LIGHTAPP_DATAOBJECT_H + +#include "LightApp.h" + +#include "CAM_DataObject.h" +#include "CAM_DataModel.h" +#include "CAM_RootObject.h" + +class LightApp_Study; + +/*!Description : Data Object has empty entry so it's children must redefine metod entry() and return some unique string*/ +// to do : decomment virtual inheritance +class LIGHTAPP_EXPORT LightApp_DataObject : public virtual CAM_DataObject +{ + class Key; + +public: + enum { CT_Value, CT_Entry, CT_IOR, CT_RefEntry }; + +public: + LightApp_DataObject( SUIT_DataObject* = 0 ); + virtual ~LightApp_DataObject(); + + virtual SUIT_DataObjectKey* key() const; + virtual QString entry() const; + + virtual SUIT_DataObject* componentObject() const; + virtual QString componentDataType() const; + +}; + +/*! + * LightApp_ModuleObject - class for optimized access to DataModel from + * CAM_RootObject.h. + * In modules which will be redefine LightApp_DataObject, LightApp_ModuleObject must be children from rederined DataObject for having necessary properties and children from LightApp_ModuleObject. + */ + +class LIGHTAPP_EXPORT LightApp_ModuleObject : public CAM_RootObject +{ +public: + LightApp_ModuleObject( SUIT_DataObject* = 0 ); + LightApp_ModuleObject ( CAM_DataModel*, SUIT_DataObject* = 0 ); + + virtual ~LightApp_ModuleObject(); + + virtual QString name() const; + virtual void insertChild( SUIT_DataObject*, int thePosition ); +}; + +#endif diff --git a/src/LightApp/LightApp_DataOwner.cxx b/src/LightApp/LightApp_DataOwner.cxx new file mode 100644 index 000000000..647b5d328 --- /dev/null +++ b/src/LightApp/LightApp_DataOwner.cxx @@ -0,0 +1,56 @@ +#include "LightApp_DataOwner.h" + +#include "LightApp_DataObject.h" + +#ifdef WNT +#include +#endif + +#include + +/*!Constructor. Initialize by \a theEntry.*/ +LightApp_DataOwner +::LightApp_DataOwner( const QString& theEntry ): + myEntry( theEntry ) +{ +} + +/*!Constructor. Initialize by \a SALOME_InteractiveObject.*/ +LightApp_DataOwner +::LightApp_DataOwner( const Handle(SALOME_InteractiveObject)& theIO ): + myEntry(!theIO.IsNull()? theIO->getEntry(): ""), + myIO(theIO) +{ +} + +/*!Destructor. Do nothing.*/ +LightApp_DataOwner +::~LightApp_DataOwner() +{ +} + +/*!Checks: Is current data owner equal \a obj.*/ +bool +LightApp_DataOwner +::isEqual( const SUIT_DataOwner& obj ) const +{ + const LightApp_DataOwner* other = dynamic_cast( &obj ); + + return other && entry() == other->entry(); +} + +/*!Gets entry.*/ +QString +LightApp_DataOwner +::entry() const +{ + return myEntry; +} + +/*!Gets SALOME_InteractiveObject.*/ +const Handle(SALOME_InteractiveObject)& +LightApp_DataOwner +::IO() const +{ + return myIO; +} diff --git a/src/LightApp/LightApp_DataOwner.h b/src/LightApp/LightApp_DataOwner.h new file mode 100644 index 000000000..6ec43e08d --- /dev/null +++ b/src/LightApp/LightApp_DataOwner.h @@ -0,0 +1,30 @@ + +#ifndef LIGHTAPP_DATAOWNER_H +#define LIGHTAPP_DATAOWNER_H + +#include "LightApp.h" +#include "SUIT_DataOwner.h" +#include "SALOME_InteractiveObject.hxx" + +/*! + This class provide data owner objects. +*/ +class LIGHTAPP_EXPORT LightApp_DataOwner : public SUIT_DataOwner +{ +public: + LightApp_DataOwner( const Handle(SALOME_InteractiveObject)& theIO ); + LightApp_DataOwner( const QString& ); + virtual ~LightApp_DataOwner(); + + virtual bool isEqual( const SUIT_DataOwner& ) const; + const Handle(SALOME_InteractiveObject)& IO() const; + QString entry() const; + +private: + QString myEntry; + Handle(SALOME_InteractiveObject) myIO; +}; + +typedef SMART(LightApp_DataOwner) LightApp_DataOwnerPtr; + +#endif diff --git a/src/LightApp/LightApp_DataSubOwner.cxx b/src/LightApp/LightApp_DataSubOwner.cxx new file mode 100644 index 000000000..50c5ca3a3 --- /dev/null +++ b/src/LightApp/LightApp_DataSubOwner.cxx @@ -0,0 +1,33 @@ +#include "LightApp_DataSubOwner.h" + +#include "LightApp_DataObject.h" + +#ifdef WNT +#include +#endif + +/*!Constructor.Initialize by \a entry and \a index*/ +LightApp_DataSubOwner::LightApp_DataSubOwner( const QString& entry, const int index ) +: LightApp_DataOwner( entry ), +myIndex( index ) +{ +} + +/*!Destructor. Do nothing.*/ +LightApp_DataSubOwner::~LightApp_DataSubOwner() +{ +} + +/*!Checks: Is current data sub owner equal \a obj.*/ +bool LightApp_DataSubOwner::isEqual( const SUIT_DataOwner& obj ) const +{ + const LightApp_DataSubOwner* other = dynamic_cast( &obj ); + + return other && entry() == other->entry() && index() == other->index(); +} + +/*!Gets index.*/ +int LightApp_DataSubOwner::index() const +{ + return myIndex; +} diff --git a/src/LightApp/LightApp_DataSubOwner.h b/src/LightApp/LightApp_DataSubOwner.h new file mode 100644 index 000000000..5240409b6 --- /dev/null +++ b/src/LightApp/LightApp_DataSubOwner.h @@ -0,0 +1,24 @@ + +#ifndef LIGHTAPP_DATASUBOWNER_H +#define LIGHTAPP_DATASUBOWNER_H + +#include +#include + +/*! + Class provide sub owner. + */ +class LIGHTAPP_EXPORT LightApp_DataSubOwner : public LightApp_DataOwner +{ +public: + LightApp_DataSubOwner( const QString&, const int ); + virtual ~LightApp_DataSubOwner(); + + virtual bool isEqual( const SUIT_DataOwner& ) const; + int index() const; + +private: + int myIndex; +}; + +#endif diff --git a/src/LightApp/LightApp_Dialog.cxx b/src/LightApp/LightApp_Dialog.cxx new file mode 100644 index 000000000..a79b5da46 --- /dev/null +++ b/src/LightApp/LightApp_Dialog.cxx @@ -0,0 +1,860 @@ +// File: LightApp_Dialog.cxx +// Author: Alexander SOLOVYOV + +#include +#include + +#include +#include +#include + +/* + Class : LightApp_Dialog + Description : Base class for all dialogs +*/ + +//======================================================================= +// name : LightApp_Dialog +// Purpose : Constructor +//======================================================================= +LightApp_Dialog::LightApp_Dialog( QWidget* parent, const char* name, bool modal, + bool allowResize, const int f, WFlags wf ) +: QtxDialog( parent, name, modal, allowResize, f, wf ), + myIsExclusive( true ), + myIsBusy( false ) +{ + setObjectPixmap( "LightApp", tr( "ICON_SELECT" ) ); +} + +//======================================================================= +// name : ~LightApp_Dialog +// Purpose : Destructor +//======================================================================= +LightApp_Dialog::~LightApp_Dialog() +{ +} + +//======================================================================= +// name : show +// Purpose : +//======================================================================= +void LightApp_Dialog::show() +{ + QtxDialog::show(); +} + +//======================================================================= +// name : isExclusive +// Purpose : +//======================================================================= +bool LightApp_Dialog::isExclusive() const +{ + return myIsExclusive; +} + +//======================================================================= +// name : updateButtons +// Purpose : +//======================================================================= +void LightApp_Dialog::updateButtons( const int _id ) +{ + if( !myIsExclusive ) + return; + + int id = _id; + + ObjectMap::const_iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + { + QToolButton* but = (QToolButton*)anIt.data().myBtn; + if( but && but->isOn() ) + { + if( id==-1 ) + id = anIt.key(); + + if( anIt.key()!=id ) + but->setOn( false ); + } + } +} + +//======================================================================= +// name : setExclusive +// Purpose : +//======================================================================= +void LightApp_Dialog::setExclusive( const bool ex ) +{ + myIsExclusive = ex; + updateButtons(); +} + +//======================================================================= +// name : showObject +// Purpose : +//======================================================================= +void LightApp_Dialog::showObject( const int id ) +{ + setObjectShown( id, true ); +} + +//======================================================================= +// name : hideObject +// Purpose : +//======================================================================= +void LightApp_Dialog::hideObject( const int id ) +{ + setObjectShown( id, false ); +} + +//======================================================================= +// name : setObjectShown +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectShown( const int id, const bool shown ) +{ + if( myObjects.contains( id ) && isObjectShown( id )!=shown ) + { + Object& obj = myObjects[ id ]; + obj.myEdit->setShown( shown ); + obj.myBtn->setShown( shown ); + obj.myLabel->setShown( shown ); + if( !shown ) + ( ( QToolButton* )obj.myBtn )->setOn( false ); + } +} + +//======================================================================= +// name : isObjectShown +// Purpose : +//======================================================================= +bool LightApp_Dialog::isObjectShown( const int id ) const +{ + return myObjects.contains( id ) && myObjects[ id ].myEdit->isShown(); +} + +//======================================================================= +// name : setObjectEnabled +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectEnabled( const int id, const bool en ) +{ + if( myObjects.contains( id ) && isObjectEnabled( id )!=en ) + { + Object& obj = myObjects[ id ]; + obj.myEdit->setEnabled( en ); + obj.myBtn->setEnabled( en ); +// obj.myLabel->setEnabled( en ); + if( !en ) + ( ( QToolButton* )obj.myBtn )->setOn( false ); + } +} + +//======================================================================= +// name : isObjectEnabled +// Purpose : +//======================================================================= +bool LightApp_Dialog::isObjectEnabled( const int id ) const +{ + return myObjects.contains( id ) && myObjects[ id ].myEdit->isEnabled(); +} + +//======================================================================= +// name : selectObject +// Purpose : +//======================================================================= +void LightApp_Dialog::selectObject( const QString& name, const int type, const QString& id, const bool update ) +{ + QStringList names; names.append( name ); + TypesList types; types.append( type ); + QStringList ids; ids.append( id ); + selectObject( names, types, ids, update ); +} + +//======================================================================= +// name : selectObject +// Purpose : +//======================================================================= +void LightApp_Dialog::selectObject( const QStringList& _names, + const TypesList& _types, + const QStringList& _ids, + const bool update ) +{ + ObjectMap::iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + if( anIt.data().myBtn->isOn() ) + selectObject( anIt.key(), _names, _types, _ids, update ); +} + +//======================================================================= +// name : hasSelection +// Purpose : +//======================================================================= +bool LightApp_Dialog::hasSelection( const int id ) const +{ + return myObjects.contains( id ) && !myObjects[ id ].myIds.isEmpty(); +} + +//======================================================================= +// name : clearSelection +// Purpose : +//======================================================================= +void LightApp_Dialog::clearSelection( const int id ) +{ + if( id==-1 ) + { + ObjectMap::const_iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + clearSelection( anIt.key() ); + } + + else if( myObjects.contains( id ) ) + { + myObjects[ id ].myIds.clear(); + myObjects[ id ].myTypes.clear(); + myObjects[ id ].myNames.clear(); + + myObjects[ id ].myEdit->setText( QString::null ); + emit selectionChanged( id ); + } +} + +//======================================================================= +// name : objectWg +// Purpose : +//======================================================================= +QWidget* LightApp_Dialog::objectWg( const int theId, const int theWgId ) const +{ + QWidget* aResWg = 0; + if( myObjects.contains( theId ) ) + { + if ( theWgId == Label ) + aResWg = myObjects[ theId ].myLabel; + else if ( theWgId == Btn ) + aResWg = myObjects[ theId ].myBtn; + else if ( theWgId == Control ) + aResWg = myObjects[ theId ].myEdit; + } + return aResWg; +} + +//======================================================================= +// name : objectText +// Purpose : +//======================================================================= +QString LightApp_Dialog::objectText( const int theId ) const +{ + return myObjects.contains( theId ) ? myObjects[ theId ].myEdit->text() : ""; +} + +//======================================================================= +// name : setObjectText +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectText( const int theId, const QString& theText ) +{ + if ( myObjects.contains( theId ) ) + myObjects[ theId ].myEdit->setText( theText ); +} + +//======================================================================= +// name : selectedObject +// Purpose : +//======================================================================= +void LightApp_Dialog::selectedObject( const int id, QStringList& list ) const +{ + if( myObjects.contains( id ) ) + list = myObjects[ id ].myIds; +} + +//======================================================================= +// name : selectedObject +// Purpose : +//======================================================================= +QString LightApp_Dialog::selectedObject( const int id ) const +{ + if ( myObjects.contains( id ) && myObjects[ id ].myIds.count() > 0 ) + return myObjects[ id ].myIds.first(); + else + return ""; +} + +//======================================================================= +// name : objectSelection +// Purpose : +//======================================================================= +void LightApp_Dialog::objectSelection( SelectedObjects& objs ) const +{ + //objs.clear(); + ObjectMap::const_iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + { + QStringList ids; + selectedObject( anIt.key(), ids ); + if( !ids.isEmpty() ) + objs.insert( anIt.key(), ids ); + } +} + +//======================================================================= +// name : createObject +// Purpose : +//======================================================================= +int LightApp_Dialog::createObject( const QString& label, QWidget* parent, const int id ) +{ + int nid = id; + if( nid<0 ) + for( nid=0; myObjects.contains( nid ); nid++ ); + + if( !myObjects.contains( nid ) ) + { + QLabel* lab = new QLabel( label, parent ); + myObjects[ nid ].myLabel = lab; + + QToolButton* but = new QToolButton( parent ); + but->setIconSet( QIconSet( myPixmap ) ); + but->setToggleButton( true ); + but->setMaximumWidth( but->height() ); + but->setMinimumWidth( but->height() ); + connect( but, SIGNAL( toggled( bool ) ), this, SLOT( onToggled( bool ) ) ); + myObjects[ nid ].myBtn = but; + + QLineEdit* ne = new QLineEdit( parent ); + ne->setReadOnly( true ); + ne->setMinimumWidth( 150 ); + connect( ne, SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) ); + myObjects[ nid ].myEdit = ne; + + myObjects[ nid ].myNI = OneNameOrCount; + } + return nid; +} + +//======================================================================= +// name : renameObject +// Purpose : +//======================================================================= +void LightApp_Dialog::renameObject( const int id, const QString& label ) +{ + if( myObjects.contains( id ) ) + myObjects[ id ].myLabel->setText( label ); +} + +//======================================================================= +// name : setObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectType( const int id, const int type1, ... ) +{ + TypesList types; + + const int* tt = &type1; + while( *tt>=0 ) + { + types.append( *tt ); + tt++; + } + + setObjectType( id, types ); +} + +//======================================================================= +// name : setObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectType( const int id, const TypesList& list ) +{ + if( !myObjects.contains( id ) ) + return; + + TypesList& internal = myObjects[ id ].myPossibleTypes; + + QMap types; + TypesList::const_iterator anIt = list.begin(), + aLast = list.end(); + for( ; anIt!=aLast; anIt++ ) + types.insert( *anIt, 0 ); + + + internal.clear(); + QMap::const_iterator aMIt = types.begin(), + aMLast = types.end(); + for( ; aMIt!=aMLast; aMIt++ ) + internal.append( aMIt.key() ); + + updateObject( id ); +} + +//======================================================================= +// name : addObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::addObjectType( const int id, const int type1, const int, ... ) +{ + TypesList types; objectTypes( id, types ); + + const int* tt = &type1; + while( *tt>=0 ) + { + types.append( *tt ); + tt++; + } + + setObjectType( id, types ); +} + +//======================================================================= +// name : addObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::addObjectType( const int id, const TypesList& list ) +{ + TypesList types = list; objectTypes( id, types ); + setObjectType( id, types ); +} + +//======================================================================= +// name : addObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::addObjectType( const int id, const int type ) +{ + TypesList types; objectTypes( id, types ); + types.append( type ); + setObjectType( id, types ); +} + +//======================================================================= +// name : removeObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::removeObjectType( const int id ) +{ + TypesList types; + setObjectType( id, types ); +} + +//======================================================================= +// name : removeObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::removeObjectType( const int id, const TypesList& list ) +{ + if( !myObjects.contains( id ) ) + return; + + TypesList& internal = myObjects[ id ].myPossibleTypes; + + QMap types; + TypesList::const_iterator anIt = internal.begin(), + aLast = internal.end(); + for( ; anIt!=aLast; anIt++ ) + types.insert( *anIt, 0 ); + anIt = list.begin(); aLast = list.end(); + for( ; anIt!=aLast; anIt++ ) + types.remove( *anIt ); + + + internal.clear(); + QMap::const_iterator aMIt = types.begin(), + aMLast = types.end(); + for( ; aMIt!=aMLast; aMIt++ ) + internal.append( aMIt.key() ); + + updateObject( id ); +} + +//======================================================================= +// name : removeObjectType +// Purpose : +//======================================================================= +void LightApp_Dialog::removeObjectType( const int id, const int type ) +{ + TypesList list; list.append( type ); + removeObjectType( id, list ); +} + +//======================================================================= +// name : hasObjectType +// Purpose : +//======================================================================= +bool LightApp_Dialog::hasObjectType( const int id, const int type ) const +{ + if( myObjects.contains( id ) ) + return myObjects[ id ].myPossibleTypes.contains( type ); + else + return false; +} + +//======================================================================= +// name : objectTypes +// Purpose : +//======================================================================= +void LightApp_Dialog::objectTypes( const int id, TypesList& list ) const +{ + if( myObjects.contains( id ) ) + { + TypesList::const_iterator anIt = myObjects[ id ].myPossibleTypes.begin(), + aLast = myObjects[ id ].myPossibleTypes.end(); + for( ; anIt!=aLast; anIt++ ) + list.append( *anIt ); + } +} + +//======================================================================= +// name : onToggled +// Purpose : +//======================================================================= +void LightApp_Dialog::onToggled( bool on ) +{ + QButton* but = ( QButton* )sender(); + int id = -1; + + if( !but ) + return; + + ObjectMap::const_iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast && id==-1; anIt++ ) + if( anIt.data().myBtn==but ) + id = anIt.key(); + + if( id!=-1 ) + if( on ) + { + updateButtons( id ); + emit objectActivated( id ); + } + else + emit objectDeactivated( id ); +} + +//======================================================================= +// name : updateObject +// Purpose : +//======================================================================= +void LightApp_Dialog::updateObject( const int id, bool emit_signal ) +{ + if( hasSelection( id ) ) + { + Object& obj = myObjects[ id ]; + filterTypes( id, obj.myNames, obj.myTypes, obj.myIds ); + obj.myEdit->setText( selectionDescription( obj.myNames, obj.myTypes, obj.myNI ) ); + if( emit_signal ) + emit selectionChanged( id ); + } +} + +//======================================================================= +// name : filterTypes +// Purpose : +//======================================================================= +void LightApp_Dialog::filterTypes( const int id, QStringList& names, TypesList& types, QStringList& ids ) const +{ + if( !myObjects.contains( id ) ) + return; + + const Object& obj = myObjects[ id ]; + if( obj.myPossibleTypes.isEmpty() ) + return; + + QStringList new_names, new_ids; + TypesList new_types; + + TypesList::const_iterator anIt1 = types.begin(), + aLast = types.end(); + QStringList::const_iterator anIt2 = names.begin(), + anIt3 = ids.begin(); + for( ; anIt1!=aLast; anIt1++, anIt2++, anIt3++ ) + if( obj.myPossibleTypes.contains( *anIt1 ) ) + { + if( new_types.count()==1 && !multipleSelection( id ) ) + break; + + new_names.append( *anIt2 ); + new_types.append( *anIt1 ); + new_ids.append( *anIt3 ); + } + names = new_names; + types = new_types; + ids = new_ids; +} + +//======================================================================= +// name : resMgr +// Purpose : +//======================================================================= +SUIT_ResourceMgr* LightApp_Dialog::resMgr() const +{ + return SUIT_Session::session()->resourceMgr(); +} + +//======================================================================= +// name : setObjectPixmap +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectPixmap( const QPixmap& p ) +{ + myPixmap = p; + ObjectMap::const_iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + ( ( QToolButton* )anIt.data().myBtn )->setIconSet( p ); +} + +//======================================================================= +// name : setObjectPixmap +// Purpose : +//======================================================================= +void LightApp_Dialog::setObjectPixmap( const QString& section, const QString& file ) +{ + SUIT_ResourceMgr* mgr = resMgr(); + if( mgr ) + setObjectPixmap( mgr->loadPixmap( section, file ) ); +} + +//======================================================================= +// name : multipleSelection +// Purpose : +//======================================================================= +bool LightApp_Dialog::multipleSelection( const int id ) const +{ + return nameIndication( id )!=OneName; +} + +//======================================================================= +// name : nameIndication +// Purpose : +//======================================================================= +LightApp_Dialog::NameIndication LightApp_Dialog::nameIndication( const int id ) const +{ + if( myObjects.contains( id ) ) + return myObjects[ id ].myNI; + else + return OneNameOrCount; +} + +//======================================================================= +// name : setNameIndication +// Purpose : +//======================================================================= +void LightApp_Dialog::setNameIndication( const int id, const NameIndication ni ) +{ + if( id==-1 ) + { + ObjectMap::iterator anIt = myObjects.begin(), + aNext, + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + { + anIt.data().myNI = ni; + setReadOnly( anIt.key(), isReadOnly( anIt.key() ) ); + aNext = anIt; aNext++; + updateObject( anIt.key(), aNext==aLast ); + } + } + else if( myObjects.contains( id ) ) + { + myObjects[ id ].myNI = ni; + setReadOnly( id, isReadOnly( id ) ); + updateObject( id, true ); + } +} + +//======================================================================= +// name : selectionDescription +// Purpose : +//======================================================================= +QString LightApp_Dialog::selectionDescription( const QStringList& names, const TypesList& types, const NameIndication ni ) const +{ + if( names.count()!=types.count() ) + return "LightApp_Dialog::selectionDescription(): Error!!!"; + + if( names.isEmpty() ) + return QString::null; + + switch( ni ) + { + case OneName: + return names.first(); + break; + + case OneNameOrCount: + if( names.count()==1 ) + return names.first(); + else + return countOfTypes( types ); + break; + + case ListOfNames: + return names.join( " " ); + break; + + case Count: + return countOfTypes( types ); + break; + }; + return QString::null; +} + +//======================================================================= +// name : countOfTypes +// Purpose : +//======================================================================= +QString LightApp_Dialog::countOfTypes( const TypesList& types ) const +{ + QMap typesCount; + QStringList typeCount; + + TypesList::const_iterator anIt = types.begin(), + aLast = types.end(); + for( ; anIt!=aLast; anIt++ ) + if( typesCount.contains( *anIt ) ) + typesCount[ *anIt ]++; + else + typesCount[ *anIt ] = 1; + + QMap::const_iterator aMIt = typesCount.begin(), + aMLast = typesCount.end(); + for( ; aMIt!=aMLast; aMIt++ ) + typeCount.append( QString( "%1 %2" ).arg( aMIt.data() ).arg( typeName( aMIt.key() ) ) ); + + return typeCount.join( ", " ); +} + +//======================================================================= +// name : typeName +// Purpose : +//======================================================================= +QString& LightApp_Dialog::typeName( const int type ) +{ + return myTypeNames[ type ]; +} + +//======================================================================= +// name : typeName +// Purpose : +//======================================================================= +const QString& LightApp_Dialog::typeName( const int type ) const +{ + return myTypeNames[ type ]; +} + + +//======================================================================= +// name : activateObject +// Purpose : +//======================================================================= +void LightApp_Dialog::activateObject( const int theId ) +{ + if ( myObjects.contains( theId ) && !myObjects[ theId ].myBtn->isOn() ) + myObjects[ theId ].myBtn->toggle(); +} + +//======================================================================= +// name : deactivateAll +// Purpose : +//======================================================================= +void LightApp_Dialog::deactivateAll() +{ + ObjectMap::iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + { + QToolButton* btn = ( QToolButton* )anIt.data().myBtn; + btn->setOn( false ); + } +} + +//======================================================================= +// name : selectObject +// Purpose : +//======================================================================= +void LightApp_Dialog::selectObject( const int id, const QString& name, const int type, const QString& selid, const bool update ) +{ + QStringList names; names.append( name ); + TypesList types; types.append( type ); + QStringList ids; ids.append( selid ); + selectObject( id, names, types, ids, update ); +} + +//======================================================================= +// name : selectObject +// Purpose : +//======================================================================= +void LightApp_Dialog::selectObject( const int id, const QStringList& _names, const TypesList& _types, + const QStringList& _ids, const bool update ) +{ + if( !myObjects.contains( id ) ) + return; + + QStringList names = _names, ids = _ids; + TypesList types = _types; + + filterTypes( id, names, types, ids ); + + Object& obj = myObjects[ id ]; + if( update ) + obj.myEdit->setText( selectionDescription( names, types, obj.myNI ) ); + obj.myTypes = types; + obj.myIds = ids; + obj.myNames = names; + + emit selectionChanged( id ); +} + +//======================================================================= +// name : setReadOnly +// Purpose : +//======================================================================= +void LightApp_Dialog::setReadOnly( const int id, const bool ro ) +{ + if( myObjects.contains( id ) ) + myObjects[ id ].myEdit->setReadOnly( nameIndication( id )==ListOfNames || nameIndication( id )==OneName ? ro : true ); +} + +//======================================================================= +// name : isReadOnly +// Purpose : +//======================================================================= +bool LightApp_Dialog::isReadOnly( const int id ) const +{ + if( myObjects.contains( id ) ) + return myObjects[ id ].myEdit->isReadOnly(); + else + return true; +} + +//======================================================================= +// name : onTextChanged +// Purpose : +//======================================================================= +void LightApp_Dialog::onTextChanged( const QString& text ) +{ + if( myIsBusy ) + return; + + myIsBusy = true; + + if( sender() && sender()->inherits( "QLineEdit" ) ) + { + QLineEdit* edit = ( QLineEdit* )sender(); + int id = -1; + ObjectMap::const_iterator anIt = myObjects.begin(), + aLast = myObjects.end(); + for( ; anIt!=aLast; anIt++ ) + if( anIt.data().myEdit == edit ) + id = anIt.key(); + + if( id>=0 && !isReadOnly( id ) ) + { + QStringList list = QStringList::split( " ", text ); + emit objectChanged( id, list ); + } + } + + myIsBusy = false; +} diff --git a/src/LightApp/LightApp_Dialog.h b/src/LightApp/LightApp_Dialog.h new file mode 100644 index 000000000..b13a0f835 --- /dev/null +++ b/src/LightApp/LightApp_Dialog.h @@ -0,0 +1,267 @@ +// File: LightApp_Dialog.h +// Author: Alexander SOLOVYOV + +#ifndef LIGHTAPP_DIALOG_H +#define LIGHTAPP_DIALOG_H + +#include "LightApp.h" +#include + +#include +#include +#include + +class QLineEdit; +class QButton; +class QLabel; + +class SUIT_ResourceMgr; + +/* + Class : LightApp_Dialog + Description : Base class for all LightApp dialogs +*/ +class LIGHTAPP_EXPORT LightApp_Dialog : public QtxDialog +{ + Q_OBJECT + +public: + typedef QValueList TypesList; + typedef QMap SelectedObjects; + + enum ObjectWg + { + Label = 0x00000001, + Btn = 0x00000002, + Control = 0x00000004 + }; + + typedef enum + { + OneName, // " is shown + ListOfNames, //! list of all names is shown + Count //! In every case " " is shown + + } NameIndication; + //! The enumeration describing how names of selected objects will be shown in line edit + //! For more details see above + +public: + LightApp_Dialog( QWidget* = 0, const char* = 0, bool = false, + bool = false, const int = Standard, WFlags = 0 ); + virtual ~LightApp_Dialog(); + + virtual void show(); + + //! Check if buttons is exclusive (as radiobuttons) + bool isExclusive() const; + + //! Set exclusive state + void setExclusive( const bool ); + + //! Check if operation according to dialog will be resumed automatically when mouse enter the dialog + bool isAutoResumed() const; + + //! Set auto resumed state + void setAutoResumed( const bool ); + + //! Show widgets corresponding to id + void showObject( const int ); + + //! Hide widgets corresponding to id + void hideObject( const int ); + + //! Change the shown state of widgets corresponding to id + void setObjectShown( const int, const bool ); + + //! Check the shown state + bool isObjectShown( const int ) const; + + //! Change the enabled state of widgets corresponding to id + void setObjectEnabled( const int, const bool ); + + //! Check the enabled state + bool isObjectEnabled( const int ) const; + + //! Get widget of object (see ObjectWg enumeration) + QWidget* objectWg( const int theId, const int theWgId ) const; + + //! Pass to all active widgets name, type and id of selected object + void selectObject( const QString&, const int, const QString&, const bool = true ); + + /*! + Pass to all active widgets list of names, types and ids of selected objects + Every active widget filters list and accept only objects with possible types + */ + void selectObject( const QStringList&, const TypesList&, const QStringList&, const bool = true ); + + //! Get text of object's control + QString objectText( const int ) const; + + //! Set text of object's control + void setObjectText( const int, const QString& ); + + //! Select in certain widget avoiding check if there is active widget + void selectObject( const int, const QString&, const int, const QString&, const bool = true ); + void selectObject( const int, const QStringList&, const TypesList&, const QStringList&, const bool = true ); + + //! Check if certain widget has selection + bool hasSelection( const int ) const; + + //! Clear selection in widgets. If parameter is -1, then selection in all widgets will be cleared + void clearSelection( const int = -1 ); + + //! Get ids list of object selected in certain widget + void selectedObject( const int, QStringList& ) const; + + //! Get ids list of object selected in certain widget + QString selectedObject( const int ) const; + + //! Get map "widget id -> ids list" + void objectSelection( SelectedObjects& ) const; + + //! Activate object selection button + void activateObject( const int ); + + //! Set all object selection buttons to inactive state + void deactivateAll(); + +signals: + //! selection in certain widget is changed + void selectionChanged ( int ); + + //! selection in certain widget is on + void objectActivated ( int ); + + //! selection in certain widget is off + void objectDeactivated( int ); + + /* + text representation of selection is changed + it is emitted only if "read only" state of line edit is false + */ + void objectChanged( int, const QStringList& ); + +protected: + //! Finds and returns resource manager + SUIT_ResourceMgr* resMgr() const; + + /*! Create label, button and line edit for object selection + * If passed id is negative, then id will be calculated automatically (first free id) + * Returns the same id (if id>=0) or calculated + */ + int createObject ( const QString&, QWidget*, const int = -1 ); + + //! Set pixmap as icon for all selection buttons + void setObjectPixmap ( const QPixmap& ); + + //! Load pixmap with section, name using resource manager and set as icon for all selection buttons + void setObjectPixmap ( const QString&, const QString& ); + + //! Change label + void renameObject ( const int, const QString& ); + + //! Set possible types for certain id. The list of arguments must be finished by negative integer + void setObjectType ( const int, const int, ... ); + + //! Set list as possible types for object selection + void setObjectType ( const int, const TypesList& ); + + /*! + Add types to list of possible types + The list of arguments must be finished by negative integer + */ + void addObjectType ( const int, const int, const int, ... ); + + //! Add types to list of possible types + void addObjectType ( const int, const TypesList& ); + + //! Add type to list of possible types + void addObjectType ( const int, const int ); + + //! Clear list of possible types (it means, that all types are welcome) + void removeObjectType( const int ); + + //! Remove types in list from list of possible types + void removeObjectType( const int, const TypesList& ); + + //! Remove a type from list of possible types + void removeObjectType( const int, const int ); + + //! Check if list of possible types contains this one + bool hasObjectType ( const int, const int ) const; + + //! Return list of possible types + void objectTypes ( const int, TypesList& ) const; + + //!Change and get type name for indicating in selection widget + QString& typeName( const int ); + const QString& typeName( const int ) const; + + //! Create string contains selection list by list of names, list of types and current name indication state + virtual QString selectionDescription( const QStringList&, const TypesList&, const NameIndication ) const; + + //! Create string by pattern " " for current list of types + virtual QString countOfTypes( const TypesList& ) const; + + //! Get and set name indication for certain widget + NameIndication nameIndication( const int ) const; + void setNameIndication( const int, const NameIndication ); + + //! Check using name indication if multiple selection in possible + bool multipleSelection( const int ) const; + + //! Set the "read only" state of object selection line edit + //! The "read only" will be false only if name indication is ListOfNames + void setReadOnly( const int, const bool ); + + //! Check the "read only" state of object selection line edit + bool isReadOnly( const int ) const; + +private slots: + //! emits if the object selection button changes state + void onToggled( bool ); + + //! text in some line edit is changed + void onTextChanged( const QString& ); + +private: + /*! + If buttons are exclusive, set to "off" all buttons except one with id + If id=-1, then all buttons, except first with "on" state, will be set to "off" + */ + void updateButtons( const int = -1 ); + + /*! + Filter types and update selection string in line edit + If bool is true, then signal is emitted + */ + void updateObject( const int, bool = true ); + + //! Remove from list not possible types and remove from names and ids lists the corresponding items + void filterTypes( const int, QStringList&, TypesList&, QStringList& ) const; + +private: + typedef struct + { + QLineEdit* myEdit; + QButton* myBtn; + QLabel* myLabel; + QStringList myNames, myIds; + TypesList myTypes, myPossibleTypes; + NameIndication myNI; + + } Object; + + typedef QMap ObjectMap; + +private: + ObjectMap myObjects; + QMap myTypeNames; + bool myIsExclusive, myIsBusy; + QPixmap myPixmap; +}; + +#endif diff --git a/src/LightApp/LightApp_Displayer.cxx b/src/LightApp/LightApp_Displayer.cxx new file mode 100644 index 000000000..f2952de04 --- /dev/null +++ b/src/LightApp/LightApp_Displayer.cxx @@ -0,0 +1,145 @@ + +#include "LightApp_Displayer.h" +#include "LightApp_Application.h" + +#include + +#include +#include +#include +#include +#include + +#include + +LightApp_Displayer::LightApp_Displayer() +{ +} + +LightApp_Displayer::~LightApp_Displayer() +{ +} + +void LightApp_Displayer::Display( const QString& entry, const bool updateViewer, SALOME_View* theViewFrame ) +{ + SALOME_View* vf = theViewFrame ? theViewFrame : GetActiveView(); + if ( vf ) + { + SALOME_Prs* prs = buildPresentation( entry, vf ); + + if ( prs ) + { + vf->BeforeDisplay( this ); + vf->Display( prs ); + vf->AfterDisplay( this ); + + if ( updateViewer ) + vf->Repaint(); + + delete prs; // delete presentation because displayer is its owner + } + } +} + +void LightApp_Displayer::Redisplay( const QString& entry, const bool updateViewer ) +{ + // Remove the object permanently ( == true) + SUIT_Session* ses = SUIT_Session::session(); + SUIT_Application* app = ses->activeApplication(); + if ( app ) + { + SUIT_Desktop* desk = app->desktop(); + QPtrList wnds = desk->windows(); + SUIT_ViewWindow* wnd; + for ( wnd = wnds.first(); wnd; wnd = wnds.next() ) + { + SUIT_ViewManager* vman = wnd->getViewManager(); + if( !vman ) + continue; + + SUIT_ViewModel* vmodel = vman->getViewModel(); + if( !vmodel ) + continue; + + SALOME_View* view = dynamic_cast(vmodel); + if( view && ( IsDisplayed( entry, view ) || view == GetActiveView() ) ) + { + Erase( entry, true, false, view ); + Display( entry, updateViewer, view ); + } + } + } +} + +void LightApp_Displayer::Erase( const QString& entry, const bool forced, + const bool updateViewer, SALOME_View* theViewFrame ) +{ + SALOME_View* vf = theViewFrame ? theViewFrame : GetActiveView(); + + if ( vf ) { + SALOME_Prs* prs = vf->CreatePrs( entry.latin1() ); + if ( prs ) { + vf->Erase( prs, forced ); + if ( updateViewer ) + vf->Repaint(); + delete prs; // delete presentation because displayer is its owner + } + } +} + +void LightApp_Displayer::EraseAll( const bool forced, const bool updateViewer, SALOME_View* theViewFrame ) const +{ + SALOME_View* vf = theViewFrame ? theViewFrame : GetActiveView(); + + if ( vf ) { + vf->EraseAll( forced ); + if ( updateViewer ) + vf->Repaint(); + } +} + +bool LightApp_Displayer::IsDisplayed( const QString& entry, SALOME_View* theViewFrame ) const +{ + SALOME_View* vf = theViewFrame ? theViewFrame : GetActiveView(); + if( vf ) + { + Handle( SALOME_InteractiveObject ) temp = new SALOME_InteractiveObject(); + temp->setEntry( entry.latin1() ); + return vf->isVisible( temp ); + } + else + return false; +} + +void LightApp_Displayer::UpdateViewer() const +{ + SALOME_View* vf = GetActiveView(); + if ( vf ) + vf->Repaint(); +} + +SALOME_Prs* LightApp_Displayer::buildPresentation( const QString& entry, SALOME_View* theViewFrame ) +{ + SALOME_Prs* prs = 0; + + SALOME_View* vf = theViewFrame ? theViewFrame : GetActiveView(); + + if ( vf ) + prs = vf->CreatePrs( entry.latin1() ); + + return prs; +} + +SALOME_View* LightApp_Displayer::GetActiveView() +{ + SUIT_Session* session = SUIT_Session::session(); + if ( SUIT_Application* app = session->activeApplication() ) { + if ( LightApp_Application* sApp = dynamic_cast( app ) ) { + if( SUIT_ViewManager* vman = sApp->activeViewManager() ) { + if ( SUIT_ViewModel* vmod = vman->getViewModel() ) + return dynamic_cast( vmod ); + } + } + } + return 0; +} diff --git a/src/LightApp/LightApp_Displayer.h b/src/LightApp/LightApp_Displayer.h new file mode 100644 index 000000000..94ccd4f90 --- /dev/null +++ b/src/LightApp/LightApp_Displayer.h @@ -0,0 +1,28 @@ + +#ifndef LIGHTAPP_DISPLAYER_HEADER +#define LIGHTAPP_DISPLAYER_HEADER + +#include + +class QString; + +class LightApp_Displayer : public SALOME_Displayer +{ +public: + LightApp_Displayer(); + virtual ~LightApp_Displayer(); + + void Display( const QString&, const bool = true, SALOME_View* = 0 ); + void Redisplay( const QString&, const bool = true ); + void Erase( const QString&, const bool forced = false, const bool updateViewer = true, SALOME_View* = 0 ); + void EraseAll( const bool forced = false, const bool updateViewer = true, SALOME_View* = 0 ) const; + bool IsDisplayed( const QString&, SALOME_View* = 0 ) const; + void UpdateViewer() const; + + static SALOME_View* GetActiveView(); + +protected: + virtual SALOME_Prs* buildPresentation( const QString&, SALOME_View* = 0 ); +}; + +#endif diff --git a/src/LightApp/LightApp_Driver.cxx b/src/LightApp/LightApp_Driver.cxx new file mode 100644 index 000000000..a37f4f5d2 --- /dev/null +++ b/src/LightApp/LightApp_Driver.cxx @@ -0,0 +1,486 @@ +#include "LightApp_Driver.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +/*! Constructor.*/ +LightApp_Driver::LightApp_Driver() +{ +} + +/*! Destructor.*/ +LightApp_Driver::~LightApp_Driver() +{ +} + +using namespace std; + +//================================================================ +// Function : SaveDatasInFile +/*! Purpose : save in file 'theFileName' datas from this driver*/ +//================================================================ +bool LightApp_Driver::SaveDatasInFile( const char* theFileName, bool isMultiFile ) +{ + int aNbModules = 0; + std::map::const_iterator it; + for (it = myMap.begin(); it != myMap.end(); ++it) + aNbModules++; + + unsigned char** aBuffer = new unsigned char*[aNbModules]; + long* aBufferSize = new long[aNbModules]; + char** aModuleName = new char*[aNbModules]; + + if(aBuffer == NULL || aBufferSize == NULL || aModuleName == NULL) + return false; + + int aFileBufferSize = 4; //4 bytes for a number of the modules that will be written to the stream; + int i = 0; + for (it = myMap.begin(); it != myMap.end(); ++it) { + aModuleName[i] = const_cast(it->first.c_str());//(it->first); + aFileBufferSize += 4; //Add 4 bytes: a length of the module name + aFileBufferSize += strlen(aModuleName[i])+1; + std::string aName(aModuleName[i]); + PutFilesToStream(aName, aBuffer[i], aBufferSize[i], isMultiFile); + aFileBufferSize += 8; //Add 8 bytes: a length of the buffer + aFileBufferSize += aBufferSize[i]; + // Remove the files and tmp directory, created by the component storage procedure + if (!isMultiFile) + RemoveTemporaryFiles(aModuleName[i], true); + i++; + } + int n = i; + + unsigned char* aFileBuffer = new unsigned char[aFileBufferSize]; + if(aFileBuffer == NULL) + return false; + + int aCurrentPos = 0; + + //Initialize 4 bytes of the buffer by 0 + memset(aFileBuffer, 0, 4); + //Copy the number of modules that will be written to the stream + memcpy(aFileBuffer, &aNbModules, ((sizeof(int) > 4) ? 4 : sizeof(int))); + aCurrentPos += 4; + + int aBufferNameSize = 0; + for (i = 0; i < n; i++) { + aBufferNameSize = strlen(aModuleName[i])+1; + //Initialize 4 bytes of the buffer by 0 + memset((aFileBuffer + aCurrentPos), 0, 4); + //Copy the length of the module name to the buffer + memcpy((aFileBuffer + aCurrentPos), &aBufferNameSize, ((sizeof(int) > 4) ? 4 : sizeof(int))); + aCurrentPos += 4; + //Copy the module name to the buffer + memcpy((aFileBuffer + aCurrentPos), aModuleName[i], aBufferNameSize); + aCurrentPos += aBufferNameSize; + + //Initialize 8 bytes of the buffer by 0 + memset((aFileBuffer + aCurrentPos), 0, 8); + //Copy the length of the module buffer to the buffer + memcpy((aFileBuffer + aCurrentPos), (aBufferSize + i), ((sizeof(long) > 8) ? 8 : sizeof(long))); + aCurrentPos += 8; + //Copy the module buffer to the buffer + memcpy((aFileBuffer + aCurrentPos), aBuffer[i], aBufferSize[i]); + aCurrentPos += aBufferSize[i]; + } + + ofstream aFile(theFileName); + aFile.write((char*)aFileBuffer, aFileBufferSize); + aFile.close(); + + delete[] aBuffer; + delete[] aBufferSize; + delete[] aModuleName; + delete[] aFileBuffer; + return true; +} + +//======================================================================= +// name : ReaDatasFromFile +/*! Purpose : filling current driver from file 'theFileName'*/ +//======================================================================= +bool LightApp_Driver::ReadDatasFromFile( const char* theFileName, bool isMultiFile ) +{ +#ifdef WNT + ifstream aFile(theFileName, ios::binary); +#else + ifstream aFile(theFileName); +#endif + + aFile.seekg(0, ios::end); + int aFileBufferSize = aFile.tellg(); + unsigned char* aFileBuffer = new unsigned char[aFileBufferSize]; + aFile.seekg(0, ios::beg); + aFile.read((char*)aFileBuffer, aFileBufferSize); + aFile.close(); + + int aNbModules = 0; + //Copy the number of files in the stream + memcpy(&aNbModules, aFileBuffer, sizeof(int)); + long aCurrentPos = 4; + int aModuleNameSize; + + for (int i = 0; i < aNbModules; i++) { + //Put a length of the module name to aModuleNameSize + memcpy(&aModuleNameSize, (aFileBuffer + aCurrentPos), ((sizeof(int) > 4) ? 4 : sizeof(int))); + aCurrentPos += 4; + + char *aModuleName = new char[aModuleNameSize]; + //Put a module name to aModuleName + memcpy(aModuleName, (aFileBuffer + aCurrentPos), aModuleNameSize); + aCurrentPos += aModuleNameSize; + + //Put a length of the file buffer to aBufferSize + long aBufferSize; + memcpy(&aBufferSize, (aFileBuffer + aCurrentPos), ((sizeof(long) > 8) ? 8 : sizeof(long))); + aCurrentPos += 8; + unsigned char *aBuffer = new unsigned char[aBufferSize]; + + //Put a buffer for current module to aBuffer + memcpy(aBuffer, (aFileBuffer + aCurrentPos), aBufferSize); + aCurrentPos += aBufferSize; + + // Put buffer to aListOfFiles and set to myMap + ListOfFiles aListOfFiles = PutStreamToFiles(aBuffer, aBufferSize, isMultiFile); + SetListOfFiles(aModuleName, aListOfFiles); + + delete[] aModuleName; + delete[] aBuffer; + } + delete[] aFileBuffer; + return true; +} + +//================================================================ +// Function : GetTmpDir +/*! Purpose : returns temp directory for path 'theURL'*/ +//================================================================ +std::string LightApp_Driver::GetTmpDir (const char* theURL, const bool isMultiFile) +{ + std::string anURLDir = GetDirFromPath(theURL); + std::string aTmpDir = isMultiFile ? anURLDir : GetTmpDir(); + + return aTmpDir; +} + +//================================================================ +// Function : GetListOfFiles +/*! Purpose : returns list of files for module with name 'theModuleName'*/ +//================================================================ +LightApp_Driver::ListOfFiles LightApp_Driver::GetListOfFiles( const char* theModuleName ) +{ + ListOfFiles aListOfFiles; + + std::string aName(theModuleName); + if (myMap.count(aName)) + aListOfFiles = myMap[aName]; + + return aListOfFiles; +} + +//================================================================ +// Function : SetListOfFiles +/*! Purpose : sets list of files for module with name 'theModuleName'*/ +//================================================================ +void LightApp_Driver::SetListOfFiles( const char* theModuleName, const ListOfFiles theListOfFiles ) +{ + std::string aName (theModuleName); + myMap[aName] = theListOfFiles; +} + +//============================================================================ +// function : PutFilesToStream +/*! Purpose : converts files which was created from module into a byte sequence unsigned char*/ +//============================================================================ +void LightApp_Driver::PutFilesToStream( const std::string& theModuleName, unsigned char*& theBuffer, + long& theBufferSize, bool theNamesOnly ) +{ + ListOfFiles aFiles = myMap[theModuleName]; + // aFiles must contain temporary directory name in its first item + // and names of files (relatively the temporary directory) in the others + + int i, aLength = aFiles.size() - 1; + if(aLength <= 0) { + theBufferSize = 0; + theBuffer = new unsigned char[theBufferSize]; + return; + } + //Get a temporary directory for saved a file + TCollection_AsciiString aTmpDir(const_cast(aFiles[0].c_str())); + + long aBufferSize = 0; + long aCurrentPos; + int aNbFiles = 0; + int* aFileNameSize= new int[aLength]; + long* aFileSize= new long[aLength]; + + //Determine the required size of the buffer + TCollection_AsciiString aFileName; + for (i = 0; i < aLength; i++) { + char* aFName = const_cast(aFiles[i+1].c_str()); + aFileName = aFName; + //Check if the file exists + if (!theNamesOnly) { // mpv 15.01.2003: if only file names must be stroed, then size of files is zero + TCollection_AsciiString aFullPath = aTmpDir + aFileName; + OSD_Path anOSDPath(aFullPath); + OSD_File anOSDFile(anOSDPath); + if(!anOSDFile.Exists()) continue; +#ifdef WNT + ifstream aFile(aFullPath.ToCString(), ios::binary); +#else + ifstream aFile(aFullPath.ToCString()); +#endif + aFile.seekg(0, ios::end); + aFileSize[i] = aFile.tellg(); + aBufferSize += aFileSize[i]; //Add a space to store the file + } + aFileNameSize[i] = strlen(aFName) + 1; + aBufferSize += aFileNameSize[i]; //Add a space to store the file name + aBufferSize += (theNamesOnly)?4:12; //Add 4 bytes: a length of the file name, + // 8 bytes: length of the file itself + aNbFiles++; + delete[] aFName; + } + + aBufferSize += 4; //4 bytes for a number of the files that will be written to the stream; + theBuffer = new unsigned char[aBufferSize]; + if(theBuffer == NULL) { + theBufferSize = 0; + theBuffer = 0; + return; + } + //Initialize 4 bytes of the buffer by 0 + memset(theBuffer, 0, 4); + //Copy the number of files that will be written to the stream + memcpy(theBuffer, &aNbFiles, ((sizeof(int) > 4) ? 4 : sizeof(int))); + + aCurrentPos = 4; + + for(i = 0; i < aLength; i++) { + ifstream *aFile; + if (!theNamesOnly) { // mpv 15.01.2003: we don't open any file if theNamesOnly = true + TCollection_AsciiString aName(const_cast(aFiles[i+1].c_str())); + TCollection_AsciiString aFullPath = aTmpDir + aName; + OSD_Path anOSDPath(aFullPath); + OSD_File anOSDFile(anOSDPath); + if(!anOSDFile.Exists()) continue; +#ifdef WNT + aFile = new ifstream(aFullPath.ToCString(), ios::binary); +#else + aFile = new ifstream(aFullPath.ToCString()); +#endif + } + //Initialize 4 bytes of the buffer by 0 + memset((theBuffer + aCurrentPos), 0, 4); + //Copy the length of the file name to the buffer + memcpy((theBuffer + aCurrentPos), (aFileNameSize + i), ((sizeof(int) > 4) ? 4 : sizeof(int))); + aCurrentPos += 4; + + //Copy the file name to the buffer + char* aFName = const_cast(aFiles[i+1].c_str()); + memcpy((theBuffer + aCurrentPos), aFName, aFileNameSize[i]); + aCurrentPos += aFileNameSize[i]; + + if (!theNamesOnly) { // mpv 15.01.2003: we don't copy file content to the buffer if !theNamesOnly + //Initialize 8 bytes of the buffer by 0 + memset((theBuffer + aCurrentPos), 0, 8); + //Copy the length of the file to the buffer + memcpy((theBuffer + aCurrentPos), (aFileSize + i), ((sizeof(long) > 8) ? 8 : sizeof(long))); + aCurrentPos += 8; + + aFile->seekg(0, ios::beg); + aFile->read((char *)(theBuffer + aCurrentPos), aFileSize[i]); + aFile->close(); + delete(aFile); + aCurrentPos += aFileSize[i]; + } + } + delete[] aFileNameSize; + delete[] aFileSize; + + theBufferSize = aBufferSize; +} + +//============================================================================ +// function : PutStreamToFile +/*! Purpose : converts a byte sequence to files and return list of them*/ +//============================================================================ +LightApp_Driver::ListOfFiles LightApp_Driver::PutStreamToFiles( const unsigned char* theBuffer, + const long theBufferSize, bool theNamesOnly ) +{ + if(theBufferSize == 0 || theBuffer == 0) + return ListOfFiles(); + + // Create a temporary directory for the component's data files + std::string aDir = GetTmpDir(); + + //Get a temporary directory for saving a file + TCollection_AsciiString aTmpDir(const_cast(aDir.c_str())); + + long aFileSize, aCurrentPos = 4; + int i, aFileNameSize, aNbFiles = 0; + + //Copy the number of files in the stream + memcpy(&aNbFiles, theBuffer, sizeof(int)); + + const int n = aNbFiles + 1; + ListOfFiles aFiles(n); + aFiles[0] = aDir; + + for(i = 0; i < aNbFiles; i++) { + //Put a length of the file name to aFileNameSize + memcpy(&aFileNameSize, (theBuffer + aCurrentPos), ((sizeof(int) > 4) ? 4 : sizeof(int))); + aCurrentPos += 4; + + char *aFileName = new char[aFileNameSize]; + //Put a file name to aFileName + memcpy(aFileName, (theBuffer + aCurrentPos), aFileNameSize); + aCurrentPos += aFileNameSize; + + //Put a length of the file to aFileSize + if (!theNamesOnly) { + memcpy(&aFileSize, (theBuffer + aCurrentPos), ((sizeof(long) > 8) ? 8 : sizeof(long))); + aCurrentPos += 8; + + TCollection_AsciiString aFullPath = aTmpDir + aFileName; + ofstream aFile(aFullPath.ToCString()); + aFile.write((char *)(theBuffer+aCurrentPos), aFileSize); + aFile.close(); + aCurrentPos += aFileSize; + } + std::string aStrFileName(aFileName); + aFiles[i+1] = aStrFileName; + delete[] aFileName; + } + return aFiles; +} + +//============================================================================ +// function : RemoveTemporaryFiles +/*! Purpose : removes files which was created from module theModuleName if is true tmp directory is also deleted if it is empty*/ +//============================================================================ +void LightApp_Driver::RemoveTemporaryFiles( const char* theModuleName, const bool IsDirDeleted ) +{ + std::string aModuleName(theModuleName); + ListOfFiles aFiles = myMap[aModuleName]; + // aFiles must contain temporary directory name in its first item + // and names of files (relatively the temporary directory) in the others + + int i, aLength = aFiles.size() - 1; + if(aLength <= 0) { + return; + } + //Get a temporary directory for saved a file + TCollection_AsciiString aDirName(const_cast(aFiles[0].c_str())); + + for(i = 0; i < aLength; i++) { + TCollection_AsciiString aFile(aDirName); + aFile += const_cast(aFiles[i+1].c_str()); + OSD_Path anOSDPath(aFile); + OSD_File anOSDFile(anOSDPath); + if(!anOSDFile.Exists()) continue; + + OSD_Protection aProtection = anOSDFile.Protection(); + aProtection.SetUser(OSD_RW); + anOSDFile.SetProtection(aProtection); + + anOSDFile.Remove(); + } + + if(IsDirDeleted) { + OSD_Path aPath(aDirName); + OSD_Directory aDir(aPath); + OSD_FileIterator anIterator(aPath, '*'); + + if(aDir.Exists() && !anIterator.More()) aDir.Remove(); + } +} + +//============================================================================ +// function : ClearDriverContents +/*! Purpose : clear map of list files*/ +//============================================================================ +void LightApp_Driver::ClearDriverContents() +{ + myMap.clear(); +} + +//============================================================================ +// function : GetTempDir +/*! Purpose : return a temp directory to store created files like "/tmp/sub_dir/" */ +//============================================================================ +std::string LightApp_Driver::GetTmpDir() +{ + //Find a temporary directory to store a file + TCollection_AsciiString aTmpDir; + + char *Tmp_dir = getenv("SALOME_TMP_DIR"); + if(Tmp_dir != NULL) { + aTmpDir = TCollection_AsciiString(Tmp_dir); +#ifdef WIN32 + if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\'; +#else + if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/'; +#endif + } + else { +#ifdef WIN32 + aTmpDir = TCollection_AsciiString("C:\\"); +#else + aTmpDir = TCollection_AsciiString("/tmp/"); +#endif + } + + srand((unsigned int)time(NULL)); + int aRND = 999 + (int)(100000.0*rand()/(RAND_MAX+1.0)); //Get a random number to present a name of a sub directory + TCollection_AsciiString aSubDir(aRND); + if(aSubDir.Length() <= 1) aSubDir = TCollection_AsciiString("123409876"); + + aTmpDir += aSubDir; //Get RND sub directory + +#ifdef WIN32 + if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\'; +#else + if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/'; +#endif + + OSD_Path aPath(aTmpDir); + OSD_Directory aDir(aPath); + + for(aRND = 0; aDir.Exists(); aRND++) { + aTmpDir.Insert((aTmpDir.Length() - 1), TCollection_AsciiString(aRND)); //Build a unique directory name + aPath = OSD_Path(aTmpDir); + aDir = OSD_Directory(aPath); + } + + OSD_Protection aProtection(OSD_RW, OSD_RWX, OSD_RX, OSD_RX); + aDir.Build(aProtection); + + return aTmpDir.ToCString(); +} + +//============================================================================ +// function : GetDirFromPath +/*! Purpose : returns the dir by the path*/ +//============================================================================ +std::string LightApp_Driver::GetDirFromPath( const std::string& thePath ) { + if(thePath == "") + return ""; + OSD_Path aPath = OSD_Path(TCollection_AsciiString(const_cast(thePath.c_str()))); + TCollection_AsciiString aDirString(aPath.Trek()); + aDirString.ChangeAll('|','/'); + return aDirString.ToCString(); +} + diff --git a/src/LightApp/LightApp_Driver.h b/src/LightApp/LightApp_Driver.h new file mode 100644 index 000000000..eb26e5633 --- /dev/null +++ b/src/LightApp/LightApp_Driver.h @@ -0,0 +1,49 @@ +#ifndef LIGHTAPP_DRIVER_H +#define LIGHTAPP_DRIVER_H + +#include + +#include "string" +#include "vector" +#include "map" + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +/*!Description : Driver can save to file and read from file list of files for light modules*/ + +class LIGHTAPP_EXPORT LightApp_Driver +{ +public: + LightApp_Driver(); + virtual ~LightApp_Driver(); + + + typedef std::vector ListOfFiles; + + bool SaveDatasInFile (const char* theFileName, bool isMultiFile ); + bool ReadDatasFromFile (const char* theFileName, bool isMultiFile ); + virtual std::string GetTmpDir (const char* theURL, const bool isMultiFile); + + ListOfFiles GetListOfFiles (const char* theModuleName); + virtual void SetListOfFiles (const char* theModuleName, const ListOfFiles theListOfFiles); + virtual void RemoveTemporaryFiles(const char* theModuleName, const bool IsDirDeleted); + + virtual void ClearDriverContents(); + +private: + void PutFilesToStream(const std::string& theModuleName, unsigned char*& theBuffer, + long& theBufferSize, bool theNamesOnly = false); + ListOfFiles PutStreamToFiles(const unsigned char* theBuffer, + const long theBufferSize, bool theNamesOnly = false); + + std::string GetTmpDir(); + std::string GetDirFromPath(const std::string& thePath); + +private: + typedef std::map MapOfListOfFiles; + MapOfListOfFiles myMap; +}; + +#endif diff --git a/src/LightApp/LightApp_GLSelector.cxx b/src/LightApp/LightApp_GLSelector.cxx new file mode 100644 index 000000000..b49ce51c1 --- /dev/null +++ b/src/LightApp/LightApp_GLSelector.cxx @@ -0,0 +1,99 @@ +#include "LightApp_GLSelector.h" + +#include "LightApp_DataOwner.h" + +#include + +#include + +/*!Constructor. Initialize by GLViewer_Viewer2d and SUIT_SelectionMgr.*/ +LightApp_GLSelector::LightApp_GLSelector( GLViewer_Viewer2d* viewer, SUIT_SelectionMgr* mgr ) +: SUIT_Selector( mgr, viewer ), + myViewer( viewer ) +{ + if ( myViewer ) + connect( myViewer, SIGNAL( selectionChanged( SelectionChangeStatus ) ), + this, SLOT( onSelectionChanged() ) ); +} + +/*!Destructor. Do nothing.*/ +LightApp_GLSelector::~LightApp_GLSelector() +{ +} + +/*!Gets viewer*/ +GLViewer_Viewer2d* LightApp_GLSelector::viewer() const +{ + return myViewer; +} + +/*!On selection changed event.*/ +void LightApp_GLSelector::onSelectionChanged() +{ + selectionChanged(); +} + +/*!Gets list of selected Data Owner objects.*/ +void LightApp_GLSelector::getSelection( SUIT_DataOwnerPtrList& aList ) const +{ + if ( !myViewer ) + return; + + GLViewer_Context* cont = myViewer->getGLContext(); + if ( !cont ) + return; + + for ( cont->InitSelected(); cont->MoreSelected(); cont->NextSelected() ) + { + GLViewer_Object* obj = cont->SelectedObject(); + if ( obj ) + { + SALOME_GLOwner* owner = dynamic_cast< SALOME_GLOwner* >( obj->owner() ); + if( owner ) + aList.append( SUIT_DataOwnerPtr( new LightApp_DataOwner( owner->entry() ) ) ); + } + } +} + +/*!Sets to selected list of Data Owner objects.*/ +void LightApp_GLSelector::setSelection( const SUIT_DataOwnerPtrList& aList ) +{ + if ( !myViewer ) + return; + + GLViewer_Context* cont = myViewer->getGLContext(); + if ( !cont ) + return; + + QMap aDisplayed; + const ObjList& displayed = cont->getObjects(); + for ( ObjList::const_iterator it = displayed.begin(); it != displayed.end(); ++it ) + { + GLViewer_Object* obj = *it; + if ( obj && obj->getVisible() ) + { + SALOME_GLOwner* owner = dynamic_cast< SALOME_GLOwner* >( obj->owner() ); + if ( owner ) + aDisplayed.insert( owner->entry(), obj ); + } + } + + int Nb = 0; + cont->clearSelected( false ); + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataOwner* owner = dynamic_cast( (*itr).operator->() ); + + if ( !owner ) + continue; + + if ( aDisplayed.contains( owner->entry() ) ) + { + cont->setSelected( aDisplayed[owner->entry()], false ); + Nb++; + } + } + + if ( Nb > 0 ) + myViewer->updateAll(); +} diff --git a/src/LightApp/LightApp_GLSelector.h b/src/LightApp/LightApp_GLSelector.h new file mode 100644 index 000000000..50a783ecb --- /dev/null +++ b/src/LightApp/LightApp_GLSelector.h @@ -0,0 +1,33 @@ +#ifndef LIGHTAPP_GLSELECTOR_H +#define LIGHTAPP_GLSELECTOR_H + +#include "LightApp.h" + +#include + +#include + +class LIGHTAPP_EXPORT LightApp_GLSelector : public SUIT_Selector +{ + Q_OBJECT + +public: + LightApp_GLSelector( GLViewer_Viewer2d*, SUIT_SelectionMgr* ); + virtual ~LightApp_GLSelector(); + + GLViewer_Viewer2d* viewer() const; + + virtual QString type() const { return GLViewer_Viewer2d::Type(); } + +private slots: + void onSelectionChanged(); + +protected: + virtual void getSelection( SUIT_DataOwnerPtrList& ) const; + virtual void setSelection( const SUIT_DataOwnerPtrList& ); + +private: + GLViewer_Viewer2d* myViewer; +}; + +#endif diff --git a/src/LightApp/LightApp_Module.cxx b/src/LightApp/LightApp_Module.cxx new file mode 100644 index 000000000..6e6c68158 --- /dev/null +++ b/src/LightApp/LightApp_Module.cxx @@ -0,0 +1,412 @@ +// File: LightApp_Module.cxx +// Created: 6/20/2005 16:30:56 AM +// Author: OCC team +// Copyright (C) CEA 2005 + +#include "LightApp_Module.h" + +#include "CAM_Application.h" + +#include "LightApp_Application.h" +#include "LightApp_DataModel.h" +#include "LightApp_Study.h" +#include "LightApp_Preferences.h" +#include "LightApp_Selection.h" +#include "LightApp_Operation.h" +#include "LightApp_SwitchOp.h" +#include "LightApp_UpdateFlags.h" +#include "LightApp_ShowHideOp.h" + +#include "SUIT_Operation.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +/*!Constructor.*/ +LightApp_Module::LightApp_Module( const QString& name ) +: CAM_Module( name ), + myPopupMgr( 0 ), + mySwitchOp( 0 ), + myDisplay( -1 ), + myErase( -1 ), + myDisplayOnly( -1 ) +{ +} + +/*!Destructor.*/ +LightApp_Module::~LightApp_Module() +{ + if ( mySwitchOp ) + delete mySwitchOp; +} + +/*!Initialize module.*/ +void LightApp_Module::initialize( CAM_Application* app ) +{ + CAM_Module::initialize( app ); + + SUIT_ResourceMgr* resMgr = app ? app->resourceMgr() : 0; + if ( resMgr ) + resMgr->raiseTranslators( name() ); +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::windows( QMap& ) const +{ +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::viewManagers( QStringList& ) const +{ +} + +/*!Context menu popup.*/ +void LightApp_Module::contextMenuPopup( const QString& client, QPopupMenu* menu, QString& /*title*/ ) +{ + LightApp_Selection* sel = createSelection(); + sel->init( client, getApp()->selectionMgr() ); + popupMgr()->updatePopup( menu, sel ); + delete sel; +} + +/*!Update object browser. + * For updating model or whole object browser use update() method can be used. +*/ +void LightApp_Module::updateObjBrowser( bool updateDataModel, SUIT_DataObject* root ) +{ + if( updateDataModel ) + if( CAM_DataModel* aDataModel = dataModel() ) + if( LightApp_DataModel* aModel = dynamic_cast( aDataModel ) ) + aModel->update( 0, dynamic_cast( getApp()->activeStudy() ) ); + getApp()->objectBrowser()->updateTree( root ); +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::selectionChanged() +{ +} + +/*!Activate module.*/ +bool LightApp_Module::activateModule( SUIT_Study* study ) +{ + bool res = CAM_Module::activateModule( study ); + + if ( res && application() && application()->resourceMgr() ) + application()->resourceMgr()->raiseTranslators( name() ); + + if ( mySwitchOp == 0 ) + mySwitchOp = new LightApp_SwitchOp( this ); + + return res; +} + +/*!Deactivate module.*/ +bool LightApp_Module::deactivateModule( SUIT_Study* ) +{ + delete mySwitchOp; + mySwitchOp = 0; + + return true; +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::MenuItem() +{ +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::createPreferences() +{ +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::preferencesChanged( const QString&, const QString& ) +{ +} + +/*!Gets application.*/ +LightApp_Application* LightApp_Module::getApp() const +{ + return (LightApp_Application*)application(); +} + +/*! + * \brief Update something in accordance with update flags + * \param theFlags - update flags +* +* Update viewer or/and object browser etc. in accordance with update flags ( see +* LightApp_UpdateFlags enumeration ). Derived modules can redefine this method for their +* own purposes +*/ +void LightApp_Module::update( const int theFlags ) +{ + if ( theFlags & UF_Model ) + { + if( CAM_DataModel* aDataModel = dataModel() ) + if( LightApp_DataModel* aModel = dynamic_cast( aDataModel ) ) + aModel->update( 0, dynamic_cast( getApp()->activeStudy() ) ); + } + if ( theFlags & UF_ObjBrowser ) + getApp()->objectBrowser()->updateTree( 0 ); + if ( theFlags & UF_Controls ) + updateControls(); + if ( theFlags & UF_Viewer ) + { + if ( SUIT_ViewManager* viewMgr = getApp()->activeViewManager() ) + if ( SUIT_ViewWindow* viewWnd = viewMgr->getActiveView() ) + { + if ( viewWnd->inherits( "SVTK_ViewWindow" ) ) + ( (SVTK_ViewWindow*)viewWnd )->Repaint(); + else if ( viewWnd->inherits( "OCCViewer_ViewWindow" ) ) + ( (OCCViewer_ViewWindow*)viewWnd )->getViewPort()->onUpdate(); + else if ( viewWnd->inherits( "Plot2d_ViewWindow" ) ) + ( (Plot2d_ViewWindow*)viewWnd )->getViewFrame()->Repaint(); + else if ( viewWnd->inherits( "GLViewer_ViewFrame" ) ) + ( (GLViewer_ViewFrame*)viewWnd )->getViewPort()->onUpdate(); + } + } +} +/*! + * \brief Updates controls +* +* Updates (i.e. disable/enable) controls states (menus, tool bars etc.). This method is +* called from update( UF_Controls ). You may redefine it in concrete module. +*/ +void LightApp_Module::updateControls() +{ +} + +/*!Create new instance of data model and return it.*/ +CAM_DataModel* LightApp_Module::createDataModel() +{ + return new LightApp_DataModel(this); +} + +/*!Create and return instance of LightApp_Selection.*/ +LightApp_Selection* LightApp_Module::createSelection() const +{ + return new LightApp_Selection(); +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::onModelOpened() +{ +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::onModelSaved() +{ +} + +/*!NOT IMPLEMENTED*/ +void LightApp_Module::onModelClosed() +{ +} + +/*!Gets popup manager.(create if not exist)*/ +QtxPopupMgr* LightApp_Module::popupMgr() +{ + if ( !myPopupMgr ) + { + myPopupMgr = new QtxPopupMgr( 0, this ); + + QPixmap p; + SUIT_Desktop* d = application()->desktop(); + + QAction + *disp = createAction( -1, tr( "TOP_DISPLAY" ), p, tr( "MEN_DISPLAY" ), tr( "STB_DISPLAY" ), + 0, d, false, this, SLOT( onShowHide() ) ), + *erase = createAction( -1, tr( "TOP_ERASE" ), p, tr( "MEN_ERASE" ), tr( "STB_ERASE" ), + 0, d, false, this, SLOT( onShowHide() ) ), + *dispOnly = createAction( -1, tr( "TOP_DISPLAY_ONLY" ), p, tr( "MEN_DISPLAY_ONLY" ), tr( "STB_DISPLAY_ONLY" ), + 0, d, false, this, SLOT( onShowHide() ) ); + myDisplay = actionId( disp ); + myErase = actionId( erase ); + myDisplayOnly = actionId( dispOnly ); + + myPopupMgr->insert( disp, -1, 0 ); + myPopupMgr->insert( erase, -1, 0 ); + myPopupMgr->insert( dispOnly, -1, 0 ); + myPopupMgr->insert( separator(), -1, 0 ); + + QString uniform = "( count( $component ) = 1 ) and ( component != activeModule ) and ( activeModule = '%1' )"; + uniform = uniform.arg( name() ); + myPopupMgr->setRule( disp, QString( "( not isVisible ) and " ) + uniform, true ); + myPopupMgr->setRule( erase, QString( "( isVisible ) and " ) + uniform, true ); + myPopupMgr->setRule( dispOnly, uniform, true ); + } + return myPopupMgr; +} + +/*!Gets preferences.*/ +LightApp_Preferences* LightApp_Module::preferences() const +{ + LightApp_Preferences* pref = 0; + if ( getApp() ) + pref = getApp()->preferences(); + return pref; +} + +/*!Add preference to preferences.*/ +int LightApp_Module::addPreference( const QString& label ) +{ + LightApp_Preferences* pref = preferences(); + if ( !pref ) + return -1; + + int catId = pref->addPreference( moduleName(), -1 ); + if ( catId == -1 ) + return -1; + + return pref->addPreference( label, catId ); +} + +/*!Add preference to preferences.*/ +int LightApp_Module::addPreference( const QString& label, const int pId, const int type, + const QString& section, const QString& param ) +{ + LightApp_Preferences* pref = preferences(); + if ( !pref ) + return -1; + + return pref->addPreference( moduleName(), label, pId, type, section, param ); +} + +/*!Gets property of preferences.*/ +QVariant LightApp_Module::preferenceProperty( const int id, const QString& prop ) const +{ + QVariant var; + LightApp_Preferences* pref = preferences(); + if ( pref ) + var = pref->itemProperty( id, prop ); + return var; +} + +/*!Set property of preferences.*/ +void LightApp_Module::setPreferenceProperty( const int id, const QString& prop, const QVariant& var ) +{ + LightApp_Preferences* pref = preferences(); + if ( pref ) + pref->setItemProperty( id, prop, var ); +} + +/*! + * \brief Starts operation with given identifier + * \param id - identifier of operation to be started +* +* Module stores operations in map. This method starts operation by id. +* If operation isn't in map, then it will be created by createOperation method +* and will be inserted to map +*/ +void LightApp_Module::startOperation( const int id ) +{ + LightApp_Operation* op = 0; + if( myOperations.contains( id ) ) + op = myOperations[ id ]; + else + { + op = createOperation( id ); + if( op ) + { + myOperations.insert( id, op ); + op->setModule( this ); + connect( op, SIGNAL( stopped( SUIT_Operation* ) ), this, SLOT( onOperationStopped( SUIT_Operation* ) ) ); + connect( op, SIGNAL( destroyed() ), this, SLOT( onOperationDestroyed() ) ); + } + } + + if( op ) + op->start(); +} + +/*! + * \brief Creates operation with given identifier + * \param id - identifier of operation to be started + * \return Pointer on created operation or NULL if operation is not created +* +* Creates operation with given id. You should not call this method, it will be called +* automatically from startOperation. You may redefine this method in concrete module to +* create operations. +*/ +LightApp_Operation* LightApp_Module::createOperation( const int id ) const +{ + if( id==-1 ) + return 0; + + if( id==myDisplay ) + return new LightApp_ShowHideOp( LightApp_ShowHideOp::DISPLAY ); + else if( id==myErase ) + return new LightApp_ShowHideOp( LightApp_ShowHideOp::ERASE ); + else if( id==myDisplayOnly ) + return new LightApp_ShowHideOp( LightApp_ShowHideOp::DISPLAY_ONLY ); + else + return 0; +} + +/*! + * \brief Virtual protected slot called when operation stopped + * \param theOp - stopped operation +* +* Virtual protected slot called when operation stopped. Redefine this slot if you want to +* perform actions after stopping operation +*/ +void LightApp_Module::onOperationStopped( SUIT_Operation* /*theOp*/ ) +{ +} + +/*! + * \brief Virtual protected slot called when operation destroyed + * \param theOp - destroyed operation +* +* Virtual protected slot called when operation destroyed. Redefine this slot if you want to +* perform actions after destroying operation. Base implementation removes pointer on +* destroyed operation from the map of operations +*/ +void LightApp_Module::onOperationDestroyed() +{ + const QObject* s = sender(); + if( s && s->inherits( "LightApp_Operation" ) ) + { + const LightApp_Operation* op = ( LightApp_Operation* )s; + MapOfOperation::const_iterator anIt = myOperations.begin(), + aLast = myOperations.end(); + for( ; anIt!=aLast; anIt++ ) + if( anIt.data()==op ) + { + myOperations.remove( anIt.key() ); + break; + } + } +} + +LightApp_Displayer* LightApp_Module::displayer() +{ + return 0; +} + +void LightApp_Module::onShowHide() +{ + if( !sender()->inherits( "QAction" ) || !popupMgr() ) + return; + + QAction* act = ( QAction* )sender(); + int id = actionId( act ); + if( id!=-1 ) + startOperation( id ); +} diff --git a/src/LightApp/LightApp_Module.h b/src/LightApp/LightApp_Module.h new file mode 100644 index 000000000..e881547da --- /dev/null +++ b/src/LightApp/LightApp_Module.h @@ -0,0 +1,119 @@ +// File: LightApp_Module.h +// Created: 6/20/2005 16:25:06 AM +// Author: OCC team +// Copyright (C) CEA 2005 + +#ifndef LIGHTAPP_MODULE_H +#define LIGHTAPP_MODULE_H + +#include "LightApp.h" +#include + +class LightApp_Application; +class LightApp_Preferences; +class LightApp_Selection; +class LightApp_Operation; +class LightApp_SwitchOp; +class LightApp_Displayer; + +class SUIT_Study; +class SUIT_DataObject; +class SUIT_Operation; +class CAM_Application; + +class QtxPopupMgr; + +class QString; +class QVariant; + +/* + Class : LightApp_Module + Description : Base class for all light modules +*/ + +class LIGHTAPP_EXPORT LightApp_Module : public CAM_Module +{ + Q_OBJECT + +public: + LightApp_Module( const QString& ); + virtual ~LightApp_Module(); + + virtual void initialize( CAM_Application* ); + virtual void windows( QMap& ) const; + virtual void viewManagers( QStringList& ) const; + + virtual void contextMenuPopup( const QString&, QPopupMenu*, QString& ); + + virtual void createPreferences(); + + LightApp_Application* getApp() const; + + virtual void update( const int ); + // Update viewer or/and object browser etc. in accordance with update flags + // ( see SalomeApp_UpdateFlags enumeration ). Derived modules can redefine this method + // for their own purposes + + virtual void updateObjBrowser( bool = true, SUIT_DataObject* = 0 ); + // Update object bropwser ( for updating model or whole object browser use update() method + // can be used ) + + virtual void selectionChanged(); + virtual void preferencesChanged( const QString&, const QString& ); + + virtual void studyActivated() {}; + + virtual LightApp_Displayer* displayer(); + +public slots: + virtual bool activateModule( SUIT_Study* ); + virtual bool deactivateModule( SUIT_Study* ); + + void MenuItem(); + +protected slots: + virtual void onModelSaved(); + virtual void onModelOpened(); + virtual void onModelClosed(); + + virtual void onOperationStopped( SUIT_Operation* ); + virtual void onOperationDestroyed(); + virtual void onShowHide(); + +protected: + virtual QtxPopupMgr* popupMgr(); + LightApp_Preferences* preferences() const; + + virtual CAM_DataModel* createDataModel(); + virtual LightApp_Selection* createSelection() const; + + int addPreference( const QString& label ); + int addPreference( const QString& label, const int pId, const int = -1, + const QString& section = QString::null, + const QString& param = QString::null ); + QVariant preferenceProperty( const int, const QString& ) const; + void setPreferenceProperty( const int, const QString&, const QVariant& ); + + /*! Module stores operations in map. This method starts operation by id. + * If operation isn't in map, then it will be created by createOperation method + * and will be inserted to map + */ + void startOperation( const int ); + /*! Create operation by its id. You must not call this method, it will be called automatically + * by startOperation. Please redefine this method in current module + */ + virtual LightApp_Operation* createOperation( const int ) const; + + virtual void updateControls(); + +private: + typedef QMap MapOfOperation; + +private: + QtxPopupMgr* myPopupMgr; + MapOfOperation myOperations; + LightApp_SwitchOp* mySwitchOp; + int myDisplay, myErase, myDisplayOnly; +}; + +#endif diff --git a/src/LightApp/LightApp_ModuleDlg.cxx b/src/LightApp/LightApp_ModuleDlg.cxx new file mode 100644 index 000000000..5faa1e189 --- /dev/null +++ b/src/LightApp/LightApp_ModuleDlg.cxx @@ -0,0 +1,198 @@ +// File : LightApp_ModuleDlg.cxx +// Author : Michael Zorin (mzn) +// Module : LightApp + +#include + +#include +#include +#include +#include +#include + +#ifndef WIN32 +using namespace std; +#endif + +/*!Default icon*/ +static const char* const default_icon[] = { +"48 48 17 1", +". c None", +"# c #161e4c", +"b c #1d3638", +"e c #2f585b", +"i c #345b5e", +"c c #386266", +"g c #3f7477", +"d c #4d8589", +"m c #519099", +"o c #6abbc1", +"a c #70c9d3", +"f c #79ddea", +"n c #7adff2", +"k c #7ce2f4", +"j c #993550", +"h c #d84b71", +"l c #ef537d", +"................................................", +"................................................", +"................................................", +"................................................", +"................................................", +"................########.########.########......", +"...............#aaaaaa###aaaaaa###aaaaaa##......", +"..............#aaaaaa#b#aaaaaa#b#aaaaaa#c#......", +".............########b########b########cc#......", +".............#dddddd#b#dddddd#b#dddddd#cc#......", +"...........########d########d########d#cc#......", +"..........#aaaaaa###aaaaaa###aaaaaa##d#cc#......", +".........#aaaaaa#b#aaaaaa#b#aaaaaa#c#d#cc#......", +"........########b########e########cc#d#c#.......", +"........#dddddd#b#dddddd#e#ffffff#cc#d####......", +"......########d########d########f#cc###g##......", +".....#aaaaaa###aaaaaa###hhhhhh##f#cc#gg#c#......", +"....#aaaaaa#b#aaaaaa#i#hhhhhh#j#f#cc###cc#......", +"...########b########i########jj#f#c#gg#cc#......", +"...#kkkkkk#b#kkkkkk#i#llllll#jj#f####g#cc#......", +"...#kkkkkk#b#kkkkkk#i#llllll#jj###m##g#cc#......", +"...#knnkkk#b#kkkkkk#i#llllll#jj#mm#c#g#cc#......", +"...#knnkkk#b#kkkkkk#i#llllll#jj###cc#g#c#.......", +"...#kkkkkk#b#kkkkkk#i#llllll#j#dd#cc#g####......", +"...#kkkkkk###kkkkkk###llllll####d#cc###g##......", +"...########g########g########o##d#cc#gg#c#......", +"....#gggggg#b#gggggg#b#oooooo#c#d#cc###cc#......", +"...########b########b########cc#d#c#gg#cc#......", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc#d####g#cc#......", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc###g##g#cc#......", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc#gg#c#g#cc#......", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc###cc#g#c#.......", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#c#gg#cc#g##........", +"...#kkkkkk###kkkkkk###kkkkkk####g#cc###.........", +"...########g########g########g##g#cc#...........", +"....#gggggg#b#gggggg#b#gggggg#c#g#cc#...........", +"...########b########b########cc#g#c#............", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc#g##.............", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc###..............", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc#................", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#cc#................", +"...#kkkkkk#b#kkkkkk#b#kkkkkk#c#.................", +"...#kkkkkk###kkkkkk###kkkkkk##..................", +"...########.########.########...................", +"................................................", +"................................................", +"................................................", +"................................................"}; + +//============================================================================================================================== +/*! + * LightApp_ModuleDlg::LightApp_ModuleDlg \n + * + * Constructor. + */ +//============================================================================================================================== +LightApp_ModuleDlg::LightApp_ModuleDlg ( QWidget * parent, const QString& component, const QPixmap icon ) + : QDialog ( parent, "ActivateModuleDlg", true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu ) +{ + QPixmap defaultIcon( ( const char** ) default_icon ); + setCaption( tr( "CAPTION" ) ); + setSizeGripEnabled( TRUE ); + + QGridLayout* ActivateModuleDlgLayout = new QGridLayout( this ); + ActivateModuleDlgLayout->setMargin( 11 ); ActivateModuleDlgLayout->setSpacing( 6 ); + + // Module's name and icon + myComponentFrame = new QFrame( this, "myComponentFrame" ); + myComponentFrame->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ) ); + myComponentFrame->setMinimumHeight( 100 ); + myComponentFrame->setFrameStyle( QFrame::Box | QFrame::Sunken ); + + QGridLayout* myComponentFrameLayout = new QGridLayout( myComponentFrame ); + myComponentFrameLayout->setMargin( 11 ); myComponentFrameLayout->setSpacing( 6 ); + + // --> icon + myComponentIcon = new QLabel( myComponentFrame, "myComponentIcon" ); + myComponentIcon->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + myComponentIcon->setPixmap( !icon.isNull() ? icon : defaultIcon ); + myComponentIcon->setScaledContents( false ); + myComponentIcon->setAlignment( AlignCenter ); + // --> name + myComponentLab = new QLabel( component, myComponentFrame, "myComponentLab" ); + QFont fnt = myComponentLab->font(); fnt.setBold( TRUE ); myComponentLab->setFont( fnt ); + myComponentLab->setAlignment( AlignCenter ); + + myComponentFrameLayout->addWidget( myComponentIcon, 0, 0 ); + myComponentFrameLayout->addWidget( myComponentLab, 0, 1 ); + + // Info + QVBoxLayout* infoLayout = new QVBoxLayout(); + infoLayout->setMargin( 0 ); infoLayout->setSpacing( 6 ); + + // --> top line + QFrame* myLine1 = new QFrame( this, "myLine1" ); + myLine1->setFrameStyle( QFrame::HLine | QFrame::Plain ); + // --> info label + myInfoLabel = new QLabel( tr ("ActivateComponent_DESCRIPTION"), this, "myInfoLabel" ); + myInfoLabel->setAlignment( AlignCenter ); + // --> bottom line + QFrame* myLine2 = new QFrame( this, "myLine2" ); + myLine2->setFrameStyle( QFrame::HLine | QFrame::Plain ); + + infoLayout->addStretch(); + infoLayout->addWidget( myLine1 ); + infoLayout->addWidget( myInfoLabel ); + infoLayout->addWidget( myLine2 ); + infoLayout->addStretch(); + + // Buttons + QHBoxLayout* btnLayout = new QHBoxLayout(); + btnLayout->setMargin( 0 ); btnLayout->setSpacing( 6 ); + + // --> New + myNewBtn = new QPushButton( tr( "NEW" ), this, "myNewBtn" ); + myNewBtn->setDefault( true ); myNewBtn->setAutoDefault( true ); + // --> Open + myOpenBtn = new QPushButton( tr( "OPEN" ), this, "myOpenBtn" ); + myOpenBtn->setAutoDefault( true ); + // --> Load + myLoadBtn = new QPushButton( tr( "LOAD" ), this, "myLoadBtn" ); + myLoadBtn->setAutoDefault( true ); + // --> Cancel + myCancelBtn = new QPushButton( tr( "CANCEL" ), this, "myCancelBtn" ); + myCancelBtn->setAutoDefault( true ); + + btnLayout->addWidget( myNewBtn ); + btnLayout->addWidget( myOpenBtn ); + btnLayout->addWidget( myLoadBtn ); + btnLayout->addStretch(); + btnLayout->addSpacing( 70 ); + btnLayout->addStretch(); + btnLayout->addWidget( myCancelBtn ); + + ActivateModuleDlgLayout->addWidget( myComponentFrame, 0, 0 ); + ActivateModuleDlgLayout->addLayout( infoLayout, 0, 1 ); + ActivateModuleDlgLayout->addMultiCellLayout( btnLayout, 1, 1, 0, 1 ); + + // signals and slots connections + connect( myNewBtn, SIGNAL( clicked() ), this, SLOT( onButtonClicked() ) ); + connect( myOpenBtn, SIGNAL( clicked() ), this, SLOT( onButtonClicked() ) ); + connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( onButtonClicked() ) ); + connect( myCancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); +} + +//============================================================================================================================== +/*! + * LightApp_ModuleDlg::onButtonClicked + * + * Buttons slot + */ +//============================================================================================================================== +void LightApp_ModuleDlg::onButtonClicked() +{ + QPushButton* btn = ( QPushButton* )sender(); + if ( btn == myNewBtn ) + done( 1 ); + if ( btn == myOpenBtn ) + done( 2 ); + if ( btn == myLoadBtn ) + done( 3 ); +} diff --git a/src/LightApp/LightApp_ModuleDlg.h b/src/LightApp/LightApp_ModuleDlg.h new file mode 100644 index 000000000..526f16f22 --- /dev/null +++ b/src/LightApp/LightApp_ModuleDlg.h @@ -0,0 +1,45 @@ +// SALOME SALOMEGUI : implementation of desktop and GUI kernel +// +// Copyright (C) 2005 CEA/DEN, EDF R&D +// +// +// +// File : LightApp_ModuleDlg.h +// Author : Michael ZORIN (mzn) +// Module : SALOME + +#ifndef LIGHTAPP_MODULEDLG_H +#define LIGHTAPP_MODULEDLG_H + +#include "LightApp.h" +#include +#include + +class QFrame; +class QLabel; +class QPushButton; + +class LIGHTAPP_EXPORT LightApp_ModuleDlg : public QDialog +{ + Q_OBJECT + +public: + LightApp_ModuleDlg ( QWidget* parent, const QString& component, const QPixmap icon = QPixmap() ) ; + ~LightApp_ModuleDlg ( ) { }; + +private slots: + void onButtonClicked(); + +private: + QFrame* myComponentFrame; + QLabel* myComponentLab; + QLabel* myComponentIcon; + QLabel* myInfoLabel; + QPushButton* myNewBtn; + QPushButton* myOpenBtn; + QPushButton* myLoadBtn; + QPushButton* myCancelBtn; +}; + +#endif + diff --git a/src/LightApp/LightApp_NameDlg.cxx b/src/LightApp/LightApp_NameDlg.cxx new file mode 100644 index 000000000..daa4e31cf --- /dev/null +++ b/src/LightApp/LightApp_NameDlg.cxx @@ -0,0 +1,128 @@ +// File : LightApp_NameDlg.cxx +// Author : Vadim SANDLER +// $Header$ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef WIN32 +using namespace std; +#endif + +/*! + Constructor +*/ +LightApp_NameDlg::LightApp_NameDlg( QWidget* parent ) +: QDialog( parent ? parent : NULL,//application()->desktop(), +"LightApp_NameDlg", +true, +WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu ) +{ + setCaption( tr("TLT_RENAME") ); + setSizeGripEnabled( TRUE ); + + QVBoxLayout* topLayout = new QVBoxLayout( this ); + topLayout->setMargin( 11 ); topLayout->setSpacing( 6 ); + + /***************************************************************/ + QGroupBox* GroupC1 = new QGroupBox( this, "GroupC1" ); + GroupC1->setColumnLayout(0, Qt::Vertical ); + GroupC1->layout()->setMargin( 0 ); GroupC1->layout()->setSpacing( 0 ); + QHBoxLayout* GroupC1Layout = new QHBoxLayout( GroupC1->layout() ); + GroupC1Layout->setAlignment( Qt::AlignTop ); + GroupC1Layout->setMargin( 11 ); GroupC1Layout->setSpacing( 6 ); + + QLabel* TextLabel = new QLabel( GroupC1, "TextLabel1" ); + TextLabel->setText( tr( "NAME_LBL" ) ); + GroupC1Layout->addWidget( TextLabel ); + + myLineEdit = new QLineEdit( GroupC1, "LineEdit1" ); + myLineEdit->setMinimumSize( 250, 0 ); + GroupC1Layout->addWidget( myLineEdit ); + + /***************************************************************/ + QGroupBox* GroupButtons = new QGroupBox( this, "GroupButtons" ); + GroupButtons->setColumnLayout(0, Qt::Vertical ); + GroupButtons->layout()->setMargin( 0 ); GroupButtons->layout()->setSpacing( 0 ); + QHBoxLayout* GroupButtonsLayout = new QHBoxLayout( GroupButtons->layout() ); + GroupButtonsLayout->setAlignment( Qt::AlignTop ); + GroupButtonsLayout->setMargin( 11 ); GroupButtonsLayout->setSpacing( 6 ); + + myButtonOk = new QPushButton( GroupButtons, "buttonOk" ); + myButtonOk->setText( tr( "BUT_OK" ) ); + myButtonOk->setAutoDefault( TRUE ); myButtonOk->setDefault( TRUE ); + GroupButtonsLayout->addWidget( myButtonOk ); + + GroupButtonsLayout->addStretch(); + + myButtonCancel = new QPushButton( GroupButtons, "buttonCancel" ); + myButtonCancel->setText( tr( "BUT_CANCEL" ) ); + myButtonCancel->setAutoDefault( TRUE ); + GroupButtonsLayout->addWidget( myButtonCancel ); + /***************************************************************/ + + topLayout->addWidget( GroupC1 ); + topLayout->addWidget( GroupButtons ); + + // signals and slots connections + connect( myButtonOk, SIGNAL( clicked() ), this, SLOT( accept() ) ); + connect( myButtonCancel, SIGNAL( clicked() ), this, SLOT( reject() ) ); + + /* Move widget on the botton right corner of main widget */ + SUIT_Tools::centerWidget( this, parent ); +} + +/*! + Destructor +*/ +LightApp_NameDlg::~LightApp_NameDlg() +{ +} + +/*! + Sets name +*/ +void LightApp_NameDlg::setName( const QString& name ) +{ + myLineEdit->setText( name ); + myLineEdit->end(false); + myLineEdit->home(true); +} + +/*! + Returns name entered by user +*/ +QString LightApp_NameDlg::name() +{ + return myLineEdit->text(); +} + +void LightApp_NameDlg::accept() +{ + if ( name().stripWhiteSpace().isEmpty() ) + return; + QDialog::accept(); +} + +/*! + Creates modal dialog and returns name entered [ static ] +*/ +QString LightApp_NameDlg::getName( QWidget* parent, const QString& oldName ) +{ + QString n; + LightApp_NameDlg* dlg = new LightApp_NameDlg( parent ); + if ( !oldName.isNull() ) + dlg->setName( oldName ); + if ( dlg->exec() == QDialog::Accepted ) + n = dlg->name(); + delete dlg; + return n; +} diff --git a/src/LightApp/LightApp_NameDlg.h b/src/LightApp/LightApp_NameDlg.h new file mode 100644 index 000000000..c0309c0f2 --- /dev/null +++ b/src/LightApp/LightApp_NameDlg.h @@ -0,0 +1,47 @@ +// SALOME SalomeApp : implementation of desktop and GUI kernel +// +// Copyright (C) 2003 CEA/DEN, EDF R&D +// +// +// +// File : LightApp_NameDlg.h +// Author : Vadim SANDLER +// Module : SALOME +// $Header$ + +#ifndef LIGHTAPP_NAMEDLG_H +#define LIGHTAPP_NAMEDLG_H + +#include "LightApp.h" +#include + +class QLineEdit; +class QPushButton; + +//================================================================================= +// class : LightApp_NameDlg +/*! purpose : Common dialog box class*/ +//================================================================================= +class LIGHTAPP_EXPORT LightApp_NameDlg : public QDialog +{ + Q_OBJECT + +public: + LightApp_NameDlg( QWidget* parent = 0 ); + ~LightApp_NameDlg(); + + void setName( const QString& name ); + QString name(); + + static QString getName( QWidget* parent = 0, const QString& oldName = QString::null ); + +protected slots: + void accept(); + +private: + QPushButton* myButtonOk; + QPushButton* myButtonCancel; + QLineEdit* myLineEdit; +}; + +#endif // LightApp_NAMEDLG_H diff --git a/src/LightApp/LightApp_OBFilter.cxx b/src/LightApp/LightApp_OBFilter.cxx new file mode 100644 index 000000000..489ec3428 --- /dev/null +++ b/src/LightApp/LightApp_OBFilter.cxx @@ -0,0 +1,29 @@ +#include "LightApp_OBFilter.h" + +#include "LightApp_SelectionMgr.h" +#include "LightApp_DataObject.h" +#include "LightApp_DataOwner.h" + +/*! + Constructor. +*/ +LightApp_OBFilter::LightApp_OBFilter( LightApp_SelectionMgr* theSelMgr ) +{ + mySelMgr = theSelMgr; +} + +/*!Destructor.*/ +LightApp_OBFilter::~LightApp_OBFilter() +{ +} + +/*!Checks: data object is ok?*/ +bool LightApp_OBFilter::isOk( const SUIT_DataObject* theDataObj ) const +{ + const LightApp_DataObject* obj = dynamic_cast( theDataObj ); + if ( obj ) + return mySelMgr->isOk( new LightApp_DataOwner( obj->entry() ) ); + + return true; +} + diff --git a/src/LightApp/LightApp_OBFilter.h b/src/LightApp/LightApp_OBFilter.h new file mode 100644 index 000000000..21a8b674a --- /dev/null +++ b/src/LightApp/LightApp_OBFilter.h @@ -0,0 +1,22 @@ +#ifndef LIGHTAPP_OBFILTER_H +#define LIGHTAPP_OBFILTER_H + +#include "LightApp.h" +#include "OB_Filter.h" + +class LightApp_SelectionMgr; + +class LIGHTAPP_EXPORT LightApp_OBFilter: public OB_Filter +{ +public: + LightApp_OBFilter( LightApp_SelectionMgr* theSelMgr ); + ~LightApp_OBFilter(); + + virtual bool isOk( const SUIT_DataObject* ) const; + +private: + LightApp_SelectionMgr* mySelMgr; + +}; + +#endif diff --git a/src/LightApp/LightApp_OBSelector.cxx b/src/LightApp/LightApp_OBSelector.cxx new file mode 100644 index 000000000..3129b240e --- /dev/null +++ b/src/LightApp/LightApp_OBSelector.cxx @@ -0,0 +1,101 @@ +#include "LightApp_OBSelector.h" + +#include "LightApp_DataOwner.h" +#include "LightApp_DataObject.h" + +#include + +#include + +/*! + Constructor +*/ +LightApp_OBSelector::LightApp_OBSelector( OB_Browser* ob, SUIT_SelectionMgr* mgr ) +: SUIT_Selector( mgr, ob ), + myBrowser( ob ) +{ + if ( myBrowser ) { + connect( myBrowser, SIGNAL( selectionChanged() ), this, SLOT( onSelectionChanged() ) ); + } +} + +/*! + Destructor +*/ +LightApp_OBSelector::~LightApp_OBSelector() +{ +} + +/*! + Gets browser. +*/ +OB_Browser* LightApp_OBSelector::browser() const +{ + return myBrowser; +} + +/*! + Gets selection. +*/ +void LightApp_OBSelector::getSelection( SUIT_DataOwnerPtrList& theList ) const +{ + if ( !myBrowser ) + return; + + DataObjectList objlist; + myBrowser->getSelected( objlist ); + for ( DataObjectListIterator it( objlist ); it.current(); ++it ) + { + LightApp_DataObject* obj = dynamic_cast( it.current() ); + if ( obj ) + { + Handle( SALOME_InteractiveObject ) aSObj = new SALOME_InteractiveObject + ( obj->entry(), obj->componentDataType(), obj->name() ); + LightApp_DataOwner* owner = new LightApp_DataOwner( aSObj ); + theList.append( SUIT_DataOwnerPtr( owner ) ); + } + } +} + +/*!Sets selection.*/ +void LightApp_OBSelector::setSelection( const SUIT_DataOwnerPtrList& theList ) +{ + if ( !myBrowser ) + return; + + QMap themap; + fillEntries( themap ); + + DataObjectList objList; + for ( SUIT_DataOwnerPtrList::const_iterator it = theList.begin(); it != theList.end(); ++it ) + { + const LightApp_DataOwner* owner = dynamic_cast( (*it).operator->() ); + if ( owner && themap.contains( owner->entry() ) ) + objList.append( themap[owner->entry()] ); + } + + myBrowser->setSelected( objList ); +} + +/*!On selection changed.*/ +void LightApp_OBSelector::onSelectionChanged() +{ + selectionChanged(); +} + +/*!Fill entries.*/ +void LightApp_OBSelector::fillEntries( QMap& entires ) +{ + entires.clear(); + + if ( !myBrowser ) + return; + + for ( SUIT_DataObjectIterator it( myBrowser->getRootObject(), + SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) + { + LightApp_DataObject* obj = dynamic_cast( it.current() ); + if ( obj ) + entires.insert( obj->entry(), obj ); + } +} diff --git a/src/LightApp/LightApp_OBSelector.h b/src/LightApp/LightApp_OBSelector.h new file mode 100644 index 000000000..22e4eae50 --- /dev/null +++ b/src/LightApp/LightApp_OBSelector.h @@ -0,0 +1,38 @@ +#ifndef LIGHTAPP_OBSELECTOR_H +#define LIGHTAPP_OBSELECTOR_H + +#include "LightApp.h" + +#include + +class OB_Browser; +class LightApp_DataObject; + +class LIGHTAPP_EXPORT LightApp_OBSelector : public SUIT_Selector +{ + Q_OBJECT + +public: + LightApp_OBSelector( OB_Browser*, SUIT_SelectionMgr* ); + virtual ~LightApp_OBSelector(); + + OB_Browser* browser() const; + + /*!Return "ObjectBrowser"*/ + virtual QString type() const { return "ObjectBrowser"; } + +private slots: + void onSelectionChanged(); + +protected: + virtual void getSelection( SUIT_DataOwnerPtrList& ) const; + virtual void setSelection( const SUIT_DataOwnerPtrList& ); + +private: + void fillEntries( QMap& ); + +private: + OB_Browser* myBrowser; +}; + +#endif diff --git a/src/LightApp/LightApp_OCCSelector.cxx b/src/LightApp/LightApp_OCCSelector.cxx new file mode 100644 index 000000000..45b26585a --- /dev/null +++ b/src/LightApp/LightApp_OCCSelector.cxx @@ -0,0 +1,103 @@ + +#include "LightApp_DataOwner.h" +#include "LightApp_OCCSelector.h" + +#include + +#include +#include + +/*! + Constructor +*/ +LightApp_OCCSelector::LightApp_OCCSelector( OCCViewer_Viewer* viewer, SUIT_SelectionMgr* mgr ) +: SUIT_Selector( mgr, viewer ), + myViewer( viewer ) +{ + if ( myViewer ) + connect( myViewer, SIGNAL( selectionChanged() ), this, SLOT( onSelectionChanged() ) ); +} + +/*! + Destructor. +*/ +LightApp_OCCSelector::~LightApp_OCCSelector() +{ +} + +/*! + Gets viewer. +*/ +OCCViewer_Viewer* LightApp_OCCSelector::viewer() const +{ + return myViewer; +} + +/*!On selection changed.*/ +void LightApp_OCCSelector::onSelectionChanged() +{ + selectionChanged(); +} + +/*!Gets selection list.*/ +void LightApp_OCCSelector::getSelection( SUIT_DataOwnerPtrList& aList ) const +{ + if ( !myViewer ) + return; + + AIS_ListOfInteractive aSelList; + myViewer->getSelectedObjects( aSelList ); + for ( AIS_ListIteratorOfListOfInteractive anIt( aSelList ); anIt.More(); anIt.Next() ) + if ( !anIt.Value().IsNull() ) + { + Handle(SALOME_InteractiveObject) anObj = Handle(SALOME_InteractiveObject)::DownCast(anIt.Value()->GetOwner()); + if( !anObj.IsNull() ) + aList.append( SUIT_DataOwnerPtr( new LightApp_DataOwner( anObj ) ) ); + } +} + +/*!Sets selection list.*/ +void LightApp_OCCSelector::setSelection( const SUIT_DataOwnerPtrList& aList ) +{ + if ( !myViewer ) + return; + + QMap aDisplayed; + Handle(AIS_InteractiveContext) aContext = myViewer->getAISContext(); + if ( aContext.IsNull() ) + return; + + AIS_ListOfInteractive aDispList, aSelList; + aContext->DisplayedObjects( aDispList ); + + for ( AIS_ListIteratorOfListOfInteractive it( aDispList ); it.More(); it.Next() ) + { + QString entryStr = entry( it.Value() ); + if ( !entryStr.isEmpty() ) + aDisplayed.insert( entryStr, it.Value() ); + } + + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataOwner* owner = dynamic_cast( (*itr).operator->() ); + if ( owner && aDisplayed.contains( owner->entry() ) ) + aSelList.Append( aDisplayed[owner->entry()] ); + } + + myViewer->unHighlightAll( false ); + myViewer->setObjectsSelected( aSelList ); +} + +/*!Gets entry ob object.*/ +QString LightApp_OCCSelector::entry( const Handle(AIS_InteractiveObject)& anAIS ) const +{ + if ( anAIS.IsNull() || !anAIS->HasOwner() ) + return QString::null; + + Handle(SALOME_InteractiveObject) anObj = Handle(SALOME_InteractiveObject)::DownCast(anAIS->GetOwner()); + + QString res; + if ( !anObj.IsNull() ) + res = QString( anObj->getEntry() ); + return res; +} diff --git a/src/LightApp/LightApp_OCCSelector.h b/src/LightApp/LightApp_OCCSelector.h new file mode 100644 index 000000000..1d00cd0f4 --- /dev/null +++ b/src/LightApp/LightApp_OCCSelector.h @@ -0,0 +1,37 @@ +#ifndef LIGHTAPP_OCCSELECTOR_H +#define LIGHTAPP_OCCSELECTOR_H + +#include "LightApp.h" + +#include + +#include + +class Handle_AIS_InteractiveObject; + +class LIGHTAPP_EXPORT LightApp_OCCSelector : public SUIT_Selector +{ + Q_OBJECT + +public: + LightApp_OCCSelector( OCCViewer_Viewer*, SUIT_SelectionMgr* ); + virtual ~LightApp_OCCSelector(); + + OCCViewer_Viewer* viewer() const; + + virtual QString type() const { return OCCViewer_Viewer::Type(); } + +private slots: + virtual void onSelectionChanged(); + +protected: + virtual void getSelection( SUIT_DataOwnerPtrList& ) const; + virtual void setSelection( const SUIT_DataOwnerPtrList& ); + + QString entry( const Handle_AIS_InteractiveObject& ) const; + +private: + OCCViewer_Viewer* myViewer; +}; + +#endif diff --git a/src/LightApp/LightApp_Operation.cxx b/src/LightApp/LightApp_Operation.cxx new file mode 100755 index 000000000..197eb93ee --- /dev/null +++ b/src/LightApp/LightApp_Operation.cxx @@ -0,0 +1,290 @@ +// LIGHT LightApp +// +// Copyright (C) 2005 CEA/DEN, EDF R&D +// +// +// +// File : LightApp_Operation.h +// Author : Sergey LITONIN +// Module : LIGHT + +#include +#include +#include +#include +#include +#include + +#include + +#include + + +/*! + * \brief Constructor +* +* Constructor sets myModule in NULL and myIsAutoResumed in TRUE +*/ +LightApp_Operation::LightApp_Operation() +: SUIT_Operation( 0 ), + myModule( 0 ), + myIsAutoResumed( true ) +{ +} + +/*! + * \brief Destructor +* +* Destructor does nothing +*/ +LightApp_Operation::~LightApp_Operation() +{ + +} + +/*! + * \brief Gets module of operation + * \return Pointer to the module +* +* Gets pointer to the module or NULL if module was not set. It is strongly recomended to +* set valid pointer on the module before start of operation +*/ +LightApp_Module* LightApp_Operation::module() const +{ + return myModule; +} + + +/*! + * \brief Sets module of operation + * \param theModule - module to be set +* +* Sets pointer to the module. It is strongly recomended to set valid pointer on the +* module before start of operation +*/ +void LightApp_Operation::setModule( LightApp_Module* theModule ) +{ + myModule = theModule; + setApplication( myModule ? myModule->application() : 0 ); + setStudy( application() ? application()->activeStudy() : 0 ); +} + +/*! + * \brief Gets desktop of operation + * \return Pointer to the desktop +* +* Gets pointer to the desktop or NULL if application was not set. It is strongly recomended +* to set valid pointer on the application before start of operation +*/ +SUIT_Desktop* LightApp_Operation::desktop() const +{ + return application() != 0 ? application()->desktop() : 0; +} + +/*! + * \brief Enable dialog of operation +* +* Virtual method redefined from the base class. Enable dialog if it was desabled (in +* suspend method) and activate selection +*/ +void LightApp_Operation::resumeOperation() +{ + SUIT_Operation::resumeOperation(); + setDialogActive( true ); +} + +/*! + * \brief Performs actions needed for starting operation +* +* Virtual method redefined from the base class. Connect signal of selection manager to +* onSelectionDone() slot +*/ +void LightApp_Operation::startOperation() +{ + if( selectionMgr() ) + connect( selectionMgr(), SIGNAL( selectionChanged() ), SLOT( onSelectionDone() ) ); + + //If suspended operation was stopped during starting other operation, + //the dialog is inactive now, We must activate it + setDialogActive( true ); +} + +/*! + * \brief Performs actions needed for suspending operation +* +* Virtual method redefined from the base class. This implementation calls corresponding +* method of base class and cals setDialogActive( false ) +*/ +void LightApp_Operation::suspendOperation() +{ + SUIT_Operation::suspendOperation(); + setDialogActive( false ); +} + +//======================================================================= +// name : abortOperation +// Purpose : Hide dialog box (if it is exists) +//======================================================================= +/*! + * \brief Performs actions needed for aborting operation +* +* Virtual method redefined from the base class calls corresponding method of base class +* and hides dialog box (if it is exists), disconnect slots from selection manager +*/ +void LightApp_Operation::abortOperation() +{ + SUIT_Operation::abortOperation(); + setDialogActive( true ); + if ( dlg() ) + dlg()->hide(); + + if( selectionMgr() ) + disconnect( selectionMgr(), SIGNAL( selectionChanged() ), this, SLOT( onSelectionDone() ) ); +} + +/*! + * \brief Performs actions needed for committing operation +* +* Virtual method redefined from the base class calls corresponding method of base class +* and hides dialog box (if it is exists), disconnect slots from selection manager +*/ +void LightApp_Operation::commitOperation() +{ + SUIT_Operation::commitOperation(); + setDialogActive( true ); + if ( dlg() ) + dlg()->hide(); + + if( selectionMgr() ) + disconnect( selectionMgr(), SIGNAL( selectionChanged() ), this, SLOT( onSelectionDone() ) ); +} + +/*! + * \brief Gets dialog + * \return Pointer to the dialog of this operation or NULL if it does not exist +* +* This method should be redefined in derived classes if they use dialogs. If this +* function returns pointer to dialog then dialog will be correctly +* -# deactivated in suspendOperation method +* -# activated in resumeOperation method +* -# hidden in abortOperation and commitOperation methods +*/ +LightApp_Dialog* LightApp_Operation::dlg() const +{ + return 0; +} + +/*! + * \brief Activates selection +* +* Virtual method should be redefined in derived classes if they use own selection modes +* (different from default) +*/ +void LightApp_Operation::activateSelection() +{ +} + +/*! + * \brief Virtual method called when selection is changed +* +* Virtual method should be redefined in derived classes if they works with selection +* to provide reaction on the change of selection +*/ +void LightApp_Operation::selectionDone() +{ +} + +/*! + * \brief Gets active operation +* +* This method provided for convinience calls SUIT_Study::activeOperation() one +*/ +SUIT_Operation* LightApp_Operation::activeOperation() const +{ + return study() != 0 ? study()->activeOperation() : 0; +} + +/*! + * \brief Gets selection manager +* +* This method provided for convinience calls LightApp_Application::selectionMgr() one +*/ +LightApp_SelectionMgr* LightApp_Operation::selectionMgr() const +{ + SUIT_Application* app = application(); + if ( app != 0 && app->inherits( "LightApp_Application" ) ) + return ( (LightApp_Application*)app )->selectionMgr(); + else + return 0; +} + +/*! + * \brief Call selectionDone() method +* +* Call selectionDone() method if operator is an active one (see selectionDone() for more +* description ) +*/ +void LightApp_Operation::onSelectionDone() +{ + if ( isActive() ) + selectionDone(); +} + +/*! + * \brief Update object browser or/and viewer etc. + * \param flags - update flags +* +* This method provided for convinience calls LightApp_Module::update() one (see +* LightApp_Module::update() for more description) +*/ +void LightApp_Operation::update( const int flags ) +{ + if ( myModule != 0 ) + myModule->update( flags ); +} + +/*! + * \brief Activate/Deactivate dialog of operation + * \param active - State of the dialog to be set +* +* Activate/Deactivate dialog of operation. This method called from startOperation(), +* suspendOperation() ones and so on +*/ +void LightApp_Operation::setDialogActive( const bool active ) +{ + if( dlg() ) + { + if( active ) + { + activateSelection(); + dlg()->setActiveWindow(); + } + } +} + +/*! + * \brief Gets autoresume property + * \return Autoresume property. +* +* Autoresume property is used during automatic resuming operation. If operation is +* suspended and cursor is moved above dialog of the operation then operation is resumed +* automatically (if possible). It can be resumed only program call otherwise (see +* LightApp_SwitchOp for more description). This property is TRUE by default and may be +* changed with setAutoResumed() method call. +*/ +bool LightApp_Operation::isAutoResumed() const +{ + return myIsAutoResumed; +} + +/*! + * \brief Sets autoresume property + * \param on - Value to be set + * \return Autoresume property. +* +* Sets autoresume property (see isAutoResumed() for more description) +*/ +void LightApp_Operation::setAutoResumed( const bool on ) +{ + myIsAutoResumed = on; +} diff --git a/src/LightApp/LightApp_Operation.h b/src/LightApp/LightApp_Operation.h new file mode 100755 index 000000000..4b07bd7b2 --- /dev/null +++ b/src/LightApp/LightApp_Operation.h @@ -0,0 +1,91 @@ +// LIGHT LightApp +// +// Copyright (C) 2005 CEA/DEN, EDF R&D +// +// +// +// File : LightApp_Operation.h +// Author : Sergey LITONIN +// Module : LIGHT + + +#ifndef LightApp_Operation_H +#define LightApp_Operation_H + +#include "LightApp.h" +#include + +class LightApp_Module; +class LightApp_Application; +class LightApp_Operation; +class LightApp_SelectionMgr; +class LightApp_Dialog; +class SUIT_Desktop; + +/* + Class : LightApp_Operation + Description : Base class for all operations +*/ + +/*! + * \brief Base class for all operations + * + * Base class for all operations (see SUIT_Operation for more description) +*/ +class LIGHTAPP_EXPORT LightApp_Operation : public SUIT_Operation +{ + Q_OBJECT + +public: + LightApp_Operation(); + virtual ~LightApp_Operation(); + + virtual void setModule( LightApp_Module* ); + LightApp_Module* module() const; + + bool isAutoResumed() const; + + virtual LightApp_Dialog* dlg() const; + +protected: + + // Methods redefined from base class + + virtual void startOperation(); + virtual void suspendOperation(); + virtual void resumeOperation(); + virtual void abortOperation(); + virtual void commitOperation(); + + // Additional virtual methods may be redefined by derived classes + + virtual void setDialogActive( const bool ); + virtual void activateSelection(); + virtual void selectionDone(); + + + // Axiluary methods + + SUIT_Desktop* desktop() const; + SUIT_Operation* activeOperation() const; + LightApp_SelectionMgr* selectionMgr() const; + void update( const int ); + void setAutoResumed( const bool ); + +private slots: + + virtual void onSelectionDone(); + +private: + + LightApp_Module* myModule; + bool myIsAutoResumed; +}; + +#endif + + + + + + diff --git a/src/LightApp/LightApp_Preferences.cxx b/src/LightApp/LightApp_Preferences.cxx new file mode 100644 index 000000000..95ea10457 --- /dev/null +++ b/src/LightApp/LightApp_Preferences.cxx @@ -0,0 +1,87 @@ +// File: LightApp_Preferences.cxx +// Author: Sergey TELKOV + +#include "LightApp_Preferences.h" + +#include + +#include + +/*! + Constructor.Initialize by resource manager and parent QWidget. +*/ +LightApp_Preferences::LightApp_Preferences( QtxResourceMgr* resMgr, QWidget* parent ) +: QtxListResourceEdit( resMgr, parent ) +{ +} + +/*! + Destructor. +*/ +LightApp_Preferences::~LightApp_Preferences() +{ +} + +/*! + Adds preference. +*/ +int LightApp_Preferences::addPreference( const QString& label, const int pId, const int type, + const QString& section, const QString& param ) +{ + return addItem( label, pId, type, section, param ); +} + +/*! + Adds preference. +*/ +int LightApp_Preferences::addPreference( const QString& mod, const QString& label, const int pId, + const int type, const QString& section, const QString& param ) +{ + int id = addItem( label, pId, type, section, param ); + if ( id != -1 && !mod.isEmpty() ) + myPrefMod.insert( id, mod ); + return id; +} + +/* + Checks: is preferences has module with name \a mod. +*/ +bool LightApp_Preferences::hasModule( const QString& mod ) const +{ + bool res = false; + for ( PrefModuleMap::ConstIterator it = myPrefMod.begin(); it != myPrefMod.end() && !res; ++it ) + res = it.data() == mod; + return res; +} + +/*!Do nothing.*/ +void LightApp_Preferences::onHelp() +{ +} + +/*!Store preferences on apply.*/ +void LightApp_Preferences::onApply() +{ + store(); +} + +/*!Emit preference changed.*/ +void LightApp_Preferences::changedResources( const QMap& map ) +{ + for ( QMap::ConstIterator it = map.begin(); it != map.end(); ++it ) + { + QString sec, param; + it.key()->resource( sec, param ); + QString mod = module( it.key()->id() ); + emit preferenceChanged( mod, sec, param ); + } +} + +/*!Gets module name by \a id, if exist.*/ +QString LightApp_Preferences::module( const int id ) const +{ + QString mod; + if ( myPrefMod.contains( id ) ) + mod = myPrefMod[id]; + return mod; +} diff --git a/src/LightApp/LightApp_Preferences.h b/src/LightApp/LightApp_Preferences.h new file mode 100644 index 000000000..75655e1ec --- /dev/null +++ b/src/LightApp/LightApp_Preferences.h @@ -0,0 +1,49 @@ +// File: LightApp_Preferences.h +// Author: Sergey TELKOV + +#ifndef LIGHTAPP_PREFERENCES_H +#define LIGHTAPP_PREFERENCES_H + +#include + +#include +#include + +#include + +class QtxResourceMgr; + +class LIGHTAPP_EXPORT LightApp_Preferences : public QtxListResourceEdit +{ + Q_OBJECT + +public: + LightApp_Preferences( QtxResourceMgr*, QWidget* = 0 ); + virtual ~LightApp_Preferences(); + + int addPreference( const QString& label, const int pId = -1, const int = -1, + const QString& section = QString::null, const QString& param = QString::null ); + int addPreference( const QString& modName, const QString& label, const int pId = -1, const int = -1, + const QString& section = QString::null, const QString& param = QString::null ); + + bool hasModule( const QString& ) const; + +signals: + void preferenceChanged( QString&, QString&, QString& ); + +private slots: + void onHelp(); + void onApply(); + virtual void changedResources( const QMap& ); + +private: + QString module( const int ) const; + +private: + typedef QMap PrefModuleMap; + +private: + PrefModuleMap myPrefMod; +}; + +#endif diff --git a/src/LightApp/LightApp_PreferencesDlg.cxx b/src/LightApp/LightApp_PreferencesDlg.cxx new file mode 100644 index 000000000..12815c4a5 --- /dev/null +++ b/src/LightApp/LightApp_PreferencesDlg.cxx @@ -0,0 +1,84 @@ +// File: LightApp_PreferencesDlg.cxx +// Author: Sergey TELKOV + +#include "LightApp_PreferencesDlg.h" + +#include "LightApp_Preferences.h" + +#include +#include + +/*! + Constructor. +*/ +LightApp_PreferencesDlg::LightApp_PreferencesDlg( LightApp_Preferences* prefs, QWidget* parent ) +: QtxDialog( parent, 0, true, false, OK | Close | Apply ), +myPrefs( prefs ) +{ + setCaption( tr( "CAPTION" ) ); + + QVBoxLayout* main = new QVBoxLayout( mainFrame(), 5 ); + + QVBox* base = new QVBox( mainFrame() ); + main->addWidget( base ); + + myPrefs->reparent( base, QPoint( 0, 0 ), true ); + + setFocusProxy( myPrefs ); + + setButtonPosition( Right, Close ); + + setDialogFlags( AlignOnce ); + + connect( this, SIGNAL( dlgHelp() ), this, SLOT( onHelp() ) ); + connect( this, SIGNAL( dlgApply() ), this, SLOT( onApply() ) ); +} + +/*! + Destructor. +*/ +LightApp_PreferencesDlg::~LightApp_PreferencesDlg() +{ + if ( !myPrefs ) + return; + + myPrefs->reparent( 0, QPoint( 0, 0 ), false ); + myPrefs = 0; +} + +/*!Show dialog.*/ +void LightApp_PreferencesDlg::show() +{ + myPrefs->retrieve(); + myPrefs->toBackup(); + + QtxDialog::show(); +} + +/*!Store preferences on accept.*/ +void LightApp_PreferencesDlg::accept() +{ + QtxDialog::accept(); + + myPrefs->store(); +} + +/*!Reject. Restore preferences from backup.*/ +void LightApp_PreferencesDlg::reject() +{ + QtxDialog::reject(); + + myPrefs->fromBackup(); +} + +/*!Do nothing.*/ +void LightApp_PreferencesDlg::onHelp() +{ +} + +/*!Store preferences on apply.*/ +void LightApp_PreferencesDlg::onApply() +{ + myPrefs->store(); + myPrefs->toBackup(); +} diff --git a/src/LightApp/LightApp_PreferencesDlg.h b/src/LightApp/LightApp_PreferencesDlg.h new file mode 100644 index 000000000..9ccaafd35 --- /dev/null +++ b/src/LightApp/LightApp_PreferencesDlg.h @@ -0,0 +1,33 @@ +// File: LightApp_PreferencesDlg.h +// Author: Sergey TELKOV + +#ifndef LIGHTAPP_PREFERENCESDLG_H +#define LIGHTAPP_PREFERENCESDLG_H + +#include + +#include + +class LightApp_Preferences; + +class LIGHTAPP_EXPORT LightApp_PreferencesDlg : public QtxDialog +{ + Q_OBJECT + +public: + LightApp_PreferencesDlg( LightApp_Preferences*, QWidget* = 0 ); + virtual ~LightApp_PreferencesDlg(); + + virtual void show(); + virtual void accept(); + virtual void reject(); + +private slots: + void onHelp(); + void onApply(); + +private: + LightApp_Preferences* myPrefs; +}; + +#endif diff --git a/src/LightApp/LightApp_RootObject.h b/src/LightApp/LightApp_RootObject.h new file mode 100644 index 000000000..38ca460f9 --- /dev/null +++ b/src/LightApp/LightApp_RootObject.h @@ -0,0 +1,33 @@ +#ifndef LIGHTAPP_ROOTOBJECT_H +#define LIGHTAPP_ROOTOBJECT_H + +#include "LightApp.h" +#include "SUIT_DataObject.h" + +class LightApp_Study; + +/*! + LightApp_RootObject - class to be instanciated by only one object - + root object of LightApp data object tree. This object is not shown + in object browser (invisible), so it has no re-definition of name(), icon(), + etc. methods. The goal of this class is to provide a unified access + to LightApp_Study object from LightApp_DataObject instances. +*/ +class LIGHTAPP_EXPORT LightApp_RootObject : public SUIT_DataObject +{ +public: + LightApp_RootObject( LightApp_Study* study ) + : myStudy( study ) + {} + + virtual ~LightApp_RootObject() {} + + void setStudy( LightApp_Study* study ) { myStudy = study; } + LightApp_Study* study() const { return myStudy; } + +private: + LightApp_Study* myStudy; + +}; + +#endif diff --git a/src/LightApp/LightApp_Selection.cxx b/src/LightApp/LightApp_Selection.cxx new file mode 100644 index 000000000..bf2d2198b --- /dev/null +++ b/src/LightApp/LightApp_Selection.cxx @@ -0,0 +1,177 @@ + +#include "LightApp_Selection.h" +#include "LightApp_SelectionMgr.h" +#include "LightApp_DataOwner.h" +#include "LightApp_Study.h" +#include "LightApp_Application.h" +#include "LightApp_Displayer.h" + +#include "SUIT_Session.h" +#include "SUIT_ViewWindow.h" + +/*! + Constructor +*/ +LightApp_Selection::LightApp_Selection() +: myStudy( 0 ) +{ +} + +/*! + Destructor. +*/ +LightApp_Selection::~LightApp_Selection() +{ +} + +/*! + Initializetion. +*/ +void LightApp_Selection::init( const QString& client, LightApp_SelectionMgr* mgr) +{ + myPopupClient = client; + + if( mgr ) + { + if ( mgr->application() ) + myStudy = dynamic_cast( mgr->application()->activeStudy() ); + if ( !myStudy ) + return; + + SUIT_DataOwnerPtrList sel; + mgr->selected( sel, client ); + SUIT_DataOwnerPtrList::const_iterator anIt = sel.begin(), aLast = sel.end(); + + QString entry, curEntry; + for( ; anIt!=aLast; anIt++ ) + { + SUIT_DataOwner* owner = ( SUIT_DataOwner* )( (*anIt ).get() ); + LightApp_DataOwner* sowner = dynamic_cast( owner ); + if( sowner ) { + curEntry = sowner->entry(); + entry = myStudy->referencedToEntry( curEntry ); + myEntries.append( entry ); + if ( curEntry == entry ) + myIsReferences.append( true ); + else + myIsReferences.append( false ); + processOwner( sowner ); + } + } + } +} + +/*! + Gets count of entries. +*/ +int LightApp_Selection::count() const +{ + return myEntries.count(); +} + +/*! + Gets QtxValue(); +*/ +QtxValue LightApp_Selection::param( const int ind, const QString& p ) const +{ + if( !( ind>=0 && indcomponentDataType( myEntries[ ind ] ); + } + else if( p=="isReference" ) + return QtxValue( isReference( ind ), false ); + + return QtxValue(); +} + +/*! + Gets global parameters. client, isActiveView, activeView etc. +*/ +QtxValue LightApp_Selection::globalParam( const QString& p ) const +{ + if ( p == "client" ) return QtxValue( myPopupClient ); + else if ( p == "activeModule" ) + { + LightApp_Application* app = dynamic_cast( myStudy->application() ); + QString mod_name = app ? QString( app->activeModule()->name() ) : QString::null; + //cout << "activeModule : " << mod_name.latin1() << endl; + if( !mod_name.isEmpty() ) + return mod_name; + else + return QtxValue(); + } + else if ( p == "isActiveView" ) return QtxValue( (bool)activeVW() ); + else if ( p == "activeView" ) return QtxValue( activeViewType() ); +#ifndef WNT + else return QtxPopupMgr::Selection::globalParam( p ); +#else + else return Selection::globalParam( p ); +#endif +} + +/*! + Do nothing. +*/ +void LightApp_Selection::processOwner( const LightApp_DataOwner* ) +{ +} + +/*! + Gets entry with index \a index. +*/ +QString LightApp_Selection::entry( const int index ) const +{ + if ( index >= 0 && index < count() ) + return myEntries[ index ]; + return QString(); +} + +/*! + Returns true if i-th selected object was reference to object with entry( i ) +*/ +bool LightApp_Selection::isReference( const int index ) const +{ + if( index >= 0 && index < count() ) + return myIsReferences[ index ]; + else + return false; +} + +/*! + Gets type of active view manager. +*/ +QString LightApp_Selection::activeViewType() const +{ + SUIT_ViewWindow* win = activeVW(); + if ( win ) { + SUIT_ViewManager* vm = win->getViewManager(); + if ( vm ) + return vm->getType(); + } + return QString::null; +} + +/*! + Gets active view window. +*/ +SUIT_ViewWindow* LightApp_Selection::activeVW() const +{ + SUIT_Session* session = SUIT_Session::session(); + if ( session ) { + SUIT_Application* app = session->activeApplication(); + if ( app ) { + SUIT_Desktop* desk = app->desktop(); + if ( desk ) + return desk->activeWindow(); + } + } + return 0; +} diff --git a/src/LightApp/LightApp_Selection.h b/src/LightApp/LightApp_Selection.h new file mode 100644 index 000000000..fc92b8ca5 --- /dev/null +++ b/src/LightApp/LightApp_Selection.h @@ -0,0 +1,70 @@ +// LightApp_Selection +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org +// +// +// +// File : LightApp_Selection.h +// Author : Alexander SOLOVYOV +// Module : GUI +// $Header$ + +#ifndef LIGHTAPP_SELECTION_HeaderFile +#define LIGHTAPP_SELECTION_HeaderFile + +#include "LightApp.h" +#include + +class LightApp_SelectionMgr; +class LightApp_DataOwner; +class LightApp_Study; +class SUIT_ViewWindow; + + +class LIGHTAPP_EXPORT LightApp_Selection : public QtxPopupMgr::Selection +{ +public: + LightApp_Selection(); + virtual ~LightApp_Selection(); + + virtual void init( const QString&, LightApp_SelectionMgr* ); + virtual void processOwner( const LightApp_DataOwner* ); + + virtual int count() const; + virtual QtxValue param( const int, const QString& ) const; + virtual QtxValue globalParam( const QString& ) const; + void setModuleName( const QString ); + +protected: + QString entry( const int ) const; + bool isReference( const int ) const; + /*!Gets study.*/ + LightApp_Study* study() const { return myStudy; } + QString activeViewType() const; + SUIT_ViewWindow* activeVW() const; + +protected: + QString myPopupClient; + QStringList myEntries; // entries of selected objects + QValueList myIsReferences; // whether i-th selected object was a reference + LightApp_Study* myStudy; +}; + +#endif diff --git a/src/LightApp/LightApp_SelectionMgr.cxx b/src/LightApp/LightApp_SelectionMgr.cxx new file mode 100644 index 000000000..5c9b48f0a --- /dev/null +++ b/src/LightApp/LightApp_SelectionMgr.cxx @@ -0,0 +1,271 @@ +#include "LightApp_SelectionMgr.h" + +#include "LightApp_Study.h" +#include "LightApp_DataOwner.h" +#include "LightApp_DataSubOwner.h" +#include "LightApp_Application.h" + +#include + +#include +#include + +// Open CASCADE Include +#include +#include +#include + +/*! + Constructor. +*/ +LightApp_SelectionMgr::LightApp_SelectionMgr( LightApp_Application* app, const bool fb ) +: SUIT_SelectionMgr( fb ), +myApp( app ) +{ +} + +/*! + Destructor. +*/ +LightApp_SelectionMgr::~LightApp_SelectionMgr() +{ +} + +/*! + Gets application. +*/ +LightApp_Application* LightApp_SelectionMgr::application() const +{ + return myApp; +} + +/*! + Get all selected objects from selection manager +*/ +void LightApp_SelectionMgr::selectedObjects( SALOME_ListIO& theList, const QString& theType, + const bool convertReferences ) const +{ + theList.Clear(); + + SUIT_DataOwnerPtrList aList; + selected( aList, theType ); + + QMap entryMap; + + QString entry; + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataOwner* owner = dynamic_cast( (*itr).operator->() ); + if( !owner ) + continue; + + LightApp_Study* study = dynamic_cast( application()->activeStudy() ); + if ( !study ) + return; + + entry = owner->entry(); + if ( convertReferences ) { + QString refEntry = study->referencedToEntry( entry ); + if( !entryMap.contains( entry ) ) { + if ( refEntry != entry ) { + QString component = study->componentDataType( refEntry ); + theList.Append( new SALOME_InteractiveObject( refEntry, component, ""/*refobj->Name().c_str()*/ ) ); + } + else + theList.Append( owner->IO() ); + } + } + else { + if( !entryMap.contains( entry ) ) + theList.Append( owner->IO() ); + } + + entryMap.insert(owner->entry(), 1); + } +} + +/*! + Append selected objects. +*/ +void LightApp_SelectionMgr::setSelectedObjects( const SALOME_ListIO& lst, const bool append ) +{ + SUIT_DataOwnerPtrList owners; + for ( SALOME_ListIteratorOfListIO it( lst ); it.More(); it.Next() ) + { + if ( it.Value()->hasEntry() ) + owners.append( new LightApp_DataOwner( it.Value() ) ); + } + + setSelected( owners, append ); +} + +/*! + Emit current selection changed. +*/ +void LightApp_SelectionMgr::selectionChanged( SUIT_Selector* theSel ) +{ + SUIT_SelectionMgr::selectionChanged( theSel ); + + emit currentSelectionChanged(); +} + +/*! + get map of indexes for the given SALOME_InteractiveObject +*/ +void LightApp_SelectionMgr::GetIndexes( const Handle(SALOME_InteractiveObject)& IObject, + TColStd_IndexedMapOfInteger& theIndex) +{ + theIndex.Clear(); + + SUIT_DataOwnerPtrList aList; + selected( aList ); + + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataSubOwner* subOwner = dynamic_cast( (*itr).operator->() ); + if ( subOwner ) + if ( subOwner->entry() == QString(IObject->getEntry()) ) + theIndex.Add( subOwner->index() ); + } + +} + +/*! + get map of indexes for the given entry of SALOME_InteractiveObject +*/ +void LightApp_SelectionMgr::GetIndexes( const QString& theEntry, TColStd_IndexedMapOfInteger& theIndex ) +{ + theIndex.Clear(); + + SUIT_DataOwnerPtrList aList; + selected( aList ); + + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataSubOwner* subOwner = dynamic_cast( (*itr).operator->() ); + if ( subOwner ) + if ( subOwner->entry() == theEntry ) + theIndex.Add( subOwner->index() ); + } + +} + +/*! + Add or remove interactive objects from selection manager. +*/ +bool LightApp_SelectionMgr::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& IObject, + const TColStd_MapOfInteger& theIndexes, + bool modeShift) +{ + SUIT_DataOwnerPtrList remainsOwners; + + SUIT_DataOwnerPtrList aList; + selected( aList ); + + if ( !modeShift ) { + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataOwner* owner = dynamic_cast( (*itr).operator->() ); + if ( owner ) + { + if ( owner->entry() != QString(IObject->getEntry()) ) + { + const LightApp_DataSubOwner* subOwner = dynamic_cast( owner ); + if ( subOwner ) + remainsOwners.append( new LightApp_DataSubOwner( subOwner->entry(), subOwner->index() ) ); + else + remainsOwners.append( new LightApp_DataOwner( owner->entry() ) ); + } + } + } + } + else + remainsOwners = aList; + + TColStd_MapIteratorOfMapOfInteger It; + It.Initialize(theIndexes); + for(;It.More();It.Next()) + remainsOwners.append( new LightApp_DataSubOwner( QString(IObject->getEntry()), It.Key() ) ); + + bool append = false; + setSelected( remainsOwners, append ); + + emit currentSelectionChanged(); + + TColStd_IndexedMapOfInteger anIndexes; + GetIndexes( IObject, anIndexes ); + return !anIndexes.IsEmpty(); + +} + +/*! + select 'subobjects' with given indexes +*/ +void LightApp_SelectionMgr::selectObjects( const Handle(SALOME_InteractiveObject)& IObject, + TColStd_IndexedMapOfInteger theIndex, bool append ) +{ + SUIT_DataOwnerPtrList aList; + + if ( theIndex.IsEmpty() ) + aList.append( new LightApp_DataOwner( QString(IObject->getEntry()) ) ); + else + { + int i; + for ( i = 1; i <= theIndex.Extent(); i++ ) + aList.append( new LightApp_DataSubOwner( QString(IObject->getEntry()), theIndex( i ) ) ); + } + + setSelected( aList, append ); + +} + +/*! + select 'subobjects' with given indexes +*/ +void LightApp_SelectionMgr::selectObjects( MapIOOfMapOfInteger theMapIO, bool append ) +{ + SUIT_DataOwnerPtrList aList; + + MapIOOfMapOfInteger::Iterator it; + for ( it = theMapIO.begin(); it != theMapIO.end(); ++it ) + { + if ( it.data().IsEmpty() ) + aList.append( new LightApp_DataOwner( QString(it.key()->getEntry()) ) ); + else + { + int i; + for ( i = 1; i <= it.data().Extent(); i++ ) + aList.append( new LightApp_DataSubOwner( QString(it.key()->getEntry()), it.data()( i ) ) ); + } + } + + setSelected( aList, append ); + +} + +/*! + get map of selected subowners : object's entry <-> map of indexes +*/ +void LightApp_SelectionMgr::selectedSubOwners( MapEntryOfMapOfInteger& theMap ) +{ + theMap.clear(); + + TColStd_IndexedMapOfInteger anIndexes; + + SUIT_DataOwnerPtrList aList; + selected( aList ); + + for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) + { + const LightApp_DataSubOwner* subOwner = dynamic_cast( (*itr).operator->() ); + if ( subOwner ) + { + if ( !theMap.contains( subOwner->entry() ) ) + { + anIndexes.Clear(); + GetIndexes( subOwner->entry(), anIndexes ); + theMap.insert( subOwner->entry(), anIndexes ); + } + } + } +} diff --git a/src/LightApp/LightApp_SelectionMgr.h b/src/LightApp/LightApp_SelectionMgr.h new file mode 100644 index 000000000..7f69ed6bf --- /dev/null +++ b/src/LightApp/LightApp_SelectionMgr.h @@ -0,0 +1,57 @@ +#ifndef LIGHTAPP_SELECTIONMGR_H +#define LIGHTAPP_SELECTIONMGR_H + +#include "LightApp.h" + +#include +#include + +#include + +class SALOME_ListIO; +class LightApp_Application; +class TColStd_IndexedMapOfInteger; +class TColStd_MapOfInteger; + +class LIGHTAPP_EXPORT LightApp_SelectionMgr : public SUIT_SelectionMgr +{ + Q_OBJECT + +public: + LightApp_SelectionMgr( LightApp_Application*, const bool = true ); + virtual ~LightApp_SelectionMgr(); + + typedef QMap< Handle(SALOME_InteractiveObject), TColStd_IndexedMapOfInteger > MapIOOfMapOfInteger; + typedef QMap< QString, TColStd_IndexedMapOfInteger > MapEntryOfMapOfInteger; + + LightApp_Application* application() const; + + void selectedObjects( SALOME_ListIO&, const QString& = QString::null, const bool = true ) const; + void setSelectedObjects( const SALOME_ListIO&, const bool = false ); + + void GetIndexes( const Handle(SALOME_InteractiveObject)& IObject, + TColStd_IndexedMapOfInteger& theIndex ); + void GetIndexes( const QString& theEntry, + TColStd_IndexedMapOfInteger& theIndex ); + + bool AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& IObject, + const TColStd_MapOfInteger& theIndices, + bool modeShift ); + + void selectObjects( const Handle(SALOME_InteractiveObject)& IObject, + TColStd_IndexedMapOfInteger theIndex, bool append ); + void selectObjects( MapIOOfMapOfInteger theMapIO, bool append ); + + void selectedSubOwners( MapEntryOfMapOfInteger& theMap ); + +signals: + void currentSelectionChanged(); + +private: + virtual void selectionChanged( SUIT_Selector* ); + +private: + LightApp_Application* myApp; +}; + +#endif diff --git a/src/LightApp/LightApp_ShowHideOp.cxx b/src/LightApp/LightApp_ShowHideOp.cxx new file mode 100644 index 000000000..6d2ae9d56 --- /dev/null +++ b/src/LightApp/LightApp_ShowHideOp.cxx @@ -0,0 +1,80 @@ + +#include "LightApp_ShowHideOp.h" +#include "LightApp_Application.h" +#include "LightApp_DataOwner.h" +#include "LightApp_Module.h" +#include "LightApp_Displayer.h" +#include "CAM_Study.h" + +#include "LightApp_SelectionMgr.h" +#include "LightApp_Selection.h" + +#include +#include + +LightApp_ShowHideOp::LightApp_ShowHideOp( ActionType type ) +: LightApp_Operation(), + myActionType( type ) +{ +} + +LightApp_ShowHideOp::~LightApp_ShowHideOp() +{ +} + +void LightApp_ShowHideOp::startOperation() +{ + LightApp_Application* app = dynamic_cast( application() ); + if( !app ) + { + abort(); + return; + } + + LightApp_SelectionMgr* mgr = app->selectionMgr(); + LightApp_Selection sel; sel.init( "", mgr ); + if( sel.count()==0 ) + { + abort(); + return; + } + QString aStr = sel.param( 0, "component" ).toString(); + QString mod_name = app->moduleTitle( aStr );//sel.param( 0, "component" ).toString() ); + LightApp_Module* m = dynamic_cast( app ? app->module( mod_name ) : 0 ); + if( !m ) + { + m = dynamic_cast( app->loadModule( mod_name ) ); + app->addModule( m ); + m->connectToStudy( dynamic_cast( app->activeStudy() ) ); + m->setMenuShown( false ); + m->setToolShown( false ); + } + + LightApp_Displayer* d = m ? m->displayer(): 0; + if( !d ) + { + abort(); + return; + } + + if( myActionType==DISPLAY_ONLY ) + d->EraseAll( false, false, 0 ); + + SALOME_ListIO selObjs; + mgr->selectedObjects( selObjs ); + SALOME_ListIteratorOfListIO anIt( selObjs ); + for( ; anIt.More(); anIt.Next() ) + { + if( anIt.Value().IsNull() ) + + continue; + + if( myActionType==DISPLAY || myActionType==DISPLAY_ONLY ) + d->Display( anIt.Value()->getEntry(), false, 0 ); + else if( myActionType==ERASE ) + d->Erase( anIt.Value()->getEntry(), false, false, 0 ); + } + d->UpdateViewer(); + commit(); +} + diff --git a/src/LightApp/LightApp_ShowHideOp.h b/src/LightApp/LightApp_ShowHideOp.h new file mode 100644 index 000000000..7f2667f71 --- /dev/null +++ b/src/LightApp/LightApp_ShowHideOp.h @@ -0,0 +1,26 @@ + +#ifndef LIGHTAPP_SHOW_HIDE_OPERATION_HEADER +#define LIGHTAPP_SHOW_HIDE_OPERATION_HEADER + +#include "LightApp_Operation.h" + +class LightApp_ShowHideOp : public LightApp_Operation +{ + Q_OBJECT + +public: + typedef enum { DISPLAY, ERASE, DISPLAY_ONLY } ActionType; + +public: + LightApp_ShowHideOp( ActionType ); + ~LightApp_ShowHideOp(); + +protected: + virtual void startOperation(); + +private: + ActionType myActionType; +}; + +#endif + diff --git a/src/LightApp/LightApp_Study.cxx b/src/LightApp/LightApp_Study.cxx new file mode 100644 index 000000000..9b05ef2b2 --- /dev/null +++ b/src/LightApp/LightApp_Study.cxx @@ -0,0 +1,393 @@ +#include "LightApp_Study.h" + +#include "CAM_DataModel.h" +#include "LightApp_Application.h" +#include "LightApp_DataModel.h" +#include "LightApp_DataObject.h" +#include "LightApp_RootObject.h" +#include "LightApp_Driver.h" + +#include "SUIT_ResourceMgr.h" +#include "SUIT_DataObjectIterator.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/*! + Constructor. +*/ +LightApp_Study::LightApp_Study( SUIT_Application* app ) +: CAM_Study( app ) +{ + myDriver = new LightApp_Driver(); +} + +/*! + Destructor. +*/ +LightApp_Study::~LightApp_Study() +{ +} + +/*! + Create document. +*/ +void LightApp_Study::createDocument() +{ + // create myRoot + setRoot( new LightApp_RootObject( this ) ); + + CAM_Study::createDocument(); + + emit created( this ); +} + +//======================================================================= +// name : openDocument +/*! Purpose : Open document*/ +//======================================================================= +bool LightApp_Study::openDocument( const QString& theFileName ) +{ + myDriver->ClearDriverContents(); + // create files for models from theFileName + if( !openStudyData(theFileName)) + return false; + + setRoot( new LightApp_RootObject( this ) ); // create myRoot + + // update loaded data models: call open() and update() on them. + ModelList dm_s; + dataModels( dm_s ); + for ( ModelListIterator it( dm_s ); it.current(); ++it ) + openDataModel( studyName(), it.current() ); + // this will build a SUIT_DataObject-s tree under myRoot member field + // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step + // but tree that corresponds to not-loaded data models will be updated any way. + ((LightApp_Application*)application())->updateObjectBrowser( false ); + + bool res = CAM_Study::openDocument( theFileName ); + + emit opened( this ); + return res; +} + +//======================================================================= +// name : loadDocument +/*! Purpose : Load document */ +//======================================================================= +bool LightApp_Study::loadDocument( const QString& theStudyName ) +{ + myDriver->ClearDriverContents(); + if( !openStudyData(theStudyName)) + return false; + + setRoot( new LightApp_RootObject( this ) ); // create myRoot + + //SRN: BugID IPAL9021, put there the same code as in a method openDocument + + // update loaded data models: call open() and update() on them. + ModelList dm_s; + dataModels( dm_s ); + + for ( ModelListIterator it( dm_s ); it.current(); ++it ) + openDataModel( studyName(), it.current() ); + + // this will build a SUIT_DataObject-s tree under myRoot member field + // passing "false" in order NOT to rebuild existing data models' trees - it was done in previous step + // but tree that corresponds to not-loaded data models will be updated any way. + ((LightApp_Application*)application())->updateObjectBrowser( false ); + + bool res = CAM_Study::openDocument( theStudyName ); + emit opened( this ); + //SRN: BugID IPAL9021: End + return res; +} + +//======================================================================= +// name : saveDocumentAs +/*! Purpose : Save document */ +//======================================================================= +bool LightApp_Study::saveDocumentAs( const QString& theFileName ) +{ + ModelList list; dataModels( list ); + + LightApp_DataModel* aModel = (LightApp_DataModel*)list.first(); + + myDriver->ClearDriverContents(); + QStringList listOfFiles; + for ( ; aModel; aModel = (LightApp_DataModel*)list.next() ) { + listOfFiles.clear(); + aModel->saveAs( theFileName, this, listOfFiles ); + if ( !listOfFiles.isEmpty() ) + saveModuleData(aModel->module()->name(), listOfFiles); + } + + bool res = saveStudyData(theFileName); + res = res && CAM_Study::saveDocumentAs( theFileName ); + //SRN: BugID IPAL9377, removed usage of uninitialized variable + if ( res ) + emit saved( this ); + + return res; +} + +//======================================================================= +// name : saveDocument +/*! Purpose : Save document */ +//======================================================================= +bool LightApp_Study::saveDocument() +{ + ModelList list; dataModels( list ); + + LightApp_DataModel* aModel = (LightApp_DataModel*)list.first(); + + myDriver->ClearDriverContents(); + QStringList listOfFiles; + for ( ; aModel; aModel = (LightApp_DataModel*)list.next() ) { + listOfFiles.clear(); + aModel->save( listOfFiles ); + saveModuleData(aModel->module()->name(), listOfFiles); + } + + bool res = saveStudyData(studyName()); + res = res && CAM_Study::saveDocument(); + if (res) + emit saved( this ); + + return res; +} + +//================================================================ +// Function : closeDocument +/*! Purpose : Close document */ +//================================================================ +void LightApp_Study::closeDocument(bool permanently) +{ + // Inform everybody that this study is going to close when it's most safe to, + // i.e. in the very beginning + emit closed( this ); + + CAM_Study::closeDocument(permanently); +} + +//================================================================ +// Function : referencedToEntry +/*! Purpose : Return current entry*/ +//================================================================ +QString LightApp_Study::referencedToEntry( const QString& entry ) +{ + return entry; +} +//================================================================ +// Function : componentDataType +/*! Purpose : Return component data type from entry*/ +//================================================================ +QString LightApp_Study::componentDataType( const QString& entry ) +{ + LightApp_DataObject* aCurObj; + for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) { + aCurObj = dynamic_cast( it.current() ); + if ( aCurObj && aCurObj->entry() == entry ) { + return aCurObj->componentDataType(); + } + } + return ""; +} + +//================================================================ +// Function : isModified +// Purpose : +//================================================================ +bool LightApp_Study::isModified() const +{ + bool isAnyChanged = CAM_Study::isModified(); + ModelList list; dataModels( list ); + + LightApp_DataModel* aModel = 0; + for ( QPtrListIterator it( list ); it.current() && !isAnyChanged; ++it ){ + aModel = dynamic_cast( it.current() ); + if ( aModel ) + isAnyChanged = aModel->isModified(); + } + return isAnyChanged; +} + +//================================================================ +// Function : isSaved +/*! Purpose : Check: data model is saved?*/ +//================================================================ +bool LightApp_Study::isSaved() const +{ + bool isAllSaved = CAM_Study::isSaved(); + ModelList list; dataModels( list ); + + LightApp_DataModel* aModel = 0; + for ( QPtrListIterator it( list ); it.current() && isAllSaved; ++it ){ + aModel = dynamic_cast( it.current() ); + if ( aModel ) + isAllSaved = aModel->isSaved(); + } + return isAllSaved; +} + +//======================================================================= +// name : saveModuleData +/*! Purpose : Create SComponent for module, necessary for SalomeApp study */ +//======================================================================= +void LightApp_Study::addComponent(const CAM_DataModel* dm) +{ +} + +//======================================================================= +// name : saveModuleData +/*! Purpose : save list file for module 'theModuleName' */ +//======================================================================= +void LightApp_Study::saveModuleData(QString theModuleName, QStringList theListOfFiles) +{ + int aNb = theListOfFiles.count(); + if ( aNb == 0 ) + return; + + std::vector aListOfFiles ( aNb ); + int anIndex = 0; + for ( QStringList::Iterator it = theListOfFiles.begin(); it != theListOfFiles.end(); ++it ) { + if ( (*it).isEmpty() ) + continue; + aListOfFiles[anIndex] = (*it).latin1(); + anIndex++; + } + myDriver->SetListOfFiles(theModuleName, aListOfFiles); +} + +//======================================================================= +// name : openModuleData +/*! Purpose : gets list of file for module 'theModuleNam' */ +//======================================================================= +void LightApp_Study::openModuleData(QString theModuleName, QStringList& theListOfFiles) +{ + std::vector aListOfFiles = myDriver->GetListOfFiles(theModuleName); + int i, aLength = aListOfFiles.size() - 1; + if (aLength < 0) + return; + + //Get a temporary directory for saved a file + theListOfFiles.append(aListOfFiles[0].c_str()); + for(i = 0; i < aLength; i++) + theListOfFiles.append(aListOfFiles[i+1].c_str()); +} + +//======================================================================= +// name : saveStudyData +/*! Purpose : save data from study */ +//======================================================================= +bool LightApp_Study::saveStudyData( const QString& theFileName ) +{ + ModelList list; dataModels( list ); + SUIT_ResourceMgr* resMgr = application()->resourceMgr(); + if( !resMgr ) + return false; + bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false ); + + bool aRes = myDriver->SaveDatasInFile(theFileName.latin1(), isMultiFile); + // clear map + std::vector aList(0); + for ( ModelListIterator it( list ); it.current(); ++it ) + myDriver->SetListOfFiles(it.current()->module()->name(), aList); + + return aRes; +} + +//======================================================================= +// name : openStudyData +/*! Purpose : open data for study */ +//======================================================================= +bool LightApp_Study::openStudyData( const QString& theFileName ) +{ + SUIT_ResourceMgr* resMgr = application()->resourceMgr(); + if( !resMgr ) + return false; + bool isMultiFile = resMgr->booleanValue( "Study", "multi_file", false ); + + bool aRes = myDriver->ReadDatasFromFile(theFileName.latin1(), isMultiFile); + return aRes; +} + +//================================================================ +// Function : openDataModel +/*! Purpose : Open data model */ +//================================================================ +bool LightApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm ) +{ + if (!dm) + return false; + + QStringList listOfFiles; + openModuleData(dm->module()->name(), listOfFiles); + if (dm && dm->open(studyName, this, listOfFiles)) { + // Remove the files and temporary directory, created + // for this module by LightApp_Driver::OpenStudyData() + bool isMultiFile = false; // TODO: decide, how to access this parameter + RemoveTemporaryFiles( dm->module()->name(), isMultiFile ); + + // Something has been read -> create data model tree + LightApp_DataModel* aDM = dynamic_cast( dm ); + if ( aDM ) + aDM->update(NULL, this); + return true; + } + return false; +} + +//================================================================ +// Function : GetTmpDir +/*! Purpose : to be used by modules*/ +//================================================================ +std::string LightApp_Study::GetTmpDir (const char* theURL, + const bool isMultiFile) +{ + return myDriver->GetTmpDir(theURL, isMultiFile); +} + +//================================================================ +// Function : GetListOfFiles +/*! Purpose : to be used by modules*/ +//================================================================ +std::vector LightApp_Study::GetListOfFiles(const char* theModuleName) const +{ + std::vector aListOfFiles; + aListOfFiles = myDriver->GetListOfFiles(theModuleName); + return aListOfFiles; +} + +//================================================================ +// Function : SetListOfFiles +/*! Purpose : to be used by modules*/ +//================================================================ +void LightApp_Study::SetListOfFiles (const char* theModuleName, const std::vector theListOfFiles) +{ + myDriver->SetListOfFiles(theModuleName, theListOfFiles); +} + +//================================================================ +// Function : RemoveTemporaryFiles +/*! Purpose : to be used by modules*/ +//================================================================ +void LightApp_Study::RemoveTemporaryFiles (const char* theModuleName, const bool isMultiFile) const +{ + if (isMultiFile) + return; + bool isDirDeleted = true; + myDriver->RemoveTemporaryFiles(theModuleName, isDirDeleted); +} diff --git a/src/LightApp/LightApp_Study.h b/src/LightApp/LightApp_Study.h new file mode 100644 index 000000000..4c206cc09 --- /dev/null +++ b/src/LightApp/LightApp_Study.h @@ -0,0 +1,70 @@ +#ifndef LIGHTAPP_STUDY_H +#define LIGHTAPP_STUDY_H + +#include +#include + +#include +#include +#include + +#include "string" +#include "vector" + +class SUIT_Application; +class CAM_DataModel; + +class LIGHTAPP_EXPORT LightApp_Study : public CAM_Study +{ + Q_OBJECT + +public: + LightApp_Study( SUIT_Application* ); + virtual ~LightApp_Study(); + + virtual void createDocument(); + virtual bool openDocument( const QString& ); + virtual bool loadDocument( const QString& ); + + virtual bool saveDocument(); + virtual bool saveDocumentAs( const QString& ); + + virtual void closeDocument(bool permanently = true); + + virtual bool isSaved() const; + virtual bool isModified() const; + + virtual void addComponent ( const CAM_DataModel* dm); + + virtual std::string GetTmpDir ( const char* theURL, const bool isMultiFile ); + + virtual QString componentDataType( const QString& ); + virtual QString referencedToEntry( const QString& ); + +protected: + virtual void saveModuleData ( QString theModuleName, QStringList theListOfFiles ); + virtual void openModuleData ( QString theModuleName, QStringList& theListOfFiles ); + virtual bool saveStudyData ( const QString& theFileName ); + virtual bool openStudyData ( const QString& theFileName ); + + virtual std::vector GetListOfFiles ( const char* theModuleName ) const; + virtual void SetListOfFiles ( const char* theModuleName, + const std::vector theListOfFiles ); + + virtual void RemoveTemporaryFiles ( const char* theModuleName, const bool isMultiFile ) const; + +protected: + virtual bool openDataModel ( const QString&, CAM_DataModel* ); + +signals: + void saved ( SUIT_Study* ); + void opened ( SUIT_Study* ); + void closed ( SUIT_Study* ); + void created( SUIT_Study* ); + + +private: + LightApp_Driver* myDriver; +}; + +#endif diff --git a/src/LightApp/LightApp_SwitchOp.cxx b/src/LightApp/LightApp_SwitchOp.cxx new file mode 100755 index 000000000..4232ced87 --- /dev/null +++ b/src/LightApp/LightApp_SwitchOp.cxx @@ -0,0 +1,164 @@ +/** +* LIGHT LightApp +* +* Copyright (C) 2005 CEA/DEN, EDF R&D +* +* +* +* File : LightApp_SwitchOp.h +* Author : Sergey LITONIN +* Module : LIGHT +*/ + +#include "LightApp_SwitchOp.h" +#include "LightApp_Module.h" +#include "LightApp_Operation.h" +#include "LightApp_Dialog.h" +#include +#include +#include +#include +#include +#include +#include + +/*! + * \brief Constructor + * \param theParent - parent of object +* +* Creates instance of the object. Connects signals and slots. Install eveny filter +* on application +*/ +LightApp_SwitchOp::LightApp_SwitchOp( LightApp_Module* theModule ) +: QObject( 0 ), + myModule( theModule ) +{ + qApp->installEventFilter( this ); +} + +/*! + * \brief Destructor +*/ +LightApp_SwitchOp::~LightApp_SwitchOp() +{ + +} + +/*! + * \brief Get module +* +* Get module. Module is a parent of this class +*/ +LightApp_Module* LightApp_SwitchOp::module() const +{ + return myModule; +} + +/*! + * \brief Get study + * \return Active study of application (in current realisation) +* +* Get study +*/ +SUIT_Study* LightApp_SwitchOp::study() const +{ + return module()->application()->activeStudy(); +} + +/*! + * \brief Get operation by widget + * \param theWg - key widget to find operation + * \return Pointer to the operations if it is found or zero +* +* Find operation containing dialog with given widget +*/ +LightApp_Operation* LightApp_SwitchOp::operation( QWidget* theWg ) const +{ + // get dialog from widget + LightApp_Dialog* aDlg = 0; + QWidget* aParent = theWg; + while( aParent && !aParent->inherits( "LightApp_Dialog" ) ) + aParent = aParent->parentWidget(); + + if ( aParent && aParent->inherits( "LightApp_Dialog" ) ) + aDlg = (LightApp_Dialog*)aParent; + + // try to find operation corresponding to the dialog + if ( aDlg != 0 && study() != 0 ) + { + QPtrListIterator anIter( study()->operations() ); + while( SUIT_Operation* anOp = anIter.current() ) + { + if ( anOp->inherits( "LightApp_Operation" ) && + ((LightApp_Operation*)anOp)->dlg() == aDlg ) + return ((LightApp_Operation*)anOp); + ++anIter; + } + } + + return 0; +} + +/*! + * \brief Event filter + * \param theObj - object + * \param theEv - event +* +* Event filter. Catched signals off application. If event concerns to dialog then +* corresponding operation is found and activated. +*/ +bool LightApp_SwitchOp::eventFilter( QObject* theObj, QEvent* theEv ) +{ + if ( theObj->inherits( "QWidget" ) && ( theEv->type() == QEvent::Enter ) ) + { + QEvent::Type aType = theEv->type(); + LightApp_Operation* anOp = operation( (QWidget*)theObj ); + if ( anOp ) + { + switch ( aType ) + { + case QEvent::Enter: + { + if ( !anOp->isActive() && anOp->isAutoResumed() && + study() && !study()->blockingOperation( anOp ) ) + study()->resume( anOp ); + } + break; + + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + if ( !anOp->isActive() ) + return true; + } + break; + + } + } + } + + return QObject::eventFilter( theObj, theEv ); +} + + + + + + + + + + + + + + + + + + + diff --git a/src/LightApp/LightApp_SwitchOp.h b/src/LightApp/LightApp_SwitchOp.h new file mode 100755 index 000000000..7c725ebf5 --- /dev/null +++ b/src/LightApp/LightApp_SwitchOp.h @@ -0,0 +1,72 @@ +/** +* LIGHT LightApp +* +* Copyright (C) 2005 CEA/DEN, EDF R&D +* +* +* +* File : LightApp_SwitchOp.h +* Author : Sergey LITONIN +* Module : LIGHT +*/ + + + +#ifndef LightApp_SwitchOp_H +#define LightApp_SwitchOp_H + +#include "LightApp.h" +#include + +class LightApp_Module; +class LightApp_Operation; +class QEvent; +class SUIT_Study; + +/*! + * \brief This class is intended for controling switching between operation + * + * Several operation may be launched simultaneously. This class is intended for + * controlling switching between such operations. This class works with operations having + * dialogs (activation of other operations is performed by SUIT_Study). When several + * operations is launched simultaneously corresponding dialogs are shown on the screen. + * Only one operation from the launched ones can be active (active operation). Other + * operations are suspended. As result only one dialog from shown ones can be active too. + * Other dialogs are disabled. This class installs event filter on application. When mouse + * cursor is moved above disabled dialog corresponding event is catched by this class. + * It finds corresponding operation and verify whether operation can be resumed (see + * SUIT_Study::isDenied( SUIT_Operation* ) method). If yes then current active + * operation is suspended and new operation activated. Module contains this class as a + * field. Then module is created instance of this class created too. + */ +class LIGHTAPP_EXPORT LightApp_SwitchOp : public QObject +{ + Q_OBJECT + +public: + + LightApp_SwitchOp( LightApp_Module* ); + virtual ~LightApp_SwitchOp(); + + // Redefined from base class + bool eventFilter( QObject*, QEvent* ); + +private: + + LightApp_Module* module() const; + LightApp_Operation* operation( QWidget* ) const; + SUIT_Study* study() const; + +private: + + LightApp_Module* myModule; + +}; + +#endif + + + + + + diff --git a/src/LightApp/LightApp_UpdateFlags.h b/src/LightApp/LightApp_UpdateFlags.h new file mode 100755 index 000000000..2fc7fa780 --- /dev/null +++ b/src/LightApp/LightApp_UpdateFlags.h @@ -0,0 +1,37 @@ +// LIGHT LightApp +// +// Copyright (C) 2005 CEA/DEN, EDF R&D +// +// +// +// File : LightApp_UpdateFlags.h +// Author : Sergey LITONIN +// Module : LIGHT + + +#ifndef LightApp_UpdateFlags_H +#define LightApp_UpdateFlags_H + +/* + Enum : UpdateFlags + Description : Enumeration for update flags. First byte is reserved for LightApp_Module. + Modules derived from this model must use other 3 bytes to define their + own update flags +*/ + +typedef enum +{ + UF_Forced = 0x00000001, + UF_Model = 0x00000002, + UF_Viewer = 0x00000004, + UF_ObjBrowser = 0x00000008, + UF_Controls = 0x00000010, +} UpdateFlags; + +#endif + + + + + + diff --git a/src/LightApp/LightApp_VTKSelector.cxx b/src/LightApp/LightApp_VTKSelector.cxx new file mode 100644 index 000000000..c31cc4341 --- /dev/null +++ b/src/LightApp/LightApp_VTKSelector.cxx @@ -0,0 +1,187 @@ +#include "LightApp_VTKSelector.h" +#include "LightApp_DataOwner.h" + +#include "SVTK_ViewModel.h" +#include "SVTK_Selector.h" +#include "SVTK_ViewWindow.h" +#include "SVTK_Functor.h" + +#include "SALOME_Actor.h" +#include "SALOME_ListIteratorOfListIO.hxx" + +#include "VTKViewer_Algorithm.h" + +#include + +/*! + Constructor. +*/ +LightApp_SVTKDataOwner +::LightApp_SVTKDataOwner( const Handle(SALOME_InteractiveObject)& theIO, + const TColStd_IndexedMapOfInteger& theIds, + Selection_Mode theMode, + SALOME_Actor* theActor): + LightApp_DataOwner( theIO ), + mySelectionMode(theMode), + myActor(theActor) +{ + myIds = theIds; // workaround - there is no constructor copy for the container +} + +/*! + Destuctor. +*/ +LightApp_SVTKDataOwner +::~LightApp_SVTKDataOwner() +{ +} + +/*! + Gets actor pointer. +*/ +SALOME_Actor* +LightApp_SVTKDataOwner +::GetActor() const +{ + return myActor.GetPointer(); +} + +/*! + Constructor. +*/ +LightApp_VTKSelector +::LightApp_VTKSelector( SVTK_Viewer* viewer, + SUIT_SelectionMgr* mgr ): + SUIT_Selector( mgr, viewer ), + myViewer( viewer ) +{ + if ( myViewer ) + connect( myViewer, SIGNAL( selectionChanged() ), this, SLOT( onSelectionChanged() ) ); +} + +/*! + Destructor. +*/ +LightApp_VTKSelector +::~LightApp_VTKSelector() +{ +} + +/*! + Gets viewer. +*/ +SVTK_Viewer* +LightApp_VTKSelector +::viewer() const +{ + return myViewer; +} + +/*! + Gets type of vtk viewer. +*/ +QString +LightApp_VTKSelector +::type() const +{ + return SVTK_Viewer::Type(); +} + +/*! + On selection changed. +*/ +void +LightApp_VTKSelector +::onSelectionChanged() +{ + selectionChanged(); +} + +/*! + Gets list of selected data owners.(output \a aList). +*/ +void +LightApp_VTKSelector +::getSelection( SUIT_DataOwnerPtrList& aList ) const +{ + if(myViewer){ + if(SUIT_ViewManager* aViewMgr = myViewer->getViewManager()){ + if(SVTK_ViewWindow* aView = dynamic_cast(aViewMgr->getActiveView())){ + if(SVTK_Selector* aSelector = aView->GetSelector()){ + Selection_Mode aMode = aSelector->SelectionMode(); + const SALOME_ListIO& aListIO = aSelector->StoredIObjects(); + SALOME_ListIteratorOfListIO anIter(aListIO); + for(; anIter.More(); anIter.Next()){ + Handle(SALOME_InteractiveObject) anIO = anIter.Value(); + if(anIO->hasEntry()){ + TColStd_IndexedMapOfInteger anIds; + aSelector->GetIndex(anIO,anIds); + SALOME_Actor* anActor = aSelector->GetActor(anIO); + if( !anActor ) + anActor = VTK::Find(aView->getRenderer()->GetActors(),VTK::TIsSameIObject(anIO)); + + aList.append(new LightApp_SVTKDataOwner(anIO,anIds,aMode,anActor)); + } + } + } + } + } + } +} + +/*! + Sets selection to selector from data owner list \a theList. +*/ +void +LightApp_VTKSelector +::setSelection( const SUIT_DataOwnerPtrList& theList ) +{ + if(myViewer){ + if(SUIT_ViewManager* aViewMgr = myViewer->getViewManager()){ + if(SVTK_ViewWindow* aView = dynamic_cast(aViewMgr->getActiveView())){ + if(SVTK_Selector* aSelector = aView->GetSelector()){ + SALOME_ListIO anAppendList; + const SALOME_ListIO& aStoredList = aSelector->StoredIObjects(); + SUIT_DataOwnerPtrList::const_iterator anIter = theList.begin(); + for(; anIter != theList.end(); ++anIter){ + const SUIT_DataOwner* aDataOwner = (*anIter).get(); + if(const LightApp_SVTKDataOwner* anOwner = dynamic_cast(aDataOwner)){ + aSelector->SetSelectionMode(anOwner->GetMode()); + Handle(SALOME_InteractiveObject) anIO = anOwner->IO(); + + if( anOwner->GetActor() ) + aSelector->AddIObject( anOwner->GetActor() ); + else + aSelector->AddIObject(anIO); + + anAppendList.Append(anIO); + aSelector->AddOrRemoveIndex(anIO,anOwner->GetIds(),false); + }else if(const LightApp_DataOwner* anOwner = dynamic_cast(aDataOwner)){ + Handle(SALOME_InteractiveObject) anIO = + new SALOME_InteractiveObject(anOwner->entry().latin1(),""); + aSelector->AddIObject(anIO); + anAppendList.Append(anIO); + } + } + // To remove IOs, which is not selected. + QMap< QString, Handle( SALOME_InteractiveObject )> toRemove; + SALOME_ListIteratorOfListIO anIt( aStoredList ); + for( ; anIt.More(); anIt.Next() ) + if( !anIt.Value().IsNull() ) + toRemove[ anIt.Value()->getEntry() ] = anIt.Value(); + + anIt = SALOME_ListIteratorOfListIO(anAppendList); + for( ; anIt.More(); anIt.Next() ) + toRemove.remove( anIt.Value()->getEntry() ); + + QMap< QString, Handle( SALOME_InteractiveObject )>::const_iterator RIt = toRemove.begin(), + REnd = toRemove.end(); + for( ; RIt!=REnd; RIt++ ) + aSelector->RemoveIObject( RIt.data() ); + + aView->onSelectionChanged(); + } + } + } + } +} diff --git a/src/LightApp/LightApp_VTKSelector.h b/src/LightApp/LightApp_VTKSelector.h new file mode 100644 index 000000000..25c4ac44e --- /dev/null +++ b/src/LightApp/LightApp_VTKSelector.h @@ -0,0 +1,78 @@ +#ifndef LIGHTAPP_VTKSELECTOR_H +#define LIGHTAPP_VTKSELECTOR_H + +#include + +#include + +#include "SUIT_Selector.h" + +#include "LightApp.h" +#include "LightApp_DataOwner.h" + +#include "SVTK_Selection.h" +#include "SALOME_InteractiveObject.hxx" + +class SALOME_Actor; +class SVTK_Viewer; + +/*! + Provide salome vtk data owner list. +*/ +class LIGHTAPP_EXPORT LightApp_SVTKDataOwner : public LightApp_DataOwner +{ + public: + LightApp_SVTKDataOwner( const Handle(SALOME_InteractiveObject)& theIO, + const TColStd_IndexedMapOfInteger& theIds, + Selection_Mode theMode = ActorSelection, + SALOME_Actor* theActor = NULL); + virtual ~LightApp_SVTKDataOwner(); + + /*!Gets dataowners ids list.*/ + const TColStd_IndexedMapOfInteger& GetIds() const + { + return myIds; + } + + /*!Gets selection mode.*/ + Selection_Mode GetMode() const + { + return mySelectionMode; + } + + SALOME_Actor* GetActor() const; + + protected: + TColStd_IndexedMapOfInteger myIds; + Selection_Mode mySelectionMode; + vtkSmartPointer myActor; +}; + + +/*! + Provide vtk selection of data owners. +*/ +class LIGHTAPP_EXPORT LightApp_VTKSelector : public SUIT_Selector +{ + Q_OBJECT; + +public: + LightApp_VTKSelector( SVTK_Viewer*, SUIT_SelectionMgr* ); + virtual ~LightApp_VTKSelector(); + + SVTK_Viewer* viewer() const; + + virtual QString type() const; + +private slots: + void onSelectionChanged(); + +protected: + virtual void getSelection( SUIT_DataOwnerPtrList& ) const; + virtual void setSelection( const SUIT_DataOwnerPtrList& ); + +private: + SVTK_Viewer* myViewer; +}; + +#endif diff --git a/src/LightApp/LightApp_WidgetContainer.cxx b/src/LightApp/LightApp_WidgetContainer.cxx new file mode 100644 index 000000000..3dd8d1f9b --- /dev/null +++ b/src/LightApp/LightApp_WidgetContainer.cxx @@ -0,0 +1,133 @@ +#include "LightApp_WidgetContainer.h" + +#include +#include + +/*! + Constructor. +*/ +LightApp_WidgetContainer::LightApp_WidgetContainer( const int type, QWidget* parent ) +: QDockWindow( QDockWindow::InDock, parent ), +myType( type ) +{ + setWidget( myStack = new QWidgetStack( this ) ); + myStack->show(); +} + +/*! + Destructor. +*/ +LightApp_WidgetContainer::~LightApp_WidgetContainer() +{ +} + +/*! + Checks: is widget container is empty? +*/ +bool LightApp_WidgetContainer::isEmpty() const +{ + const QObjectList* lst = myStack->children(); + if ( !lst ) + return true; + + bool res = true; + for ( QObjectListIt it( *lst ); it.current() && res; ++it ) + { + if ( it.current()->isWidgetType() && myStack->id( (QWidget*)it.current() ) != -1 ) + res = false; + } + return res; +} + +/*! + Gets type of widget container. +*/ +int LightApp_WidgetContainer::type() const +{ + return myType; +} + +/*! + Checks: is container contains widget with id \a id. +*/ +bool LightApp_WidgetContainer::contains( const int id ) const +{ + return myStack->widget( id ) != 0; +} + +/*! + * Insert widget(\a wid with id \a id) to container.And return id of widget in stack. + *\warning remove widget with id = \a id , if it was in container. + */ +int LightApp_WidgetContainer::insert( const int id, QWidget* wid ) +{ + if ( id == -1 || !wid ) + return -1; + + if ( contains( id ) ) + remove( id ); + + int stackId = myStack->addWidget( wid, id ); + if ( !myStack->visibleWidget() ) + myStack->raiseWidget( wid ); + + setCaption( myStack->visibleWidget() ? myStack->visibleWidget()->caption() : QString::null ); + + return stackId; +} + +/*! + Remove widget(\a wid) from stack. +*/ +void LightApp_WidgetContainer::remove( const int id ) +{ + remove( myStack->widget( id ) ); + + setCaption( myStack->visibleWidget() ? myStack->visibleWidget()->caption() : QString::null ); +} + +/*! + Remove widget(\a wid) from stack. +*/ +void LightApp_WidgetContainer::remove( QWidget* wid ) +{ + myStack->removeWidget( wid ); + + setCaption( myStack->visibleWidget() ? myStack->visibleWidget()->caption() : QString::null ); +} + +/*! + Raise widget with id = \a id. +*/ +void LightApp_WidgetContainer::activate( const int id ) +{ + myStack->raiseWidget( id ); + + setCaption( myStack->visibleWidget() ? myStack->visibleWidget()->caption() : QString::null ); +} + +/*! + Raise widget (\a wid). +*/ +void LightApp_WidgetContainer::activate( QWidget* wid ) +{ + myStack->raiseWidget( wid ); + + setCaption( myStack->visibleWidget() ? myStack->visibleWidget()->caption() : QString::null ); +} + +/*! + Gets widget from container list(stack) by id = \a id. +*/ +QWidget* LightApp_WidgetContainer::widget( const int id ) const +{ + return myStack->widget( id ); +} + +/*! + Gets visible widget. +*/ +QWidget* LightApp_WidgetContainer::active() const +{ + return myStack->visibleWidget(); +} diff --git a/src/LightApp/LightApp_WidgetContainer.h b/src/LightApp/LightApp_WidgetContainer.h new file mode 100644 index 000000000..6479eb949 --- /dev/null +++ b/src/LightApp/LightApp_WidgetContainer.h @@ -0,0 +1,42 @@ +#ifndef LIGHTAPP_WIDGETCONTAINER_H +#define LIGHTAPP_WIDGETCONTAINER_H + +#include "LightApp.h" + +#include + +class QWidget; +class QWidgetStack; + +/*! + Class which privade widget container. +*/ +class LIGHTAPP_EXPORT LightApp_WidgetContainer : public QDockWindow +{ + Q_OBJECT + +public: + LightApp_WidgetContainer( const int, QWidget* = 0 ); + virtual ~LightApp_WidgetContainer(); + + bool isEmpty() const; + + int type() const; + + int insert( const int, QWidget* ); + void remove( QWidget* ); + void remove( const int ); + bool contains( const int ) const; + + void activate( QWidget* ); + void activate( const int ); + + QWidget* active() const; + QWidget* widget( const int ) const; + +private: + int myType; + QWidgetStack* myStack; +}; + +#endif diff --git a/src/LightApp/Makefile.in b/src/LightApp/Makefile.in new file mode 100755 index 000000000..dc1d74cda --- /dev/null +++ b/src/LightApp/Makefile.in @@ -0,0 +1,114 @@ +# File : Makefile.in +# Author : OCC team (OCN) +# Module : LightApp +# $Header$ + +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +VPATH=.:@srcdir@:@srcdir@/resources + + +@COMMENCE@ + +# header files +EXPORT_HEADERS= LightApp.h \ + LightApp_AboutDlg.h \ + LightApp_Application.h \ + LightApp_DataModel.h \ + LightApp_DataObject.h \ + LightApp_DataOwner.h \ + LightApp_DataSubOwner.h \ + LightApp_Dialog.h \ + LightApp_Displayer.h \ + LightApp_Driver.h \ + LightApp_GLSelector.h \ + LightApp_Module.h \ + LightApp_ModuleDlg.h \ + LightApp_NameDlg.h \ + LightApp_OBFilter.h \ + LightApp_OBSelector.h \ + LightApp_OCCSelector.h \ + LightApp_Operation.h \ + LightApp_Selection.h \ + LightApp_SelectionMgr.h \ + LightApp_ShowHideOp.h \ + LightApp_Study.h \ + LightApp_SwitchOp.h \ + LightApp_Preferences.h \ + LightApp_PreferencesDlg.h \ + LightApp_RootObject.h \ + LightApp_UpdateFlags.h \ + LightApp_VTKSelector.h \ + LightApp_WidgetContainer.h + +# .po files to transform in .qm +PO_FILES = LightApp_images.po \ + LightApp_msg_en.po + +# Libraries targets +LIB = libLightApp.la + +LIB_SRC= LightApp_AboutDlg.cxx \ + LightApp_Application.cxx \ + LightApp_DataModel.cxx \ + LightApp_DataObject.cxx \ + LightApp_DataOwner.cxx \ + LightApp_DataSubOwner.cxx \ + LightApp_Dialog.cxx \ + LightApp_Displayer.cxx \ + LightApp_Driver.cxx \ + LightApp_GLSelector.cxx \ + LightApp_Module.cxx \ + LightApp_ModuleDlg.cxx \ + LightApp_NameDlg.cxx \ + LightApp_OBFilter.cxx \ + LightApp_OBSelector.cxx \ + LightApp_OCCSelector.cxx \ + LightApp_Operation.cxx \ + LightApp_Selection.cxx \ + LightApp_SelectionMgr.cxx \ + LightApp_ShowHideOp.cxx \ + LightApp_Study.cxx \ + LightApp_SwitchOp.cxx \ + LightApp_Preferences.cxx \ + LightApp_PreferencesDlg.cxx \ + LightApp_VTKSelector.cxx \ + LightApp_WidgetContainer.cxx + +LIB_MOC = LightApp_AboutDlg.h \ + LightApp_Application.h \ + LightApp_DataModel.h \ + LightApp_Dialog.h \ + LightApp_Driver.h \ + LightApp_GLSelector.h \ + LightApp_OBSelector.h \ + LightApp_OCCSelector.h \ + LightApp_Operation.h \ + LightApp_Module.h \ + LightApp_ModuleDlg.h \ + LightApp_NameDlg.h \ + LightApp_SelectionMgr.h \ + LightApp_ShowHideOp.h \ + LightApp_Study.h \ + LightApp_SwitchOp.h \ + LightApp_Preferences.h \ + LightApp_PreferencesDlg.h \ + LightApp_VTKSelector.h \ + LightApp_WidgetContainer.h + +RESOURCES_FILES = icon_about.png \ + icon_applogo.png \ + icon_default.png \ + icon_module.png \ + icon_module_big.png \ + icon_select.png \ + LightApp.ini \ + LightApp.xml + +CPPFLAGS+=$(PYTHON_INCLUDES) $(QT_INCLUDES) $(QWT_INCLUDES) $(OCC_INCLUDES) $(VTK_INCLUDES) + +LDFLAGS+=$(PYTHON_LIBS) $(QT_MT_LIBS) +LIBS+= -lsuit -lstd -lCAM -lObjBrowser -lLogWindow $(CAS_KERNEL) -lPlot2d -lGLViewer -lOCCViewer -lVTKViewer -lSalomeObject -lSOCC -lSVTK -lPyInterp -lPythonConsole + +@CONCLUDE@ diff --git a/src/LightApp/resources/LightApp.ini b/src/LightApp/resources/LightApp.ini new file mode 100755 index 000000000..814a5ec84 --- /dev/null +++ b/src/LightApp/resources/LightApp.ini @@ -0,0 +1,21 @@ +# The resources mapping file for LightApp application + +[language] +language = en + +[launch] +modules = LIGHT + +[resources] +SUIT = $(SUITRoot)/resources +STD = $(SUITRoot)/resources +LightApp = $(SUITRoot)/resources +Plot2d = $(SUITRoot)/resources +GLViewer = $(SUITRoot)/resources +OCCViewer = $(SUITRoot)/resources +VTKViewer = $(SUITRoot)/resources +LIGHT = $(LIGHT_ROOT_DIR)/share/salome/resources + +[LIGHT] +name = Light +icon = LIGHT diff --git a/src/LightApp/resources/LightApp.xml b/src/LightApp/resources/LightApp.xml new file mode 100644 index 000000000..b5884f858 --- /dev/null +++ b/src/LightApp/resources/LightApp.xml @@ -0,0 +1,70 @@ + +
+ + + + + +
+
+ + + + + + +
+
+ + +
+
+ + + + + + + + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + + +
+
+ + +
+
+ + + + + + + +
+ +
+ + +
+
diff --git a/src/LightApp/resources/LightApp_images.po b/src/LightApp/resources/LightApp_images.po new file mode 100644 index 000000000..c1ee44b39 --- /dev/null +++ b/src/LightApp/resources/LightApp_images.po @@ -0,0 +1,33 @@ +// File: LightApp_images.po +// Created: May, 2005 +// Author: OCC team +// Copyright (C) CEA 2005 + +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2002-05-28 10:57:43 AM CEST\n" +"PO-Revision-Date: YYYY-MM-DD\n" +"Last-Translator: FULLNAME \n" +"Content-Type: text/plain; charset=iso-8859-1\n" + +msgid "ABOUT" +msgstr "icon_about.png" + +msgid "ABOUT_SPLASH" +msgstr "icon_about.png" + +msgid "APP_DEFAULT_ICO" +msgstr "icon_default.png" + +msgid "APP_MODULE_ICO" +msgstr "icon_module.png" + +msgid "APP_MODULE_BIG_ICO" +msgstr "icon_module_big.png" + +msgid "ICON_SELECT" +msgstr "icon_select.png" + +msgid "APP_BASE_LOGO" +msgstr "icon_applogo.png" diff --git a/src/LightApp/resources/LightApp_msg_en.po b/src/LightApp/resources/LightApp_msg_en.po new file mode 100644 index 000000000..f5c4a8f89 --- /dev/null +++ b/src/LightApp/resources/LightApp_msg_en.po @@ -0,0 +1,252 @@ +# This is a Qt message file in .po format. Each msgid starts with +# a scope. This scope should *NOT* be translated - eg. "Foo::Bar" +# would be translated to "Pub", not "Foo::Pub". +msgid "" +msgstr "" +"Project-Id-Version: example-Qt-message-extraction\n" +"POT-Creation-Date: 1999-02-23 15:38+0200\n" +"PO-Revision-Date: 1999-02-23 15:38+0200\n" +"Last-Translator: \n" +"Content-Type: text/plain; charset=iso-8859-1\n" + +msgid "LightApp_Application::ACTIVATING_MODULE" +msgstr "Trying to activate module \"%1\"" + +msgid "LightApp_Application::TOT_DESK_PREFERENCES" +msgstr "Preferences" + +msgid "LightApp_Application::MEN_DESK_PREFERENCES" +msgstr "Preferences..." + +msgid "LightApp_Application::TOT_DESK_MRU" +msgstr "Most recently used" + +msgid "LightApp_Application::MEN_DESK_MRU" +msgstr "Most recently used" + +msgid "LightApp_Application::PRP_DESK_PREFERENCES" +msgstr "Allow to change the preferences" + +msgid "LightApp_Application::INF_TOOLBAR_MODULES" +msgstr "Modules" + +msgid "LightApp_Application::APP_NAME" +msgstr "SALOME" + +msgid "LightApp_Application::PRP_APP_MODULE" +msgstr "Switch to SALOME platform neutral point" + +msgid "LightApp_Application::PRP_MODULE" +msgstr "Switch to the mocule \"%1\"" + +msgid "LightApp_Application::NEW_WINDOW_0" +msgstr "GL view" + +msgid "LightApp_Application::NEW_WINDOW_1" +msgstr "Plot2d view" + +msgid "LightApp_Application::NEW_WINDOW_2" +msgstr "OCC view" + +msgid "LightApp_Application::NEW_WINDOW_3" +msgstr "VTK view" + +msgid "LightApp_Application::INF_CANCELLED" +msgstr "Module activation cancelled" + +msgid "LightApp_Application::DATA_MODELS" +msgstr "Data models" + +msgid "LightApp_Application::OBJECT_BROWSER" +msgstr "Object Browser" + +msgid "LightApp_Application::OBJ_BROWSER_NAME" +msgstr "Object" + +msgid "LightApp_Application::LOG_WINDOW" +msgstr "Message Window" + +//======================================================================================= + +msgid "LightApp_Application::MEN_DESK_MODULE_HELP" +msgstr "Module help" + +//======================================================================================= + +msgid "LightApp_Application::PREFERENCES_NOT_LOADED" +msgstr "Preferences for module \"%1\" will be available when the module will be loaded" + +msgid "LightApp_Application::PREF_CATEGORY_SALOME" +msgstr "SALOME" + +msgid "LightApp_Application::PREF_TAB_GENERAL" +msgstr "General" + +msgid "LightApp_Application::PREF_GROUP_STUDY" +msgstr "Study properties" + +msgid "LightApp_Application::PREF_MULTI_FILE" +msgstr "Multi file save" + +msgid "LightApp_Application::PREF_ASCII_FILE" +msgstr "ASCII save" + +msgid "LightApp_Application::PREF_UNDO_LEVEL" +msgstr "Undo level" + +msgid "LightApp_Application::PREF_GROUP_EXT_BROWSER" +msgstr "External browser" + +msgid "LightApp_Application::PREF_APP" +msgstr "Application" + +msgid "LightApp_Application::PREF_PARAM" +msgstr "Parameters" + +msgid "LightApp_Application::PREF_GROUP_PY_CONSOLE" +msgstr "Python console properties" + +msgid "LightApp_Application::PREF_FONT" +msgstr "Font" + +msgid "LightApp_Application::PREF_TAB_OBJBROWSER" +msgstr "Object browser" + +msgid "LightApp_Application::PREF_GROUP_DEF_COLUMNS" +msgstr "Default columns" + +msgid "LightApp_Application::PREF_TAB_VIEWERS" +msgstr "Viewers" + +msgid "LightApp_Application::PREF_GROUP_OCCVIEWER" +msgstr "OCC Viewer 3d" + +msgid "LightApp_Application::PREF_GROUP_VTKVIEWER" +msgstr "VTK Viewer 3d" + +msgid "LightApp_Application::PREF_VIEWER_BACKGROUND" +msgstr "Background color" + +msgid "LightApp_Application::PREF_TRIHEDRON_SIZE" +msgstr "Trihedron size" + +msgid "LightApp_Application::PREF_ISOS_U" +msgstr "Number of isolines along U" +msgid "LightApp_Application::PREF_ISOS_V" +msgstr "Number of isolines along V" + +msgid "LightApp_Application::PREF_TRIHEDRON_SHOW" +msgstr "Show trihedron" + +msgid "LightApp_Application::PREF_GROUP_PLOT2DVIEWER" +msgstr "Plot2d Viewer" + +msgid "LightApp_Application::PREF_SHOW_LEGEND" +msgstr "Show legend" + +msgid "LightApp_Application::PREF_LEGEND_POSITION" +msgstr "Legend position:" + +msgid "LightApp_Application::PREF_LEFT" +msgstr "Left" + +msgid "LightApp_Application::PREF_RIGHT" +msgstr "Right" + +msgid "LightApp_Application::PREF_TOP" +msgstr "Top" + +msgid "LightApp_Application::PREF_BOTTOM" +msgstr "Bottom" + +msgid "LightApp_Application::PREF_CURVE_TYPE" +msgstr "Curve type:" + +msgid "LightApp_Application::PREF_POINTS" +msgstr "Points" + +msgid "LightApp_Application::PREF_LINES" +msgstr "Lines" + +msgid "LightApp_Application::PREF_SPLINE" +msgstr "Spline" + +msgid "LightApp_Application::PREF_MARKER_SIZE" +msgstr "Marker size:" + +msgid "LightApp_Application::PREF_LINEAR" +msgstr "Linear" + +msgid "LightApp_Application::PREF_LOGARITHMIC" +msgstr "Logarithmic" + +msgid "LightApp_Application::PREF_HOR_AXIS_SCALE" +msgstr "Horizontal axis scale:" + +msgid "LightApp_Application::PREF_VERT_AXIS_SCALE" +msgstr "Vertical axis scale:" + +msgid "LightApp_Application::PREF_TAB_DIRECTORIES" +msgstr "Directories" + +msgid "LightApp_Application::PREF_GROUP_DIRECTORIES" +msgstr "Quick directory list" + +msgid "LightApp_Application::MEN_REFRESH" +msgstr "Refresh" + +//======================================================================================= + +msgid "LightApp_PreferencesDlg::CAPTION" +msgstr "Preferences" + +//======================================================================================= + +msgid "LightApp_Module::TOP_DISPLAY" +msgstr "Display" + +msgid "LightApp_Module::MEN_DISPLAY" +msgstr "Display" + +msgid "LightApp_Module::STB_DISPLAY" +msgstr "Display" + +msgid "LightApp_Module::TOP_ERASE" +msgstr "Erase" + +msgid "LightApp_Module::MEN_ERASE" +msgstr "Erase" + +msgid "LightApp_Module::STB_ERASE" +msgstr "Erase" + +msgid "LightApp_Module::TOP_DISPLAY_ONLY" +msgstr "Display only" + +msgid "LightApp_Module::MEN_DISPLAY_ONLY" +msgstr "Display only" + +msgid "LightApp_Module::STB_DISPLAY_ONLY" +msgstr "Display only" + +//======================================================================================= + + +msgid "LightApp_ModuleDlg::CAPTION" +msgstr "Activate module" + +msgid "LightApp_ModuleDlg::NEW" +msgstr "&New" + +msgid "LightApp_ModuleDlg::OPEN" +msgstr "&Open" + +msgid "LightApp_ModuleDlg::LOAD" +msgstr "&Load" + +msgid "LightApp_ModuleDlg::CANCEL" +msgstr "&Cancel" + +msgid "LightApp_ModuleDlg::ActivateComponent_DESCRIPTION" +msgstr "Create, open or load study." + diff --git a/src/LightApp/resources/icon_about.png b/src/LightApp/resources/icon_about.png new file mode 100755 index 0000000000000000000000000000000000000000..287b4f766aa88ed3bcfc8e3137f2be4dba84e35b GIT binary patch literal 195122 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 literal 0 HcmV?d00001 diff --git a/src/LightApp/resources/icon_applogo.png b/src/LightApp/resources/icon_applogo.png new file mode 100755 index 0000000000000000000000000000000000000000..7be65180ada6ab17be0313beb31306bcecd57bf0 GIT binary patch literal 2383 zcmV-V39$BwP)004R=004l4008;_004mK004C`008P>0026d000+nm#LZ5000Qu zNkl07cIi0~!SzEyb!u9EyTgQYalfMQj5GT$D(s z{$N3k`F>10_bzuhmve>h`)kkhE`?Syh`t#I8$NeOdi4^+hbFe2!5D)j1V^cuEF$i1 zO0=sNBubM=!!+2^a0}cw%Sdf7K-RX{9~95C6>rfOotn#2zePTmVINCI^EH*C!=PRL z^H`QZr9FAw(oMG&H_yxRou4@2BsDT+-D{V}+bfj*efU3)^;xG@Z&4P%)J*F63i7DG=QQGAqN>Jr@}^AGpAx3Uy?# z)sz9-^Y7n3FlJ(6!s{_m3IhlrxC&20B?f6Z5r)9&dl-`DA7a>c`7y)0FF!%5!19~V z-DP@Neu@9zwMegM+| zD+|MiPhT0{fBXOpfPV}gW{M1_?!IPNcJvlQ=F;N~%xpmCaI!J{`SXY29}xfk$G}jt z;S59Xrjrcok6vSV`t%vl-=7G^7zh9a5Zq%{%3=)H8p9aoL|X&h@}I$b@^%J?p3Mwz z-hTwT>pMf|j!O&;r97_L5i z0nA7L8BX4P$)E(x(5p_|W)SD+VmJZJ3tKKeVsO`zU|ae@)Z~=e;G_AxEQM3wHW@hb2G4Ta56A6GZW=8fB=Gf?8vR>3>9lm0!uqy1`eR; zd0+{dY_Gu}&BxAAyX721kghaCfsG7;`UR9#%&iEE3!+RI1o^lb)?a!IPP%`9G0Y5%FjgLRhK;x1F+87lf#E06Tz3N*hB8kbqC5r= zfRM6TK@fnn9>N!Q+g4l@xhkl{sch7K5Q@4!L2q#G`Of{cIF3~m zMV$q(J2%+M5;s*t=o%Kn!iySQ%R54DgAs`@1@Z((Ry5e>65+(ev1)Op_KkrF$8|BI zkaKPkupW}U#)*ECJ0?jfAi5u1l)@@Iz_WD-)(2w@PZCB^Jy5<4g#HMD&#{pWT3SL& z6YQqz4Q(u^M5H#y0f)05S6mi!#_K4Ax~1dCRP~&YDR2zWI;BZUGo8V-)~l7>HJs3K`t$|No&NjU7bdySgeE z$kepWmFC{`zQm#Y=R(S%BqTG)-5>}vqruuiob%Wn?xZmR_Sh?syaY-B-O`2#?UR|f zdzzU&<$#!lnzBC4OPq`+g1dQ`h;Io0iCX~S@EDQ;poP4=s3j377D0}Kg*1o{3ILD? zz;y^P_I?0k9K;93ASjuEGQEh12!p7oC|EBz_@DuW4d9a_1^@&QL62brppbmZN7 zFbse^0*W0_O!M>eGe}EIgJY1`5)B{t^7$h$wR~cbkd(!c`vq*Ov9U6N-2xCmWO)o3 zfI=2MbU{fK6q~S^1jQaG>4E?&D=R$N!D1McOhKMz1&VB_*$ z1x$h*DhzDQj~VXWdCai?#C--HVNnJid2@yBUh7Idu(&zg&V053b!{c>CrrgH>P(gSS^WgQ&P9I7P4n>!vH0uY3duAO?`f z{tp2FY?uCj{`A%V1=FhjCq^3lKYjA#|F2)ZVpV(b;>8aD0ffK(KZpPeu#F`lCCXr> z%g4aY^pZhBMxKF-n+vCUfB+gY9s_~DA5SwV^K4@fW_!&rYgRL`K>CeSEkFRV+`D)0 zBe0%f`S}xA2_OOFBK$wJjzTZiLE?ne;nPbD09E!MK73}le0CcH^XE+rJS;yLp1c=l zICyv=!}V(q8RFwI7!(xb;pPFW6P8=IZhZs@FaVd9R$sX}XLkSq002ovPDHLkV1fe3 BH~atq literal 0 HcmV?d00001 diff --git a/src/LightApp/resources/icon_default.png b/src/LightApp/resources/icon_default.png new file mode 100644 index 0000000000000000000000000000000000000000..0140a6667b1232eee2ee1680bf0ef475025b0ca4 GIT binary patch literal 684 zcmV;d0#p5oP)1u zMC(dLP(cK%ATBKUKq&Q9S}iTc8XFU%ZPKJkCYf|5lg#|?Tu5xQaN(lg_MH3Ro(r(R ze+SWw>Hc~D&Dl!j_Mr>O{y()#r;j+Sx4I|P->QO#imNetMY|hNgk)4>()U#cX9!DlJ%p zROV-_M^O|rMUgruLogjdif-X(KokR@VL&zdKx5wsfR%P>>UDc`Gy$>b=bgzyiI}Zo zMG#nJFlV@?b?=s)=HUnh0ILB2o_^aw#K-#D3^aen*GlZ^4pXFW1q~Wf2cQDTvINnu zlkn)}4;UWjL9Aj02$UQc6$>t#riaT7iV1{o{J!C_qlY0r)&~Z<4AVut&0<6+ysf6r zz$zcI*xDdp6kzDXi25a-lnR3KLPdtlc8B{Fi=)_OV}Y{=03qBslt{<~+~Spptf#w7 zM*TrEOYWb{R#T!VT;(guzv@0_n8`8Q#r z*Y93tshniAs!zpg>U~to6!~(;@})+`>sc}~k<6=&>Zmz}eFuQ!^KG=izvmY*NB literal 0 HcmV?d00001 diff --git a/src/LightApp/resources/icon_module.png b/src/LightApp/resources/icon_module.png new file mode 100644 index 0000000000000000000000000000000000000000..9fdd5fb01222465f14b6dd39a8607b0486bda000 GIT binary patch literal 1385 zcmV-v1(y1WP)E*${}5JJ`f000McNliru)dUm_9wbGCV_pCN1olZp zK~#90ZIr=J+g2RMf3{y78z**L0)>Pu34^k3L!+vus+zQ3rfS-%N$bv)cG$6({U1B^ zuIF56@UJu>AeVdib-D;LaBxs@9Ov5W*RS_aPfvfNl&+LY zrL#__LlFQ#9LGYMraB>H7Gpfl7`vn>%8aV2k}S&z07Q(jbar+&Pbsavc<}%j z@B8S@n>TECcQ+=4v^nQi9LJ+D3`GDC5CFjH>MFl_^(p`Wmt~pc^LZhPBGm161>3ga z|rquU+J4up#jIo`jDFpzI(ljknO26`bziwI9Eyh^h^E|oP zYznUH0%HuKD1tOi!S{XW^?INvifEdqGCe(Ay>sWzt!lL@t*x#7`S9UGf`T9@A08h5 z{OZ-K4}IU~2qDRJUGebn5XQ&Hp;RhCtyY74J`a>qa2y9lqY=omELoOSUtV6WNRqTj zDOIxB>@teu7`0lh;`8UvFIkoqiK3W_q9_ao0}w?K=H}*LVPWC?oh-|crYVe#je(|V znOrV6rfJ#~La2Inc4nYftK~j^{P^kS=4Rx&?nJRz)TXAUSQv()AP6u%J`ROK0Vt*5 zx-KM10=ljP=bRgc;T4O;fvT!qP17(!2uXyH!PeH+)@U?(={SxG02R|TGm4_1FbtvJ z@5Ax&G3@T{LaWsRMNz;sO_s@I!hAm8uq^A3ot>SPIFA3eEUPOu8V&Aw-jEP7P*rtC zlB6X~)8tB}BAKQsV2lOZwgF=dg+c*pwHjxPrJ^V%6B82_V{FZ`tj%V#X%RvO5&*!1 z2M@UK`;!Qv?{c}^=b21K(sg|_GcyCFQVA|!zRXS2l` zqG{T0uh%>EeIFwLfMT%-v$L}!P18KaSe(gZ5T(?294CViG5|p0oO4xG{jssJezjWF zDwRqxm&+l?ai(=$FB*n%bS{TSj~?-bg@vIk%b{TyvZ|_%BuSgKTFu$t-~V7R7^u3g z#{kgCX0xlgTyDoS&HivWJlx;k-`L#T+}+#T^DxELX~`gjWE+h}cWZ0w#P|IK0QmXf!NCEy zZ9ANtoP3$4>0z(e69hpB%H{I!*=+V&p-@OBCMH^zWgTyCZ+CZgc2ZfECD(P+AP6u3 zjL!A-jvxql5CjAO5&#gMJ$u%4UH8{849ko$<@EH_cU{*dghZWAhhCKZ+ko&NhyM#j rQIH@AGGi>mIcG_dByZoa|Lgw)N}}v>NL48|00000NkvXXu0mjfY-5lX literal 0 HcmV?d00001 diff --git a/src/LightApp/resources/icon_module_big.png b/src/LightApp/resources/icon_module_big.png new file mode 100755 index 0000000000000000000000000000000000000000..99e10b1ff7802e5652aea93f3d535506b198ed92 GIT binary patch literal 3630 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 literal 0 HcmV?d00001 -- 2.30.2