Shortcut Mgr is now actually responsible for managing shortcuts: it is solely responsible and capable to dynamically bind actions with hotkey combinations and (de)serialize shortcut preference changes using SUIT_ResourceMgr.
Add SUIT_ShortcutContainer, which ensures that there are no conflicts between shortcuts. Added the ability to change shortcut preferences through the GUI.
Add a development tool to grab all shortcuts of created at runtime QtxActions .
The tool also grabs tooltips of the actions for further dynamic translation from actionID to actionName in runtime
before actions with these ID are created. Both grabbed shortcuts and translations are dumped in XML files with
identical to project-conventional resource files formatting.
-.. _setting_preferences_page:
+.. _setting_preferences_page:
*******************
Setting Preferences
- Available preferences sections are listed in the left part of the dialog box; usually this list contains "SALOME" item that specifies general application preferences and a separate section for each SALOME module available in the current session.
- The tabbed widget at the right side of the dialog box provides controls that can be used to customize the preferences.
-.. note:: The preferences for modules become accessible only after explicit loading of these modules. Until then the dialog box will show the corresponding warning message.
+.. note:: The preferences for modules become accessible only after explicit loading of these modules. Until then the dialog box will show the corresponding warning message.
More detailed information about preferences for certain modules can be found in the User's guide of the corresponding module.
If the study has just been started and other
modules have not been loaded yet, it will be possible to change only the settings which refer to
-the whole GUI SALOME session.
+the whole GUI SALOME session.
General Preferences
###################
- **Show splash screen at start-up** - allows showing or hiding the splash screen at start-up.
- **Opaque resize** - force opaque resize mode for viewers area (tabbed workspace). Clear this checkbox for less perfomant workstations.
- - **Drop-down buttons in toolbars for action groups** - when checked, the action groups are represented in the viewer toolbars as a single drop-down button, switchable by the user. Otherwise, all the buttons from the action groups are displayed in the toolbar.
+ - **Drop-down buttons in toolbars for action groups** - when checked, the action groups are represented in the viewer toolbars as a single drop-down button, switchable by the user. Otherwise, all the buttons from the action groups are displayed in the toolbar.
- **Study Properties**
- - **Multi file save** - if checked in, your study will be saved in several HDF files (one basic HDF file which will store the main information about the saved study and several other files for the data created by each component used during the study session). Opening of this study requires that **ALL** saved files should be stored in the **SAME** directory. If you would like to copy your saved study in another directory or machine, you should copy all stored files. Otherwise, if you try to open this study, some data will be lost and it will lead to invalid functioning of the SALOME platform.
+ - **Multi file save** - if checked in, your study will be saved in several HDF files (one basic HDF file which will store the main information about the saved study and several other files for the data created by each component used during the study session). Opening of this study requires that **ALL** saved files should be stored in the **SAME** directory. If you would like to copy your saved study in another directory or machine, you should copy all stored files. Otherwise, if you try to open this study, some data will be lost and it will lead to invalid functioning of the SALOME platform.
- **ASCII save** - if checked in, your study will be saved in ASCII format file (or files).
- **Automatic loading of light modules when opening study** - if checked in, Light Modules of the current study will be automatically loaded at the next study opening, allowing completion of object browser.
- **Store positions of windows** - if checked in, positions of windows will be saved in a special file at the end of the current session and then restored for a new session.
- **Multi file python dump** - allows to generate multiple files (separately for each component) for dumping of a study to a python script. If the option is disabled, the study is dumped to a single python script.
- **Save GUI state in python dump** - if this option is switched on, the Python script resulting from Dump Python operation will include commands related to the GUI state.
-- **External browser** - allows to define what browser will be used to show SALOME reference manuals: internal (built-in SALOME browser) or external (IE, Netscape, Mozilla, ...). In addition, it is possible to specify
+- **External browser** - allows to define what browser will be used to show SALOME reference manuals: internal (built-in SALOME browser) or external (IE, Netscape, Mozilla, ...). In addition, it is possible to specify
- **Application** - this option allows you to set an external browser (IE, Netscape) which will be used for viewing SALOME reference manuals. By default, Mozilla is used.
- **Parameters** - additional parameters required for launching of the external browser (if applicable).
- **Font** - allows quickly setting the parameters (style, size, face) of the :ref:`font_color_dlg` used in embedded Python console.
- **Show banner** - this option allows to show/hide the Python banner on top of the console window.
-- **Show MRU items** - allows to define the maximum **Number** of items in **Most Recently Used** list and the **Link type**:
+- **Show MRU items** - allows to define the maximum **Number** of items in **Most Recently Used** list and the **Link type**:
- - **Long** - shows the full path to the file.
+ - **Long** - shows the full path to the file.
- **Short** - shows the file name only.
- **Auto** - shows full paths to the files only if some files from different locations have the same name.
-- **Full-screen**
+- **Full-screen**
- **Hide object browser and viewers toolbars** - switches automatic hiding of Object Browser and OCC viewer toolbar in full-screen mode.
- **Enable V-Sync** - activates vertical synchronization.
- **Enable quad-buffer support** - allows quad-buffered rendering.
- .. note::
+ .. note::
It is neccessary to enable quad-buffered stereoscopic rendering manually in graphic driver settings. SALOME does not do it automatically.
- .. note::
+ .. note::
All existing OCC 3D views should be re-created for quad-buffer support.
- **Background** - specifies the default background for the viewers, separately for (for more details, refer to the :ref:`viewer_background` page"):
- Checkerboard
- Split View Port Horizontal
- .. note::
+ .. note::
The stereo pair type selected in this combobox is applied for all existing VTK 3D views with stereo rendering already turned on within the same SALOME GUI session. It is not possible to use different stereo modes in several VTK 3D views at the same time within the same SALOME GUI session.
- **Anaglyph filter** - specifies the format of anaglyph stereo pair:
- **Enable quad-buffer support** - allows quad-buffered rendering.
- .. note::
+ .. note::
It is neccessary to enable quad-buffered stereoscopic rendering manually in graphic driver settings. SALOME does not do it automatically.
- .. note::
+ .. note::
All existing VTK 3D views should be re-created for quad-buffer support.
- **Selection**
- **Preselection** - allows to choose among three possible preselection modes:
- **Standard** - this mode works quickly, by checking only bounding boxes of objects. It does not deal with the order of actors in the view or with their data (points/ cells).
- - **Dynamic** - works directly with cells of actors, which provides the exact area of preselection. This mode is much more slower.
+ - **Dynamic** - works directly with cells of actors, which provides the exact area of preselection. This mode is much more slower.
- **Disabled** - switches off the preselection.
- **Enable selection** - switches selection on/off.
- **Decrease Speed Increment** - decreases by 1 the speed increment used for the keyboard (same as [-] key).
- **Increase Speed Increment** - increase by 1 the speed increment used for the keyboard (same as [+] key).
- - **Dominant / combined switch** - toggles button to switch to dominant or combined movements.
+ - **Dominant / combined switch** - toggles button to switch to dominant or combined movements.
- **AVI Recording**
- **Mode** - allows to choose from two recording regimes:
- - **Recording all displayed frames** - records exactly at the FPS rate specified by the user.
+ - **Recording all displayed frames** - records exactly at the FPS rate specified by the user.
- **Recording at a given FPS** - records only when the contents of the viewer change (some activity is performed). In the AVI file non-recorded images are substituted with the copies of the latest recorded image, which produces files with lower quality but requires less system resources.
- **FPS** - allows to define the FPS (frames per second) rate for the clip. Set greater value for better quality.
:align: center
- **Background color** - this submenu allows to select the background color. Click on the colored line to access to the :ref:`select_color_and_font_page` dialog box.
-- **Selection color** - this submenu allows to select the color of selected object in the viewer.
+- **Selection color** - this submenu allows to select the color of selected object in the viewer.
- **Viewer** - allows specifying the properties of the Plot 2D Viewer.
- **Curve Type** - this allows to set the representation of graphs in your presentations. You can see only **Points**, points connected with **Lines** or points connected with smooth **Splines**.
- **Marker Size** - this submenu allows you to set the size of markers in your graphs.
- **Horizontal** and **Vertical axis scale** - this submenus allow you to set the scale for vertical and horizontal axes. It can be either **Linear** or **Logarithmic**. Note that the **Logarithmic** scale can be used only if the minimum value of corresponding component (abscissa or ordinate) of all points displayed in the viewer is greater than zero. If this condition is not met, the scale is switched to **Linear** automatically, even if it is set to **Logarithmic**.
- - **Deviation marker color** - this submenu allows to select the color of the deviation marker.
- - **Deviation marker line width** allows to define line width of the deviation marker.
- - **Deviation marker tick size** allows to define size of the upper and lower horizontal lines of the deviation marker.
+ - **Deviation marker color** - this submenu allows to select the color of the deviation marker.
+ - **Deviation marker line width** allows to define line width of the deviation marker.
+ - **Deviation marker tick size** allows to define size of the upper and lower horizontal lines of the deviation marker.
- **Legend** - allows specifying the properties of the legend.
- **Legend Position** - this submenu allows to set the default position of the legend, it can be located to the left, to the right, on top or on bottom of the graph.
- **Symbol type** you can select the type of legend item symbol from "Marker on line" or "Marker above line"
- **Legend font** - this allows to set type and face for the font of Legend item.
- - **Legend font color** - this allows to select the color of the font of the legend item.
- - **Highlighted legend font color** - this submenu allows to select the color of the font of the selected legend item.
+ - **Legend font color** - this allows to select the color of the font of the legend item.
+ - **Highlighted legend font color** - this submenu allows to select the color of the font of the selected legend item.
.. _default_python_preferences:
.. image:: ../images/pref_salome_pythonviewer.png
:align: center
-.. note::
+.. note::
The following settings are default and will be applied only for newly created Python viewers. Customization of already opened viewers can be done using local :ref:`custom_python_preferences` called by clicking on the corresponding icon of :ref:`python_viewer_page`.
- **Font settings** allows setting font variant, size and style.
- **Default columns** - these checkboxes allow to display or hide **Value**, **Entry**, **IOR** and **Reference entry** columns in the Object Browser.
-Shortcuts Preferences
+Shortcut Preferences
#####################
.. image:: ../images/pref_salome_shortcuts.png
:align: center
-- **Shortcuts settings** widget allows to define custom shortcuts for various operations. To change keyboard sequence for a certain action - select the action and press the custom keys combination.
+- **Shortcut settings** widget allows to define custom shortcuts for various operations. To change keyboard sequence for a certain action - select the action and press the custom keys combination.
:ref:`select_color_and_font_page`: "Font and color preferences"
When you change settings (click **OK** or **Apply** button) each module
receives the notification about what preferences are changed. You can
also click **Defaults** button to restore default preferences or **Close**
-button to quit the dialog box without any changes.
+button to quit the dialog box without any changes.
**Import** button allows loading specific user file containing
preferences from any location at the computer through a standard
are saved to the file in the end of the working session and restored
at the application start-up.
-.. note::
+.. note::
The preferences you set will be default preferences for all **new** objects, but they are not retroactive and do not automatically apply to the existing objects.
# e081f044dacf408690aa128eca010f21
#: ../../../../../../SRC/GUI_SRC/doc/salome/gui/input/setting_preferences.rst:357
msgid ""
-"**Shortcuts settings** widget allows to define custom shortcuts for "
+"**Shortcut settings** widget allows to define custom shortcuts for "
"various operations. To change keyboard sequence for a certain action - "
"select the action and press the custom keys combination."
msgstr ""
#include <SUIT_Desktop.h>
#include <SUIT_Session.h>
#include <SUIT_ResourceMgr.h>
+#include <SUIT_ShortcutMgr.h>
#include <QMenu>
{
if ( !menuMgr() )
return -1;
-
+
return menuMgr()->insert( subMenu, menu, group, id, idx, menuObj );
}
{
if ( !a || !menuMgr() )
return -1;
-
+
ActionMgrLocker lock( menuMgr(), !myMenuShown );
int regId = registerAction( id, a );
if ( !myMenuShown )
setMenuShown( a, false );
-
+
return intId != -1 ? regId : -1;
}
setToolShown( action( id ), on );
}
+QString CAM_Module::makeActionID(const QString& theInModuleActionID) const
+{
+ return SUIT_ShortcutMgr::makeActionID(name(), theInModuleActionID);
+}
+
/*!
\brief Get action by specified \a id.
\param id action ID
\param icon action icon
\param menu menu text
\param tip status bar tip
- \param key keyboard accelerator
+ \param key will be disabled by SUIT_ShortcutMgr!
\param parent parent object
\param toggle if \c true, the action will be toggled
\param reciever action activation signal receiver object
\param member action activation signal receiver slot
+ \param inModuleActionID module-unique action ID
*/
QAction* CAM_Module::createAction( const int id, const QString& text, const QIcon& icon,
const QString& menu, const QString& tip, const int key,
QObject* parent, const bool toggle, QObject* reciever,
- const char* member, const QString& shortcutAction )
+ const char* member, const QString& inModuleActionID )
{
- return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, shortcutAction );
+ return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, inModuleActionID );
}
/*!
\param icon action icon
\param menu menu text
\param tip status bar tip
- \param key keyboard accelerator
+ \param key will be disabled by SUIT_ShortcutMgr!
\param parent parent object
\param toggle if \c true, the action will be toggled
\param reciever action activation signal receiver object
\param member action activation signal receiver slot
+ \param inModuleActionID module-unique action ID
*/
QAction* CAM_Module::createAction( const int id, const QString& text, const QIcon& icon,
const QString& menu, const QString& tip, const QKeySequence& key,
QObject* parent, const bool toggle, QObject* reciever,
- const char* member, const QString& shortcutAction )
+ const char* member, const QString& inModuleActionID )
{
- QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, shortcutAction );
+ const QString actionID = makeActionID(inModuleActionID);
+ QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, actionID );
a->setStatusTip( tip );
connect( a, SIGNAL( triggered( bool ) ), this, SLOT( moduleActionActivated() ), Qt::UniqueConnection );
QtxActionMenuMgr* menuMgr() const;
QtxActionToolMgr* toolMgr() const;
+ QString makeActionID(const QString& theInModuleActionID) const;
+
virtual QAction* action( const int ) const;
virtual int actionId( const QAction* ) const;
virtual QAction* createAction( const int, const QString&, const QIcon&, const QString&,
virtual void logAction( QAction* );
bool isActionLoggingEnabled() const;
void setActionLoggingEnabled( bool );
-
+
static QAction* separator();
public slots:
private slots:
void onInfoChanged( QString );
-protected:
+protected:
virtual bool isSelectionCompatible();
virtual CAM_DataModel* createDataModel();
QMap<int, QAction*> myActionMap; //!< menu actions
bool myMenuShown; //!< menu shown flag
bool myToolShown; //!< tool shown flag
- bool myActionLoggingEnabled; //!< action logging enabled
+ bool myActionLoggingEnabled; //!< action logging enabled
friend class CAM_Application;
};
MESSAGE("Removing of an extension was cancelled");
return; // cancelled
}
-
+
if (activeStudy() && activeStudy()->isModified() && !onSaveDoc())
{
// doc is not saved, or saving cancelled
resourceMgr()->save();
// Update shortcuts
- shortcutMgr()->updateShortcuts();
+ shortcutMgr()->rebindActionsToKeySequences();
}
delete prefDlg;
// .. "Shortcuts" preferences tab <<start>>
int shortcutTab = pref->addPreference( tr( "PREF_TAB_SHORTCUTS" ), salomeCat );
- // ... "Shortcuts settings" group <<start>>
- int shortcutGroup = pref->addPreference( tr( "PREF_GROUP_SHORTCUTS" ), shortcutTab );
- pref->addPreference( tr( "" ), shortcutGroup,
- LightApp_Preferences::ShortcutTree, "shortcuts" );
- // ... "Shortcuts settings" group <<end>>
+ pref->addPreference( tr( "" ), shortcutTab, LightApp_Preferences::ShortcutTree, "shortcuts" );
// .. "Shortcuts" preferences tab <<end>>
// . Top-level "SALOME" preferences group <<end>>
/*!Update object browser.
* For updating model or whole object browser use update() method can be used.
*/
-void LightApp_Module::updateObjBrowser( bool theIsUpdateDataModel,
+void LightApp_Module::updateObjBrowser( bool theIsUpdateDataModel,
SUIT_DataObject* theDataObject )
{
if (!getApp()->objectBrowser())
if ( action(myErase) )
action(myErase)->setEnabled(true);
- application()->shortcutMgr()->setSectionEnabled( moduleName() );
+ application()->shortcutMgr()->setActionsWithPrefixInIDEnabled( moduleName() );
/* BUG 0020498 : The Entry column is always shown at module activation
The registration of column is moved into LightApp_Application
if ( action(myErase) )
action(myErase)->setEnabled(false);
- application()->shortcutMgr()->setSectionEnabled( moduleName(), false );
-
+ application()->shortcutMgr()->setActionsWithPrefixInIDEnabled( moduleName(), false );
+
/* BUG 0020498 : The Entry column is always shown at module activation
QString EntryCol = QObject::tr( "ENTRY_COLUMN" );
LightApp_DataModel* m = dynamic_cast<LightApp_DataModel*>( dataModel() );
void LightApp_Module::studyClosed( SUIT_Study* theStudy )
{
CAM_Module::studyClosed( theStudy );
-
+
myIsFirstActivate = true;
-
+
LightApp_Application* app = dynamic_cast<LightApp_Application*>(application());
if ( app ) {
SUIT_DataBrowser* ob = app->objectBrowser();
QPixmap p;
SUIT_Desktop* d = application()->desktop();
-
- QAction
+
+ QAction
*disp = createAction( -1, tr( "TOP_SHOW" ), p, tr( "MEN_SHOW" ), tr( "STB_SHOW" ),
- 0, d, false, this, SLOT( onShowHide() ), QString("General:Show object(s)") ),
+ 0, d, false, this, SLOT( onShowHide() ), QString("#General/Objects(s)/Show") ),
*erase = createAction( -1, tr( "TOP_HIDE" ), p, tr( "MEN_HIDE" ), tr( "STB_HIDE" ),
- 0, d, false, this, SLOT( onShowHide() ) , QString("General:Hide object(s)") ),
+ 0, d, false, this, SLOT( onShowHide() ) , QString("#General/Objects(s)/Hide") ),
*dispOnly = createAction( -1, tr( "TOP_DISPLAY_ONLY" ), p, tr( "MEN_DISPLAY_ONLY" ), tr( "STB_DISPLAY_ONLY" ),
0, d, false, this, SLOT( onShowHide() ) ),
*eraseAll = createAction( -1, tr( "TOP_ERASE_ALL" ), p, tr( "MEN_ERASE_ALL" ), tr( "STB_ERASE_ALL" ),
myDisplayOnly = actionId( dispOnly );
myEraseAll = actionId( eraseAll );
- myPopupMgr->insert( disp, -1, 0 );
+ myPopupMgr->insert( disp, -1, 0 );
myPopupMgr->insert( erase, -1, 0 );
myPopupMgr->insert( dispOnly, -1, 0 );
myPopupMgr->insert( eraseAll, -1, 0 );
*
* 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.
+* create operations.
*/
LightApp_Operation* LightApp_Module::createOperation( const int id ) const
{
/*!
\brief Returns instance of operation by its id; if there is no operation
corresponding to this id, null pointer is returned
- \param id - operation id
+ \param id - operation id
\return operation instance
*/
LightApp_Operation* LightApp_Module::operation( const int id ) const
bool LightApp_Module::reusableOperation( const int /*id*/ )
{
return true;
-}
+}
/*!
virtual method
// update visibility state of objects
LightApp_Application* app = dynamic_cast<LightApp_Application*>(SUIT_Session::session()->activeApplication());
if ( !app ) return;
-
+
SUIT_DataBrowser* ob = app->objectBrowser();
if ( !ob || !ob->model() ) return;
SUIT_DataObject* rootObj = ob->root();
if ( !rootObj ) return;
-
+
DataObjectList listObj = rootObj->children( true );
-
+
SUIT_ViewModel* vmod = 0;
if ( SUIT_ViewManager* vman = app->activeViewManager() )
vmod = vman->getViewModel();
LightApp_DataObject* lo = dynamic_cast<LightApp_DataObject*>( theObject );
if ( !lo ) return;
-
+
// detect action index (from LightApp level)
int id = -1;
-
+
if ( study->visibilityState( lo->entry() ) == Qtx::ShownState )
id = myErase;
else if ( study->visibilityState( lo->entry() ) == Qtx::HiddenState )
id = myDisplay;
-
+
if ( id != -1 )
startOperation( id );
}
if ( myPrefs && myPrefs->resourceMgr() )
{
QtxResourceMgr::WorkingMode prev = myPrefs->resourceMgr()->setWorkingMode( QtxResourceMgr::IgnoreUserValues );
- myPrefs->retrieve();
+ myPrefs->retrieveDefault();
myPrefs->resourceMgr()->setWorkingMode( prev );
}
emit defaultPressed();
<parameter name="rt_reflection" value="true"/>
<parameter name="rt_antialiasing" value="false"/>
<parameter name="rt_shadow" value="true"/>
- <parameter name="rt_trans_shadow" value="false"/>
+ <parameter name="rt_trans_shadow" value="false"/>
<parameter name="light_color" value="255, 255, 255"/>
<parameter name="light_dx" value="0.0"/>
<parameter name="light_dy" value="0.0"/>
<parameter name="animation" value="0"/>
<parameter name="size" value="300"/>
</section>
- <!--Salome shortcut settings-->
- <section name="shortcuts_settings">
- <parameter name="general_sections" value="General;Viewers"/>
- </section>
- <section name="shortcuts:General">
- <parameter name="Show object(s)" value="Ctrl+Alt+S"/>
- <parameter name="Hide object(s)" value="Ctrl+Alt+H"/>
- </section>
- <section name="shortcuts:Viewers">
- <parameter name="Front view" value="Ctrl+Alt+F"/>
- <parameter name="Back view" value="Ctrl+Alt+B"/>
- <parameter name="Top view" value="Ctrl+Alt+P"/>
- <parameter name="Bottom view" value="Ctrl+Alt+O"/>
- <parameter name="Left view" value="Ctrl+Alt+J"/>
- <parameter name="Right view" value="Ctrl+Alt+G"/>
- <parameter name="Reset view" value="Ctrl+Alt+E"/>
- </section>
- <section name="shortcuts:Geometry">
- <parameter name="Increase number of isolines" value="Meta+I"/>
- <parameter name="Decrease number of isolines" value="Meta+D"/>
- <parameter name="Increase transparency" value="Meta+Y"/>
- <parameter name="Decrease transparency" value="Meta+T"/>
+ <!--Salome shortcut settings
+ See SUIT_ShortcutMgr for details.
+ -->
+ <section name="shortcuts:">
+ <!--Actions of these shortcuts are available even if no module is active-->
+ <parameter name="TOT_DESK_FILE_NEW" value="Ctrl+N"/>
+ <parameter name="TOT_DESK_FILE_OPEN" value="Ctrl+O"/>
+ <parameter name="TOT_DESK_FILE_CLOSE" value="Ctrl+W"/>
+ <parameter name="TOT_DESK_FILE_EXIT" value="Ctrl+Q"/>
+ <parameter name="TOT_DESK_FILE_SAVE" value="Ctrl+S"/>
+ <parameter name="TOT_DESK_FILE_SAVEAS" value="Ctrl+Shift+S"/>
+ <parameter name="TOT_DESK_EDIT_COPY" value="Ctrl+C"/>
+ <parameter name="TOT_DESK_EDIT_PASTE" value="Ctrl+V"/>
+ <parameter name="#General/Objects(s)/Show" value="Ctrl+Alt+S"/>
+ <parameter name="#General/Objects(s)/Hide" value="Ctrl+Alt+H"/>
+ <parameter name="#Viewers/View/Set X+" value="Ctrl+Alt+B"/>
+ <parameter name="#Viewers/View/Set X-" value="Ctrl+Alt+F"/>
+ <parameter name="#Viewers/View/Set Y+" value="Ctrl+Alt+J"/>
+ <parameter name="#Viewers/View/Set Y-" value="Ctrl+Alt+G"/>
+ <parameter name="#Viewers/View/Set Z+" value="Ctrl+Alt+O"/>
+ <parameter name="#Viewers/View/Set Z-" value="Ctrl+Alt+P"/>
+ <parameter name="#Viewers/View/Rotate anticlockwise" value=""/>
+ <parameter name="#Viewers/View/Rotate clockwise" value=""/>
+ <parameter name="#Viewers/View/Reset" value="Ctrl+Alt+E"/>
+ </section>
+ <section name="shortcuts:SHAPER">
+ </section>
+ <section name="shortcuts:GEOM">
+ <parameter name="Isolines/Increase number" value="Meta+I"/>
+ <parameter name="Isolines/Decrease number" value="Meta+D"/>
+ <parameter name="Transparency/Increase" value="Meta+Y"/>
+ <parameter name="Transparency/Decrease" value="Meta+T"/>
+ </section>
+ <!--Names of actions for shortcut editor
+ See SUIT_ShortcutMgr for details
+ -->
+ <section name="shortcut_translations:/#General/Objects(s)/Show">
+ <parameter name="en" value="Show"/>
+ <parameter name="fr" value="Afficher"/>
+ <parameter name="ja" value="表示"/>
+ </section>
+ <section name="shortcut_translations:/#General/Objects(s)/Hide">
+ <parameter name="en" value="Hide"/>
+ <parameter name="fr" value="Cacher"/>
+ <parameter name="ja" value="非表示"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Set X+">
+ <parameter name="en" value="Back view"/>
+ <parameter name="fr" value="Vue arrière"/>
+ <parameter name="ja" value="背面図"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Set X-">
+ <parameter name="en" value="Front view"/>
+ <parameter name="fr" value="Vue de devant"/>
+ <parameter name="ja" value="正面"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Set Y+">
+ <parameter name="en" value="Left view"/>
+ <parameter name="fr" value="Vue de gauche"/>
+ <parameter name="ja" value="左側のビュー"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Set Y-">
+ <parameter name="en" value="Right view"/>
+ <parameter name="fr" value="Vue de droite"/>
+ <parameter name="ja" value="右側のビュー"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Set Z+">
+ <parameter name="en" value="Bottom view"/>
+ <parameter name="fr" value="Vue de dessous"/>
+ <parameter name="ja" value="下から表示します。"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Set Z-">
+ <parameter name="en" value="Top view"/>
+ <parameter name="fr" value="Vue de dessus"/>
+ <parameter name="ja" value="上から見る"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Rotate anticlockwise">
+ <parameter name="en" value="Rotate view counterclockwise"/>
+ <parameter name="fr" value="Tourner la vue à gauche"/>
+ <parameter name="ja" value="表示を左に"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Rotate clockwise">
+ <parameter name="en" value="Rotate view clockwise"/>
+ <parameter name="fr" value="Tourner à droite"/>
+ <parameter name="ja" value="右のビューを回転させる"/>
+ </section>
+ <section name="shortcut_translations:/#Viewers/View/Reset">
+ <parameter name="en" value="Reset view point"/>
+ <parameter name="fr" value="Restaurer le point de vue"/>
+ <parameter name="ja" value="ビューのポイントを復元します。"/>
+ </section>
+ <section name="shortcut_translations:GEOM/Isolines/Increase number">
+ <parameter name="en" value="Increase number of isolines"/>
+ <parameter name="fr" value="Augmenter le nombre d'isolignes"/>
+ <parameter name="ja" value="等値線の数を増やす"/>
+ </section>
+ <section name="shortcut_translations:GEOM/Isolines/Decrease number">
+ <parameter name="en" value="Decrease number of isolines"/>
+ <parameter name="fr" value="Diminuer le nombre d'isolignes"/>
+ <parameter name="ja" value="等値線の数を減らす"/>
+ </section>
+ <section name="shortcut_translations:GEOM/Transparency/Increase">
+ <parameter name="en" value="Increase transparency"/>
+ <parameter name="fr" value="Augmenter la transparence"/>
+ <parameter name="ja" value="透明度を高める"/>
+ </section>
+ <section name="shortcut_translations:GEOM/Transparency/Decrease">
+ <parameter name="en" value="Decrease transparency"/>
+ <parameter name="fr" value="Diminuer la transparence"/>
+ <parameter name="ja" value="透明度を下げる"/>
</section>
<section name="ExternalBrowser" >
<!-- External HELP browser settings -->
</message>
<message>
<source>PREF_GROUP_SHORTCUTS</source>
- <translation>Shortcuts settings</translation>
+ <translation>Shortcut settings</translation>
</message>
<message>
<source>PREF_GROUP_FULL_SCREEN</source>
"................................",
"................................"};
-
+
/*!
\brief Constructor
\param theDesktop main window of application
// Projections
aAction = new QtxAction(tr("MNU_FRONT_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_FRONT" ) ),
- tr( "MNU_FRONT_VIEW" ), 0, this, false, "Viewers:Front view");
+ tr( "MNU_FRONT_VIEW" ), 0, this, false, "/#Viewers/View/Set X-");
aAction->setStatusTip(tr("DSC_FRONT_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onFrontView()));
this->addAction(aAction);
toolMgr()->registerAction( aAction, FrontId );
aAction = new QtxAction(tr("MNU_BACK_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_BACK" ) ),
- tr( "MNU_BACK_VIEW" ), 0, this, false, "Viewers:Back view");
+ tr( "MNU_BACK_VIEW" ), 0, this, false, "/#Viewers/View/Set X+");
aAction->setStatusTip(tr("DSC_BACK_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onBackView()));
this->addAction(aAction);
toolMgr()->registerAction( aAction, BackId );
aAction = new QtxAction(tr("MNU_TOP_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_TOP" ) ),
- tr( "MNU_TOP_VIEW" ), 0, this, false, "Viewers:Top view");
+ tr( "MNU_TOP_VIEW" ), 0, this, false, "/#Viewers/View/Set Z-");
aAction->setStatusTip(tr("DSC_TOP_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onTopView()));
this->addAction(aAction);
toolMgr()->registerAction( aAction, TopId );
aAction = new QtxAction(tr("MNU_BOTTOM_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_BOTTOM" ) ),
- tr( "MNU_BOTTOM_VIEW" ), 0, this, false, "Viewers:Bottom view");
+ tr( "MNU_BOTTOM_VIEW" ), 0, this, false, "/#Viewers/View/Set Z+");
aAction->setStatusTip(tr("DSC_BOTTOM_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onBottomView()));
this->addAction(aAction);
toolMgr()->registerAction( aAction, BottomId );
aAction = new QtxAction(tr("MNU_LEFT_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_LEFT" ) ),
- tr( "MNU_LEFT_VIEW" ), 0, this, false, "Viewers:Left view");
+ tr( "MNU_LEFT_VIEW" ), 0, this, false, "/#Viewers/View/Set Y+");
aAction->setStatusTip(tr("DSC_LEFT_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onLeftView()));
this->addAction(aAction);
toolMgr()->registerAction( aAction, LeftId );
aAction = new QtxAction(tr("MNU_RIGHT_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_RIGHT" ) ),
- tr( "MNU_RIGHT_VIEW" ), 0, this, false, "Viewers:Right view");
+ tr( "MNU_RIGHT_VIEW" ), 0, this, false, "/#Viewers/View/Set Y-");
aAction->setStatusTip(tr("DSC_RIGHT_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onRightView()));
this->addAction(aAction);
// rotate anticlockwise
aAction = new QtxAction(tr("MNU_ANTICLOCKWISE_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_ANTICLOCKWISE" ) ),
- tr( "MNU_ANTICLOCKWISE_VIEW" ), 0, this, false, "Viewers:Rotate anticlockwise");
+ tr( "MNU_ANTICLOCKWISE_VIEW" ), 0, this, false, "/#Viewers/View/Rotate anticlockwise");
aAction->setStatusTip(tr("DSC_ANTICLOCKWISE_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onAntiClockWiseView()));
this->addAction(aAction);
// rotate clockwise
aAction = new QtxAction(tr("MNU_CLOCKWISE_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_CLOCKWISE" ) ),
- tr( "MNU_CLOCKWISE_VIEW" ), 0, this, false, "Viewers:Rotate clockwise");
+ tr( "MNU_CLOCKWISE_VIEW" ), 0, this, false, "/#Viewers/View/Rotate clockwise");
aAction->setStatusTip(tr("DSC_CLOCKWISE_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onClockWiseView()));
this->addAction(aAction);
aProjectionGroup->addAction( toolMgr()->action( OrthographicId ) );
aProjectionGroup->addAction( toolMgr()->action( PerspectiveId ) );
connect(aProjectionGroup, SIGNAL(triggered(QAction*)), this, SLOT(onProjectionType(QAction*)));
-
+
// Reset
aAction = new QtxAction(tr("MNU_RESET_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_VIEW_RESET" ) ),
- tr( "MNU_RESET_VIEW" ), 0, this, false, "Viewers:Reset view");
+ tr( "MNU_RESET_VIEW" ), 0, this, false, "/#Viewers/View/Reset");
aAction->setStatusTip(tr("DSC_RESET_VIEW"));
connect(aAction, SIGNAL(triggered()), this, SLOT(onResetView()));
this->addAction(aAction);
Handle(V3d_View) aView3d = myViewPort->getView();
if (myAutomaticZoom)
{
- if ( !aView3d.IsNull() )
+ if ( !aView3d.IsNull() )
aView3d->SetProj (V3d_Xpos);
onViewFitAll();
}
Handle(V3d_View) aView3d = myViewPort->getView();
if (myAutomaticZoom)
{
- if ( !aView3d.IsNull() )
+ if ( !aView3d.IsNull() )
aView3d->SetProj (V3d_Xneg);
onViewFitAll();
}
Handle(V3d_View) aView3d = myViewPort->getView();
if (myAutomaticZoom)
{
- if ( !aView3d.IsNull() )
+ if ( !aView3d.IsNull() )
aView3d->SetProj (V3d_Zpos);
onViewFitAll();
}
Handle(V3d_View) aView3d = myViewPort->getView();
if (myAutomaticZoom)
{
- if ( !aView3d.IsNull() )
+ if ( !aView3d.IsNull() )
aView3d->SetProj (V3d_Zneg);
onViewFitAll();
}
Handle(V3d_View) aView3d = myViewPort->getView();
if (myAutomaticZoom)
{
- if ( !aView3d.IsNull() )
+ if ( !aView3d.IsNull() )
aView3d->SetProj (V3d_Yneg);
onViewFitAll();
}
Handle(V3d_View) aView3d = myViewPort->getView();
if (myAutomaticZoom)
{
- if ( !aView3d.IsNull() )
+ if ( !aView3d.IsNull() )
aView3d->SetProj (V3d_Ypos);
onViewFitAll();
}
Image_PixMap aPix;
view->ToPixMap(aPix, aWidth, aHeight, Graphic3d_BT_RGB);
-
+
QImage anImage( aWidth, aHeight, QImage::Format_ARGB32 );
for ( int i = 0; i < aWidth; i++ ) {
for ( int j = 0; j < aHeight; j++ ) {
anImage.setPixelColor( i, j, color );
}
}
-
+
if ( aPix.IsTopDown() )
anImage = anImage.mirrored();
return anImage;
aProps.getPosition( aPosition[0], aPosition[1], aPosition[2] );
aProps.getViewUp( anUpDir[0], anUpDir[1], anUpDir[2] );
aProps.getAxialScale( anAxialScale[0], anAxialScale[1], anAxialScale[2] );
-
+
try {
aDestView->SetAt( aFocalPoint[0], aFocalPoint[1], aFocalPoint[2] );
aDestView->SetEye( aPosition[0], aPosition[1], aPosition[2] );
getViewPort()->setAxialScale( anAxialScale[0], anAxialScale[1], anAxialScale[2] );
aDestView->SetImmediateUpdate( Standard_True );
aDestView->Redraw();
- }
+ }
catch (Standard_Failure&) {
}
# --- options ---
# additional include directories
-INCLUDE_DIRECTORIES(${QT_INCLUDES})
+INCLUDE_DIRECTORIES(
+ ${QT_INCLUDES}
+ ${PROJECT_SOURCE_DIR}/src/SUIT
+)
# additional preprocessor / compiler flags
ADD_DEFINITIONS(${QT_DEFINITIONS})
<file>images/open.png</file>
<file>images/close.png</file>
<file>images/appicon.png</file>
+ <file>images/shortcut_disable.svg</file>
+ <file>images/shortcut_restore.svg</file>
</qresource>
</RCC>
-
+
\class QtxAction
\brief Generic action class.
- The class QtxAction inherits QWidgetAction class and can be used
+ The class QtxAction inherits QWidgetAction class and can be used
as base class when implementing any custom menu/toolbar actions.
- It is necessary to subclass from QtxAction and redefine virtual
+ It is necessary to subclass from QtxAction and redefine virtual
callback methods addedTo(), removedFrom() (which are called automatically
when the action is added to the widget and removed from it) to customize
- the action behavior.
+ the action behavior.
*/
/*!
\brief Constructor.
- Creates an action owned by \a parent.
+ Creates an action owned by \a parent.
Parameter \a toggle can be used to make the action checkable.
- Parameter \a shortcutAction can be used to assign the shortcut from
- preferences. This parameter value corresponds to shortcut action identifier
- in shortcut preferences.
+ Parameter \a ID is used to de(serialize) shortcut settings.
\param parent parent object
\param toggle if \c true the action will be a toggle action
- \param shortcutAction shortcut action identifier
+ \param ID shortcut action identifier
*/
-QtxAction::QtxAction( QObject* parent, bool toggle, const QString& shortcutAction )
+QtxAction::QtxAction( QObject* parent, bool toggle, const QString& ID )
: QWidgetAction( parent )
{
setCheckable( toggle );
- setShortcutActionName(shortcutAction);
+ setID(ID);
QApplication::instance()->installEventFilter( this );
}
\brief Constructor.
Creates an action owned by \a parent. Parameters \a text,
- \a icon, \a menuText and \a accel specify the action's attributes.
+ \a icon, \a menuText and \a ID specify the action's attributes.
Parameter \a toggle can be used to make the action checkable.
- Parameter \a shortcutAction can be used to assign the shortcut from
- preferences. This parameter value corresponds to shortcut action identifier
- in shortcut preferences.
+ Parameter \a ID is used to de(serialize) shortcut settings.
\param text tooltip text
\param icon iconset
\param menuText menu text
- \param accel shortcut key sequence
+ \param accel will be disabled by SUIT_ShortcutMgr!
\param parent parent object
\param toggle if \c true the action will be a toggle action
- \param shortcutAction shortcut action identifier
+ \param ID shortcut action identifier
*/
-QtxAction::QtxAction( const QString& text, const QIcon& icon, const QString& menuText,
- int accel, QObject* parent, bool toggle, const QString& shortcutAction )
+QtxAction::QtxAction( const QString& text, const QIcon& icon, const QString& menuText,
+ int accel, QObject* parent, bool toggle, const QString& ID )
: QWidgetAction( parent )
{
setIcon( icon );
setText( menuText );
setToolTip( text );
- setShortcut( accel );
setCheckable( toggle );
- setShortcutActionName(shortcutAction);
+ setID(ID);
+ setShortcut(accel);
QApplication::instance()->installEventFilter( this );
}
\brief Constructor.
Creates an action owned by \a parent. Parameters \a text,
- \a icon, \a menuText and \a accel specify the action's attributes.
+ \a icon, \a menuText and \a ID specify the action's attributes.
Parameter \a toggle can be used to make the action checkable.
- Parameter \a shortcutAction can be used to assign the shortcut from
- preferences. This parameter value corresponds to shortcut action identifier
- in shortcut preferences.
+ Parameter \a ID is used to de(serialize) shortcut settings.
\param text tooltip text
\param icon iconset
\param menuText menu text
- \param accel shortcut key sequence
+ \param accel will be disabled by SUIT_ShortcutMgr!
\param parent parent object
\param toggle if \c true the action will be a toggle action
- \param shortcutAction shortcut action identifier
+ \param ID shortcut action identifier
*/
-QtxAction::QtxAction( const QString& text, const QIcon& icon, const QString& menuText,
- const QKeySequence& accel, QObject* parent, bool toggle, const QString& shortcutAction )
+QtxAction::QtxAction( const QString& text, const QIcon& icon, const QString& menuText,
+ const QKeySequence& accel, QObject* parent, bool toggle, const QString& ID )
: QWidgetAction( parent )
{
setIcon( icon );
setText( menuText );
setToolTip( text );
- setShortcut( accel );
setCheckable( toggle );
- setShortcutActionName(shortcutAction);
+ setID(ID);
+ setShortcut(accel);
QApplication::instance()->installEventFilter( this );
}
\brief Constructor.
Creates an action owned by \a parent. Parameters \a text,
- \a menuText and \a accel specify the action's attributes.
+ \a menuText and \a ID specify the action's attributes.
Parameter \a toggle can be used to make the action checkable.
- Parameter \a shortcutAction can be used to assign the shortcut from
- preferences. This parameter value corresponds to shortcut action identifier
- in shortcut preferences.
+ Parameter \a ID is used to de(serialize) shortcut settings.
\param text tooltip text
\param menuText menu text
- \param accel shortcut key sequence
+ \param accel will be disabled by SUIT_ShortcutMgr!
\param parent parent object
\param toggle if \c true the action is a toggle action
- \param shortcutAction shortcut action identifier
+ \param ID shortcut action identifier
*/
QtxAction::QtxAction( const QString& text, const QString& menuText,
- int accel, QObject* parent, bool toggle, const QString& shortcutAction )
+ int accel, QObject* parent, bool toggle, const QString& ID )
: QWidgetAction( parent )
{
setText( menuText );
setToolTip( text );
- setShortcut( accel );
setCheckable( toggle );
- setShortcutActionName(shortcutAction);
-
+ setID(ID);
+ setShortcut(accel);
+
QApplication::instance()->installEventFilter( this );
}
\brief Constructor.
Creates an action owned by \a parent. Parameters \a text,
- \a menuText and \a accel specify the action's attributes.
+ \a menuText and \a ID specify the action's attributes.
Parameter \a toggle can be used to make the action checkable.
- Parameter \a shortcutAction can be used to assign the shortcut from
- preferences. This parameter value corresponds to shortcut action identifier
- in shortcut preferences.
+ Parameter \a ID is used to de(serialize) shortcut settings.
\param text tooltip text
\param menuText menu text
- \param accel shortcut key sequence
+ \param accel will be disabled by SUIT_ShortcutMgr!
\param parent parent object
\param toggle if \c true the action is a toggle action
- \param shortcutAction shortcut action identifier
+ \param ID shortcut action identifier
*/
QtxAction::QtxAction( const QString& text, const QString& menuText,
- const QKeySequence& accel, QObject* parent, bool toggle, const QString& shortcutAction )
+ const QKeySequence& accel, QObject* parent, bool toggle, const QString& ID )
: QWidgetAction( parent )
{
setText( menuText );
setToolTip( text );
- setShortcut( accel );
setCheckable( toggle );
- setShortcutActionName(shortcutAction);
-
+ setID(ID);
+ setShortcut(accel);
+
QApplication::instance()->installEventFilter( this );
}
/*!
\brief Customize action events.
-
- Sends a notification event to the action when it is added to
+
+ Sends a notification event to the action when it is added to
the widget or removed from it in order to perform custom processing.
\param o object
return QWidgetAction::eventFilter( o, e );
}
+QString QtxAction::shortcutActionName() const
+{
+ return myID;
+}
+
+void QtxAction::setShortcutActionName( const QString& shortcutAction )
+{
+ myID = shortcutAction;
+}
+
+const QString& QtxAction::ID() const {
+ return myID;
+}
+
+void QtxAction::setID( const QString& theID) {
+ myID = theID;
+}
+
/*!
\brief Called when the action is added to the widget.
- This method can be redefined in the subclasses to customize
- the action behavior. Base implementation does nothing.
+ This method can be redefined in the subclasses to customize
+ the action behavior. Base implementation does nothing.
\param w widget (should be menu or toolbar)
\sa removedFrom()
/*!
\brief Process notification events.
-
+
Calls addedTo() method when the action is added to the widget
and removedFrom() when it is removed from the widget
in order to perform custom processing.
else
removedFrom( ae->widget() );
}
-
-/*!
- \brief Return shortcut action name for the action.
-
- \return shortcut action name
- \sa setShortcutActionName()
-*/
-QString QtxAction::shortcutActionName() const
-{
- return myShortcutActionName;
-}
-
-/*!
- \brief Set shortcut action name to the action.
-
- Shortcut action name is used for shortcuts customization.
-
- \param shortcutAction shortcut action name
- \sa shortcutActionName()
-*/
-void QtxAction::setShortcutActionName( const QString& shortcutAction )
-{
- myShortcutActionName = shortcutAction;
-}
virtual bool eventFilter( QObject*, QEvent* );
+ [[deprecated("Use ID() instead.")]]
QString shortcutActionName() const;
+
+ [[deprecated("Use setID() instead.")]]
void setShortcutActionName( const QString& );
+ /** Unique for the entire application ID. */
+ const QString& ID() const;
+ void setID( const QString& theID);
+
protected:
virtual void addedTo( QWidget* );
virtual void removedFrom( QWidget* );
virtual void customEvent( QEvent* );
private:
- QString myShortcutActionName;
+ QString myID;
};
#ifdef WIN32
#include "QtxBackgroundTool.h"
#include "QtxResourceMgr.h"
+#include "SUIT_ShortcutMgr.h"
+
#include <QEvent>
#include <QLayout>
#include <QToolBox>
{
if ( myDecimals == dec )
return;
-
+
myDecimals = dec;
updateEditor();
}
\sa echoMode()
*/
void QtxPagePrefEditItem::setEchoMode( const int echo )
-{
+{
if ( myEchoMode == echo )
return;
-
+
myEchoMode = echo;
updateEditor();
}
default:
myEditor->setEchoMode(QLineEdit::Normal);
}
-
+
QValidator* val = 0;
switch ( inputType() )
{
{
setControl( mySlider = new QSlider( Qt::Horizontal ) );
widget()->layout()->addWidget( myLabel = new QLabel( ) );
-
+
setMinimum( 0 );
setMaximum( 0 );
setSingleStep( 1 );
setPageStep( 1 );
-
+
mySlider->setTickPosition( QSlider::TicksBothSides );
-
+
connect (mySlider, SIGNAL(valueChanged(int)), this, SLOT(setIcon(int)));
updateSlider();
}
*/
void QtxPagePrefSliderItem::setIcons( const QList<QIcon>& icns )
{
- if ( icns.isEmpty() )
+ if ( icns.isEmpty() )
return;
myIcons = icns;
-
- QSize maxsize(0, 0);
+
+ QSize maxsize(0, 0);
for ( QList<QIcon>::const_iterator it = myIcons.begin(); it != myIcons.end(); ++it ) {
if ( (*it).isNull() ) continue;
maxsize = maxsize.expandedTo( (*it).availableSizes().first() );
}
myLabel->setFixedSize( maxsize );
-
+
updateSlider();
}
control()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
mySlider->setFocusPolicy(Qt::StrongFocus);
-
+
mySlider->setValue( val );
setSingleStep( stp );
setPageStep( ptp );
setMinimum( min );
setMaximum( max );
-
+
myLabel->setVisible( !myIcons.empty() );
widget()->layout()->setSpacing( !myIcons.empty() ? 6 : 0 );
}
for ( QList<QVariant>::const_iterator it = ids.begin(); it != ids.end(); ++it, i++ ) {
if ( i >= mySelector->count() )
mySelector->addItem(QString("") );
-
+
mySelector->setId( i, *it );
}
}
void QtxPagePrefSelectItem::retrieve()
{
QString txt = getString();
-
+
// try to find via the id
int idx = mySelector->index( txt );
if ( idx < 0 )
\brief GUI implementation of the resources item to store a bi-color value.
The main color is specified explicitly. The secondary color is calculated
- by changing "value" and "saturation" parameters of the main color in the
+ by changing "value" and "saturation" parameters of the main color in the
HSV notation using specified delta.
*/
}
/*!
- \brief Specifies whether widget works in Native or Custom mode. Native mode
- is intended for working with system fonts. Custom mode is intended for
- working with manually defined set of fonts. Set of custom fonts can be
- specified with setFonts() method
+ \brief Specifies whether widget works in Native or Custom mode. Native mode
+ is intended for working with system fonts. Custom mode is intended for
+ working with manually defined set of fonts. Set of custom fonts can be
+ specified with setFonts() method
\param mode mode from QtxFontEdit::Mode enumeration
\sa mode()
*/
}
/*!
- \brief Sets list of custom fonts.
+ \brief Sets list of custom fonts.
<b>This method is intended for working in Custom mode only.</b>
\param fams list of families
\sa fonts(), setMode()
}
/*!
- \brief Gets list of custom fonts
+ \brief Gets list of custom fonts
\return list of families
\sa setFonts(), setMode()
*/
}
/*!
- \brief Sets list of available font sizes.
- <b>This method is intended for working in Custom mode only.</b> The list of sizes can
+ \brief Sets list of available font sizes.
+ <b>This method is intended for working in Custom mode only.</b> The list of sizes can
be empty. In this case system generate listof size automatically from 8 till 72.
\param sizes list of sizes
\sa sizes(), setMode()
}
/*!
- \brief Gets list of custom fonts
+ \brief Gets list of custom fonts
\return list of families
\sa setFonts(), setMode()
*/
myDateTime->setDisplayFormat( dispFmt );
}
-/*!
- \brief Constructor.
- \param title preference item title
- \param parent parent preference item
- \param sect resource file section associated with the preference item
- \param param resource file parameter associated with the preference item
-*/
-QtxPagePrefShortcutBtnsItem::QtxPagePrefShortcutBtnsItem( const QString& title, QtxPreferenceItem* parent, const QString& sect,
- const QString& param ): QtxPageNamedPrefItem( title, parent, sect, param )
-{
- setControl( myShortcut = new QtxShortcutEdit() );
-}
-
-/*!
- \brief Destructor.
-*/
-QtxPagePrefShortcutBtnsItem::~QtxPagePrefShortcutBtnsItem()
-{
-}
/*!
- \brief Store preference item to the resource manager.
- \sa retrieve()
+ \brief Creates preference item for editing of key bindings
+ \param theParent parent preference item. Must not be nullptr.
*/
-void QtxPagePrefShortcutBtnsItem::store()
+QtxPagePrefShortcutTreeItem::QtxPagePrefShortcutTreeItem(QtxPreferenceItem* theParent)
+ : QtxPagePrefItem(QString(), theParent)
{
- setString( myShortcut->shortcut().toString() );
-}
+ auto container = std::shared_ptr<SUIT_ShortcutContainer>();
+ const auto itContainers = QtxPagePrefShortcutTreeItem::shortcutContainers.find(rootItem());
+ if (itContainers == QtxPagePrefShortcutTreeItem::shortcutContainers.end()) {
+ container.reset(new SUIT_ShortcutContainer());
+ QtxPagePrefShortcutTreeItem::shortcutContainers.emplace(rootItem(), container);
+ }
+ else {
+ container = itContainers->second.lock();
+ if (!container) {
+ container.reset(new SUIT_ShortcutContainer());
+ itContainers->second = container;
+ }
+ }
-/*!
- \brief Retrieve preference item from the resource manager.
- \sa store()
-*/
-void QtxPagePrefShortcutBtnsItem::retrieve()
-{
- myShortcut->setShortcut( QKeySequence::fromString( getString() ) );
+ QtxShortcutTree* tree = new QtxShortcutTree(container);
+ tree->myModuleIDs = SUIT_ShortcutMgr::get()->getShortcutModuleIDs();
+ setWidget(tree);
}
/*!
- \brief Constructor.
-
- Creates preference item for editing of key bindings
-
- \param title preference item title
- \param parent parent preference item
- \param sect resource file section associated with the preference item
- \param param resource file parameter associated with the preference item
+ \brief Retrieves shortcut preferences from ShortcutMgr.
+ Updates UI of controlling widget.
+ \sa store()
*/
-QtxPagePrefShortcutTreeItem::QtxPagePrefShortcutTreeItem( const QString& title, QtxPreferenceItem* parent, const QString& sect,
- const QString& /*param*/ ): QtxPageNamedPrefItem( title, parent, sect, "" )
+void QtxPagePrefShortcutTreeItem::retrieve()
{
- mySection = sect;
-
- myShortcutTree = new QtxShortcutTree();
-
- // Retrieve shortcuts common sections from resources
- QtxResourceMgr* resMgr = resourceMgr();
- if ( resMgr ){
- QString generalSections = resourceMgr()->stringValue( "shortcuts_settings", "general_sections", QString() );
- QStringList sectionsList = generalSections.split( ";", QString::SkipEmptyParts );
- myShortcutTree->setGeneralSections( sectionsList );
- }
-
- setControl( myShortcutTree );
+ static_cast<QtxShortcutTree*>(widget())->setShortcutsFromManager();
}
/*!
- \brief Destructor.
-*/
-QtxPagePrefShortcutTreeItem::~QtxPagePrefShortcutTreeItem()
-{
-}
-
-/*!
- \brief Retrieve preference item from the resource manager.
+ \brief Retrieves shortcut preferences from resource files, ignoring user preferences.
+ Updates UI of controlling widget.
\sa store()
*/
-void QtxPagePrefShortcutTreeItem::retrieve()
+void QtxPagePrefShortcutTreeItem::retrieveDefault()
{
- QtxResourceMgr* resMgr = resourceMgr();
- if ( resMgr ){
- QStringList secLst = resMgr->subSections( mySection, false );
- ShortcutMap aMap; QStringList paramLst;
- for( int i = 0; i < secLst.size(); i++ ) {
- paramLst = resMgr->parameters( QStringList() << mySection << secLst.at( i ) );
- for( int j = 0; j < paramLst.size(); j++ )
- resMgr->value( mySection + resMgr->sectionsToken() + secLst.at( i ), paramLst.at( j ),aMap[ paramLst.at( j ) ], false );
- myShortcutTree->setBindings( secLst.at( i ), aMap );
- aMap.clear();
- }
- }
+ static_cast<QtxShortcutTree*>(widget())->setDefaultShortcuts();
}
-
+
/*!
- \brief Store preference item to the resource manager.
+ \brief Applies modified shortcut preferences to ShortcutMgr.
+ Updates UI of controlling widget.
+ And ShortcutMgr, in turn, serilizes shortcut preferences using the resource manager.
\sa retrieve()
*/
void QtxPagePrefShortcutTreeItem::store()
{
- QStringList lst = myShortcutTree->sections();
- QString aSection;
- QtxResourceMgr* resMgr = resourceMgr();
-
- if ( resMgr ) {
- for( int i = 0; i < lst.size(); i++ ) {
- ShortcutMap* aMap( myShortcutTree->bindings( lst.at( i ) ) );
- aSection = mySection + resMgr->sectionsToken() + lst.at( i );
- for( ShortcutMap::const_iterator it = aMap->constBegin(); it != aMap->constEnd(); ++it )
- resMgr->setValue( aSection, it.key(), it.value() );
- }
- }
+ static_cast<QtxShortcutTree*>(widget())->applyChangesToShortcutMgr();
}
+/*static*/ std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>> QtxPagePrefShortcutTreeItem::shortcutContainers =
+std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>>();
+
+
/*!
\class QtxPagePrefBackgroundItem
\brief GUI implementation of the resources item to store background data.
- texture image file
- simple two-color gradient
- complex custom gradient (NOT IMPLEMENTED YET)
-
+
Allowed background modes can be specified using setModeAllowed() method.
Texture modes can be enabled/disabled using setTextureModeAllowed() method.
Also, showing texture controls can be enabled/disabled by means of
/*!
\brief Constructor.
- Creates preference item of user defined widget. The item widget has to be inherited from
+ Creates preference item of user defined widget. The item widget has to be inherited from
QtxUserDefinedContent class. An instance of this class has to be installed into the item
- with help of setContent method. Methods optionValue and setOptionValue use pointer on the
+ with help of setContent method. Methods optionValue and setOptionValue use pointer on the
content widget an qint64 value.
\param parent parent preference item
: QtxPageNamedPrefItem(QString(), parent), myContent(0)
{
}
-
+
/*!
\brief Lets to Store preferences for content instance
\sa retrieve()
/*!
* \brief Sets option value
- * \param theName is a string "content"
+ * \param theName is a string "content"
* \param theVal is a pointer on QtxUserDefinedContent class instance represented as qint64 value
*/
void QtxUserDefinedItem::setOptionValue( const QString& theName, const QVariant& theVal)
} else
QtxPreferenceItem::setOptionValue( theName, theVal );
}
-
+
/*!
- * \brief Defines content of the property item as a Widget which has to be inherited from
+ * \brief Defines content of the property item as a Widget which has to be inherited from
* QtxUserDefinedContent class.
* \param theContent is an QtxUserDefinedContent class instance.
*/
-void QtxUserDefinedItem::setContent( QtxUserDefinedContent* theContent )
-{
- myContent = theContent;
+void QtxUserDefinedItem::setContent( QtxUserDefinedContent* theContent )
+{
+ myContent = theContent;
setControl(myContent);
}
#include <QPointer>
#include <QIcon>
+#include <map>
+#include <memory>
+
class QtxGridBox;
class QtxFontEdit;
class QtxGroupBox;
class QtxComboBox;
class QtxColorButton;
class QtxBiColorTool;
-class QtxShortcutEdit;
class QtxShortcutTree;
class QtxBackgroundTool;
int decimals() const;
void setDecimals( const int );
-
+
int echoMode() const;
void setEchoMode( const int );
int pageStep() const;
int minimum() const;
int maximum() const;
- QList<QIcon> icons() const;
+ QList<QIcon> icons() const;
void setSingleStep( const int& );
void setPageStep( const int& );
QDateTimeEdit* myDateTime;
};
-class QTX_EXPORT QtxPagePrefShortcutBtnsItem : public QtxPageNamedPrefItem
-{
-public:
- QtxPagePrefShortcutBtnsItem( const QString&, QtxPreferenceItem* = 0,
- const QString& = QString(), const QString& = QString() );
- virtual ~QtxPagePrefShortcutBtnsItem();
- virtual void store();
- virtual void retrieve();
-private:
- QtxShortcutEdit* myShortcut;
-};
+class SUIT_ShortcutContainer;
+
-class QTX_EXPORT QtxPagePrefShortcutTreeItem : public QtxPageNamedPrefItem
+class QTX_EXPORT QtxPagePrefShortcutTreeItem : public QtxPagePrefItem
{
public:
- QtxPagePrefShortcutTreeItem( const QString&, QtxPreferenceItem* = 0,
- const QString& = QString(), const QString& = QString() );
- virtual ~QtxPagePrefShortcutTreeItem();
- virtual void store();
+ QtxPagePrefShortcutTreeItem(QtxPreferenceItem* theParent);
+ virtual ~QtxPagePrefShortcutTreeItem() = default;
+
virtual void retrieve();
-
+ virtual void retrieveDefault();
+ virtual void store();
+
private:
QtxShortcutTree* myShortcutTree;
- QString mySection;
+
+ // { root item (preference window), shortcut container of synchronized trees (widgets within the same window) }
+ static std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>> shortcutContainers;
+ /** Why is this?
+ * Every QtxPagePrefMgr is eventually a preference window. Each preference window has button "Apply".
+ * When the button is pressed, all descendants of the QtxPagePrefMgr store changes they carry into preferences.
+ * The pitfall with shortcut trees is as follows: made in independent shortcut trees, changes may conflict,
+ * and merge of such changes is ambiguous. And the solution is to keep shortcut trees within the same window
+ * synchronized - all changes being made in a tree of a synchronized bundle are projected to other trees from the bundle
+ * without interacting with SUIT_ShortcutMgr.
+ *
+ * Every time shortcut preferences stored to the ShortcutMgr, all instances of QtxShortcutTree are updated.
+ */
};
class QTX_EXPORT QtxPagePrefBackgroundItem : public QObject, public QtxPageNamedPrefItem
\class QtxPreferenceItem
\brief Base class for implementing of all the preference items.
- To implement any specific preference item, cubclass from the
+ To implement any specific preference item, subclass from the
QtxPreferenceItem and redefine store() and retrieve() methods.
*/
/*!
\brief Insert child preference item before specified item.
- If the before item is 0 then new item is appended.
+ If the before item is 0, then new item is appended.
Removes (if necessary) the item from the previous parent.
\sa store()
*/
+/*! \brief Restore preference item (for example, from the resource file, ignoring user preferences).
+ If not overridden, it is equivalent to \ref retrieve().
+*/
+void QtxPreferenceItem::retrieveDefault()
+{
+ retrieve();
+}
+
/*!
\brief Get the value of the associated resource file setting.
\return associated resource file setting value
(*it)->retrieve();
}
+/*!
+ \brief Retrieve all preference items from the resource manager, ignoring user preferences.
+ \sa store()
+*/
+void QtxPreferenceMgr::retrieveDefault()
+{
+ QList<QtxPreferenceItem*> items = childItems( true );
+ for ( QList<QtxPreferenceItem*>::iterator it = items.begin(); it != items.end(); ++it )
+ (*it)->retrieveDefault();
+}
+
/*!
\brief Dumps all values to the backup container.
\sa fromBackup()
virtual void store() = 0;
virtual void retrieve() = 0;
+ virtual void retrieveDefault();
QString resourceValue() const;
void setResourceValue( const QString& );
virtual void store();
virtual void retrieve();
+ virtual void retrieveDefault();
virtual void update();
#include <QToolButton>
#include <QLineEdit>
+#include <QLabel>
#include <QTableWidgetItem>
+#include <QTextEdit>
#include <QMessageBox>
+#include <QPushButton>
+#include <QBrush>
+#include <QColor>
#include <QKeyEvent>
#include <QKeySequence>
+
#define COLUMN_SIZE 500
-static const char* delete_icon[] = {
-"16 16 3 1",
-"` c #810000",
-" c none",
-"# c #ffffff",
-" ",
-" ",
-" ``# ``# ",
-" ````# ``# ",
-" ````# ``# ",
-" ```# `# ",
-" `````# ",
-" ```# ",
-" `````# ",
-" ```# ``# ",
-" ```# ``# ",
-" ```# `# ",
-" ```# `# ",
-" `# `# ",
-" ",
-" "
-};
-/*!
- \brief Constructor
- \param parent parent widget
-*/
-QtxShortcutEdit::QtxShortcutEdit( QWidget* parent )
-: QFrame( parent )
+QtxKeySequenceEdit::QtxKeySequenceEdit(QWidget* parent)
+: QFrame(parent)
{
initialize();
- myShortcut->installEventFilter(this);
+ myKeySequenceLineEdit->installEventFilter(this);
}
-/*!
- \brief Destructor
-*/
-QtxShortcutEdit::~QtxShortcutEdit()
+/*! \brief Set a key sequence to edit. */
+void QtxKeySequenceEdit::setConfirmedKeySequence(const QKeySequence& theKeySequence)
{
+ myConfirmedKeySequenceString = theKeySequence.toString();
+ myKeySequenceLineEdit->setText(myConfirmedKeySequenceString);
+ myPrevKeySequenceString = myConfirmedKeySequenceString;
}
-/*!
- \brief Sets custom shortcut
- \param seq a key sequence describes a combination of keys
- \sa shortcut()
-*/
-void QtxShortcutEdit::setShortcut( const QKeySequence& seq )
+void QtxKeySequenceEdit::setEditedKeySequence(const QKeySequence& theKeySequence)
{
- QString txt = seq.toString();
- myPrevShortcutText = txt;
- myShortcut->setText( txt );
+ const QString keySequenceString = theKeySequence.toString();
+ myKeySequenceLineEdit->setText(keySequenceString);
+ myPrevKeySequenceString = keySequenceString;
}
-/*!
- \brief Gets custom shortcut
- \return a key sequence describes a combination of keys
- \sa setShortcut()
-*/
-QKeySequence QtxShortcutEdit::shortcut()
+QKeySequence QtxKeySequenceEdit::editedKeySequence() const
{
- return QKeySequence::fromString( myShortcut->text() );
+ return QKeySequence::fromString(myKeySequenceLineEdit->text());
+}
+
+/*! \returns true, if the edited key sequence differs from confirmed one. */
+bool QtxKeySequenceEdit::isKeySequenceModified() const
+{
+ return QKeySequence(myConfirmedKeySequenceString) != editedKeySequence();
+}
+
+/*! \brief Set confirmed key sequence to line editor. */
+void QtxKeySequenceEdit::restoreKeySequence()
+{
+ myKeySequenceLineEdit->setText(myConfirmedKeySequenceString);
+ myPrevKeySequenceString = myConfirmedKeySequenceString;
}
/*!
- \brief Gets the key sequence from keys that were pressed
+ \brief Gets the key sequence from keys that were pressed
\param e a key event
- \return a string representation of the key sequence
+ \returns a string representation of the key sequence
*/
-QString QtxShortcutEdit::parseEvent( QKeyEvent* e )
+/*static*/ QString QtxKeySequenceEdit::parseEvent(QKeyEvent* e)
{
bool isShiftPressed = e->modifiers() & Qt::ShiftModifier;
bool isControlPressed = e->modifiers() & Qt::ControlModifier;
bool isAltPressed = e->modifiers() & Qt::AltModifier;
bool isMetaPressed = e->modifiers() & Qt::MetaModifier;
- bool isModifiersPressed = isShiftPressed || isControlPressed || isAltPressed || isMetaPressed;
+ bool isModifiersPressed = isControlPressed || isAltPressed || isMetaPressed; // Do not treat Shift alone as a modifier!
int result=0;
- if( isControlPressed )
+ if(isControlPressed)
result += Qt::CTRL;
- if( isAltPressed )
+ if(isAltPressed)
result += Qt::ALT;
- if( isShiftPressed )
+ if(isShiftPressed)
result += Qt::SHIFT;
- if( isMetaPressed )
+ if(isMetaPressed)
result += Qt::META;
int aKey = e->key();
- if ( ( isValidKey( aKey ) && isModifiersPressed ) || ( ( aKey >= Qt::Key_F1 ) && ( aKey <= Qt::Key_F12 ) ) )
+ if ((isValidKey(aKey) && isModifiersPressed) || ((aKey >= Qt::Key_F1) && (aKey <= Qt::Key_F12)))
result += aKey;
- return QKeySequence( result ).toString();
+ return QKeySequence(result).toString();
}
/*!
\brief Check if the key event contains a 'valid' key
- \param aKey the code of the key
- \return \c true if the key is 'valid'
+ \param theKey the code of the key
+ \returns \c true if the key is 'valid'
*/
-
-bool QtxShortcutEdit::isValidKey( int aKey )
+/*static*/ bool QtxKeySequenceEdit::isValidKey(int theKey)
{
- if ( aKey == Qt::Key_Underscore || aKey == Qt::Key_Escape ||
- ( aKey >= Qt::Key_Backspace && aKey <= Qt::Key_Delete ) ||
- ( aKey >= Qt::Key_Home && aKey <= Qt::Key_PageDown ) ||
- ( aKey >= Qt::Key_F1 && aKey <= Qt::Key_F12 ) ||
- ( aKey >= Qt::Key_Space && aKey <= Qt::Key_Asterisk ) ||
- ( aKey >= Qt::Key_Comma && aKey <= Qt::Key_Question ) ||
- ( aKey >= Qt::Key_A && aKey <= Qt::Key_AsciiTilde ) )
+ if ( theKey == Qt::Key_Underscore || theKey == Qt::Key_Escape ||
+ ( theKey >= Qt::Key_Backspace && theKey <= Qt::Key_Delete ) ||
+ ( theKey >= Qt::Key_Home && theKey <= Qt::Key_PageDown ) ||
+ ( theKey >= Qt::Key_F1 && theKey <= Qt::Key_F12 ) ||
+ ( theKey >= Qt::Key_Space && theKey <= Qt::Key_Asterisk ) ||
+ ( theKey >= Qt::Key_Comma && theKey <= Qt::Key_Question ) ||
+ ( theKey >= Qt::Key_A && theKey <= Qt::Key_AsciiTilde ) )
return true;
return false;
}
-/*!
- \brief Called when "Clear" button is clicked.
-*/
-void QtxShortcutEdit::onCliked()
+/*! \brief Called when "Clear" button is clicked. */
+void QtxKeySequenceEdit::onClear()
{
- myShortcut->setText( "" );
+ myKeySequenceLineEdit->setText("");
+ myPrevKeySequenceString = "";
+ emit editingFinished();
}
-/*!
- \brief Called when myShortcut loses focus.
-*/
-void QtxShortcutEdit::onEditingFinished()
+/*! \brief Called when myKeySequenceLineEdit loses focus. */
+void QtxKeySequenceEdit::onEditingFinished()
{
- if ( myShortcut->text().endsWith("+") )
- myShortcut->setText( myPrevShortcutText );
+ if (myKeySequenceLineEdit->text().endsWith("+"))
+ myKeySequenceLineEdit->setText(myPrevKeySequenceString);
+ else
+ myPrevKeySequenceString = myKeySequenceLineEdit->text();
+ emit editingFinished();
}
/*!
\brief Custom event filter.
\param obj event receiver object
\param event event
- \return \c true if further event processing should be stopped
+ \returns \c true if further event processing should be stopped
*/
-bool QtxShortcutEdit::eventFilter(QObject* obj, QEvent* event)
-{
- if ( obj == myShortcut ) {
- if (event->type() == QEvent::KeyPress ) {
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
- QString text = parseEvent( keyEvent );
- if ( keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace )
- onCliked();
- if ( text != "" )
- myShortcut->setText( text );
+bool QtxKeySequenceEdit::eventFilter(QObject* theObject, QEvent* theEvent)
+{
+ if (theObject == myKeySequenceLineEdit) {
+ if (theEvent->type() == QEvent::KeyPress) {
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(theEvent);
+ QString text = parseEvent(keyEvent);
+ if (keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace)
+ myKeySequenceLineEdit->setText("");
+ if (!text.isEmpty())
+ myKeySequenceLineEdit->setText(text);
+
+ emit editingStarted();
return true;
}
- if ( event->type() == QEvent::KeyRelease ) {
- if ( myShortcut->text().endsWith("+") )
- myShortcut->setText( myPrevShortcutText );
- else myPrevShortcutText = myShortcut->text();
-
+ if (theEvent->type() == QEvent::KeyRelease) {
+ onEditingFinished();
return true;
}
- }
+ }
return false;
}
/*
\brief Perform internal intialization.
*/
-void QtxShortcutEdit::initialize()
+void QtxKeySequenceEdit::initialize()
{
- myPrevShortcutText = QString();
+ static const int PIXMAP_SIZE = 30;
QHBoxLayout* base = new QHBoxLayout( this );
- base->setMargin( 0 );
- base->setSpacing( 5 );
+ base->setMargin(0);
+ base->setSpacing(5);
+
+ base->addWidget(myKeySequenceLineEdit = new QLineEdit(this));
+ setFocusProxy(myKeySequenceLineEdit);
+
+ QToolButton* clearBtn = new QToolButton();
+ auto clearPixmap = QPixmap(":/images/shortcut_disable.svg");
+ clearPixmap.scaled(QSize(PIXMAP_SIZE, PIXMAP_SIZE), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ clearBtn->setIcon(clearPixmap);
+ clearBtn->setToolTip(tr("Disable shortcut."));
+ base->addWidget(clearBtn);
+
+ QToolButton* restoreBtn = new QToolButton();
+ auto restorePixmap = QPixmap(":/images/shortcut_restore.svg");
+ restorePixmap.scaled(QSize(PIXMAP_SIZE, PIXMAP_SIZE), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ restoreBtn->setIcon(restorePixmap);
+ restoreBtn->setToolTip(tr("Restore the currently applied key sequence."));
+ base->addWidget(restoreBtn);
+
+ myKeySequenceLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ clearBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ restoreBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ connect(clearBtn, SIGNAL(clicked()), this, SLOT(onClear()));
+ connect(restoreBtn, SIGNAL(clicked()), this, SIGNAL(restoreFromShortcutMgrClicked()));
+ connect(myKeySequenceLineEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
+}
- base->addWidget( myShortcut = new QLineEdit( this ) );
- QToolButton* deleteBtn = new QToolButton();
- deleteBtn->setIcon( QPixmap( delete_icon ) );
- base->addWidget( deleteBtn );
-
- myShortcut->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
- deleteBtn->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
+/*! \param theParent must not be nullptr. */
+QtxEditKeySequenceDialog::QtxEditKeySequenceDialog(QtxShortcutTree* theParent)
+: QDialog(theParent)
+{
+ setMinimumWidth(500);
+ setWindowTitle(tr("Change key sequence"));
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ myActionName = new QLabel(this);
+ myActionName->setTextFormat(Qt::RichText);
+ myKeySequenceEdit = new QtxKeySequenceEdit(this);
+ myTextEdit = new QTextEdit(this);
+ layout->addWidget(myActionName);
+ layout->addWidget(myKeySequenceEdit);
+ layout->addWidget(myTextEdit);
+ myActionName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ myKeySequenceEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ myTextEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+ myTextEdit->setReadOnly(true);
+ myTextEdit->setAcceptRichText(true);
+ myTextEdit->setPlaceholderText(tr("No conflicts."));
+ setFocusProxy(myKeySequenceEdit);
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout(this);
+ layout->addLayout(buttonLayout);
+ QPushButton* confirmButton = new QPushButton(tr("Confirm"), this);
+ confirmButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ QPushButton* cancelButton = new QPushButton(tr("Cancel"), this);
+ cancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ buttonLayout->addStretch();
+ buttonLayout->addWidget(confirmButton);
+ buttonLayout->addWidget(cancelButton);
+
+ connect(myKeySequenceEdit, SIGNAL(editingStarted()), this, SLOT(onEditingStarted()));
+ connect(myKeySequenceEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
+ connect(myKeySequenceEdit, SIGNAL(restoreFromShortcutMgrClicked()), this, SLOT(onRestoreFromShortcutMgr()));
+ connect(confirmButton, SIGNAL(clicked()), this, SLOT(onConfirm()));
+ connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+}
- connect( deleteBtn, SIGNAL( clicked() ), this, SLOT( onCliked() ) );
- connect( myShortcut, SIGNAL( editingFinished() ), this, SLOT( onEditingFinished() ) );
+void QtxEditKeySequenceDialog::setModuleAndActionID(const QString& theModuleID, const QString& theInModuleActionID)
+{
+ myModuleID = theModuleID;
+ myInModuleActionID = theInModuleActionID;
}
-/*!
- \brief Constructor
- \param parent parent widget
-*/
-QtxShortcutTree::QtxShortcutTree( QWidget * parent ) : QTreeWidget( parent )
+const QString& QtxEditKeySequenceDialog::moduleID() const { return myModuleID; }
+const QString& QtxEditKeySequenceDialog::inModuleActionID() const { return myInModuleActionID; }
+
+void QtxEditKeySequenceDialog::setModuleAndActionName(const QString& theModuleName, const QString& theActionName)
+{
+ myActionName->setText("<b>" + theModuleName + "</b> " + theActionName);
+}
+
+void QtxEditKeySequenceDialog::setConfirmedKeySequence(const QKeySequence& theSequence)
{
- setColumnCount( 2 );
- setSelectionMode( QAbstractItemView::SingleSelection );
- setColumnWidth ( 0, COLUMN_SIZE);
- setSortingEnabled(false);
- headerItem()->setHidden ( true );
+ myKeySequenceEdit->setConfirmedKeySequence(theSequence);
+}
- this->installEventFilter(this);
- connect( this, SIGNAL( currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( onCurrentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem* ) ) );
+QKeySequence QtxEditKeySequenceDialog::editedKeySequence() const
+{
+ return myKeySequenceEdit->editedKeySequence();
+}
+int QtxEditKeySequenceDialog::exec()
+{
+ myKeySequenceEdit->setFocus(Qt::ActiveWindowFocusReason);
+ return QDialog::exec();
}
-/*!
- \brief Destructor
-*/
-QtxShortcutTree::~QtxShortcutTree(){}
+void QtxEditKeySequenceDialog::onEditingStarted()
+{
+ myTextEdit->setEnabled(false);
+}
-/*!
- \brief Custom event filter.
- \param obj event receiver object
- \param event event
- \return \c true if further event processing should be stopped
-*/
-bool QtxShortcutTree::eventFilter(QObject* /*obj*/, QEvent* event)
-{
- if ( currentItem() && currentItem()->isSelected() ) {
-
- if (event->type() == QEvent::KeyPress ) {
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
- QString text = QtxShortcutEdit::parseEvent( keyEvent );
- if ( keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace )
- currentItem()->setText( 1, "" );
- if ( text != "" ) {
- if ( text.endsWith( "+" ) || checkUniqueness( currentItem(), text ) )
- currentItem()->setText( 1, text );
+void QtxEditKeySequenceDialog::onEditingFinished()
+{
+ updateConflictsMessage();
+}
+
+void QtxEditKeySequenceDialog::onRestoreFromShortcutMgr()
+{
+ const auto shortcutMgr = SUIT_ShortcutMgr::get();
+ myKeySequenceEdit->setEditedKeySequence(shortcutMgr->getKeySequence(myModuleID, myInModuleActionID));
+ updateConflictsMessage();
+}
+
+/*! Updates message with list of actions, whose shortcuts will be disabled on Confirm. */
+void QtxEditKeySequenceDialog::updateConflictsMessage()
+{
+ myTextEdit->setEnabled(true);
+ QTextDocument* doc = myTextEdit->document();
+ if (!doc) {
+ doc = new QTextDocument(myTextEdit);
+ myTextEdit->setDocument(doc);
+ }
+
+ if (!myKeySequenceEdit->isKeySequenceModified()) {
+ doc->clear();
+ return;
+ }
+
+ const QKeySequence newKeySequence = editedKeySequence();
+
+ const auto shortcutTree = static_cast<QtxShortcutTree*>(parentWidget());
+ /** {moduleID, inModuleActionID}[] */
+ std::set<std::pair<QString, QString>> conflicts = shortcutTree->shortcutContainer()->getConflicts(myModuleID, myInModuleActionID, newKeySequence);
+ if (!conflicts.empty()) {
+ const auto shortcutMgr = SUIT_ShortcutMgr::get();
+
+ QString report = "<b>" + tr("These shortcuts will be disabled on confirm:") + "</b>";
+ {
+ report += "<ul>";
+ for (const auto& conflict : conflicts) {
+ const QString conflictingModuleName = shortcutMgr->getModuleName(conflict.first);
+ const QString conflictingActionName = shortcutMgr->getActionName(conflict.first, conflict.second);
+ report += "<li><b>" + conflictingModuleName + "</b> " + conflictingActionName + "</li>";
}
- return true;
+ report += "</ul>";
}
- if ( event->type() == QEvent::KeyRelease ) {
- if ( currentItem()->text( 1 ).endsWith( "+" ) )
- currentItem()->setText( 1, myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] );
- else myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] = currentItem()->text( 1 );
+ doc->setHtml(report);
+ }
+ else /* if no conflicts */ {
+ doc->clear();
+ }
+}
- return true;
- }
- }
- return false;
+void QtxEditKeySequenceDialog::onConfirm()
+{
+ if (myKeySequenceEdit->isKeySequenceModified())
+ accept();
+ else
+ reject();
}
-/*!
- \brief Called when the current item changes.
- \param cur the current item
- \param prev the previous current item
-*/
-void QtxShortcutTree::onCurrentItemChanged( QTreeWidgetItem* /*cur*/, QTreeWidgetItem* prev )
+
+/*! \param theContainer Share the same container between several trees,
+to edit them synchronously even without exchange of changes with SUIT_ShortcutMgr.
+Pass nullptr to create non-synchronized tree. */
+QtxShortcutTree::QtxShortcutTree(
+ std::shared_ptr<SUIT_ShortcutContainer> theContainer,
+ QWidget* theParent
+) : QTreeWidget(theParent),
+myShortcutContainer(theContainer ? theContainer : std::shared_ptr<SUIT_ShortcutContainer>(new SUIT_ShortcutContainer()))
{
- if ( prev && prev->text( 1 ).endsWith( "+" ) )
- prev->setText( 1, myPrevBindings[ prev->parent()->text( 0 ) ][ prev->text( 0 ) ] );
+ setColumnCount(2);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+ setColumnWidth(0, COLUMN_SIZE);
+ setSortingEnabled(false); // Items are sorted in the same way, as in ShortcutContainer.
+ headerItem()->setHidden(true);
+ setExpandsOnDoubleClick(false); // Open shortcut editor on double click instead.
+ setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+ setToolTip(tr("Double click to edit key sequence."));
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myEditDialog = new QtxEditKeySequenceDialog(this);
+
+ this->installEventFilter(this);
+ connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int)));
+
+ QtxShortcutTree::instances[myShortcutContainer.get()].emplace(this);
}
-/*!
- \brief Set key bindings to the tree
- \param title the name of top-level item
- \param theShortcutMap map of key bindings
-*/
-void QtxShortcutTree::setBindings( const QString& title, const ShortcutMap& theShortcutMap )
+QtxShortcutTree::~QtxShortcutTree()
{
- QTreeWidgetItem* item= new QTreeWidgetItem();
- QFont font = item->font(0);
- font.setBold(true);
-
- if ( findItems( title, Qt::MatchFixedString ).isEmpty() ) {
- item->setText( 0, title );
- item->setFont( 0, font );
- addTopLevelItem( item );
- item->setFlags( Qt::ItemIsEnabled );
- } else {
- item = findItems( title, Qt::MatchFixedString ).first();
- item->takeChildren();
- }
- for( ShortcutMap::const_iterator it = theShortcutMap.constBegin(); it != theShortcutMap.constEnd(); ++it )
- item->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
- myPrevBindings.insert( title, theShortcutMap);
+ QtxShortcutTree::instances[myShortcutContainer.get()].erase(this);
+ if (QtxShortcutTree::instances[myShortcutContainer.get()].empty())
+ QtxShortcutTree::instances.erase(myShortcutContainer.get());
}
-/*!
- \brief Get all sections names.
- \return list of section names
-*/
-QStringList QtxShortcutTree::sections() const
+/*! \brief Copies shortcuts from ShortcutMgr. (Re)displays shortcuts of myModuleIDs. */
+void QtxShortcutTree::setShortcutsFromManager()
{
- QStringList lst;
- for( int i = 0; i < topLevelItemCount(); i++ )
- lst << topLevelItem( i )->text( 0 );
- return lst;
+ const auto shortcutMgr = SUIT_ShortcutMgr::get();
+ *myShortcutContainer = shortcutMgr->getShortcutContainer();
+ // nb! ShortcutMgr never removes shortcuts from its container, only disables.
+
+ updateItems(false /*theHighlightModified*/, true /*theUpdateSyncTrees*/);
}
-ShortcutMap* QtxShortcutTree::bindings( const QString& sec ) const
+/*! \brief Copies shortcuts from resources, user files are not accounted. (Re)displays shortcuts of myModuleIDs. */
+void QtxShortcutTree::setDefaultShortcuts()
{
- ShortcutMap* aMap = new ShortcutMap();
- QTreeWidgetItem* item = findItems( sec, Qt::MatchFixedString ).first();
- int nbChildren = item->childCount();
+ SUIT_ShortcutContainer defaultShortcuts;
+ SUIT_ShortcutMgr::fillContainerFromPreferences(defaultShortcuts, true /*theDefaultOnly*/);
- for( int i = 0; i < nbChildren; i++ ) {
- QTreeWidgetItem* child = item->child(i);
- aMap->insert( child->text( 0 ), child->text( 1 ) );
- }
+ myShortcutContainer->merge(defaultShortcuts, true /*theOverride*/, true /*theTreatAbsentIncomingAsDisabled*/);
+ // nb! SUIT_ShortcutContainer never erases shortcuts, only disables.
- return aMap;
+ updateItems(true /*theHighlightModified*/, true /*theUpdateSyncTrees*/);
}
-void QtxShortcutTree::focusOutEvent ( QFocusEvent* event )
+/*! \brief Applies pending changes to ShortcutMgr. Updates other instances of QtxShortcutTree. */
+void QtxShortcutTree::applyChangesToShortcutMgr()
{
- QWidget::focusOutEvent( event );
- if ( currentItem() && currentItem()->isSelected() )
- currentItem()->setText( 1, myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] );
+ const auto mgr = SUIT_ShortcutMgr::get();
+ mgr->mergeShortcutContainer(*myShortcutContainer);
+
+ // Update non-synchronized with this instances.
+ for (const auto& containerAndSyncTrees : QtxShortcutTree::instances) {
+ if (containerAndSyncTrees.first == myShortcutContainer.get())
+ continue;
+
+ const std::set<QtxShortcutTree*>& syncTrees = containerAndSyncTrees.second;
+ const auto itFirstSyncTree = syncTrees.begin();
+ if (itFirstSyncTree == syncTrees.end())
+ continue;
+
+ (*itFirstSyncTree)->setShortcutsFromManager();
+ const auto editDialog = (*itFirstSyncTree)->myEditDialog;
+ editDialog->setConfirmedKeySequence(mgr->getShortcutContainer().getKeySequence(editDialog->moduleID(), editDialog->inModuleActionID()));
+ editDialog->updateConflictsMessage();
+ }
}
-/*!
- \brief Set the list of shortcuts general sections.
-
- Key combinations in general sections should not intersect
- with any other key combinations.
+std::shared_ptr<const SUIT_ShortcutContainer> QtxShortcutTree::shortcutContainer() const
+{
+ return myShortcutContainer;
+}
- \param sectionsList list of common section names
-*/
-void QtxShortcutTree::setGeneralSections( const QStringList& sectionsList )
+/*! \param If theUpdateSyncTrees, trees sharing the same shortcut container are updated. */
+void QtxShortcutTree::updateItems(bool theHighlightModified, bool theUpdateSyncTrees)
{
- myGeneralSections = sectionsList;
+ const auto shortcutMgr = SUIT_ShortcutMgr::get();
+
+ for (const QString& moduleID : myModuleIDs) {
+ const auto& moduleShortcuts = myShortcutContainer->getModuleShortcutsInversed(moduleID);
+ if (moduleShortcuts.empty()) {
+ // Do not display empty module.
+ const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
+ if (moduleItemAndIdx.second >= 0)
+ takeTopLevelItem(moduleItemAndIdx.second);
+
+ continue;
+ }
+
+ const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
+ QtxShortcutTreeItem* moduleItem = moduleItemAndIdx.first;
+ if (!moduleItem) {
+ moduleItem = QtxShortcutTreeItem::createFolderItem(moduleID);
+ moduleItem->setName(shortcutMgr->getModuleName(moduleID));
+ addTopLevelItem(moduleItem);
+ moduleItem->setFlags(Qt::ItemIsEnabled);
+
+ for (const auto& shortcut : moduleShortcuts) {
+ const QString& inModuleActionID = shortcut.first;
+ const QKeySequence& keySequence = shortcut.second;
+ const QString keySequenceString = keySequence.toString();
+
+ auto shortcutItem = QtxShortcutTreeItem::createShortcutItem(moduleID, inModuleActionID);
+ if (!shortcutItem) {
+ ShCutDbg("QtxShortcutTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
+ continue;
+ }
+
+ shortcutItem->setName(shortcutMgr->getActionName(moduleID, inModuleActionID));
+ shortcutItem->setKeySequence(keySequenceString);
+
+ if (theHighlightModified) {
+ const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, inModuleActionID);
+ shortcutItem->highlightKeySequenceAsModified(keySequence != appliedKeySequence);
+ }
+
+ moduleItem->addChild(shortcutItem);
+ }
+
+ moduleItem->setExpanded(true); // Make tree expanded on first show.
+ }
+ else /* if the tree has the module-item */ {
+ for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
+ // Update exisiting items of a module.
+ QtxShortcutTreeItem* const childItem = static_cast<QtxShortcutTreeItem*>(moduleItem->child(childIdx));
+ const auto itShortcut = moduleShortcuts.find(childItem->myInModuleActionID);
+ if (itShortcut == moduleShortcuts.end()) {
+ // Shortcut of the item has been removed from myShortcutContainer - impossible.
+ continue;
+ }
+ const QKeySequence& newKeySequence = itShortcut->second;
+ const QString newKeySequenceString = newKeySequence.toString();
+ if (childItem->keySequence() != newKeySequenceString)
+ childItem->setKeySequence(newKeySequenceString);
+
+ if (theHighlightModified) {
+ const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, childItem->myInModuleActionID);
+ childItem->highlightKeySequenceAsModified(newKeySequence != appliedKeySequence);
+ }
+ else
+ childItem->highlightKeySequenceAsModified(false);
+ }
+
+ // Add new items if myShortcutContainer acquired new shortcuts, which may happen if a developer forgot
+ // to add shortcuts for registered actions to resource files.
+ if (moduleItem->childCount() < moduleShortcuts.size()) {
+ // Module shortcuts and tree items must be ordered with the same comparator. Now it is std::less(inModuleActionID_A, inModuleActionID_B).
+ std::set<QString> actionIDsOfItems;
+ for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
+ QtxShortcutTreeItem* const childItem = static_cast<QtxShortcutTreeItem*>(moduleItem->child(childIdx));
+ actionIDsOfItems.emplace(childItem->myInModuleActionID);
+ }
+
+ for (const auto& shortcut : moduleShortcuts) {
+ const QString& inModuleActionID = shortcut.first;
+ const QKeySequence& keySequence = shortcut.second;
+
+ auto itNewActionID = actionIDsOfItems.emplace(inModuleActionID).first;
+ int newItemIdx = 0;
+ // Replace this with std::distance if C++ >= 17.
+ auto it = actionIDsOfItems.begin();
+ while (it != itNewActionID) {
+ it++;
+ newItemIdx++;
+ }
+
+ const auto shortcutItem = QtxShortcutTreeItem::createShortcutItem(moduleID, inModuleActionID);
+ if (!shortcutItem) {
+ ShCutDbg("QtxShortcutTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
+ continue;
+ }
+
+ shortcutItem->setName(shortcutMgr->getActionName(moduleID, inModuleActionID));
+ shortcutItem->setKeySequence(keySequence.toString());
+
+ if (theHighlightModified) {
+ const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, inModuleActionID);
+ shortcutItem->highlightKeySequenceAsModified(keySequence != appliedKeySequence);
+ }
+
+ moduleItem->insertChild(newItemIdx, shortcutItem);
+ }
+ }
+ }
+ }
+
+ if (theUpdateSyncTrees) {
+ const std::set<QtxShortcutTree*>& syncTrees = QtxShortcutTree::instances[myShortcutContainer.get()];
+ for (const auto syncTree: syncTrees) {
+ if (syncTree == this)
+ continue;
+
+ syncTree->updateItems(theHighlightModified, false /*theUpdateSyncTrees*/);
+ const auto editDialog = syncTree->myEditDialog;
+ editDialog->setConfirmedKeySequence(myShortcutContainer->getKeySequence(editDialog->moduleID(), editDialog->inModuleActionID()));
+ editDialog->updateConflictsMessage();
+ }
+ }
}
-/*!
- \brief Check uniqueness of the shortcut.
- \param item current item of the shortcut tree
- \param shortcut shortcut appointed for the current item
- \return \c true if the given shortcut is allowed
-*/
-bool QtxShortcutTree::checkUniqueness( QTreeWidgetItem* item, const QString& shortcut )
-{
- // List of sections to check shortcut intersections
- QStringList sectionsList;
-
- // Current section
- QString currentSection = currentItem()->parent()->text( 0 );
-
- // If the current section is general
- if ( myGeneralSections.contains(currentSection) ) {
- sectionsList = sections();
- int currentSectionIndex = sectionsList.indexOf(currentSection);
- sectionsList.move( currentSectionIndex, 0);
- }
- else {
- sectionsList = myGeneralSections;
- sectionsList.prepend(currentSection);
+/*! \returns Pointer and index of top-level item.
+If the tree does not contain an item with theModuleID, returns {nullptr, -1}. */
+std::pair<QtxShortcutTreeItem*, int> QtxShortcutTree::findModuleFolderItem(const QString& theModuleID) const
+{
+ for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
+ QtxShortcutTreeItem* moduleItem = static_cast<QtxShortcutTreeItem*>(topLevelItem(moduleIdx));
+ if (moduleItem->myModuleID == theModuleID)
+ return std::pair<QtxShortcutTreeItem*, int>(moduleItem, moduleIdx);
}
+ return std::pair<QtxShortcutTreeItem*, int>(nullptr, -1);
+}
- // Iterate on sections
- QStringList::const_iterator it;
- for( it = sectionsList.constBegin(); it != sectionsList.constEnd(); ++it ) {
- QString section = *it;
-
- // Iterate on actual section
- QTreeWidgetItem* sectionRoot = findItems( section, Qt::MatchFixedString ).first();
- int nbChildren = sectionRoot->childCount();
-
- for( int i = 0; i < nbChildren; i++ ) {
- QTreeWidgetItem* child = sectionRoot->child(i);
-
- if ( (child != item) && (shortcut == child->text( 1 )) ) {
- bool res = QMessageBox::warning( parentWidget(), tr("Warning"),
- tr("The \"%1\" shortcut has already used by the \"%2\" action.\n")
- .arg(shortcut, section + ":" + child->text( 0 ) ) +
- tr("Do you want to reassign it from that action to the current one?"),
- QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
- if (res)
- child->setText( 1, "" );
- return res;
+void QtxShortcutTree::onItemDoubleClicked(QTreeWidgetItem* theItem, int theColIdx)
+{
+ QtxShortcutTreeItem* const item = static_cast<QtxShortcutTreeItem*>(theItem);
+ // Do not react if folder-item is clicked.
+ if (item->isFolder())
+ return;
+
+ myEditDialog->setModuleAndActionID(item->myModuleID, item->myInModuleActionID);
+ myEditDialog->setModuleAndActionName(static_cast<QtxShortcutTreeItem*>(item->parent())->name(), item->name());
+ myEditDialog->setConfirmedKeySequence(QKeySequence::fromString(item->keySequence()));
+ myEditDialog->updateConflictsMessage();
+ const bool somethingChanged = myEditDialog->exec() == QDialog::Accepted;
+
+ if (!somethingChanged)
+ return;
+
+ const QKeySequence newKeySequence = myEditDialog->editedKeySequence();
+
+ /** { moduleID, inModuleActionID }[] */
+ std::set<std::pair<QString, QString>> disabledActionIDs = myShortcutContainer->setShortcut(item->myModuleID, item->myInModuleActionID, newKeySequence, true /*override*/);
+
+ /** { moduleID, {inModuleActionID, keySequence}[] }[] */
+ std::map<QString, std::map<QString, QString>> changes;
+ changes[item->myModuleID][item->myInModuleActionID] = newKeySequence.toString();
+ for (const auto moduleAndActionID : disabledActionIDs) {
+ changes[moduleAndActionID.first][moduleAndActionID.second] = QString();
+ }
+
+ // Set new key sequences to shortcut items.
+ for (const auto& moduleIDAndChanges : changes) {
+ const QString& moduleID = moduleIDAndChanges.first;
+
+ const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
+ const auto moduleItem = moduleItemAndIdx.first;
+ if (!moduleItem)
+ continue;
+
+ /** {inModuleActionID, newKeySequence}[] */
+ const std::map<QString, QString>& moduleChanges = moduleIDAndChanges.second;
+
+ // Go through module' shortcut items, and highlight those, whose key sequences differ from applied key sequences.
+ for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
+ QtxShortcutTreeItem* const childItem = static_cast<QtxShortcutTreeItem*>(moduleItem->child(childIdx));
+ const auto itChange = moduleChanges.find(childItem->myInModuleActionID);
+ if (itChange == moduleChanges.end()) {
+ // The shortcut has not been changed.
+ continue;
}
+
+ childItem->setKeySequence(itChange->second);
+
+ const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, childItem->myInModuleActionID);
+ childItem->highlightKeySequenceAsModified(QKeySequence::fromString(itChange->second) != appliedKeySequence);
}
}
+}
+
+/*static*/ std::map<SUIT_ShortcutContainer*, std::set<QtxShortcutTree*>> QtxShortcutTree::instances =
+std::map<SUIT_ShortcutContainer*, std::set<QtxShortcutTree*>>();
+
+
+QtxShortcutTreeItem::QtxShortcutTreeItem(const QString& theModuleID, const QString& theInModuleActionID)
+: QTreeWidgetItem(), myModuleID(theModuleID), myInModuleActionID(theInModuleActionID)
+{ }
+
+/*static*/ QtxShortcutTreeItem* QtxShortcutTreeItem::createFolderItem(const QString& theModuleID)
+{
+ auto item = new QtxShortcutTreeItem(theModuleID, QString());
+
+ QFont font = item->font(ElementIdx::Name);
+ font.setBold(true);
+ item->setFont(ElementIdx::Name, font);
+
+ return item;
+}
+
+/*! \returns nullptr if theInModuleActionID is empty. */
+/*static*/ QtxShortcutTreeItem* QtxShortcutTreeItem::createShortcutItem(const QString& theModuleID, const QString& theInModuleActionID)
+{
+ if (theInModuleActionID.isEmpty()) {
+ ShCutDbg("QtxShortcutTreeItem: attempt to create item with empty action ID.");
+ return nullptr;
+ }
+
+ return new QtxShortcutTreeItem(theModuleID, theInModuleActionID);
+}
- return true;
+bool QtxShortcutTreeItem::isFolder() const
+{
+ return myInModuleActionID.isEmpty();
+}
+
+/*! \brief Highlights text at ElementIdx::KeySequence. */
+void QtxShortcutTreeItem::highlightKeySequenceAsModified(bool theHighlight)
+{
+ static const QBrush bgHighlitingBrush = QBrush(Qt::darkGreen);
+ static const QBrush fgHighlitingBrush = QBrush(Qt::white);
+ static const QBrush noBrush = QBrush();
+
+ setBackground(ElementIdx::KeySequence, theHighlight ? bgHighlitingBrush : noBrush);
+ setForeground(ElementIdx::KeySequence, theHighlight ? fgHighlitingBrush : noBrush);
+}
+
+void QtxShortcutTreeItem::setName(const QString& theName)
+{
+ setText(ElementIdx::Name, theName);
}
+
+QString QtxShortcutTreeItem::name() const
+{
+ return text(ElementIdx::Name);
+}
+
+void QtxShortcutTreeItem::setKeySequence(const QString& theKeySequence)
+{
+ setText(ElementIdx::KeySequence, theKeySequence);
+}
+
+QString QtxShortcutTreeItem::keySequence() const
+{
+ return text(ElementIdx::KeySequence);
+}
\ No newline at end of file
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
-#ifndef QTXSHORTCUTEDIT_H
-#define QTXSHORTCUTEDIT_H
+#ifndef QTXSHORTCUTTREE_H
+#define QTXSHORTCUTTREE_H
#include "Qtx.h"
-
+#include <QDialog>
#include <QFrame>
#include <QTreeWidget>
+#include "SUIT_ShortcutMgr.h"
+#include <memory>
+#include <map>
+#include <set>
class QLineEdit;
+class QLabel;
class QPushButton;
class QTreeWidgetItem;
-typedef QMap< QString, QString > ShortcutMap;
-
-class QTX_EXPORT QtxShortcutEdit : public QFrame
+class QTX_EXPORT QtxKeySequenceEdit : public QFrame
{
Q_OBJECT
public:
- QtxShortcutEdit( QWidget* = 0 );
- virtual ~QtxShortcutEdit();
- void setShortcut( const QKeySequence& );
- QKeySequence shortcut();
- static QString parseEvent( QKeyEvent* );
- static bool isValidKey( int );
+ QtxKeySequenceEdit(QWidget* = nullptr);
+ virtual ~QtxKeySequenceEdit() = default;
+
+ void setConfirmedKeySequence(const QKeySequence&);
+ void setEditedKeySequence(const QKeySequence&);
+ QKeySequence editedKeySequence() const;
+ bool isKeySequenceModified() const;
+ void restoreKeySequence();
+ static QString parseEvent(QKeyEvent*);
+ static bool isValidKey(int);
+
+signals:
+ void editingStarted();
+ void editingFinished();
+ void restoreFromShortcutMgrClicked();
private slots:
- void onCliked();
+ void onClear();
void onEditingFinished();
protected:
- virtual bool eventFilter( QObject*, QEvent* );
+ virtual bool eventFilter(QObject*, QEvent*);
private:
void initialize();
private:
- QLineEdit* myShortcut;
- QString myPrevShortcutText;
+ QLineEdit* myKeySequenceLineEdit;
+ QString myConfirmedKeySequenceString;
+
+ // Last valid key sequence string from myKeySequenceLineEdit.
+ QString myPrevKeySequenceString;
+};
+
+
+class QtxShortcutTree;
+class QtxShortcutTreeItem;
+class QTextEdit;
+
+
+class QTX_EXPORT QtxEditKeySequenceDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ QtxEditKeySequenceDialog(QtxShortcutTree* theParent);
+ QtxEditKeySequenceDialog(const QtxEditKeySequenceDialog&) = delete;
+ QtxEditKeySequenceDialog& operator=(const QtxEditKeySequenceDialog&) = delete;
+ virtual ~QtxEditKeySequenceDialog() = default;
+
+ void setModuleAndActionID(const QString& theModuleID, const QString& theInModuleActionID);
+ const QString& moduleID() const;
+ const QString& inModuleActionID() const;
+
+ void setModuleAndActionName(const QString& theModuleName, const QString& theActionName);
+
+ void setConfirmedKeySequence(const QKeySequence& theSequence);
+ QKeySequence editedKeySequence() const;
+
+ void updateConflictsMessage();
+
+ int exec();
+
+private slots:
+ void onEditingStarted();
+ void onEditingFinished();
+ void onRestoreFromShortcutMgr();
+ void onConfirm();
+
+private:
+ QString myModuleID;
+ QString myInModuleActionID;
+ QLabel* myActionName;
+ QtxKeySequenceEdit* myKeySequenceEdit;
+ QTextEdit* myTextEdit;
};
+
class QTX_EXPORT QtxShortcutTree : public QTreeWidget
{
Q_OBJECT
public:
- QtxShortcutTree( QWidget * parent = 0 );
+ QtxShortcutTree(
+ std::shared_ptr<SUIT_ShortcutContainer> theContainer = std::shared_ptr<SUIT_ShortcutContainer>(),
+ QWidget* theParent = nullptr
+ );
+ QtxShortcutTree(const QtxShortcutTree&) = delete;
+ QtxShortcutTree& operator=(const QtxShortcutTree&) = delete;
virtual ~QtxShortcutTree();
- void setBindings( const QString&, const ShortcutMap& );
- ShortcutMap* bindings( const QString& ) const;
- QStringList sections() const;
- void setGeneralSections( const QStringList& );
-protected:
- virtual bool eventFilter( QObject*, QEvent* );
- virtual void focusOutEvent( QFocusEvent* );
- virtual bool checkUniqueness( QTreeWidgetItem*, const QString& );
+ void setShortcutsFromManager();
+ void setDefaultShortcuts();
+ void applyChangesToShortcutMgr();
+
+ std::shared_ptr<const SUIT_ShortcutContainer> shortcutContainer() const;
+
+private:
+ void updateItems(bool theHighlightModified, bool theUpdateSyncTrees);
+ std::pair<QtxShortcutTreeItem*, int> findModuleFolderItem(const QString& theModuleID) const;
private slots:
- void onCurrentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* );
+ void onItemDoubleClicked(QTreeWidgetItem* theWidgetItem, int theColIdx);
+
+public:
+ /** Keeps IDs of modules, which will be shown on setShortcutsFromManager(). */
+ std::set<QString> myModuleIDs;
private:
- QMap< QString, ShortcutMap > myPrevBindings;
- QStringList myGeneralSections;
+ /** Allows to modify plenty of shortcuts and then apply them to SUIT_ShortcutMgr as a batch. */
+ const std::shared_ptr<SUIT_ShortcutContainer> myShortcutContainer;
+
+ QtxEditKeySequenceDialog* myEditDialog;
+
+ /**
+ * Ensures that, if several QtxShortcutTree instances coexist,
+ * all of them are updated when one of them applies pending changes to SUIT_ShortcutMgr.
+ *
+ * Sharing of SUIT_ShortcutContainer allows to keep some trees synchronized even without
+ * applying changes to SUIT_ShortcutMgr. Why? See QtxPagePrefShortcutTreeItem.
+ *
+ * Access is not synchronized in assumption, that all instances live in the same thread.
+ */
+ static std::map<SUIT_ShortcutContainer*, std::set<QtxShortcutTree*>> instances;
+};
+
+
+class QtxShortcutTreeItem : public QTreeWidgetItem
+{
+private:
+ QtxShortcutTreeItem(const QString& theModuleID, const QString& theInModuleActionID);
+
+ enum ElementIdx {
+ Name = 0,
+ KeySequence = 1, // Empty, if item is used as folder.
+ };
+
+public:
+ static QtxShortcutTreeItem* createFolderItem(const QString& theModuleID);
+ static QtxShortcutTreeItem* createShortcutItem(const QString& theModuleID, const QString& theInModuleActionID);
+ virtual ~QtxShortcutTreeItem() = default;
+
+ bool isFolder() const;
+ void highlightKeySequenceAsModified(bool theHighlight);
+
+ void setName(const QString& theName);
+ QString name() const;
+
+ void setKeySequence(const QString& theKeySequence);
+ QString keySequence() const;
+
+ const QString myModuleID;
+ const QString myInModuleActionID; // Empty, if item is used as folder.
};
-#endif // QTXSHORTCUTEDIT_H
+#endif // QTXSHORTCUTTREE_H
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg">
+<g fill="none" fill-rule="evenodd" stroke="#328930" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0 -1 1 0 2.5 15.5)">
+<path d="m0 5.82842712v7.17157288c0 1.1045695.8954305 2 2 2h6c1.1045695 0 2-.8954305 2-2v-7.17157288c0-.53043297-.21071368-1.0391408-.58578644-1.41421356l-3.70710678-3.70710678c-.39052429-.39052429-1.02368927-.39052429-1.41421356 0l-3.70710678 3.70710678c-.37507276.37507276-.58578644.88378059-.58578644 1.41421356z"/>
+<g transform="matrix(0 1 -1 0 14 4)">
+<path d="m3 11 4-4"/>
+<path d="m3 7 4 4"/>
+</g>
+</g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg">
+<g fill="none" fill-rule="evenodd" stroke="#328930" stroke-linecap="round" stroke-linejoin="round" transform="translate(3 6)">
+<path d="m1.378 1.376 4.243.003v4.242" transform="matrix(-.70710678 .70710678 .70710678 .70710678 3.500179 -1.449821)"/>
+<path d="m5.5 9.49998326h5c2 .00089417 3-.99910025 3-2.99998326s-1-3.00088859-3-3.00001674h-10"/>
+</g>
+</svg>
<translation>%1 a été développé en utilisant %2</translation>
</message>
</context>
+<context>
+ <name>QtxKeySequenceEdit</name>
+ <message>
+ <source>Disable shortcut.</source>
+ <translation>Désactivez le raccourci.</translation>
+ </message>
+ <message>
+ <source>Restore the currently applied key sequence.</source>
+ <translation>Restaurez la séquence de touches actuellement appliquée.</translation>
+ </message>
+</context>
+<context>
+ <name>QtxEditKeySequenceDialog</name>
+ <message>
+ <source>Change key sequence</source>
+ <translation>Modifier la séquence de touches</translation>
+ </message>
+ <message>
+ <source>No conflicts.</source>
+ <translation>Aucun conflit.</translation>
+ </message>
+ <message>
+ <source>Confirm</source>
+ <translation>Confirmer</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>These shortcuts will be disabled on confirm:</source>
+ <translation>Ces raccourcis seront désactivés lors de la confirmation :</translation>
+ </message>
+</context>
+<context>
+ <name>QtxShortcutTree</name>
+ <message>
+ <source>Double click to edit key sequence.</source>
+ <translation>Double-cliquez pour modifier la séquence de touches.</translation>
+ </message>
+</context>
</TS>
<translation>%1 は %2 を使用して開発されています。</translation>
</message>
</context>
+ <context>
+ <name>QtxKeySequenceEdit</name>
+ <message>
+ <source>Disable shortcut.</source>
+ <translation>ショートカットを無効にします。</translation>
+ </message>
+ <message>
+ <source>Restore the currently applied key sequence.</source>
+ <translation>現在適用されているキー シーケンスを復元します。</translation>
+ </message>
+ </context>
+ <context>
+ <name>QtxEditKeySequenceDialog</name>
+ <message>
+ <source>Change key sequence</source>
+ <translation>キーシーケンスを変更する</translation>
+ </message>
+ <message>
+ <source>No conflicts.</source>
+ <translation>競合はありません。</translation>
+ </message>
+ <message>
+ <source>Confirm</source>
+ <translation>確認する</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+ <message>
+ <source>These shortcuts will be disabled on confirm:</source>
+ <translation>これらのショートカットは確認時に無効になります。</translation>
+ </message>
+ </context>
+ <context>
+ <name>QtxShortcutTree</name>
+ <message>
+ <source>Double click to edit key sequence.</source>
+ <translation>ダブルクリックしてキー シーケンスを編集します。</translation>
+ </message>
+ </context>
</TS>
Preferences = 4,
Tools = 5,
Window = 6,
- Help = 7
+ Help = 7
};
enum {
#endif
};
-enum {
+enum {
PT_Auto = LightApp_Preferences::Auto,
PT_Space = LightApp_Preferences::Space,
- PT_Bool = LightApp_Preferences::Bool,
+ PT_Bool = LightApp_Preferences::Bool,
PT_Color = LightApp_Preferences::Color,
- PT_String = LightApp_Preferences::String,
- PT_Selector = LightApp_Preferences::Selector,
- PT_DblSpin = LightApp_Preferences::DblSpin,
- PT_IntSpin = LightApp_Preferences::IntSpin,
- PT_Double = LightApp_Preferences::Double,
- PT_Integer = LightApp_Preferences::Integer,
- PT_GroupBox = LightApp_Preferences::GroupBox,
- PT_Tab = LightApp_Preferences::Tab,
- PT_Frame = LightApp_Preferences::Frame,
- PT_Font = LightApp_Preferences::Font,
- PT_DirList = LightApp_Preferences::DirList,
- PT_File = LightApp_Preferences::File,
- PT_Slider = LightApp_Preferences::Slider,
- PT_Shortcut = LightApp_Preferences::Shortcut,
- PT_ShortcutTree = LightApp_Preferences::ShortcutTree,
- PT_BiColor = LightApp_Preferences::BiColor,
- PT_Background = LightApp_Preferences::Background,
- PT_UserDefined = LightApp_Preferences::UserDefined,
+ PT_String = LightApp_Preferences::String,
+ PT_Selector = LightApp_Preferences::Selector,
+ PT_DblSpin = LightApp_Preferences::DblSpin,
+ PT_IntSpin = LightApp_Preferences::IntSpin,
+ PT_Double = LightApp_Preferences::Double,
+ PT_Integer = LightApp_Preferences::Integer,
+ PT_GroupBox = LightApp_Preferences::GroupBox,
+ PT_Tab = LightApp_Preferences::Tab,
+ PT_Frame = LightApp_Preferences::Frame,
+ PT_Font = LightApp_Preferences::Font,
+ PT_DirList = LightApp_Preferences::DirList,
+ PT_File = LightApp_Preferences::File,
+ PT_Slider = LightApp_Preferences::Slider,
+ PT_ShortcutTree = LightApp_Preferences::ShortcutTree,
+ PT_BiColor = LightApp_Preferences::BiColor,
+ PT_Background = LightApp_Preferences::Background,
+ PT_UserDefined = LightApp_Preferences::UserDefined,
};
class UserDefinedContent: public QWidget
//! Orientation
enum Orientation {
- Horizontal = 0, //!< Horizontal orientation
+ Horizontal = 0, //!< Horizontal orientation
Vertical = 1 //!< Vertical orientation
};
};
#endif
-enum VisibilityState
+enum VisibilityState
{
ShownState, //!< Object is shown in viewer
HiddenState, //!< Object is hidden in viewer
- UnpresentableState //!< Unpresentable object
+ UnpresentableState //!< Unpresentable object
};
#ifndef DISABLE_PLOT2DVIEWER
yRight = QwtPlot::yRight,
xBottom = QwtPlot::xBottom,
xTop = QwtPlot::xTop,
-};
+};
#endif
class SalomePyQt
static void setColor( const QString&, const QColor& );
static QColor getColor( const QString& );
- static void setReference( const QString&, const QString& );
+ static void setReference( const QString&, const QString& );
static QString getReference( const QString& );
static QIcon loadIcon( const QString&, const QString& );
static int createMenu( const QString&, const int = -1,
const int = -1, const int = -1, const int = -1 );
- static int createMenu( const QString&, const QString& = QString(),
+ static int createMenu( const QString&, const QString& = QString(),
const int = -1, const int = -1, const int = -1 );
static int createMenu( const int, const int = -1,
const int = -1, const int = -1 );
- static int createMenu( const int, const QString& = QString(),
+ static int createMenu( const int, const QString& = QString(),
const int = -1, const int = -1 );
- static int createMenu( QAction*, const int, const int = -1,
+ static int createMenu( QAction*, const int, const int = -1,
const int = -1, const int = -1 );
- static int createMenu( QAction*, const QString&, const int = -1,
+ static int createMenu( QAction*, const QString&, const int = -1,
const int = -1, const int = -1 );
static QAction* createSeparator();
static QAction* createAction( const int, const QString&,
- const QString& = QString(), const QString& = QString(),
+ const QString& = QString(), const QString& = QString(),
const QString& = QString(), const int = 0, const bool = false );
-
+
static QtxActionGroup* createActionGroup( const int, const bool = true );
static QAction* action( const int );
static void message( const QString&, bool = true );
static void clearMessages();
-
+
static QList<int> getViews();
static int getActiveView();
static QString getViewType( const int );
Preferences = 4,
Tools = 5,
Window = 6,
- Help = 7
+ Help = 7
};
enum WindowType {
WT_User
};
-enum PrefType {
+enum PrefType {
PT_Auto,
PT_Space,
- PT_Bool,
+ PT_Bool,
PT_Color,
- PT_String,
- PT_Selector,
- PT_DblSpin,
- PT_IntSpin,
- PT_Double,
- PT_Integer,
- PT_GroupBox,
- PT_Tab,
- PT_Frame,
- PT_Font,
- PT_DirList,
- PT_File,
+ PT_String,
+ PT_Selector,
+ PT_DblSpin,
+ PT_IntSpin,
+ PT_Double,
+ PT_Integer,
+ PT_GroupBox,
+ PT_Tab,
+ PT_Frame,
+ PT_Font,
+ PT_DirList,
+ PT_File,
PT_Slider,
- PT_Shortcut,
PT_ShortcutTree,
PT_BiColor,
PT_Background,
};
enum Orientation {
- Horizontal = 0,
- Vertical = 1
+ Horizontal = 0,
+ Vertical = 1
};
enum Action {
- MoveWidget = 0,
- LeaveWidget = 1,
- SplitAt = 2
+ MoveWidget = 0,
+ LeaveWidget = 1,
+ SplitAt = 2
};
class QtxAction : QWidgetAction
virtual void retrieve();
};
-enum VisibilityState
+enum VisibilityState
{
ShownState,
HiddenState,
- UnpresentableState
+ UnpresentableState
};
class SalomePyQt
static QString getFileName ( QWidget*, const QString&, const QStringList&, const QString&, bool ) /ReleaseGIL/ ;
static QStringList getOpenFileNames ( QWidget*, const QString&, const QStringList&, const QString& ) /ReleaseGIL/ ;
static QString getExistingDirectory( QWidget*, const QString&, const QString& ) /ReleaseGIL/ ;
-
+
static void createRoot() /ReleaseGIL/ ;
static QString createObject( const QString& = QString("") ) /ReleaseGIL/ ;
static QString createObject( const QString&,
static void setColor( const QString&, const QColor& ) /ReleaseGIL/ ;
static QColor getColor( const QString& ) /ReleaseGIL/ ;
- static void setReference( const QString& ,const QString& ) /ReleaseGIL/ ;
+ static void setReference( const QString& ,const QString& ) /ReleaseGIL/ ;
static QString getReference( const QString& ) /ReleaseGIL/ ;
static void removeObject(const QString& ) /ReleaseGIL/ ;
static int createMenu( const QString&, const int,
const int = -1, const int = -1, const int = -1 ) /ReleaseGIL/ ;
- static int createMenu( const QString&, const QString&,
+ static int createMenu( const QString&, const QString&,
const int = -1, const int = -1, const int = -1 ) /ReleaseGIL/ ;
static int createMenu( const int, const int,
const int = -1, const int = -1 ) /ReleaseGIL/ ;
- static int createMenu( const int, const QString&,
+ static int createMenu( const int, const QString&,
const int = -1, const int = -1 ) /ReleaseGIL/ ;
- static int createMenu( QAction*, const int, const int = -1,
+ static int createMenu( QAction*, const int, const int = -1,
const int = -1, const int = -1 ) /ReleaseGIL/ ;
- static int createMenu( QAction*, const QString&, const int = -1,
+ static int createMenu( QAction*, const QString&, const int = -1,
const int = -1, const int = -1 ) /ReleaseGIL/ ;
static QAction* createSeparator() /ReleaseGIL/ ;
- static QAction* createAction( const int, const QString&,
- const QString& = QString(), const QString& = QString(),
+ static QAction* createAction( const int, const QString&,
+ const QString& = QString(), const QString& = QString(),
const QString& = QString(), const int = 0, const bool = false ) /ReleaseGIL/ ;
static QtxActionGroup* createActionGroup( const int, const bool = true ) /ReleaseGIL/ ;
const QString& = QString(),
const QString& = QString() ) /ReleaseGIL/ ;
static QVariant preferenceProperty( const int, const QString& ) /ReleaseGIL/ ;
- static void setPreferenceProperty( const int,
+ static void setPreferenceProperty( const int,
const QString&,
const QVariant& ) /ReleaseGIL/ ;
- static void setPreferencePropertyWg( const int,
- const QString&,
+ static void setPreferencePropertyWg( const int,
+ const QString&,
UserDefinedContent* ) /ReleaseGIL/ ;
- static void addPreferenceProperty( const int,
- const QString&,
- const int,
+ static void addPreferenceProperty( const int,
+ const QString&,
+ const int,
const QVariant& ) /ReleaseGIL/ ;
static void message( const QString&, bool = true ) /ReleaseGIL/ ;
static void clearMessages() /ReleaseGIL/ ;
-
+
static QList<int> getViews() /ReleaseGIL/ ;
static int getActiveView() /ReleaseGIL/ ;
static QString getViewType( const int ) /ReleaseGIL/ ;
static bool isViewVisible( const int id ) /ReleaseGIL/ ;
static void setViewClosable( const int id, const bool ) /ReleaseGIL/ ;
static bool isViewClosable( const int id ) /ReleaseGIL/ ;
-
+
static bool groupAllViews() /ReleaseGIL/ ;
static bool splitView( const int, Orientation, Action ) /ReleaseGIL/ ;
static bool moveView( const int, const int, const bool ) /ReleaseGIL/ ;
static QList<int> neighbourViews( const int ) /ReleaseGIL/ ;
-
+
%If (ENABLE_PLOT2D)
// start Plot2d-related functionality
static void displayCurve(const int, Plot2d_Curve*) /ReleaseGIL/ ;
createAction( FileNewId, tr( "TOT_DESK_FILE_NEW" ),
resMgr->loadPixmap( "STD", tr( "ICON_FILE_NEW" ) ),
tr( "MEN_DESK_FILE_NEW" ), tr( "PRP_DESK_FILE_NEW" ),
- Qt::CTRL+Qt::Key_N, desk, false, this, SLOT( onNewDoc() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onNewDoc() ), "/TOT_DESK_FILE_NEW" );
createAction( FileOpenId, tr( "TOT_DESK_FILE_OPEN" ),
resMgr->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
tr( "MEN_DESK_FILE_OPEN" ), tr( "PRP_DESK_FILE_OPEN" ),
- Qt::CTRL+Qt::Key_O, desk, false, this, SLOT( onOpenDoc() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onOpenDoc() ), "/TOT_DESK_FILE_OPEN" );
createAction( FileReopenId, tr( "TOT_DESK_FILE_REOPEN" ), QIcon(),
tr( "MEN_DESK_FILE_REOPEN" ), tr( "PRP_DESK_FILE_REOPEN" ),
createAction( FileCloseId, tr( "TOT_DESK_FILE_CLOSE" ),
resMgr->loadPixmap( "STD", tr( "ICON_FILE_CLOSE" ) ),
tr( "MEN_DESK_FILE_CLOSE" ), tr( "PRP_DESK_FILE_CLOSE" ),
- Qt::CTRL+Qt::Key_W, desk, false, this, SLOT( onCloseDoc() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onCloseDoc() ), "/TOT_DESK_FILE_CLOSE" );
//no need in this action for mono-study application as it is same as NewDoc
action( FileCloseId )->setVisible( false );
createAction( FileExitId, tr( "TOT_DESK_FILE_EXIT" ), QIcon(),
tr( "MEN_DESK_FILE_EXIT" ), tr( "PRP_DESK_FILE_EXIT" ),
- Qt::CTRL+Qt::Key_Q, desk, false, this, SLOT( onExit() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onExit() ), "/TOT_DESK_FILE_EXIT" );
createAction( FileSaveId, tr( "TOT_DESK_FILE_SAVE" ),
resMgr->loadPixmap( "STD", tr( "ICON_FILE_SAVE" ) ),
tr( "MEN_DESK_FILE_SAVE" ), tr( "PRP_DESK_FILE_SAVE" ),
- Qt::CTRL+Qt::Key_S, desk, false, this, SLOT( onSaveDoc() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onSaveDoc() ), "/TOT_DESK_FILE_SAVE" );
createAction( FileSaveAsId, tr( "TOT_DESK_FILE_SAVEAS" ), QIcon(),
tr( "MEN_DESK_FILE_SAVEAS" ), tr( "PRP_DESK_FILE_SAVEAS" ),
- Qt::CTRL+Qt::SHIFT+Qt::Key_S, desk, false, this, SLOT( onSaveAsDoc() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onSaveAsDoc() ), "/TOT_DESK_FILE_SAVEAS");
createAction( EditCopyId, tr( "TOT_DESK_EDIT_COPY" ),
resMgr->loadPixmap( "STD", tr( "ICON_EDIT_COPY" ) ),
tr( "MEN_DESK_EDIT_COPY" ), tr( "PRP_DESK_EDIT_COPY" ),
- Qt::CTRL+Qt::Key_C, desk, false, this, SLOT( onCopy() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onCopy() ), "/TOT_DESK_EDIT_COPY" );
createAction( EditPasteId, tr( "TOT_DESK_EDIT_PASTE" ),
resMgr->loadPixmap( "STD", tr( "ICON_EDIT_PASTE" ) ),
tr( "MEN_DESK_EDIT_PASTE" ), tr( "PRP_DESK_EDIT_PASTE" ),
- Qt::CTRL+Qt::Key_V, desk, false, this, SLOT( onPaste() ) );
+ QKeySequence::UnknownKey, desk, false, this, SLOT( onPaste() ), "/TOT_DESK_EDIT_PASTE" );
QAction* a = createAction( ViewStatusBarId, tr( "TOT_DESK_VIEW_STATUSBAR" ),
QIcon(), tr( "MEN_DESK_VIEW_STATUSBAR" ),
createMenu( FileNewId, fileMenu, 0 );
createMenu( FileOpenId, fileMenu, 0 );
- createMenu( FileReopenId, fileMenu, 0 );
+ createMenu( FileReopenId, fileMenu, 0 );
createMenu( FileSaveId, fileMenu, 5 );
createMenu( FileSaveAsId, fileMenu, 5 );
createMenu( FileCloseId, fileMenu, 5 );
QApplication::setOverrideCursor( Qt::WaitCursor );
bool res = openAction( openChoice( aName ), aName );
-
+
QApplication::restoreOverrideCursor();
return res;
// delete study
delete study;
study = 0;
-
+
// post closing actions
afterCloseDoc();
/*!
\brief Show notification with specified text and title.
-
+
Notification will be automatically hidden after specified \a timeout
(given in milliseconds). If \a timeout is zero, the notification
is not automatically hidden; it can be only closed by the user manually.
-
+
\param text - Notification text
\param title - Notification title
\param timeout - Timeout in milliseconds
*/
SUIT_ShortcutMgr* SUIT_Application::shortcutMgr() const
{
- return SUIT_ShortcutMgr::getShortcutMgr();
+ return SUIT_ShortcutMgr::get();
}
#define DEFAULT_MESSAGE_DELAY 3000
\param toggle - if it is \c true the action will be a toggle action, otherwise it will be a command action
\param reciever - object that contains slot
\param member - slot to be called when action is activated
+ \param actionID - application-unique action ID
*/
QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
const QString& menu, const QString& tip, const int key,
- QObject* parent, const bool toggle, QObject* reciever,
- const char* member, const QString& shortcutAction )
+ QObject* parent, const bool toggle, QObject* reciever,
+ const char* member, const QString& actionID )
{
- return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, shortcutAction );
+ return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, actionID );
}
/*!
\param toggle - if it is TRUE the action will be a toggle action, otherwise it will be a command action
\param reciever - object that contains slot
\param member - slot to be called when action is activated
+ \param actionID - application-unique action ID
*/
QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
const QString& menu, const QString& tip, const QKeySequence& key,
- QObject* parent, const bool toggle, QObject* reciever,
- const char* member, const QString& shortcutAction )
+ QObject* parent, const bool toggle, QObject* reciever,
+ const char* member, const QString& actionID )
{
- QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, shortcutAction );
+ QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, actionID );
a->setStatusTip( tip );
if ( reciever && member )
*/
/*!
An <b>Application</b> is a class which defines application configuration and behaviour.
- For example Application object defines what Viewers are used in this application, what auxilliary windows
- are present, how user can dial with them. Also Application object defines an sertain type of data structure by
+ For example, Application object defines what Viewers are used in this application, what auxilliary windows
+ are present, how user can dial with them. Also Application object defines an certain type of data structure by
holding of pointer on an instance of SUIT_Study class (which represents Document data structure). In other words
Application defines type of sata structure, type of used Viewers, type of main GUI widget (Desktop),
and other auxilliary tools.
//! Returns main widget (Desktop) of the application (if it exists)
virtual SUIT_Desktop* desktop();
- /*! Returns \c false if application can not be closed (because of non saved data for example).
+ /*! Returns \c false if application can not be closed (because of non saved data for example).
This method called by SUIT_Session whin closing of application was requested. */
virtual bool isPossibleToClose( bool& );
//! Creates new empty Study if active Study = 0
virtual void createEmptyStudy();
- /*! Returns number of Studies.
+ /*! Returns number of Studies.
* Must be redefined in Applications which support several studies for one Application instance. */
virtual int getNbStudies() const;
SUIT_ShortcutMgr* shortcutMgr() const;
- //! Puts the message to the status bar
+ //! Puts the message to the status bar
void putInfo ( const QString&, const int = 0 );
//! Invokes application-specific "Open/Save File" dialog and returns the selected file name.
- virtual QString getFileName( bool open, const QString& initial, const QString& filters,
+ virtual QString getFileName( bool open, const QString& initial, const QString& filters,
const QString& caption, QWidget* parent ) = 0;
//! Invokes application-specific "Select Directory" dialog and returns the selected directory name.
//! Creates a new Study instance. Must be redefined in new application according to its Study type.
virtual SUIT_Study* createNewStudy();
virtual void setActiveStudy( SUIT_Study* );
-
+
/** @name Set menu shown functions*/ //@{
void setMenuShown( QAction*, const bool );
void setMenuShown( const int, const bool );//@}
case DirList:
item = new QtxPagePrefPathListItem( Qtx::PT_Directory, title, parent, sect, param );
break;
- case Shortcut:
- item = new QtxPagePrefShortcutBtnsItem( title, parent, sect, param );
- break;
case ShortcutTree:
- item = new QtxPagePrefShortcutTreeItem( title, parent, sect, param );
+ item = new QtxPagePrefShortcutTreeItem( parent );
break;
case BiColor:
item = new QtxPagePrefBiColorItem( title, parent, sect, param );
typedef enum { Auto, Space, Bool, Color, String, Selector,
DblSpin, IntSpin, Double, Integer,
GroupBox, Tab, Frame, Font, DirList, File,
- Slider, Shortcut, ShortcutTree, BiColor, Background,
+ Slider, ShortcutTree, BiColor, Background,
UserDefined = 1000 } PrefItemType;
public:
#include "SUIT_Session.h"
#include "SUIT_ResourceMgr.h"
+#include "SUIT_MessageBox.h"
+#include <QAction>
#include <QtxAction.h>
#include <QApplication>
#include <QActionEvent>
+#include <QKeySequence>
+#include <QDebug>
-SUIT_ShortcutMgr* SUIT_ShortcutMgr::myShortcutMgr = NULL;
+#include <list>
-/*!
- \brief Constructor
+
+#include <iostream>
+#include <string>
+const std::wstring SHORTCUT_MGR_LOG_PREFIX = L"SHORTCUT_MGR_DBG: ";
+bool ShCutDbg(const QString& theString)
+{
+ if (ShCutDbg()) {
+ std::wcout << SHORTCUT_MGR_LOG_PREFIX << theString.toStdWString() << std::endl;
+ return true;
+ }
+ return false;
+}
+bool ShCutDbg(const char* src)
+{
+ if (ShCutDbg()) {
+ std::wcout << SHORTCUT_MGR_LOG_PREFIX << std::wstring(src, src + strlen(src)) << std::endl;
+ return true;
+ }
+ return false;
+}
+
+void Warning(const QString& theString)
+{
+ std::wcout << theString.toStdWString() << std::endl;
+}
+void Warning(const char* src)
+{
+ std::wcout << std::wstring(src, src + strlen(src)) << std::endl;
+}
+
+
+static const QKeySequence NO_KEYSEQUENCE = QKeySequence(QString(""));
+static const QString NO_ACTION = QString("");
+/** Separates tokens in action ID. */
+static const QString TOKEN_SEPARATOR = QString("/");
+static const QString ROOT_MODULE_ID = QString("");
+static const QString META_ACTION_PREFIX = QString("#");
+
+/** Prefix of names of shortcut setting sections in preference files. */
+static const QString SECTION_NAME_PREFIX = QString("shortcuts");
+
+
+const QString DEFAULT_LANG = QString("en");
+const QStringList LANG_PRIORITY_LIST = QStringList({DEFAULT_LANG, "fr"});
+const QString LANG_SECTION = QString("language");
+
+/** Prefix of names of sections in preference files with shortcut actions' names. */
+static const QString SECTION_SHORTCUT_NAMES_PREFIX = QString("shortcut_translations");
+
+
+
+/**
+ * Uncomment this, to start collecting all shortcuts and action name translations (1),
+ * from instances of QtxActions, if a shortcut or name translation is absent in resource files.
+ *
+ * (1) Set required language in the application settings and run features of interest.
+ * For all actions from these features, their toolTip()s will be dumped to appropriate places in dump files.
+ *
+ * Content of dump files is appended on every run. Files are located in "<APP_DIR>/shortcut_mgr_dev/".
*/
+// #define SHORTCUT_MGR_DEVTOOLS
+#ifdef SHORTCUT_MGR_DEVTOOLS
+#include <QDir>
+#include <QFile>
+#include <QTextStream>
+#include "QtxMap.h"
+#include <functional>
+#ifndef QT_NO_DOM
+#include <QDomDocument>
+#include <QDomElement>
+#include <QDomNode>
+#endif // QT_NO_DOM
+
+/*! \brief Generates XML files with appearing in runtime shortcuts,
+ using key sequences of QActions passed to the shortcut manager,
+ and translations, using QAction::toolTip(), of QtxActions passed to the shortcut manager.
+ Content of these files can be easily copied to resource files. */
+class DevTools
+{
+private:
+ DevTools() : myActionsWithInvalidIDsFile(nullptr) {};
+ DevTools(const DevTools&) = delete;
+ void operator=(const DevTools&) = delete;
+
+public:
+ ~DevTools()
+ {
+ for (const auto& fileNameAndPtrs : myXMLFilesAndDocs) {
+ delete fileNameAndPtrs.second.second;
+ delete fileNameAndPtrs.second.first;
+ }
+ }
+
+ static DevTools* get() {
+ if (!DevTools::instance)
+ DevTools::instance = new DevTools();
+
+ return DevTools::instance;
+ }
+
+ void collectShortcut(
+ const QString& theModuleID,
+ const QString& theInModuleActionID,
+ const QKeySequence& theKeySequence
+ ) {
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID)) {
+ auto& moduleShortcuts = myShortcutsOfMetaActions[theModuleID];
+ moduleShortcuts[theInModuleActionID] = theKeySequence.toString();
+
+ const QString fileName = theModuleID + DevTools::SHORTCUTS_OF_META_SUFFIX;
+ const QString sectionName = SECTION_NAME_PREFIX + DevTools::XML_SECTION_TOKENS_SEPARATOR + ROOT_MODULE_ID;
+ std::map<QString, std::map<QString, QString>> sections;
+ sections[sectionName] = moduleShortcuts;
+ writeToXMLFile(fileName, sections);
+ }
+ else {
+ auto& moduleShortcuts = myShortcuts[theModuleID];
+ moduleShortcuts[theInModuleActionID] = theKeySequence.toString();
+
+ const QString fileName = theModuleID + DevTools::SHORTCUTS_SUFFIX;
+ const QString sectionName = SECTION_NAME_PREFIX + DevTools::XML_SECTION_TOKENS_SEPARATOR + theModuleID;
+ std::map<QString, std::map<QString, QString>> sections;
+ sections[sectionName] = moduleShortcuts;
+ writeToXMLFile(fileName, sections);
+ }
+ }
+
+ void collectTranslation(
+ const QString& theModuleID,
+ const QString& theInModuleActionID,
+ const QString& theLang,
+ const QString& theActionName
+ ) {
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID)) {
+ QString actionID = SUIT_ShortcutMgr::makeActionID(ROOT_MODULE_ID, theInModuleActionID);
+ // { actionID, {lang, actionName}[] } []
+ auto& moduleTranslations = myTranslationsOfMetaActions[theModuleID];
+
+ // {lang, actionName}[]
+ auto& actionTranslations = moduleTranslations[actionID];
+ actionTranslations[theLang] = theActionName;
+
+ const QString fileName = theModuleID + DevTools::TRANSLATIONS_OF_META_SUFFIX;
+ std::map<QString, std::map<QString, QString>> sections;
+ for (auto itAction = moduleTranslations.begin(); itAction != moduleTranslations.end(); itAction++) {
+ const QString sectionName = SECTION_SHORTCUT_NAMES_PREFIX + DevTools::XML_SECTION_TOKENS_SEPARATOR + ROOT_MODULE_ID;
+
+ // {lang, actionName}[]
+ std::map<QString, QString>& actionTranslations = itAction->second;
+ std::map<QString, QString>& section = sections[sectionName];
+ for (auto itTranslation = actionTranslations.begin(); itTranslation != actionTranslations.end(); itTranslation++) {
+ section[itTranslation->first] = itTranslation->second;
+ }
+ }
+ writeToXMLFile(fileName, sections);
+ }
+ else {
+ QString actionID = SUIT_ShortcutMgr::makeActionID(theModuleID, theInModuleActionID);
+ // { actionID, {lang, actionName}[] } []
+ auto& moduleTranslations = myTranslations[theModuleID];
+ // {lang, actionName}[]
+ auto& actionTranslations = moduleTranslations[actionID];
+ actionTranslations[theLang] = theActionName;
+
+ const QString fileName = theModuleID + DevTools::TRANSLATIONS_SUFFIX;
+ std::map<QString, std::map<QString, QString>> sections;
+ for (auto itAction = moduleTranslations.begin(); itAction != moduleTranslations.end(); itAction++) {
+ const QString sectionName = SECTION_SHORTCUT_NAMES_PREFIX + DevTools::XML_SECTION_TOKENS_SEPARATOR + itAction->first;
+
+ // {lang, actionName}[]
+ std::map<QString, QString>& actionTranslations = itAction->second;
+ std::map<QString, QString>& section = sections[sectionName];
+ for (auto itTranslation = actionTranslations.begin(); itTranslation != actionTranslations.end(); itTranslation++) {
+ section[itTranslation->first] = itTranslation->second;
+ }
+ }
+ writeToXMLFile(fileName, sections);
+ }
+ }
+
+ void collectShortcutAndTranslation(const QtxAction* const theAction)
+ {
+ const auto moduleIDAndActionID = SUIT_ShortcutMgr::splitIntoModuleIDAndInModuleID(theAction->ID());
+ if (moduleIDAndActionID.second.isEmpty())
+ return;
+
+ if (!SUIT_ShortcutMgr::get()->getShortcutContainer().hasShortcut(moduleIDAndActionID.first, moduleIDAndActionID.second))
+ collectShortcut(moduleIDAndActionID.first, moduleIDAndActionID.second, theAction->shortcut());
+
+ { // Collect action name (translation) in current language, if it is not provided in resource files.
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("DevTools for SUIT_ShortcutMgr can't retrieve resource manager!");
+ return;
+ }
+
+ const QString lang = resMgr->stringValue(LANG_SECTION, LANG_SECTION);
+ if (lang.isEmpty())
+ return;
+
+ if (SUIT_ShortcutMgr::getActionNameFromResources(theAction->ID(), lang).first)
+ return;
+
+ collectTranslation(moduleIDAndActionID.first, moduleIDAndActionID.second, lang, theAction->toolTip());
+ }
+ }
+
+private:
+ /*! Appends new entries to content of dump files. */
+ bool writeToXMLFile(const QString& theFileName, const std::map<QString, std::map<QString, QString>>& theSections)
+ {
+#ifdef QT_NO_DOM
+ Warning("DebugTools for SUIT_ShortcutMgr can't create XML - #QT_NO_DOM is defined.");
+ return false;
+#else QT_NO_DOM
+ static const QString DOC_TAG = "document";
+ static const QString SECTION_TAG = "section";
+ static const QString PARAMETER_TAG = "parameter";
+ static const QString NAME_ATTR = "name";
+ static const QString VAL_ATTR = "value";
+
+ const auto itFileAndDoc = myXMLFilesAndDocs.find(theFileName);
+ if (itFileAndDoc == myXMLFilesAndDocs.end()) {
+ const QString fullPath = DevTools::SAVE_PATH + theFileName + ".xml";
+ if (!Qtx::mkDir(QFileInfo(fullPath).absolutePath())) {
+ myXMLFilesAndDocs[theFileName] = std::pair<QFile*, QDomDocument*>(nullptr, nullptr);
+ return false;
+ }
+
+ QFile* file = new QFile(fullPath);
+ if (!file->open(QFile::ReadWrite | QIODevice::Text)) {
+ delete file;
+ myXMLFilesAndDocs[theFileName] = std::pair<QFile*, QDomDocument*>(nullptr, nullptr);
+ return false;
+ }
+
+ QDomDocument* dom = new QDomDocument(DOC_TAG);
+ QTextStream instream(file);
+ dom->setContent(instream.readAll());
+ myXMLFilesAndDocs[theFileName] = std::pair<QFile*, QDomDocument*>(file, dom);
+ }
+ else if (itFileAndDoc->second.first == nullptr) {
+ return false;
+ }
+
+ const auto fileAndDom = myXMLFilesAndDocs[theFileName];
+ QFile* const file = fileAndDom.first;
+ QDomDocument* const dom = fileAndDom.second;
+
+ QDomElement doc = dom->documentElement();
+ if (doc.isNull()) {
+ *dom = QDomDocument(DOC_TAG);
+ doc = dom->createElement(DOC_TAG);
+ dom->appendChild(doc);
+ }
+
+ static const std::function<void(const std::map<QString, QString>&, QDomDocument&, QDomElement&)> mergeParamsToSection =
+ [&](const std::map<QString, QString>& parameters, QDomDocument& dom, QDomElement& sectionInDom)
+ {
+ for (const std::pair<QString, QString>& nameAndVal : parameters) {
+ const QString& paramName = nameAndVal.first;
+ const QString& paramVal = nameAndVal.second;
+ bool fileHasParam = false;
+ for (QDomElement paramInDom = sectionInDom.firstChildElement(PARAMETER_TAG); !paramInDom.isNull(); paramInDom = paramInDom.nextSiblingElement(PARAMETER_TAG)) {
+ const QString paramNameInDom = paramInDom.attribute(NAME_ATTR);
+ if (paramName == paramNameInDom) {
+ const QString paramValInDom = paramInDom.attribute(VAL_ATTR);
+ if (paramValInDom != paramVal) {
+ QDomElement replaceElement = dom.createElement(PARAMETER_TAG);
+ replaceElement.setAttribute(NAME_ATTR, paramName);
+ replaceElement.setAttribute(VAL_ATTR, paramVal);
+ sectionInDom.replaceChild(replaceElement, paramInDom);
+ }
+
+ fileHasParam = true;
+ break;
+ }
+ }
+ if (!fileHasParam) {
+ QDomElement newParam = dom.createElement(PARAMETER_TAG);
+ newParam.setAttribute(NAME_ATTR, paramName);
+ newParam.setAttribute(VAL_ATTR, paramVal);
+ sectionInDom.insertAfter(newParam, sectionInDom.lastChildElement(PARAMETER_TAG));
+ }
+ }
+ return;
+ };
+
+ for (const auto& sectionNameAndParams : theSections) {
+ const QString& sectionName = sectionNameAndParams.first;
+ const std::map<QString, QString>& parameters = sectionNameAndParams.second;
+
+ bool fileHasSection = false;
+ for (QDomElement sectionInDom = doc.firstChildElement(SECTION_TAG); !sectionInDom.isNull(); sectionInDom = sectionInDom.nextSiblingElement(SECTION_TAG)) {
+ QString sectionNameInDom = sectionInDom.attribute(NAME_ATTR);
+ if (sectionNameInDom == sectionName) {
+ mergeParamsToSection(parameters, *dom, sectionInDom);
+ fileHasSection = true;
+ break;
+ }
+ }
+
+ if (!fileHasSection) {
+ QDomElement newSection = dom->createElement(SECTION_TAG);
+ newSection.setAttribute(NAME_ATTR, sectionName);
+ doc.insertAfter(newSection, doc.lastChildElement(SECTION_TAG));
+ mergeParamsToSection(parameters, *dom, newSection);
+ }
+ }
+
+ file->resize(0);
+ QTextStream outstream(file);
+ outstream << dom->toString();
+
+ return true;
+#endif // QT_NO_DOM
+ }
+
+public:
+ void collectAssetsOfActionWithInvalidID(const QAction* const theAction)
+ {
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("DevTools for SUIT_ShortcutMgr can't retrieve resource manager!");
+ return;
+ }
+
+ const QString lang = resMgr->stringValue(LANG_SECTION, LANG_SECTION);
+ if (lang.isEmpty())
+ return;
+
+ if (!myActionsWithInvalidIDsFile) {
+ const QString fullPath = DevTools::SAVE_PATH + lang + DevTools::INVALID_ID_ACTIONS_SUFFIX + ".csv";
+ if (!Qtx::mkDir(QFileInfo(fullPath).absolutePath()))
+ return;
+
+ myActionsWithInvalidIDsFile = new QFile(fullPath);
+ if (!myActionsWithInvalidIDsFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
+ delete myActionsWithInvalidIDsFile;
+ myActionsWithInvalidIDsFile = nullptr;
+ return;
+ }
+
+ QTextStream ostream(myActionsWithInvalidIDsFile);
+ ostream << "text\t" << "tool tip\t" << "status tip\t" << "key sequence\t" << "QtxAction?\t" << "ID\n";
+ ostream.flush();
+ }
+
+ QTextStream ostream(myActionsWithInvalidIDsFile);
+ const auto aQtxAction = qobject_cast<const QtxAction*>(theAction);
+ ostream << theAction->text() << "\t" << theAction->toolTip() << "\t" << theAction->statusTip() << "\t"
+ << theAction->shortcut().toString() << "\t" << (aQtxAction ? "yes\t" : "no\t") << (aQtxAction ? aQtxAction->ID() + "\n" : "\n");
+ ostream.flush();
+ }
+
+ static const QString SAVE_PATH;
+ static const QString SHORTCUTS_SUFFIX;
+ static const QString SHORTCUTS_OF_META_SUFFIX;
+ static const QString TRANSLATIONS_SUFFIX;
+ static const QString TRANSLATIONS_OF_META_SUFFIX;
+ static const QString INVALID_ID_ACTIONS_SUFFIX;
+
+ static DevTools* instance;
+ static const QString XML_SECTION_TOKENS_SEPARATOR;
+
+ /** { moduleID, { inModuleActionID, keySequence }[] }[]. keySequence can be empty. */
+ std::map<QString, std::map<QString, QString>> myShortcuts;
+
+ /** { moduleID, { inModuleActionID, keySequence }[] }[]. keySequence can be empty. */
+ std::map<QString, std::map<QString, QString>> myShortcutsOfMetaActions;
+
+ /** { moduleID, { actionID, {language, actionName} }[] }[] */
+ std::map<QString, std::map<QString, std::map<QString, QString>>> myTranslations;
+
+ /** { moduleID, { actionID, {language, actionName} }[] }[] */
+ std::map<QString, std::map<QString, std::map<QString, QString>>> myTranslationsOfMetaActions;
+
+#ifndef QT_NO_DOM
+ // { filename, {file, domDoc} }[]
+ std::map<QString, std::pair<QFile*, QDomDocument*>> myXMLFilesAndDocs;
+#endif // QT_NO_DOM
+
+ QFile* myActionsWithInvalidIDsFile;
+};
+/*static*/ DevTools* DevTools::instance = nullptr;
+/*static*/ const QString DevTools::SAVE_PATH = "shortcut_mgr_dev/";
+/*static*/ const QString DevTools::SHORTCUTS_SUFFIX = "_shortcuts";
+/*static*/ const QString DevTools::SHORTCUTS_OF_META_SUFFIX = "_shortcuts_of_meta_actions";
+/*static*/ const QString DevTools::TRANSLATIONS_SUFFIX = "_translations";
+/*static*/ const QString DevTools::TRANSLATIONS_OF_META_SUFFIX = "_translations_of_meta_actions";
+/*static*/ const QString DevTools::XML_SECTION_TOKENS_SEPARATOR = ":";
+/*static*/ const QString DevTools::INVALID_ID_ACTIONS_SUFFIX = "_actions_with_invalid_IDs";
+#endif // SHORTCUT_MGR_DEVTOOLS
+
+
+
+SUIT_ShortcutContainer::SUIT_ShortcutContainer()
+{
+ myShortcuts.emplace(ROOT_MODULE_ID, std::map<QKeySequence, QString>());
+ myShortcutsInversed.emplace(ROOT_MODULE_ID, std::map<QString, QKeySequence>());
+}
+
+std::set<QString> SUIT_ShortcutContainer::getIDsOfInterferingModules(const QString& theModuleID) const
+{
+ std::set<QString> IDsOfInterferingModules;
+ if (theModuleID == ROOT_MODULE_ID) {
+ for (const auto& moduleIDAndShortcuts : myShortcuts) {
+ IDsOfInterferingModules.emplace(moduleIDAndShortcuts.first);
+ }
+ }
+ else {
+ IDsOfInterferingModules.emplace(ROOT_MODULE_ID);
+ if (theModuleID != ROOT_MODULE_ID)
+ IDsOfInterferingModules.emplace(theModuleID);
+ }
+ return IDsOfInterferingModules;
+}
+
+std::set<QString> SUIT_ShortcutContainer::getIDsOfAllModules() const
+{
+ std::set<QString> res;
+ for (const auto& moduleIDAndShortcuts : myShortcutsInversed) {
+ res.emplace(moduleIDAndShortcuts.first);
+ }
+ return res;
+}
+
+std::set<std::pair<QString, QString>> SUIT_ShortcutContainer::setShortcut(QString theModuleID, const QString& theInModuleActionID, const QKeySequence& theKeySequence, bool theOverride)
+{
+ if (!SUIT_ShortcutMgr::isModuleIDValid(theModuleID)) {
+ ShCutDbg() && ShCutDbg("Attempt to define a shortcut using invalid module ID = \"" + theModuleID + "\".");
+ return std::set<std::pair<QString, QString>>();
+ }
+
+ if (!SUIT_ShortcutMgr::isInModuleActionIDValid(theInModuleActionID)) {
+ ShCutDbg() && ShCutDbg("Attempt to define a shortcut using invalid in-module action ID = \"" + theInModuleActionID + "\".");
+ return std::set<std::pair<QString, QString>>();
+ }
+
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID))
+ theModuleID = ROOT_MODULE_ID;
+
+ auto itModuleShortcuts = myShortcuts.find(theModuleID);
+ auto itModuleShortcutsInversed = myShortcutsInversed.find(theModuleID);
+ if (itModuleShortcuts == myShortcuts.end()) {
+ itModuleShortcuts = myShortcuts.emplace(theModuleID, std::map<QKeySequence, QString>()).first;
+ itModuleShortcutsInversed = myShortcutsInversed.emplace(theModuleID, std::map<QString, QKeySequence>()).first;
+ }
+
+ std::map<QKeySequence, QString>& moduleShortcuts = itModuleShortcuts->second;
+ std::map<QString, QKeySequence>& moduleShortcutsInversed = itModuleShortcutsInversed->second;
+
+ if (theKeySequence.isEmpty()) {
+ // Disable shortcut.
+
+ auto itShortcutInversed = moduleShortcutsInversed.find(theInModuleActionID);
+ if (itShortcutInversed == moduleShortcutsInversed.end()) {
+ // No key sequence was mapped to the action earlier.
+ // Set disabled shortcut.
+ moduleShortcutsInversed.emplace(theInModuleActionID, NO_KEYSEQUENCE);
+ return std::set<std::pair<QString, QString>>();
+ }
+ else /* if keySequence was mapped to the action earlier. */ {
+ QKeySequence& keySequence = itShortcutInversed->second;
+
+ moduleShortcuts.erase(keySequence);
+ keySequence = NO_KEYSEQUENCE;
+
+ return std::set<std::pair<QString, QString>>();
+ }
+ }
+
+ { // Check if the shortcut is already set.
+ const auto itShortcut = moduleShortcuts.find(theKeySequence);
+ if (itShortcut != moduleShortcuts.end()) {
+ if (itShortcut->second == theInModuleActionID) {
+ // The shortcut was set earlier. Nothing to change.
+ return std::set<std::pair<QString, QString>>();
+ }
+ }
+ }
+
+ auto conflictingActionIDs = std::set<std::pair<QString, QString>>();
+ { // Look for conflicting shortcuts with the same key sequence from interfering modules.
+ std::set<QString> IDsOfInterferingModules = getIDsOfInterferingModules(theModuleID);
+ for (const QString& IDOfInterferingModule : IDsOfInterferingModules) {
+ std::map<QKeySequence, QString>& shortcutsOfInterferingModule = myShortcuts.at(IDOfInterferingModule);
+ auto itConflictingShortcut = shortcutsOfInterferingModule.find(theKeySequence);
+ if (itConflictingShortcut != shortcutsOfInterferingModule.end()) {
+ const QString& conflictingActionID = itConflictingShortcut->second;
+
+ conflictingActionIDs.insert(std::pair<QString, QString>(IDOfInterferingModule, conflictingActionID));
+
+ if (theOverride) {
+ // Disable conflicting shortcuts.
+ std::map<QString, QKeySequence>& shortcutsOfInterferingModuleInversed = myShortcutsInversed.at(IDOfInterferingModule);
+ shortcutsOfInterferingModuleInversed[conflictingActionID] = NO_KEYSEQUENCE;
+ shortcutsOfInterferingModule.erase(itConflictingShortcut);
+ }
+ }
+ }
+
+ if (!theOverride && !conflictingActionIDs.empty())
+ return conflictingActionIDs;
+ }
+
+ { // Ensure, that the module has only shortcut for the action ID.
+ auto itShortcutInversed = moduleShortcutsInversed.find(theInModuleActionID);
+ if (itShortcutInversed != moduleShortcutsInversed.end()) {
+ // Redefine key sequence for existing action.
+
+ QKeySequence& keySequence = itShortcutInversed->second;
+
+ moduleShortcuts.erase(keySequence);
+ moduleShortcuts[theKeySequence] = theInModuleActionID;
+
+ keySequence = theKeySequence;
+ }
+ else /* if the action has not been added earlier. */ {
+ moduleShortcuts[theKeySequence] = theInModuleActionID;
+ moduleShortcutsInversed[theInModuleActionID] = theKeySequence;
+ }
+ }
+
+ return conflictingActionIDs;
+}
+
+std::set<std::pair<QString, QString>> SUIT_ShortcutContainer::getConflicts(
+ QString theModuleID,
+ const QString& theInModuleActionID,
+ const QKeySequence& theKeySequence
+) const
+{
+ if (theKeySequence.isEmpty())
+ return std::set<std::pair<QString, QString>>();
+
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID))
+ theModuleID = ROOT_MODULE_ID;
+
+ { // Check if the shortcut is set.
+ const auto itModuleShortcuts = myShortcuts.find(theModuleID);
+ if (itModuleShortcuts != myShortcuts.end()) {
+ const std::map<QKeySequence, QString>& moduleShortcuts = itModuleShortcuts->second;
+ const auto itShortcut = moduleShortcuts.find(theKeySequence);
+ if (itShortcut != moduleShortcuts.end()) {
+ if (itShortcut->second == theInModuleActionID) {
+ // The shortcut is set => no conflicts.
+ return std::set<std::pair<QString, QString>>();
+ }
+ }
+ }
+ }
+
+ auto conflictingActionIDs = std::set<std::pair<QString, QString>>();
+ { // Look for conflicting shortcuts with the same key sequence from interfering modules.
+ std::set<QString> IDsOfInterferingModules = getIDsOfInterferingModules(theModuleID);
+ for (const QString& IDOfInterferingModule : IDsOfInterferingModules) {
+ const std::map<QKeySequence, QString>& shortcutsOfInterferingModule = myShortcuts.at(IDOfInterferingModule);
+ const auto itConflictingShortcut = shortcutsOfInterferingModule.find(theKeySequence);
+ if (itConflictingShortcut != shortcutsOfInterferingModule.end()) {
+ const QString& conflictingActionID = itConflictingShortcut->second;
+ conflictingActionIDs.insert(std::pair<QString, QString>(IDOfInterferingModule, conflictingActionID));
+ }
+ }
+ }
+ return conflictingActionIDs;
+}
+
+const QKeySequence& SUIT_ShortcutContainer::getKeySequence(QString theModuleID, const QString& theInModuleActionID) const
+{
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID))
+ theModuleID = ROOT_MODULE_ID;
+
+ const auto itModuleShortcutsInversed = myShortcutsInversed.find(theModuleID);
+ if (itModuleShortcutsInversed == myShortcutsInversed.end())
+ return NO_KEYSEQUENCE;
+
+ const auto& moduleShortcutsInversed = itModuleShortcutsInversed->second;
+ const auto itShortcutInversed = moduleShortcutsInversed.find(theInModuleActionID);
+ if (itShortcutInversed == moduleShortcutsInversed.end())
+ return NO_KEYSEQUENCE;
+
+ return itShortcutInversed->second;
+}
+
+bool SUIT_ShortcutContainer::hasShortcut(QString theModuleID, const QString& theInModuleActionID) const
+{
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID))
+ theModuleID = ROOT_MODULE_ID;
+
+ const auto itModuleShortcutsInversed = myShortcutsInversed.find(theModuleID);
+ if (itModuleShortcutsInversed == myShortcutsInversed.end())
+ return false;
+
+ const auto& moduleShortcutsInversed = itModuleShortcutsInversed->second;
+ const auto itShortcutInversed = moduleShortcutsInversed.find(theInModuleActionID);
+ if (itShortcutInversed == moduleShortcutsInversed.end())
+ return false;
+
+ return true;
+}
+
+const std::map<QString, QKeySequence>& SUIT_ShortcutContainer::getModuleShortcutsInversed(const QString& theModuleID) const
+{
+ static const std::map<QString, QKeySequence> EMPTY_RES;
+ const auto it = myShortcutsInversed.find(theModuleID);
+ if (it == myShortcutsInversed.end())
+ return EMPTY_RES;
+
+ return it->second;
+}
+
+const std::map<QString, QKeySequence> SUIT_ShortcutContainer::getModuleShortcutsInversed(const QString& theModuleID, const QString& theActionIDPrefix) const
+{
+ const auto it = myShortcutsInversed.find(theModuleID);
+ if (it == myShortcutsInversed.end())
+ return std::map<QString, QKeySequence>();
+
+ std::map<QString, QKeySequence> shortcutsInversed;
+ for (const auto& existingShortcut : it->second) {
+ if (existingShortcut.first.startsWith(theActionIDPrefix))
+ shortcutsInversed[existingShortcut.first] = existingShortcut.second;
+ }
+ return shortcutsInversed;
+}
+
+QString SUIT_ShortcutContainer::toString() const
+{
+ QString text;
+ text += "Shortcuts inversed:\n";
+ for (auto it = myShortcutsInversed.begin(); it != myShortcutsInversed.end(); it++) {
+ const QString& moduleID = it->first;
+ const auto& moduleShortcuts = it->second;
+ text += (it == myShortcutsInversed.begin() ? "\"" : "\n\"") + moduleID + "\"";
+ for (const auto& shortcut : moduleShortcuts) {
+ text += "\n\t\"" + shortcut.first + "\"\t\"" + shortcut.second.toString() + "\"";
+ }
+ }
+ text += "\nShortcuts:\n";
+ for (auto it = myShortcuts.begin(); it != myShortcuts.end(); it++) {
+ const QString& moduleID = it->first;
+ const auto& moduleShortcuts = it->second;
+ text += (it == myShortcuts.begin() ? "\"" : "\n\"") + moduleID + "\"";
+ for (const auto& shortcut : moduleShortcuts) {
+ text += "\n\t\"" + shortcut.first.toString() + "\"\t\"" + shortcut.second + "\"";
+ }
+ }
+ return text;
+}
+
+std::map<QString, std::map<QString, QKeySequence>> SUIT_ShortcutContainer::merge(
+ const SUIT_ShortcutContainer& theOther,
+ bool theOverride,
+ bool theTreatAbsentIncomingAsDisabled
+) {
+ std::map<QString, std::map<QString, QKeySequence>> changesOfThis;
+
+ for (const auto& shortcutsInversedOfOtherPair : theOther.myShortcutsInversed) {
+ const QString& moduleIDOther = shortcutsInversedOfOtherPair.first;
+ const auto& shortcutsInversedOther = shortcutsInversedOfOtherPair.second;
+ for (const auto& shortcutInversedOther : shortcutsInversedOther) {
+ const QString& inModuleActionIDOther = shortcutInversedOther.first;
+ const QKeySequence& keySequenceOther = shortcutInversedOther.second;
+ if (theOverride) {
+ if (hasShortcut(moduleIDOther, inModuleActionIDOther) && getKeySequence(moduleIDOther, inModuleActionIDOther) == keySequenceOther) {
+ continue;
+ }
+ else /* if this has no shortcut for the action or if this has a shortcut for the action, but the key sequence differs. */ {
+ const auto disabledActionsOfThis = setShortcut(moduleIDOther, inModuleActionIDOther, keySequenceOther, true);
+ changesOfThis[moduleIDOther][inModuleActionIDOther] = keySequenceOther;
+ for (const auto& disabledActionOfThis : disabledActionsOfThis) {
+ changesOfThis[disabledActionOfThis.first][disabledActionOfThis.second] = NO_KEYSEQUENCE;
+ }
+ }
+ }
+ else /* if (!theOverride) */ {
+ if (hasShortcut(moduleIDOther, inModuleActionIDOther))
+ continue;
+ else {
+ const auto conflictingActionsOfThis = setShortcut(moduleIDOther, inModuleActionIDOther, keySequenceOther, false);
+ if (conflictingActionsOfThis.empty()) {
+ changesOfThis[moduleIDOther][inModuleActionIDOther] = keySequenceOther;
+ }
+ else /* if this has no shortcut for the action, but the incoming key sequence conflicts with others shortcuts. */ {
+ changesOfThis[moduleIDOther][inModuleActionIDOther] = NO_KEYSEQUENCE;
+ }
+ }
+ }
+ }
+ }
+
+ if (theOverride && theTreatAbsentIncomingAsDisabled) {
+ // Disable existing shortcuts, if they are absent in theOther.
+ for (auto& shortcutsInversedPair : myShortcutsInversed) {
+ const QString& moduleID = shortcutsInversedPair.first;
+ auto& moduleShortcutsInversed = shortcutsInversedPair.second;
+ for (auto& inversedShortcut : moduleShortcutsInversed) {
+ if (theOther.hasShortcut(moduleID, inversedShortcut.first))
+ continue;
+
+ if (inversedShortcut.second.isEmpty())
+ continue; // Existing shortcut is already disabled.
+
+ auto itShortcutsPair = myShortcuts.find(moduleID);
+ if (itShortcutsPair == myShortcuts.end())
+ continue; // The check is an overhead in an error-free designed class, but let be just in case.
+
+ auto& moduleShortcuts = itShortcutsPair->second;
+ moduleShortcuts.erase(inversedShortcut.second);
+ inversedShortcut.second = NO_KEYSEQUENCE;
+ changesOfThis[moduleID][inversedShortcut.first] = NO_KEYSEQUENCE;
+ }
+ }
+ }
+
+ return changesOfThis;
+}
+
+
+SUIT_ShortcutMgr* SUIT_ShortcutMgr::myShortcutMgr = nullptr;
+
SUIT_ShortcutMgr::SUIT_ShortcutMgr()
: QObject()
{
qApp->installEventFilter( this );
}
-/*!
- \brief Destructor
-*/
SUIT_ShortcutMgr::~SUIT_ShortcutMgr()
{
qApp->removeEventFilter( this );
}
-/*!
- \brief Create new instance of shortcut manager.
-*/
-void SUIT_ShortcutMgr::Init()
+/*static*/ void SUIT_ShortcutMgr::Init()
{
- if( myShortcutMgr==NULL )
+ if( myShortcutMgr == nullptr) {
myShortcutMgr = new SUIT_ShortcutMgr();
+ myShortcutMgr->setShortcutsFromPreferences();
+ }
}
-/*!
- \brief Return shortcut manager.
-*/
-SUIT_ShortcutMgr* SUIT_ShortcutMgr::getShortcutMgr()
+/*static*/ SUIT_ShortcutMgr* SUIT_ShortcutMgr::get()
{
Init();
-
return myShortcutMgr;
}
-/*!
- \brief Custom event filter for qapplication .
-
- Redefined from QObject::eventFilter();
-*/
-bool SUIT_ShortcutMgr::eventFilter( QObject* o, QEvent* e )
+/*static*/ bool SUIT_ShortcutMgr::isKeySequenceValid(const QKeySequence& theKeySequence)
+{
+ // TODO Perform check whether a key sequence is platform-compatible.
+ return true;
+}
+
+/*static*/ std::pair<bool, QKeySequence> SUIT_ShortcutMgr::toKeySequenceIfValid(const QString& theKeySequenceString)
+{
+ auto res = std::pair<bool, QKeySequence>(false, QKeySequence());
+
+ try {
+ res.second = QKeySequence::fromString(theKeySequenceString);
+ if (res.second.toString() != theKeySequenceString)
+ return std::pair<bool, QKeySequence>(false, QKeySequence());
+
+ if (!SUIT_ShortcutMgr::isKeySequenceValid(res.second))
+ return std::pair<bool, QKeySequence>(false, QKeySequence());
+ }
+ catch (...) {
+ return std::pair<bool, QKeySequence>(false, QKeySequence());
+ }
+
+ res.first = true;
+ return res;
+}
+
+/*static*/ bool SUIT_ShortcutMgr::isModuleIDValid(const QString& theModuleID)
+{
+ if (theModuleID.contains(TOKEN_SEPARATOR))
+ return false;
+
+ if (theModuleID.simplified() != theModuleID)
+ return false;
+
+ return true;
+}
+
+/*static*/ bool SUIT_ShortcutMgr::isInModuleActionIDValid(const QString& theInModuleActionID)
{
- if ( e->type() == QEvent::ActionAdded ) {
- QActionEvent* anActionEvent = (QActionEvent*)e;
- if (anActionEvent) {
- QtxAction* anAction = qobject_cast<QtxAction*>( anActionEvent->action() );
- if ( anAction )
- processAction( anAction );
+ QStringList tokens = theInModuleActionID.split(TOKEN_SEPARATOR);
+ for (QStringList::size_type i = 0; i < tokens.length(); i++) {
+ const QString simplifiedToken = tokens[i].simplified();
+ if (
+ simplifiedToken.isEmpty() ||
+ simplifiedToken != tokens[i] ||
+ i == 0 && simplifiedToken == META_ACTION_PREFIX ||
+ i != 0 && simplifiedToken.startsWith(META_ACTION_PREFIX)
+ )
+ return false;
+ }
+ return true;
+}
+
+/*static*/ bool SUIT_ShortcutMgr::isInModuleMetaActionID(const QString& theInModuleActionID)
+{
+ return theInModuleActionID.startsWith(META_ACTION_PREFIX);
+}
+
+/*static*/ std::pair<QString, QString> SUIT_ShortcutMgr::splitIntoModuleIDAndInModuleID(const QString& theActionID)
+{
+ QStringList tokens = theActionID.split(TOKEN_SEPARATOR);
+ if (tokens.length() < 2)
+ return std::pair<QString, QString>();
+
+ auto res = std::pair<QString, QString>();
+
+ if (tokens[0].simplified() != tokens[0])
+ return std::pair<QString, QString>();
+
+ res.first = tokens[0];
+ tokens.pop_front();
+
+ for (QStringList::size_type i = 0; i < tokens.length(); i++) {
+ const QString simplifiedToken = tokens[i].simplified();
+ if (
+ simplifiedToken.isEmpty() ||
+ simplifiedToken != tokens[i] ||
+ i == 0 && simplifiedToken == META_ACTION_PREFIX ||
+ i != 0 && simplifiedToken.startsWith(META_ACTION_PREFIX)
+ )
+ return std::pair<QString, QString>();
+ }
+ res.second = tokens.join(TOKEN_SEPARATOR);
+
+ return res;
+}
+
+/*static*/ bool SUIT_ShortcutMgr::isActionIDValid(const QString& theActionID)
+{
+ return !SUIT_ShortcutMgr::splitIntoModuleIDAndInModuleID(theActionID).second.isEmpty();
+}
+
+/*static*/ QString SUIT_ShortcutMgr::makeActionID(const QString& theModuleID, const QString& theInModuleActionID)
+{
+ if (!SUIT_ShortcutMgr::isModuleIDValid(theModuleID))
+ return QString();
+
+ if (!isInModuleActionIDValid(theInModuleActionID))
+ return QString();
+
+ return theModuleID + TOKEN_SEPARATOR + theInModuleActionID;
+}
+
+/*static*/ void SUIT_ShortcutMgr::fillContainerFromPreferences(SUIT_ShortcutContainer& theContainer, bool theDefaultOnly)
+{
+ ShCutDbg() && ShCutDbg("Retrieving preferences from resources.");
+
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("SUIT_ShortcutMgr can't retrieve resource manager!");
+ return;
+ }
+
+ const auto resMgrWorkingModeBefore = resMgr->workingMode();
+ if (theDefaultOnly)
+ resMgr->setWorkingMode(QtxResourceMgr::IgnoreUserValues);
+
+ /** List of modules with invalid IDs. */
+ QStringList invalidModuleIDs;
+
+ /** { moduleID, {inModuleActionID, keySequence}[] }[] */
+ std::map<QString, std::list<std::pair<QString, QString>>> invalidShortcuts;
+
+ /**
+ * Shortcuts, which have not been set, because they are in conflict with previously parsed shortcuts.
+ * { moduleID, {inModuleActionID, keySequence}[] }[] */
+ std::map<QString, std::list<std::pair<QString, QKeySequence>>> conflicts;
+
+ // Resource manager strips leading and trailing whitespaces from subsections' names.
+ // And then it is not able to retrieve parametes from that subsections,
+ // because parsed subsection names differ from the ones in resource file.
+ // Anyway, it does not affect operability of ShortcutMgr.
+ QStringList moduleIDs = resMgr->subSections(SECTION_NAME_PREFIX, true);
+ if (ShCutDbg()) {
+ if (moduleIDs.isEmpty())
+ ShCutDbg("No discovered shortcut modules.");
+ else
+ ShCutDbg("Discovered shortcut modules: \"" + moduleIDs.join("\", \"") + ".");
+ }
+ moduleIDs.push_front(ROOT_MODULE_ID); // Resource manager filters out empty section suffices.
+ moduleIDs.removeDuplicates();
+
+ for (size_t i = 0; i < moduleIDs.size(); i++) {
+ const auto& moduleID = moduleIDs[i];
+ if (!SUIT_ShortcutMgr::isModuleIDValid(moduleID)) {
+ invalidModuleIDs.push_back(moduleID);
+ continue;
+ }
+
+ const QString sectionName = SECTION_NAME_PREFIX + resMgr->sectionsToken() + moduleID;
+ QStringList moduleActionIDs = resMgr->parameters(sectionName);
+
+ for(const QString& inModuleActionID : moduleActionIDs) {
+ QString keySequenceString = QString("");
+ resMgr->value(sectionName, inModuleActionID, keySequenceString);
+ const auto keySequence = SUIT_ShortcutMgr::toKeySequenceIfValid(keySequenceString);
+
+ ShCutDbg() && ShCutDbg("Shortcut discovered: \"" + moduleID + "\"\t\"" + inModuleActionID + "\"\t\"" + keySequenceString + "\".");
+
+ if (
+ !SUIT_ShortcutMgr::isInModuleActionIDValid(inModuleActionID) ||
+ !keySequence.first ||
+ SUIT_ShortcutMgr::isInModuleMetaActionID(inModuleActionID) && moduleID != ROOT_MODULE_ID
+ ) {
+ std::list<std::pair<QString, QString>>& moduleInvalidShortcuts = invalidShortcuts[moduleID];
+ moduleInvalidShortcuts.push_back(std::pair<QString, QString>(inModuleActionID, keySequenceString));
+ continue;
+ }
+
+ const auto shortcutConflicts = theContainer.setShortcut(moduleID, inModuleActionID, keySequence.second, false /*override*/);
+ if (!shortcutConflicts.empty()) {
+ auto& moduleConflicts = conflicts[moduleID];
+ moduleConflicts.push_back(std::pair<QString, QKeySequence>(inModuleActionID, keySequence.second));
+ }
+ }
+ }
+
+ if (!invalidModuleIDs.isEmpty() || !invalidShortcuts.empty() || !conflicts.empty())
+ { // Prepare report and show warning.
+ QString report;
+ if (!invalidModuleIDs.isEmpty()) {
+ report += tr("Invalid module IDs") + ":";
+ for (const QString& invalidModuleID : invalidModuleIDs) {
+ report += "\n\t\"" + invalidModuleID + "\"" ;
+ }
+ }
+
+ if (!invalidShortcuts.empty()) {
+ if (!report.isEmpty())
+ report += "\n\n";
+
+ report += tr("Invalid shortcuts") + ":";
+ for (const auto& moduleAndShortcuts : invalidShortcuts) {
+ report += "\n\t\"" + moduleAndShortcuts.first + "\"";
+ const std::list<std::pair<QString, QString>>& moduleShortcuts = moduleAndShortcuts.second;
+ for (const auto& shortcut : moduleShortcuts) {
+ report += "\n\t\t\"" + shortcut.first + "\"\t\"" + shortcut.second + "\"";
+ }
+ }
+ }
+
+ if (!conflicts.empty()) {
+ if (!report.isEmpty())
+ report += "\n\n";
+
+ report += tr("These shortcuts have not been set to theContainer, because they conflict with previously parsed ones") + ":";
+ for (const auto& moduleAndShortcuts : conflicts) {
+ report += "\n\t\"" + moduleAndShortcuts.first + "\"";
+
+ const std::list<std::pair<QString, QKeySequence>>& moduleShortcuts = moduleAndShortcuts.second;
+ for (const auto& shortcut : moduleShortcuts) {
+ report += "\n\t\t\"" + shortcut.first + "\"\t\"" + shortcut.second.toString() + "\"";
+ }
+ }
}
+
+ report += "\n.";
+
+ const auto text = tr("Invalid shortcuts in preferences");
+ const auto informativeText = tr("Fix the following entries in the preference files manually");
+ if (!theDefaultOnly) {
+ // If user preferences are accounted, show warning in UI.
+ SUIT_Application* app = SUIT_Session::session()->activeApplication();
+ if (app && app->desktop()) {
+ // Is not compiled without cast or with static_cast<QWidget*>.
+ QMessageBox msgBox((QWidget*)app->desktop());
+ msgBox.setIcon(QMessageBox::Warning);
+ msgBox.setTextFormat(Qt::RichText);
+ msgBox.setText("<b>" + text + "</b>");
+ msgBox.setInformativeText(informativeText + ":");
+ msgBox.setWindowFlags(Qt::WindowType::Popup);
+ msgBox.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
+ msgBox.setDetailedText(report);
+ msgBox.setStandardButtons(QMessageBox::Ok);
+ msgBox.setDefaultButton(QMessageBox::Ok);
+ msgBox.setMinimumWidth(600);
+ msgBox.exec();
+ }
+ }
+ Warning(text + ". " + informativeText + ":\n" + report);
}
- return QObject::eventFilter( o, e );
+ if (theDefaultOnly)
+ resMgr->setWorkingMode(resMgrWorkingModeBefore);
+
+ ShCutDbg() && ShCutDbg("theContainer holds following shortcuts:\n" + theContainer.toString());
}
-/*!
- \brief Return key sequence for shortcut action name.
- \param actionName name of shortcut action in preferences
- \return key sequence defined in preferences or empty sequence
-*/
-QKeySequence SUIT_ShortcutMgr::getShortcutByActionName( const QString& actionName ) const
+/*static*/ std::pair<bool, QString> SUIT_ShortcutMgr::getActionNameFromResources(const QString& theActionID, QString theLanguage)
{
SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("SUIT_ShortcutMgr can't retrieve resource manager!");
+ return std::pair<bool, QString>(false, QString());
+ }
+
+ if (theLanguage.isEmpty())
+ theLanguage = resMgr->stringValue(LANG_SECTION, LANG_SECTION);
+
+ if (theLanguage.isEmpty())
+ return std::pair<bool, QString>(false, QString());
+
+ QStringList actionIDs = resMgr->subSections(SECTION_SHORTCUT_NAMES_PREFIX, false);
+ if (actionIDs.indexOf(theActionID) == -1)
+ return std::pair<bool, QString>(false, QString());
+
+ const QString sectionName = SECTION_SHORTCUT_NAMES_PREFIX + resMgr->sectionsToken() + theActionID;
+ QStringList availableActionNameLangs = resMgr->parameters(sectionName);
+ if (availableActionNameLangs.indexOf(theLanguage) == -1)
+ return std::pair<bool, QString>(false, QString());
+
+ QString actionName;
+ const bool nameInCurLangExists = resMgr->value(sectionName, theLanguage, actionName);
+
+ if (!nameInCurLangExists)
+ return std::pair<bool, QString>(false, QString());
+
+ return std::pair<bool, QString>(true, actionName);
+}
+
+
+void SUIT_ShortcutMgr::registerAction(const QString& theActionID, QAction* theAction)
+{
+ const auto moduleIDAndActionID = splitIntoModuleIDAndInModuleID(theActionID);
+ const QString& moduleID = moduleIDAndActionID.first;
+ const QString& inModuleActionID = moduleIDAndActionID.second;
+
+ if (inModuleActionID.isEmpty()) {
+ ShCutDbg() && ShCutDbg("Attempt to register an action \"" + theAction->toolTip() + "\" with invalid ID \"" + theActionID + "\".");
+ if (theAction->shortcut() != NO_KEYSEQUENCE)
+ theAction->setShortcut(NO_KEYSEQUENCE);
+
+ return;
+ }
+
+ { // An action with the same memory address was registered earlier.
+ // Clear all data about it to start registering procedure from scratch.
+ auto itPreviousModuleAndActionID = myActionIDs.find(theAction);
+ if (itPreviousModuleAndActionID != myActionIDs.end()) {
+ // Clear the data from myActions.
+ const auto& previousModuleAndActionID = itPreviousModuleAndActionID->second;
+ auto itActions = myActions.find(previousModuleAndActionID.first);
+ if (itActions != myActions.end()) {
+ std::map<QString, std::set<QAction*>>& moduleActions = itActions->second;
+ auto itModuleActions = moduleActions.find(previousModuleAndActionID.second);
+ if (itModuleActions != moduleActions.end()) {
+ std::set<QAction*>& registeredActions = itModuleActions->second;
+ registeredActions.erase(theAction);
+ }
+ }
+
+ myActionIDs.erase(itPreviousModuleAndActionID);
+ }
+ }
+
+ auto itActions = myActions.find(moduleID);
+ if (itActions == myActions.end()) {
+ itActions = myActions.emplace(moduleID, std::map<QString, std::set<QAction*>>()).first;
+ }
- QString section = actionName.section( resMgr->sectionsToken(), 0, 0 );
- section.prepend( QString("shortcuts") + resMgr->sectionsToken() );
- QString parameter = actionName.section( resMgr->sectionsToken(), 1, 1 );
+ std::map<QString, std::set<QAction*>>& moduleActions = itActions->second;
+ auto itModuleActions = moduleActions.find(inModuleActionID);
+ if (itModuleActions != moduleActions.end()) {
+ std::set<QAction*>& registeredActions = itModuleActions->second;
+ const bool actionIsNew = registeredActions.emplace(theAction).second;
+ if (actionIsNew)
+ myActionIDs[theAction] = moduleIDAndActionID;
+ }
+ else {
+ std::set<QAction*>& registeredActions = moduleActions[inModuleActionID];
+ registeredActions.emplace(theAction);
+ myActionIDs[theAction] = moduleIDAndActionID;
+ }
- QString shortcutValue;
- bool hasValue = resMgr->value( section, parameter, shortcutValue, false );
+ connect(theAction, SIGNAL(destroyed(QObject*)), this, SLOT (onActionDestroyed(QObject*)));
- if ( !hasValue )
- return QKeySequence();
+ if (myShortcutContainer.hasShortcut(moduleID, inModuleActionID)) {
+ const QKeySequence& keySequence = getKeySequence(moduleID, inModuleActionID);
+ theAction->setShortcut(keySequence);
+ }
+ else {
+ ShCutDbg(
+ "Action with ID \"" +
+ (SUIT_ShortcutMgr::isInModuleMetaActionID(inModuleActionID) ? ROOT_MODULE_ID + TOKEN_SEPARATOR + inModuleActionID : theActionID) +
+ "\" is not added to default resource files."
+ );
+ auto conflicts = myShortcutContainer.setShortcut(moduleID, inModuleActionID, theAction->shortcut(), false);
+ if (!conflicts.empty())
+ theAction->setShortcut(NO_KEYSEQUENCE); // Unbind any key sequence, if it was bound outside of the class and interferes with other shortcuts.
+ }
+}
- return QKeySequence::fromString( shortcutValue );
+void SUIT_ShortcutMgr::registerAction(QtxAction* theAction)
+{
+ registerAction(theAction->ID(), theAction);
}
-/*!
- \brief Set shortcut to the given action if the shortcut is defined.
- \param action action to process
- */
-void SUIT_ShortcutMgr::processAction( QtxAction* action )
+std::set<QAction*> SUIT_ShortcutMgr::getActions(const QString& theModuleID, const QString& theInModuleActionID) const
{
- QString shortcutActionName = action->shortcutActionName();
-
- if ( !shortcutActionName.isEmpty() ) {
- // Add action to the actions map
- if ( !myShortcutActions.contains( shortcutActionName, action ) ) {
- myShortcutActions.insert( shortcutActionName, action );
- connect( action, SIGNAL( destroyed( QObject* ) ),
- this, SLOT ( onActionDestroyed( QObject* ) ) );
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(theInModuleActionID)) {
+ std::set<QAction*> actions;
+ for (const auto& actionAndID : myActionIDs) {
+ if (actionAndID.second.second == theInModuleActionID)
+ actions.emplace(actionAndID.first);
}
+ return actions;
+ }
+ else {
+ const auto itActions = myActions.find(theModuleID);
+ if (itActions == myActions.end())
+ return std::set<QAction*>();
- QKeySequence keySeq = getShortcutByActionName( shortcutActionName );
- action->setShortcut( keySeq );
+ const std::map<QString, std::set<QAction*>>& moduleActions = itActions->second;
+ const auto itModuleActions = moduleActions.find(theInModuleActionID);
+ if (itModuleActions == moduleActions.end())
+ return std::set<QAction*>();
+
+ return itModuleActions->second;
}
}
-/*!
- \brief Enable/disable a shortcuts section.
+std::pair<QString, QString> SUIT_ShortcutMgr::getModuleIDAndInModuleID(const QAction* theAction) const {
+ const auto it = myActionIDs.find(const_cast<QAction*>(theAction));
+ if (it == myActionIDs.end())
+ return std::pair<QString, QString>();
- Enables or disables actions which belong to the given shortcuts section.
- Only actions which have an active desktop as a parent widget
- are taken into account.
+ return it->second;
+}
- \param section shorcuts section
- \param on if \c true - action will be enabled, otherwise - disabled
-*/
-void SUIT_ShortcutMgr::setSectionEnabled( const QString& section, const bool on )
-{
- QMap<QString, QtxAction*>::ConstIterator it;
- for ( it = myShortcutActions.constBegin(); it != myShortcutActions.constEnd(); ++it ) {
- QtxAction* action = it.value();
- QString shortcutActionName = action->shortcutActionName();
- QString actionSection = shortcutActionName.section( ":", 0, 0 );
- if ( actionSection == section ) {
- // Check if the action parent widget equals to the active desktop
- SUIT_Application* app = SUIT_Session::session()->activeApplication();
- if ( !app )
- return;
- if ( action->parentWidget() == (QWidget*)app->desktop() )
- action->setEnabled( on );
+bool SUIT_ShortcutMgr::hasAction(const QAction* theAction) const
+{
+ return myActionIDs.find(const_cast<QAction*>(theAction)) != myActionIDs.end();
+}
+
+QString SUIT_ShortcutMgr::getActionID(const QAction* theAction) const
+{
+ const auto it = myActionIDs.find(const_cast<QAction*>(theAction));
+ if (it == myActionIDs.end())
+ return QString();
+
+ return SUIT_ShortcutMgr::makeActionID(it->second.first, it->second.second);
+}
+
+void SUIT_ShortcutMgr::setActionsOfModuleEnabled(const QString& theModuleID, const bool theEnable) const
+{
+ const auto itModuleActions = myActions.find(theModuleID);
+ if (itModuleActions == myActions.end())
+ return;
+
+ SUIT_Application* app = SUIT_Session::session()->activeApplication();
+ if (!app)
+ return;
+
+ const std::map<QString, std::set<QAction*>>& moduleActions = itModuleActions->second;
+ for (const auto& idAndActions : moduleActions) {
+ const std::set<QAction*>& actions = idAndActions.second;
+ for (QAction* const action : actions) {
+ if (action->parentWidget() == (QWidget*)app->desktop()) // Is not compiled without cast or with static_cast<QWidget*>.
+ action->setEnabled(theEnable);
}
}
}
-/*!
- \brief Update shortcuts from preferences.
-*/
-void SUIT_ShortcutMgr::updateShortcuts()
+void SUIT_ShortcutMgr::setActionsWithPrefixInIDEnabled(const QString& theInModuleActionIDPrefix, bool theEnable) const
{
- QMap<QString, QtxAction*>::ConstIterator it;
- for ( it = myShortcutActions.constBegin(); it != myShortcutActions.constEnd(); ++it ) {
- QtxAction* action = it.value();
- QKeySequence keySeq = getShortcutByActionName( action->shortcutActionName() );
- action->setShortcut( keySeq );
+ SUIT_Application* app = SUIT_Session::session()->activeApplication();
+ if (!app)
+ return;
+
+ for (const std::pair<QAction*, std::pair<QString, QString>>& actionAndID : myActionIDs) {
+ QAction* const action = actionAndID.first;
+ // Is not compiled without cast or with static_cast<QWidget*>.
+ if (action->parentWidget() == (QWidget*)app->desktop()) {
+ const QString& inModuleActionID = actionAndID.second.second;
+ if (inModuleActionID.startsWith(theInModuleActionIDPrefix))
+ action->setEnabled(theEnable);
+ }
}
}
-/*!
- \brief Called when the corresponding action is destroyed.
-
- Removes destroyed action from the actions list.
+void SUIT_ShortcutMgr::setSectionEnabled(const QString& theInModuleActionIDPrefix, bool theEnable) const
+{
+ setActionsWithPrefixInIDEnabled(theInModuleActionIDPrefix, theEnable);
+}
- \param obj action being destroyed
-*/
-void SUIT_ShortcutMgr::onActionDestroyed( QObject* obj )
+void SUIT_ShortcutMgr::rebindActionsToKeySequences() const
+{
+ ShCutDbg() && ShCutDbg("SUIT_ShortcutMgr::rebindActionsToKeySequences()");
+ for (const std::pair<QAction*, std::pair<QString, QString>>& actionAndID : myActionIDs) {
+ actionAndID.first->setShortcut(getKeySequence(actionAndID.second.first, actionAndID.second.second));
+ }
+}
+
+void SUIT_ShortcutMgr::updateShortcuts() const
+{
+ rebindActionsToKeySequences();
+}
+
+std::set<std::pair<QString, QString>> SUIT_ShortcutMgr::setShortcut(const QString& theActionID, const QKeySequence& theKeySequence, bool theOverride)
+{
+ const auto moduleIDAndActionID = splitIntoModuleIDAndInModuleID(theActionID);
+ const QString& moduleID = moduleIDAndActionID.first;
+ const QString& inModuleActionID = moduleIDAndActionID.second;
+
+ if (inModuleActionID.isEmpty()) {
+ ShCutDbg() && ShCutDbg("Attempt to set shortcut with invalid action ID \"" + theActionID + "\".");
+ return std::set<std::pair<QString, QString>>();
+ }
+
+ return setShortcutNoIDChecks(moduleID, inModuleActionID, theKeySequence, theOverride);
+}
+
+std::set<std::pair<QString, QString>> SUIT_ShortcutMgr::setShortcut(const QString& theModuleID, const QString& theInModuleActionID, const QKeySequence& theKeySequence, bool theOverride)
+{
+ if (!SUIT_ShortcutMgr::isModuleIDValid(theModuleID)) {
+ ShCutDbg() && ShCutDbg("Attempt to set shortcut with invalid module ID \"" + theModuleID + "\".");
+ return std::set<std::pair<QString, QString>>();
+ }
+
+ if (!SUIT_ShortcutMgr::isInModuleActionIDValid(theInModuleActionID)) {
+ ShCutDbg() && ShCutDbg("Attempt to set shortcut with invalid in-module action ID \"" + theInModuleActionID + "\".");
+ return std::set<std::pair<QString, QString>>();
+ }
+
+ return setShortcutNoIDChecks(theModuleID, theInModuleActionID, theKeySequence, theOverride);
+}
+
+const SUIT_ShortcutContainer& SUIT_ShortcutMgr::getShortcutContainer() const
{
- QtxAction* anAction = (QtxAction*)obj;
-
- if ( anAction )
- myShortcutActions.remove( anAction->shortcutActionName(), anAction );
+ return myShortcutContainer;
}
+
+void SUIT_ShortcutMgr::mergeShortcutContainer(const SUIT_ShortcutContainer& theContainer, bool theOverride, bool theTreatAbsentIncomingAsDisabled)
+{
+ ShCutDbg() && ShCutDbg("ShortcutMgr merges shortcut container...");
+ const auto changes = myShortcutContainer.merge(theContainer, theOverride, theTreatAbsentIncomingAsDisabled);
+ ShCutDbg() && ShCutDbg("ShortcutMgr keeps following shortcuts:\n" + myShortcutContainer.toString());
+
+ // Turn off hotkeys for disabled shortcuts.
+ for (const auto& moduleIDAndChanges : changes) {
+ const QString& moduleID = moduleIDAndChanges.first;
+ const auto& moduleChanges = moduleIDAndChanges.second;
+ for (const std::pair<QString, QKeySequence>& modifiedShortcut : moduleChanges) {
+ if (modifiedShortcut.second == NO_KEYSEQUENCE) {
+ const std::set<QAction*> actions = getActions(moduleID, modifiedShortcut.first);
+ for (QAction* const action : actions) {
+ action->setShortcut(NO_KEYSEQUENCE);
+ }
+ }
+ }
+ }
+
+ // Turn on hotkeys for enabled shortcuts.
+ for (const auto& moduleIDAndChanges : changes) {
+ const QString& moduleID = moduleIDAndChanges.first;
+ const auto& moduleChanges = moduleIDAndChanges.second;
+ for (const std::pair<QString, QKeySequence>& modifiedShortcut : moduleChanges) {
+ if (modifiedShortcut.second != NO_KEYSEQUENCE) {
+ const std::set<QAction*> actions = getActions(moduleID, modifiedShortcut.first);
+ for (QAction* const action : actions) {
+ action->setShortcut(modifiedShortcut.second);
+ }
+ }
+ }
+ }
+
+ SUIT_ShortcutMgr::saveShortcutsToPreferences(changes);
+}
+
+QKeySequence SUIT_ShortcutMgr::getKeySequence(const QString& theModuleID, const QString& theInModuleActionID) const
+{
+ return myShortcutContainer.getKeySequence(theModuleID, theInModuleActionID);
+}
+
+const std::map<QString, QKeySequence>& SUIT_ShortcutMgr::getModuleShortcutsInversed(const QString& theModuleID) const
+{
+ return myShortcutContainer.getModuleShortcutsInversed(theModuleID);
+}
+
+std::set<QString> SUIT_ShortcutMgr::getShortcutModuleIDs() const
+{
+ return myShortcutContainer.getIDsOfAllModules();
+}
+
+std::set<QString> SUIT_ShortcutMgr::getIDsOfInterferingModules(const QString& theModuleID) const
+{
+ return myShortcutContainer.getIDsOfInterferingModules(theModuleID);
+}
+
+QString SUIT_ShortcutMgr::getModuleName(const QString& theModuleID) const
+{
+ return theModuleID == ROOT_MODULE_ID ? tr("General") : theModuleID;
+
+ /*
+ // TODO ? The SUIT_ShortcutMgr should be renamed and moved to CAM folder.
+ // Because the CAM_Application class is the closest to SUIT_Application in the inheritance hierarchy,
+ // who has concept of application module. Enabling this chunk of code, due to the presence of CAM_Application,
+ // requires to heap up cyclic dependencies in compilation units.
+ // Or it is reasond to add like-action-name-resources to preference files.
+
+ SUIT_Application* aSUIT_Application = SUIT_Session::session()->activeApplication();
+ const auto aCAM_Application = dynamic_cast<CAM_Application*>(aSUIT_Application);
+ if (aCAM_Application)
+ return aCAM_Application->moduleTitle(theModuleID);
+ */
+
+ // At least something meaningful.
+ return theModuleID;
+}
+
+QString SUIT_ShortcutMgr::getActionName(const QString& theModuleID, const QString& theInModuleActionID) const
+{
+ const QString actionID = SUIT_ShortcutMgr::makeActionID(theModuleID, theInModuleActionID);
+ if (actionID.isEmpty()) {
+ ShCutDbg() && ShCutDbg("Can't get action name: either/both module ID \"" + theModuleID + "\" or/and in-module action ID \"" + theInModuleActionID + "\" is/are invalid.");
+ return actionID;
+ }
+ return getActionName(actionID);
+}
+
+QString SUIT_ShortcutMgr::getActionName(const QString& theActionID) const
+{
+ const auto moduleAndInModuleActionIDs = SUIT_ShortcutMgr::splitIntoModuleIDAndInModuleID(theActionID);
+ if (moduleAndInModuleActionIDs.second.isEmpty()) {
+ ShCutDbg() && ShCutDbg("Can't get action name using invalid action ID \"" + theActionID + "\".");
+ return QString();
+ }
+
+ const auto itActionNames = myActionNames.find(theActionID);
+ if (itActionNames != myActionNames.end() && !itActionNames->second.empty()) {
+ QString lang;
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("SUIT_ShortcutMgr can't retrieve resource manager!");
+ lang = DEFAULT_LANG;
+ }
+ else {
+ lang = resMgr->stringValue(LANG_SECTION, LANG_SECTION, DEFAULT_LANG);
+ }
+
+ QStringList langPriorityList = LANG_PRIORITY_LIST;
+ langPriorityList.push_front(lang);
+ langPriorityList.removeDuplicates();
+
+ const std::map<QString, QString>& translations = itActionNames->second;
+ for (const QString& lang : langPriorityList) {
+ const auto itTranslation = translations.find(lang);
+ if (itTranslation != translations.end()) {
+ return itTranslation->second;
+ }
+ }
+ return translations.begin()->second;
+ }
+ else /* if action ID has no loaded name in any language. */ {
+ // Try to get action->toolTip() and use it as a name.
+
+ // Pitfall of the approach: at the time this code block is called, the action may not exist.
+ // Moreover, an action with such an ID may not even have been created at the time of calling this method.
+ // Thus, even buffering of names of every action ever created at runtime does not guarantee,
+ // that the name will be available at any point in the life of the application,
+ // unless the name is added to dedicated section in a preference file.
+
+ const QString& moduleID = moduleAndInModuleActionIDs.first;
+ const QString& inModuleActionID = moduleAndInModuleActionIDs.second;
+
+ if (SUIT_ShortcutMgr::isInModuleMetaActionID(inModuleActionID)) {
+ for (const auto& actionAndID : myActionIDs) {
+ if (actionAndID.second.second == inModuleActionID)
+ return actionAndID.first->toolTip();
+ }
+ return inModuleActionID;
+ }
+ else {
+ const auto itModuleActions = myActions.find(moduleID);
+ if (itModuleActions == myActions.end())
+ return inModuleActionID;
+
+ const std::map<QString, std::set<QAction*>>& moduleActions = itModuleActions->second;
+ const auto itActions = moduleActions.find(inModuleActionID);
+ if (itActions == moduleActions.end())
+ return inModuleActionID;
+
+ const std::set<QAction*>& actions = itActions->second;
+ if (actions.empty())
+ return inModuleActionID;
+
+ return (*actions.begin())->toolTip();
+ }
+ }
+}
+
+void SUIT_ShortcutMgr::onActionDestroyed(QObject* theObject)
+{
+ QAction* action = static_cast<QAction*>(theObject);
+
+ auto itID = myActionIDs.find(action);
+ if (itID == myActionIDs.end())
+ return;
+
+ const QString& moduleID = itID->second.first;
+ const QString& inModuleActionID = itID->second.second;
+
+ auto itModuleActions = myActions.find(moduleID);
+ if (itModuleActions != myActions.end()) {
+ std::map<QString, std::set<QAction*>>& moduleActions = itModuleActions->second;
+ auto itActions = moduleActions.find(inModuleActionID);
+ if (itActions != moduleActions.end()) {
+ std::set<QAction*>& actions = itActions->second;
+ actions.erase(action);
+ }
+ }
+
+ myActionIDs.erase(itID);
+}
+
+bool SUIT_ShortcutMgr::eventFilter(QObject* theObject, QEvent* theEvent)
+{
+ if (theEvent) {
+ if (theEvent->type() == QEvent::ActionAdded) {
+ auto anActionEvent = static_cast<QActionEvent*>(theEvent);
+
+ QtxAction* aQtxAction = qobject_cast<QtxAction*>(anActionEvent->action());
+ if (aQtxAction) {
+#ifdef SHORTCUT_MGR_DBG
+ {
+ const auto moduleIDAndActionID = splitIntoModuleIDAndInModuleID(aQtxAction->ID());
+ if (moduleIDAndActionID.second.isEmpty())
+ ShCutDbg("ActionAdded event, but ID of the action is invalid. Action name = \"" + aQtxAction->toolTip() + "\", ID = \"" + aQtxAction->ID() + "\".");
+ else if (!myShortcutContainer.hasShortcut(moduleIDAndActionID.first, moduleIDAndActionID.second))
+ ShCutDbg("ActionAdded event, but shortcut container has no shortcut for the action. It is ok, if preference files has not been parsed yet. Action ID = \"" + moduleIDAndActionID.second + "\".");
+ }
+#endif//SHORTCUT_MGR_DBG
+#ifdef SHORTCUT_MGR_DEVTOOLS
+ {
+ DevTools::get()->collectShortcutAndTranslation(aQtxAction);
+ const auto moduleIDAndActionID = splitIntoModuleIDAndInModuleID(aQtxAction->ID());
+ if (moduleIDAndActionID.second.isEmpty())
+ DevTools::get()->collectAssetsOfActionWithInvalidID(aQtxAction);
+ }
+#endif//SHORTCUT_MGR_DEVTOOLS
+ registerAction(aQtxAction);
+ }
+ else {
+ QAction* aQAction = qobject_cast<QAction*>(anActionEvent->action());
+#ifdef SHORTCUT_MGR_DEVTOOLS
+ if (aQAction)
+ DevTools::get()->collectAssetsOfActionWithInvalidID(aQAction);
+#endif//SHORTCUT_MGR_DEVTOOLS
+ if (aQAction && aQAction->shortcut() != NO_KEYSEQUENCE) {
+#ifdef SHORTCUT_MGR_DBG
+ ShCutDbg("ActionAdded event, but the added action is not QtxAction and bound to non-empty key sequence. name: \"" + aQAction->toolTip() + "\".");
+#endif//SHORTCUT_MGR_DBG
+ // Since non-QtxAction has no ID, it is impossible to properly manage its shortcut.
+ // And the shortcut may interfere with managed ones.
+ aQAction->setShortcut(NO_KEYSEQUENCE);
+ }
+ }
+ }
+ }
+
+ return QObject::eventFilter(theObject, theEvent);
+}
+
+std::set<std::pair<QString, QString>> SUIT_ShortcutMgr::setShortcutNoIDChecks(const QString& theModuleID, const QString& theInModuleActionID, const QKeySequence& theKeySequence, bool theOverride)
+{
+ std::set<std::pair<QString, QString>> disabledShortcutsIDs = myShortcutContainer.setShortcut(theModuleID, theInModuleActionID, theKeySequence, theOverride);
+
+ if (theOverride || disabledShortcutsIDs.empty()) {
+ // Bind actions to corresponding modified key sequences. Save changes to preferences.
+
+ /** { moduleID, {inModuleActionID, keySequence}[] }[] */
+ std::map<QString, std::map<QString, QKeySequence>> modifiedShortcuts;
+
+ for (const auto& moduleIDAndActionID : disabledShortcutsIDs) {
+ // Unbind actions of disabled shortcuts.
+
+ const QString& moduleID = moduleIDAndActionID.first;
+ const QString& inModuleActionID = moduleIDAndActionID.second;
+
+ std::map<QString, QKeySequence>& modifiedModuleShortcuts = modifiedShortcuts[moduleID];
+ modifiedModuleShortcuts[inModuleActionID] = NO_KEYSEQUENCE;
+
+ const std::set<QAction*> actions = getActions(moduleID, inModuleActionID);
+ for (QAction* const action : actions) {
+ action->setShortcut(NO_KEYSEQUENCE);
+ }
+ }
+
+ { // Bind actions to theKeySequence.
+ std::map<QString, QKeySequence>& modifiedModuleShortcuts = modifiedShortcuts[theModuleID];
+ modifiedModuleShortcuts[theInModuleActionID] = theKeySequence;
+
+ const std::set<QAction*> actions = getActions(theModuleID, theInModuleActionID);
+ for (QAction* const action : actions) {
+ action->setShortcut(theKeySequence);
+ }
+ }
+
+ SUIT_ShortcutMgr::saveShortcutsToPreferences(modifiedShortcuts);
+ }
+
+ return disabledShortcutsIDs;
+}
+
+void SUIT_ShortcutMgr::setShortcutsFromPreferences()
+{
+ ShCutDbg() && ShCutDbg("ShortcutMgr is initializing...");
+
+ SUIT_ShortcutContainer container;
+ SUIT_ShortcutMgr::fillContainerFromPreferences(container, false /*theDefaultOnly*/);
+ mergeShortcutContainer(container, true /*theOverrde*/, false /*theTreatAbsentIncomingAsDisabled*/);
+ setActionNamesFromResources();
+
+ ShCutDbg() && ShCutDbg("ShortcutMgr has been initialized.");
+}
+
+/*static*/ void SUIT_ShortcutMgr::saveShortcutsToPreferences(const std::map<QString, std::map<QString, QKeySequence>>& theShortcutsInversed)
+{
+ ShCutDbg() && ShCutDbg("Saving preferences to resources.");
+
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("SUIT_ShortcutMgr can't retrieve resource manager!");
+ return;
+ }
+
+ for (const auto& moduleIDAndShortcutsInversed : theShortcutsInversed) {
+ const auto& moduleID = moduleIDAndShortcutsInversed.first;
+ const auto& moduleShortcutsInversed = moduleIDAndShortcutsInversed.second;
+ for (const auto& shortcutInversed : moduleShortcutsInversed) {
+ if (shortcutInversed.first.isEmpty()) {
+ ShCutDbg("Attempt to serialize a shortcut with empty action ID.");
+ continue;
+ }
+
+ const QString sectionName = SECTION_NAME_PREFIX + resMgr->sectionsToken() + moduleID;
+ resMgr->setValue(sectionName, shortcutInversed.first, shortcutInversed.second.toString());
+
+ ShCutDbg() && ShCutDbg("Saving shortcut: \"" + moduleID + "\"\t\"" + shortcutInversed.first + "\"\t\"" + shortcutInversed.second.toString() + "\"");
+ }
+ }
+}
+
+void SUIT_ShortcutMgr::setActionNamesFromResources(QString theLanguage)
+{
+ ShCutDbg() && ShCutDbg("Retrieving action names (translations) from preference files.");
+
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ if (!resMgr) {
+ Warning("SUIT_ShortcutMgr can't retrieve resource manager!");
+ return;
+ }
+
+ if (theLanguage.isEmpty())
+ theLanguage = resMgr->stringValue(LANG_SECTION, LANG_SECTION, DEFAULT_LANG);
+
+ QStringList langPriorityList = LANG_PRIORITY_LIST;
+ langPriorityList.push_front(theLanguage);
+ langPriorityList.removeDuplicates();
+
+ QStringList actionIDs = resMgr->subSections(SECTION_SHORTCUT_NAMES_PREFIX, false);
+ for (const QString& actionID : actionIDs) {
+ // {language, actionName}[]
+ std::map<QString, QString>& actionTranslations = myActionNames[actionID];
+ const QString sectionName = SECTION_SHORTCUT_NAMES_PREFIX + resMgr->sectionsToken() + actionID;
+ QStringList availableActionNameLangs = resMgr->parameters(sectionName);
+
+ QString actionName = actionID;
+ const bool nameInCurLangExists = resMgr->value(sectionName, theLanguage, actionName);
+ if (nameInCurLangExists) {
+ actionTranslations[theLanguage] = actionName;
+ }
+ else {
+ bool nameInlinguaFrancaExists = false;
+ QString usedLanguage = QString();
+ for (int i = 1; i < langPriorityList.length(); i++) {
+ nameInlinguaFrancaExists = resMgr->value(sectionName, langPriorityList[i], actionName);
+ if (nameInlinguaFrancaExists) {
+ usedLanguage = langPriorityList[i];
+ break;
+ }
+ }
+ actionTranslations[theLanguage] = actionName;
+
+#ifdef SHORTCUT_MGR_DBG
+ if (nameInlinguaFrancaExists)
+ ShCutDbg("Can't find in preference files a name for action with ID \"" + actionID + "\" at current (" + theLanguage + ") language. " + usedLanguage + " is used for the name." );
+ else
+ ShCutDbg("Can't find in preference files a name for action with ID \"" + actionID + "\". Also tried " + langPriorityList.join(", ") + " languages." );
+#endif
+ }
+ }
+}
\ No newline at end of file
#include "SUIT.h"
#include <QObject>
-#include <QMultiMap>
+#include <QString>
+#include <map>
+#include <set>
+#include <utility>
+class QAction;
class QtxAction;
-
class QKeySequence;
#if defined WIN32
#pragma warning( disable: 4251 )
#endif
+// Define SHORTCUT_MGR_DBG to enable SUIT_ShortcutMgr debug logging.
+// #define SHORTCUT_MGR_DBG
+/*! \returns true, if SUIT_ShortcutMgr debug logging is enabled. */
+SUIT_EXPORT extern inline bool ShCutDbg() {
+#ifdef SHORTCUT_MGR_DBG
+ return true;
+#else
+ return false;
+#endif
+}
+/*! \brief Prints theString to std::wcout, if SUIT_ShortcutMgr debug logging is enabled. */
+SUIT_EXPORT extern bool ShCutDbg(const QString& theString);
+/*! \brief Prints theString to std::wcout, if SUIT_ShortcutMgr debug logging is enabled. */
+SUIT_EXPORT extern bool ShCutDbg(const char* theString);
+
+
+/*!
+ \class SUIT_ShortcutContainer
+ \brief Provides means to keep and edit shortcuts in compliance with the application logics.
+ \ref See SUIT_ShortcutMgr for details.
+*/
+class SUIT_EXPORT SUIT_ShortcutContainer
+{
+public:
+ SUIT_ShortcutContainer();
+
+ /*! \returns IDs of modules, which interfere with the module:
+ if the module is root (theModuleID is empty) - returns all module IDs, otherwise returns ["", theModuleID]. */
+ std::set<QString> getIDsOfInterferingModules(const QString& theModuleID) const;
+
+ std::set<QString> getIDsOfAllModules() const;
+
+ /*! \brief Checks for conflicts. If theOverride, modifies incoming and disables all conflicting shortcuts.
+ Redefining a key sequence for the action, if theKeySequence does not conflict with other shortcuts, is not considered as a conflict.
+ \param theModuleID The method has no effect if theModuleID is invalid. \ref See SUIT_ShortcutMgr::isModuleIDValid(const QString&) for details.
+ \param theInModuleActionID The method has no effect if theInModuleActionID is invalid. \ref See SUIT_ShortcutMgr::isInModuleActionIDValid(const QString&).
+ If theInModuleActionID is meta-action ID, the shortcut is set to root module, and theModuleID is ignored.
+ \param theKeySequence Empty theKeySequence does not cause conflicts, in this case
+ a shortcut for the action is disabled: theInModuleActionID is added/retained in the container but mapped to empty key sequence.
+ \param theOverride If true, conflicting shortcuts are disabled.
+ \returns {moduleID, inModuleActionID}[] - Set of conflicting actions if theOverride = false,
+ otherwise set of actions (without incoming one), whose shortcuts have been disabled. */
+ std::set<std::pair<QString, QString>> setShortcut(
+ QString theModuleID,
+ const QString& theInModuleActionID,
+ const QKeySequence& theKeySequence,
+ bool theOverride
+ );
+
+ /*! \brief Checks for conflicts. Existence of a shortcut with another key sequence for the action,
+ if theKeySequence does not conflict with other shortcuts, is not considered as a conflict.
+ \param theInModuleActionID If theInModuleActionID is meta-action ID, the shortcut is looked for in root module, and theModuleID is ignored.
+ \param theKeySequence Empty theKeySequence does not have conflicts.
+ \returns {moduleID, inModuleActionID}[] - Set of conflicting actions. */
+ std::set<std::pair<QString, QString>> getConflicts(
+ QString theModuleID,
+ const QString& theInModuleActionID,
+ const QKeySequence& theKeySequence
+ ) const;
+
+ /*! \returns empty key sequence if shortcut for the action is not set.
+ \param theInModuleActionID If theInModuleActionID is meta-action ID, seeks in root module, and theModuleID is ignored.*/
+ const QKeySequence& getKeySequence(QString theModuleID, const QString& theInModuleActionID) const;
+
+ /*! \returns true, if shortcut for the action is set (even if the mapped key sequence is empty).
+ \param theInModuleActionID If theInModuleActionID is meta-action ID, seeks in root module, and theModuleID is ignored.*/
+ bool hasShortcut(QString theModuleID, const QString& theInModuleActionID) const;
+
+ /*! \returns {inModuleActionID, keySequence}[] - If the module was not added, the map is empty. */
+ const std::map<QString, QKeySequence>& getModuleShortcutsInversed(const QString& theModuleID) const;
+
+ /*! \brief Seeks for shortcuts in the module with in-module action IDs, which start with theInModuleActionIDPrefix.
+ \returns {inModuleActionID, keySequence}[] - If the module was not added, the map is empty. */
+ const std::map<QString, QKeySequence> getModuleShortcutsInversed(const QString& theModuleID, const QString& theInModuleActionIDPrefix) const;
+
+ /*! \brief Merges shortcuts of theOther into this.
+ \param theOverride if true, overrides conflicting shortcuts.
+ If false, and this has no shortcut for an incoming action, and the incoming shortcut conflicts
+ with an existing shortcut, disabled shortcut for the incoming action is set.
+ \param theTreatAbsentIncomingAsDisabled If theOverride == false, theTreatAbsentIncomingAsDisabled is ignored.
+ If theOverride and theTreatAbsentIncomingAsDisabled, and theOther has no shortcut for an action, which exists in this,
+ the existing shortcut in this is set disabled.
+ \returns { moduleID, { inModuleActionID, keySequence }[] }[] - Modiified shortcuts inversed. */
+ std::map<QString, std::map<QString, QKeySequence>> merge(
+ const SUIT_ShortcutContainer& theOther,
+ bool theOverride,
+ bool theTreatAbsentIncomingAsDisabled = false
+ );
+
+ /*! \brief Generates human-readable text representation of content. */
+ QString toString() const;
+
+private:
+ /** { moduleID, { keySequence, inModuleActionID }[] }[]. keySequence can not be empty.
+ * Can not contain entries like { <non-root module ID>, { keySequence, <meta-action ID> } }. */
+ std::map<QString, std::map<QKeySequence, QString>> myShortcuts;
+
+ /** { moduleID, { inModuleActionID, keySequence }[] }[]. keySequence can be empty.
+ * Can not contain entries like { <non-root module ID>, { <meta-action ID>, keySequence } }. */
+ std::map<QString, std::map<QString, QKeySequence>> myShortcutsInversed;
+};
+
+
/*!
\class SUIT_ShortcutMgr
- \brief Class which manages shortcuts customization.
+ \brief Handles action shortcut customization.
+
+ Register actions under action IDs. Set shortcuts, which are [action ID]<->[key sequence] mappings.
+ Every time an action is registered or a shorcut is set, if there are an action and a shortcut,
+ which are mapped to the same action ID, the action is bound to the key sequence of the shortcut.
+ Action IDs are also used to (de)serialize shortcut settings.
+ Several QActions may be registered under the same ID.
+
+ Most of actions are intercepted on creation in SUIT_ShortcutMgr:eventFilter(QObject* theObject, QEvent* theEvent).
+ If an intercepted action is instance of QtxAction, it is registered automatically.
+ Since non-QtxActions have no member ID(), SUIT_ShortcutMgr is unable to register them automatically
+ in SUIT_ShortcutMgr::eventFilter(). Thus, every non-QtxAction should be
+ passed to SUIT_ShortcutMgr::registerAction(const QString& theActionID, QAction* theAction).
+
+ Action ID is application-unique must be composed as <moduleID>/<inModuleActionID>.
+ If an action belongs to a desktop or is available even if no module is active (e.g. 'Save As'),
+ use empty string as <moduleID>. Let's call such actions as root actions.
+
+ There is a need to keep multiple actions, which do the same from user' perspective,
+ bound to the same key sequence. E.g. 'Front view'. Let's call such set of actions as meta-action.
+ Actions of a meta-action may belong to different modules, and/or there may be several actions
+ of the same meta-action in the same module. <inModuleActionID> of all members of a meta-action
+ must be the same and start with "#".
+ Meta-action is root action when it comes to checking for conflicts.
+ Shortcuts of meta-actions are (de)serialized to the same section of preference files as root shortcuts.
+
+ <inModuleActionID> can contain several "/". Go to \ref isInModuleActionIDValid(const QString&) for details.
+ You can refer to multiple actions, whose <inModuleActionID> starts with the prefix.
+
+ Only one module can be active at instance. So a key sequence must be unique within a joined temporary table of
+ root and active module shortcuts. An action is allowed to be bound with only key sequence.
+
+ WARNING!
+ Avoid assigning shortcuts to instances of QAction and all its descendants directly.
+ (1) Key sequence being bound directly to any registered/intercepted action with valid ID,
+ if the key sequence does not conflict with shortcuts kept by SUIT_ShortcutMgr,
+ is added to the manager and appears in user preference file. If it does conflict,
+ it is reassigned with a key sequence from preference files or
+ disabled and added to user preference files (if the files have no shortcut for the action).
+ (2) Key sequences being bound directly to non-QtxAction instances are disabled.
*/
-class SUIT_EXPORT SUIT_ShortcutMgr: public QObject
+class SUIT_EXPORT SUIT_ShortcutMgr: public QObject
{
Q_OBJECT
-public:
- static void Init();
- static SUIT_ShortcutMgr* getShortcutMgr();
- void setSectionEnabled( const QString&, const bool = true );
- void updateShortcuts();
+private:
+ SUIT_ShortcutMgr();
+ SUIT_ShortcutMgr(const SUIT_ShortcutMgr&) = delete;
+ SUIT_ShortcutMgr& operator=(const SUIT_ShortcutMgr&) = delete;
protected:
- SUIT_ShortcutMgr();
virtual ~SUIT_ShortcutMgr();
+public:
+ /*! \brief Create new singleton-instance of shortcut manager, if it has not been created. */
+ static void Init();
+
+ static SUIT_ShortcutMgr* get();
+
+ /*! \brief Checks whether the theKeySequence is platform-compatible. */
+ static bool isKeySequenceValid(const QKeySequence& theKeySequence);
+
+ /*! \returns {false, _ } if theKeySequenceString is invalid. */
+ static std::pair<bool, QKeySequence> toKeySequenceIfValid(const QString& theKeySequenceString);
+
+ /*! \brief Valid module ID does not contain "/" and equals to result of QString(theModuleID).simplified().
+ Empty module ID is valid - it is root module ID. */
+ static bool isModuleIDValid(const QString& theModuleID);
+
+ /*! \brief Valid in-module action ID may consist of several tokens, separated by "/":
+ <token_0>/<token_1>...<token_N>/<token_N-1>.
+ Each <token> must be non-empty and be equal to QString(<token>).simplified().
+ Empty or "#" in-module action ID is not valid. */
+ static bool isInModuleActionIDValid(const QString& theInModuleActionID);
+
+ /*! \returns true, is theInModuleActionID starts with "#". */
+ static bool isInModuleMetaActionID(const QString& theInModuleActionID);
+
+ /*! \brief Extracts module ID and in-module action ID from application-unique action ID.
+ The theActionID must be composed as <moduleID>/<inModuleActionID>.
+ \returns { _ , "" }, if theActionID is invalid. */
+ static std::pair<QString, QString> splitIntoModuleIDAndInModuleID(const QString& theActionID);
+
+ /*! See \ref splitIntoModuleIDAndInModuleID(const QString&). */
+ static bool isActionIDValid(const QString& theActionID);
+
+ /*! \brief Creates application-unique action ID. Reverse to splitIntoModuleIDAndInModuleID.
+ \returns Emppty string, if either theModuleID or theInModuleActionID is invalid*/
+ static QString makeActionID(const QString& theModuleID, const QString& theInModuleActionID);
+
+ /*! \brief Sets all shortcuts from preferences to theContainer. Incoming shortcuts override existing ones.
+ If the container has shortcut for an action, which is absent in preferences, and the existing shortcut
+ does not conflict with incoming ones, it is untouched.
+ See \ref setShortcutsFromPreferences() for details.
+ \param theDefaultOnly If true, user preferences are ignored and only default preferences are used. */
+ static void fillContainerFromPreferences(SUIT_ShortcutContainer& theContainer, bool theDefaultOnly);
+
+ /*! \brief Checks the resource manager directly.
+ \returns {nameExists, name}. */
+ static std::pair<bool, QString> getActionNameFromResources(const QString& theActionID, QString theLanguage = QString());
+
+
+ /*! \brief Add theAction to map of managed actions. */
+ void registerAction(const QString& theActionID, QAction* theAction);
+
+ /*! \brief Add theAction to map of managed actions. QtxAction::ID() is used as action ID. */
+ void registerAction(QtxAction* theAction);
+
+ /*! \brief Get registered actions. If theInModuleActionID is meta-action ID, seeks in all modules. */
+ std::set<QAction*> getActions(const QString& theModuleID, const QString& theInModuleActionID) const;
+
+ /*! \brief Get module ID and in-module-ID of theAction.
+ \returns { _ , "" } if theAction is not registered. */
+ std::pair<QString, QString> getModuleIDAndInModuleID(const QAction* theAction) const;
+
+ /*! Returns true if theAction is registered. */
+ bool hasAction(const QAction* theAction) const;
+
+ /*! \brief Get action ID of theActon.
+ \returns empty string if theAction is not registered. */
+ QString getActionID(const QAction* theAction) const;
+
+ /*! \brief Enables/disable actions of the module.
+ Only those actions are affected, whose parent widget is active desktop. */
+ void setActionsOfModuleEnabled(const QString& theModuleID, const bool theEnable = true) const;
+
+ /*! \brief Enables/disables all registered actions whose in-module action ID begins with theInModuleActionIDPrefix.
+ Only those actions are affected, whose parent widget is active desktop. */
+ void setActionsWithPrefixInIDEnabled(const QString& theInModuleActionIDPrefix, bool theEnable = true) const;
+
+ [[deprecated("Use setActionsWithPrefixInIDEnabled(const QString&, bool) instead.")]]
+ void setSectionEnabled(const QString& theInModuleActionIDPrefix, bool theEnable = true) const;
+
+ /*! \brief For all registered actions binds key sequences from myShortcutContainer. */
+ void rebindActionsToKeySequences() const;
+
+ [[deprecated("Use rebindActionsToKeySequences() instead.")]]
+ void updateShortcuts() const;
+
+ /*! \brief Checks for conflicts. If theOverride, modifies incoming and disables all conflicting shortcuts.
+ Then binds key sequences with corresponding registered actions. Saves changes to preferences.
+
+ Redefining a key sequence for the action, if the key sequence does not conflict with other shortcuts, is not considered as a conflict.
+ \param theInModuleActionID The method has no effect if theInModuleActionID is empty.
+ \param theKeySequence Empty theKeySequence does not cause conflicts, in this case
+ a shortcut for the action is disabled: theInModuleActionID is added/retained in the container but mapped to empty key sequence.
+ \param theOverride If true, conflicting shortcuts are disabled.
+ \returns {moduleID, inModuleActionID}[] - Set of conflicting actions if theOverride = false,
+ otherwise set of actions (without incoming one), whose shortcuts have been disabled. */
+ std::set<std::pair<QString, QString>> setShortcut(const QString& theActionID, const QKeySequence& theKeySequence, bool theOverride = false);
+ std::set<std::pair<QString, QString>> setShortcut(const QString& theModuleID, const QString& theInModuleActionID, const QKeySequence& theKeySequence, bool theOverride = false);
+
+ const SUIT_ShortcutContainer& getShortcutContainer() const;
+
+ /*! \brief Does not perform validity checks on theModuleID and theInModuleActionID. */
+ void mergeShortcutContainer(const SUIT_ShortcutContainer& theContainer, bool theOverride = true, bool theTreatAbsentIncomingAsDisabled = false);
+
+ /*! \brief Get a key sequence mapped to the action. */
+ QKeySequence getKeySequence(const QString& theModuleID, const QString& theInModuleActionID) const;
+
+ /*! \returns {inModuleActionID, keySequence}[] */
+ const std::map<QString, QKeySequence>& getModuleShortcutsInversed(const QString& theModuleID) const;
+
+ /*! \returns All module IDs, which were added to myShortcutContainer. */
+ std::set<QString> getShortcutModuleIDs() const;
+
+ /*! \returns IDs of modules, which interfere with the module:
+ if the module is root (theModuleID is empty) - returns all module IDs, otherwise returns ["", theModuleID]. */
+ std::set<QString> getIDsOfInterferingModules(const QString& theModuleID) const;
+
+ /*! \brief Retrieves module name translated to appropriate language. */
+ QString getModuleName(const QString& theModuleID) const;
+
+ /*! \brief Retrieves at runtime action name translated to appropriate language,
+ if the language was loaded using \ref setActionNamesFromResources(QString). */
+ QString getActionName(const QString& theModuleID, const QString& theInModuleActionID) const;
+
+ /*! \brief Retrieves at runtime action name translated to appropriate language,
+ if the language was loaded using \ref setActionNamesFromResources(QString). */
+ QString getActionName(const QString& theActionID) const;
+
private slots:
- void onActionDestroyed( QObject* );
+ /*!
+ \brief Called when the corresponding action is destroyed.
+ Removes destroyed action from maps of registered actions. Preserves shortcut.
+ \param theObject action being destroyed.
+ */
+ void onActionDestroyed(QObject* theObject);
private:
- virtual bool eventFilter( QObject* o, QEvent* e );
+ /*! \brief Overrides QObject::eventFilter().
+ If theEvent is QEvent::ActionAdded and the action is instance of QtxAction, registers it. */
+ virtual bool eventFilter(QObject* theObject, QEvent* theEvent);
+
+ /*! \brief Does not perform validity checks on theModuleID and theInModuleActionID. */
+ std::set<std::pair<QString, QString>> setShortcutNoIDChecks(const QString& theModuleID, const QString& theInModuleActionID, const QKeySequence& theKeySequence, bool theOverride);
+
+ /*! \brief Set shortcuts from preference files. The method is intended to be called before any calls to setShortcut() or mergeShortcutContainer().
+ Definition of this method assumes, that shortcut settings are serialized as prerefence entries {name=<inModuleActionID>, val=<keySequence>}
+ in dedicated section for each module, with names of sections being composed as "shortcuts:<moduleID>".
- void processAction( QtxAction* );
- QKeySequence getShortcutByActionName( const QString& ) const;
+ E.g. in case of XML file it may look like this:
+ <!--
+ <section name="<module ID>">
+ ...
+ <parameter name="<in-module action ID>" value="key sequence">
+ ...
+ </section>
+ -->
+ <section name="shortcuts:">
+ <parameter name="TOT_DESK_FILE_NEW" value="Ctrl+N"/>
+ <parameter name="TOT_DESK_FILE_OPEN" value="Ctrl+O"/>
+ <parameter name="#General/Show object(s)" value="Ctrl+Alt+S"/>
+ <parameter name="#General/Hide object(s)" value="Ctrl+Alt+H"/>
+ <parameter name="#Viewers/Back view" value="Ctrl+Alt+B"/>
+ <parameter name="#Viewers/Front view" value="Ctrl+Alt+F"/>
+ </section>
+ <section name="shortcuts:GEOM">
+ <parameter name="Isolines/Increase number" value="Meta+I"/>
+ <parameter name="Isolines/Decrease number" value="Meta+D"/>
+ <parameter name="Transparency/Increase" value="Meta+Y"/>
+ <parameter name="Transparency/Decrease" value="Meta+T"/>
+ </section>
+
+ Empty inModuleActionIDs are ignored.
+
+ nb! For any theQtxAction you wish user be able to assign it to a shortcut,
+ add theQtxAction.ID() to default resource files (you can map it to no key sequence).*/
+ void setShortcutsFromPreferences();
+
+ /*! \brief Writes shortcuts to preference files.
+ \param theShortcuts { moduleID, { inModuleActionID, keySequence }[] }[]. Empty inModuleActionIDs are ignored. */
+ static void saveShortcutsToPreferences(const std::map<QString, std::map<QString, QKeySequence>>& theShortcutsInversed);
+
+ /*! Fills myActionNames from preference files in theLanguage.
+ \param theLanguage If default, fills names in current language.
+ If a name in requested language is not found, seeks for the name EN in and then in FR.
+
+ In case if resource file is XML, it should look like this:
+ <!--
+ <section name="<action ID>"> Note, that apllication-unique must be typed, not in-module action ID.
+ ...
+ <parameter name="<language>" value="action name">
+ ...
+ </section>
+ -->
+ <section name="shortcut_translations:/#Viewers/Reset view">
+ <parameter name="en" value="Reset View Point"/>
+ <parameter name="fr" value="Restaurer le point de vue"/>
+ <parameter name="ja" value="ビューのポイントを復元します。"/>
+ </section>
+ <section name="shortcut_translations:GEOM/Isolines/Increase number">
+ <parameter name="en" value="Increase number of isolines"/>
+ <parameter name="fr" value="Augmenter le nombre d'isolignes"/>
+ <parameter name="ja" value="等値線の数を増やす"/>
+ </section>
+ */
+ void setActionNamesFromResources(QString theLanguage = QString());
private:
static SUIT_ShortcutMgr* myShortcutMgr;
- QMultiMap<QString, QtxAction*> myShortcutActions;
+
+ /** { moduleID, { inModuleActionID, action[] }[] }[]. May contain entries like { <non-root module ID>, { <meta-action ID>, actions[] } }. */
+ std::map<QString, std::map<QString, std::set<QAction*>>> myActions;
+
+ /** { action, { moduleID, inModuleActionID } }[]. May contain entries like { <non-root module ID>, { <meta-action ID>, actions[] } }. */
+ std::map<QAction*, std::pair<QString, QString>> myActionIDs; // To maintain uniqueness of actions and effectively retrieve IDs of registered actions.
+
+ /** Can not contain entries like { <non-root module ID>, { <meta-action ID>, actions[] } }. */
+ SUIT_ShortcutContainer myShortcutContainer;
+
+ /* nb!
+ Sets of moduleIDs and inModuleActionIDs are equal for myActions and myActionIDs.
+ Sets of moduleIDs and inModuleActionIDs may NOT be equal for myActions and myShortcutContainer.
+ */
+
+ /** { actionID, {language, actionName} }[] */
+ std::map<QString, std::map<QString, QString>> myActionNames;
};
#if defined WIN32
<source>TLT_IMAGE_FILES</source>
<translation>Fichiers images (*.bmp *.png *.jpg *.jpeg)</translation>
</message>
-</context>
+</context>
+<context>
+ <name>SUIT_ShortcutMgr</name>
+ <message>
+ <source>General</source>
+ <translation>Général</translation>
+ </message>
+ <message>
+ <source>Invalid module IDs</source>
+ <translation>ID de module invalides</translation>
+ </message>
+ <message>
+ <source>Invalid shortcuts</source>
+ <translation>Raccourcis invalides</translation>
+ </message>
+ <message>
+ <source>These shortcuts have not been set, because they conflict with previously parsed ones</source>
+ <translation>Ces raccourcis n'ont pas été définis car ils entrent en conflit avec ceux analysés précédemment</translation>
+ </message>
+ <message>
+ <source>Invalid shortcuts in preferences</source>
+ <translation>Raccourcis invalides dans les préférence</translation>
+ </message>
+ <message>
+ <source>Fix the following entries in the preference files manually</source>
+ <translation>Corrigez manuellement les entrées suivantes dans les fichiers de préférences</translation>
+ </message>
+</context>
</TS>
<source>TLT_IMAGE_FILES</source>
<translation>イメージ (*.bmp *.png *.jpg *.jpeg) ファイル</translation>
</message>
-</context>
+</context>
+<context>
+ <name>SUIT_ShortcutMgr</name>
+ <message>
+ <source>General</source>
+ <translation>一般的な</translation>
+ </message>
+ <message>
+ <source>Invalid module IDs</source>
+ <translation>無効なモジュール ID</translation>
+ </message>
+ <message>
+ <source>Invalid shortcuts</source>
+ <translation>無効なショートカットです</translation>
+ </message>
+ <message>
+ <source>These shortcuts have not been set, because they conflict with previously parsed ones</source>
+ <translation>これらのショートカットは、以前に解析されたショートカットと競合するため、設定されていません</translation>
+ </message>
+ <message>
+ <source>Invalid shortcuts in preferences</source>
+ <translation>環境設定のショートカットが無効です</translation>
+ </message>
+ <message>
+ <source>Fix the following entries in the preference files manually</source>
+ <translation>設定ファイル内の次のエントリを手動で修正します</translation>
+ </message>
+</context>
</TS>
case SUIT_Accel::RotateLeft : return SVTK::RotateLeftEvent;
case SUIT_Accel::RotateRight : return SVTK::RotateRightEvent;
case SUIT_Accel::RotateUp : return SVTK::RotateUpEvent;
- case SUIT_Accel::RotateDown : return SVTK::RotateDownEvent;
+ case SUIT_Accel::RotateDown : return SVTK::RotateDownEvent;
}
return accelAction;
}
( getAction( ChangeRotationPointId ), this, "SVTK_SetRotationPointDlg" );
myViewParameterDlg = new SVTK_ViewParameterDlg
( getAction( ViewParametersId ), this, "SVTK_ViewParameterDlg" );
-
+
myDefaultInteractorStyle = SVTK_InteractorStyle::New();
myInteractor->PushInteractorStyle(myDefaultInteractorStyle);
myDefaultInteractorStyle->Delete();
-
+
myRecorder = SVTK_Recorder::New();
-
+
myRecorder->SetNbFPS( 17.3 );
myRecorder->SetQuality( 100 );
myRecorder->SetProgressiveMode( true );
myRecorder->SetUseSkippedFrames( true );
myRecorder->SetRenderWindow( myInteractor->getRenderWindow() );
-
+
setCentralWidget(myInteractor);
-
+
myAxesWidget = salomevtk::vtkPVAxesWidget::New();
myAxesWidget->SetParentRenderer(aRenderer->GetDevice());
myAxesWidget->SetViewport(0, 0, 0.25, 0.25);
/*!
\return corresponding view
*/
-SVTK_View* SVTK_ViewWindow::getView()
-{
- return myView;
+SVTK_View* SVTK_ViewWindow::getView()
+{
+ return myView;
}
/*!
\return corresponding vtk selector
*/
SVTK_Selector* SVTK_ViewWindow::GetSelector() const
-{
- return GetInteractor()->GetSelector();
+{
+ return GetInteractor()->GetSelector();
}
/*!
/*!
Unhilights all objects in viewer
*/
-void SVTK_ViewWindow::unHighlightAll()
+void SVTK_ViewWindow::unHighlightAll()
{
myView->unHighlightAll();
}
\param theIsHighlight - if it is true, object will be hilighted, otherwise it will be unhilighted
\param theIsUpdate - update current viewer
*/
-void SVTK_ViewWindow::highlight(const Handle(SALOME_InteractiveObject)& theIO,
- bool theIsHighlight,
- bool theIsUpdate )
+void SVTK_ViewWindow::highlight(const Handle(SALOME_InteractiveObject)& theIO,
+ bool theIsHighlight,
+ bool theIsUpdate )
{
myView->highlight( theIO, theIsHighlight, theIsUpdate );
}
\return true if object is in viewer or in collector
\param theIO - object to be checked
*/
-bool SVTK_ViewWindow::isInViewer( const Handle(SALOME_InteractiveObject)& theIO )
+bool SVTK_ViewWindow::isInViewer( const Handle(SALOME_InteractiveObject)& theIO )
{
return myView->isInViewer( theIO );
}
\return true if object is displayed in viewer
\param theIO - object to be checked
*/
-bool SVTK_ViewWindow::isVisible( const Handle(SALOME_InteractiveObject)& theIO )
+bool SVTK_ViewWindow::isVisible( const Handle(SALOME_InteractiveObject)& theIO )
{
return myView->isVisible( theIO );
}
Display object
\param theEntry - entry that corresponds to intractive objects
*/
-Handle(SALOME_InteractiveObject) SVTK_ViewWindow::FindIObject(const char* theEntry)
+Handle(SALOME_InteractiveObject) SVTK_ViewWindow::FindIObject(const char* theEntry)
{
return myView->FindIObject(theEntry);
}
\param theImmediatly - update viewer
*/
void SVTK_ViewWindow::Display(const Handle(SALOME_InteractiveObject)& theIO,
- bool theImmediatly)
+ bool theImmediatly)
{
myView->Display(theIO,theImmediatly);
}
\param theImmediatly - update viewer
*/
void SVTK_ViewWindow::Erase(const Handle(SALOME_InteractiveObject)& theIO,
- bool theImmediatly)
+ bool theImmediatly)
{
myView->Erase(theIO,theImmediatly);
}
Display only passed object
\param theIO - object
*/
-void SVTK_ViewWindow::DisplayOnly(const Handle(SALOME_InteractiveObject)& theIO)
+void SVTK_ViewWindow::DisplayOnly(const Handle(SALOME_InteractiveObject)& theIO)
{
myView->DisplayOnly(theIO);
}
/*!
Display all objects in view
*/
-void SVTK_ViewWindow::DisplayAll()
+void SVTK_ViewWindow::DisplayAll()
{
myView->DisplayAll();
}
/*!
Erase all objects in view
*/
-void SVTK_ViewWindow::EraseAll()
+void SVTK_ViewWindow::EraseAll()
{
myView->EraseAll();
}
*/
void SVTK_ViewWindow::Repaint(bool theUpdateTrihedron)
{
- if(theUpdateTrihedron)
+ if(theUpdateTrihedron)
GetRenderer()->OnAdjustTrihedron();
GetInteractor()->update();
if( GetRenderer() ) {
aStyle->SetCurrentRenderer(GetRenderer()->GetDevice());
}
- }
+ }
#endif
aStyle->OnTimer();
}
/*!
Redirect the request to #SVTK_Renderer::GetScale
*/
-void SVTK_ViewWindow::GetScale( double theScale[3] )
+void SVTK_ViewWindow::GetScale( double theScale[3] )
{
GetRenderer()->GetScale( theScale );
}
/*!
Redirect the request to #SVTK_Renderer::SetScale
*/
-void SVTK_ViewWindow::SetScale( double theScale[3] )
+void SVTK_ViewWindow::SetScale( double theScale[3] )
{
GetRenderer()->SetScale( theScale );
Repaint();
QtxAction* a = getAction( EnableSelectionId );
if ( a->isChecked() != theEnable)
a->setChecked( theEnable );
- QtxActionGroup* aPreselectionGroup =
+ QtxActionGroup* aPreselectionGroup =
dynamic_cast<QtxActionGroup*>( getAction( PreselectionId ) );
if ( aPreselectionGroup )
aPreselectionGroup->setEnabled( theEnable );
{
SVTK_Viewer* aViewer = dynamic_cast<SVTK_Viewer*>(myModel);
if(aViewer)
- aViewer->enableSelection(on);
+ aViewer->enableSelection(on);
}
/*!
\param theBtn2 - spacemouse button for the "increase speed increment"
\param theBtn3 - spacemouse button for the "dominant combined switch"
*/
-void SVTK_ViewWindow::SetSpacemouseButtons(const int theBtn1,
+void SVTK_ViewWindow::SetSpacemouseButtons(const int theBtn1,
const int theBtn2,
const int theBtn3)
{
Redirect the request to #SVTK_Renderer::OnAdjustTrihedron
*/
void SVTK_ViewWindow::onAdjustTrihedron()
-{
+{
GetRenderer()->OnAdjustTrihedron();
}
Redirect the request to #SVTK_Renderer::OnAdjustCubeAxes
*/
void SVTK_ViewWindow::onAdjustCubeAxes()
-{
+{
GetRenderer()->OnAdjustCubeAxes();
}
/*!
Redirect the request to #SVTK_Renderer::AddActor
*/
-void SVTK_ViewWindow::AddActor( VTKViewer_Actor* theActor,
+void SVTK_ViewWindow::AddActor( VTKViewer_Actor* theActor,
bool theUpdate,
bool theIsAdjustActors )
{
GetRenderer()->AddActor(theActor, theIsAdjustActors);
- if(theUpdate)
+ if(theUpdate)
Repaint();
emit actorAdded(theActor);
}
/*!
Redirect the request to #SVTK_Renderer::RemoveActor
*/
-void SVTK_ViewWindow::RemoveActor( VTKViewer_Actor* theActor,
+void SVTK_ViewWindow::RemoveActor( VTKViewer_Actor* theActor,
bool theUpdate,
bool theIsAdjustActors )
{
myDefaultInteractorStyle->FreeActors();
if ( myKeyFreeInteractorStyle )
myKeyFreeInteractorStyle->FreeActors();
- if(theUpdate)
+ if(theUpdate)
Repaint();
emit actorRemoved(theActor);
}
int* aSize = aWindow->GetSize();
int aWidth = aSize[0];
int aHeight = aSize[1];
-
+
#ifndef DISABLE_GLVIEWER
OpenGLUtils_FrameBuffer aFrameBuffer;
if( aFrameBuffer.init( aWidth, aHeight ) )
// draw scene
aWindow->Render();
-
+
//aFrameBuffer.unbind();
glPopAttrib();
#endif
// if frame buffers are unsupported, use old functionality
- unsigned char *aData =
+ unsigned char *aData =
aWindow->GetRGBACharPixelData( 0, 0, aWidth-1, aHeight-1, 0 );
-
+
QImage anImage( aData, aWidth, aHeight, QImage::Format_ARGB32 );
anImage = anImage.rgbSwapped();
{
if( myDumpImage.isNull() )
return dumpViewContent();
-
+
RefreshDumpImage();
return myDumpImage;
}
anExporter->SetSort((vtkGL2PSExporter::SortScheme)optionsDlg->getSortType());
anExporter->SetWrite3DPropsAsRasterImage((int)optionsDlg->isRasterize3D());
anExporter->SetPS3Shading((int)optionsDlg->isPs3Shading());
-
+
if ( format == "PS" ) {
anExporter->SetFileFormatToPS();
anExporter->CompressOff();
}
-
+
if ( format == "EPS" ) {
anExporter->SetFileFormatToEPS();
anExporter->CompressOff();
if ( format == "PDF" ) {
anExporter->SetFileFormatToPDF();
}
-
+
QString aFilePrefix(fileName);
QString anExtension(SUIT_Tools::extension(fileName));
aFilePrefix.truncate(aFilePrefix.length() - 1 - anExtension.length());
anExporter->Delete();
}
delete optionsDlg;
- return true;
+ return true;
}
/*!
/*!
Redirect the request to #SVTK_Renderer::SetSelectionProp
*/
-void SVTK_ViewWindow::SetSelectionProp(const double& theRed,
- const double& theGreen,
- const double& theBlue,
- const int& theWidth)
+void SVTK_ViewWindow::SetSelectionProp(const double& theRed,
+ const double& theGreen,
+ const double& theBlue,
+ const int& theWidth)
{
myView->SetSelectionProp(theRed,theGreen,theBlue,theWidth);
}
/*!
Redirect the request to #SVTK_Renderer::SetSelectionProp
*/
-void SVTK_ViewWindow::SetPreselectionProp(const double& theRed,
- const double& theGreen,
- const double& theBlue,
- const int& theWidth)
+void SVTK_ViewWindow::SetPreselectionProp(const double& theRed,
+ const double& theGreen,
+ const double& theBlue,
+ const int& theWidth)
{
myView->SetPreselectionProp(theRed,theGreen,theBlue,theWidth);
}
/*!
Redirect the request to #SVTK_Renderer::SetSelectionTolerance
*/
-void SVTK_ViewWindow::SetSelectionTolerance(const double& theTolNodes,
+void SVTK_ViewWindow::SetSelectionTolerance(const double& theTolNodes,
const double& theTolItems,
const double& theTolObjects)
{
}
-// old visual parameters had 13 values. New format added additional
+// old visual parameters had 13 values. New format added additional
// 76 values for graduated axes, so both numbers are processed.
const int nNormalParams = 13; // number of view windows parameters excluding graduated axes params
const int nGradAxisParams = 25; // number of parameters of ONE graduated axis (X, Y, or Z)
writer.writeEndElement();
writer.writeEndElement();
- //params.sprintf( "* Graduated Axis: * Name *%u*%s*%.2f*%.2f*%.2f*%u*%u*%u*%u", isVisible,
+ //params.sprintf( "* Graduated Axis: * Name *%u*%s*%.2f*%.2f*%.2f*%u*%u*%u*%u", isVisible,
// title.toLatin1().data(), color[0], color[1], color[2], font, bold, italic, shadow );
// Labels
writer.writeAttribute("B", QString("%1").arg(color[2]));
writer.writeEndElement();
writer.writeEndElement();
- // params += QString().sprintf( "* Labels *%u*%u*%u*%.2f*%.2f*%.2f*%u*%u*%u*%u", isVisible, labels, offset,
+ // params += QString().sprintf( "* Labels *%u*%u*%u*%.2f*%.2f*%.2f*%u*%u*%u*%u", isVisible, labels, offset,
// color[0], color[1], color[2], font, bold, italic, shadow );
// Tick marks
writer.writeAttribute("isVisible", QString("%1").arg(isVisible));
writer.writeAttribute("Length", QString("%1").arg(length));
writer.writeEndElement();
-
+
//params += QString().sprintf( "* Tick marks *%u*%u", isVisible, length );
-
+
writer.writeEndElement();
//return params;
}
do {
reader.readNext();
} while (!reader.isStartElement());
-
+
// Read title color
aAttr = reader.attributes();
do {
reader.readNext();
- } while (!reader.isStartElement());
+ } while (!reader.isStartElement());
// Read labels
aAttr = reader.attributes();
isVisible = aAttr.value("isVisible").toString().toUShort();
do {
reader.readNext();
- } while (!reader.isStartElement());
+ } while (!reader.isStartElement());
// Read Color
aAttr = reader.attributes();
// Tick Marks
do {
reader.readNext();
- } while (!reader.isStartElement());
+ } while (!reader.isStartElement());
aAttr = reader.attributes();
// retrieve and set tick marks properties
isVisible = aAttr.value("isVisible").toString().toUShort();
int length = aAttr.value("Length").toString().toInt();
-
+
actor->SetTickVisibility( isVisible );
actor->SetTickLength( length );
}
QString SVTK_ViewWindow::getVisualParameters()
{
double pos[3], focalPnt[3], viewUp[3], parScale, scale[3];
-
+
// save position, focal point, viewUp, scale
vtkCamera* camera = getRenderer()->GetActiveCamera();
camera->GetPosition( pos );
GetScale( scale );
// Parameters are given in the following format:view position (3 digits), focal point position (3 digits)
- // view up values (3 digits), parallel scale (1 digit), scale (3 digits,
+ // view up values (3 digits), parallel scale (1 digit), scale (3 digits,
// Graduated axes parameters (X, Y, Z axes parameters)
QString retStr;
QXmlStreamWriter aWriter(&retStr);
/*!
The method restores visual parameters of this view or postpones it untill the view is shown
-*/
+*/
void SVTK_ViewWindow::setVisualParameters( const QString& parameters )
{
//printf("#### %s\n", qPrintable(parameters));
SVTK_RenderWindowInteractor* anInteractor = GetInteractor();
if ( anInteractor->isVisible() ) {
- doSetVisualParameters( parameters );
+ doSetVisualParameters( parameters );
}
else {
myVisualParams = parameters;
QtxActionToolMgr* mgr = toolMgr();
// Dump view
- anAction = new QtxAction(tr("MNU_DUMP_VIEW"),
+ anAction = new QtxAction(tr("MNU_DUMP_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_DUMP" ) ),
tr( "MNU_DUMP_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_DUMP_VIEW"));
mgr->registerAction( anAction, DumpId );
// FitAll
- anAction = new QtxAction(tr("MNU_FITALL"),
+ anAction = new QtxAction(tr("MNU_FITALL"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_FITALL" ) ),
tr( "MNU_FITALL" ), 0, this);
anAction->setStatusTip(tr("DSC_FITALL"));
mgr->registerAction( anAction, FitAllId );
// FitRect
- anAction = new QtxAction(tr("MNU_FITRECT"),
+ anAction = new QtxAction(tr("MNU_FITRECT"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_FITAREA" ) ),
tr( "MNU_FITRECT" ), 0, this);
anAction->setStatusTip(tr("DSC_FITRECT"));
mgr->registerAction( anAction, FitSelectionId );
// Zoom
- anAction = new QtxAction(tr("MNU_ZOOM_VIEW"),
+ anAction = new QtxAction(tr("MNU_ZOOM_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_ZOOM" ) ),
tr( "MNU_ZOOM_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_ZOOM_VIEW"));
mgr->registerAction( anAction, ZoomId );
// Panning
- anAction = new QtxAction(tr("MNU_PAN_VIEW"),
+ anAction = new QtxAction(tr("MNU_PAN_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_PAN" ) ),
tr( "MNU_PAN_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_PAN_VIEW"));
mgr->registerAction( anAction, PanId );
// Global Panning
- anAction = new QtxAction(tr("MNU_GLOBALPAN_VIEW"),
+ anAction = new QtxAction(tr("MNU_GLOBALPAN_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_GLOBALPAN" ) ),
tr( "MNU_GLOBALPAN_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_GLOBALPAN_VIEW"));
mgr->registerAction( anAction, GlobalPanId );
// Change rotation point
- anAction = new QtxAction(tr("MNU_CHANGINGROTATIONPOINT_VIEW"),
+ anAction = new QtxAction(tr("MNU_CHANGINGROTATIONPOINT_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_ROTATION_POINT" ) ),
tr( "MNU_CHANGINGROTATIONPOINT_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_CHANGINGROTATIONPOINT_VIEW"));
mgr->registerAction( anAction, ChangeRotationPointId );
// Rotation
- anAction = new QtxAction(tr("MNU_ROTATE_VIEW"),
+ anAction = new QtxAction(tr("MNU_ROTATE_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_ROTATE" ) ),
tr( "MNU_ROTATE_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_ROTATE_VIEW"));
mgr->registerAction( anAction, RotationId );
// Projections
- anAction = new QtxAction(tr("MNU_FRONT_VIEW"),
+ anAction = new QtxAction(tr("MNU_FRONT_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_FRONT" ) ),
- tr( "MNU_FRONT_VIEW" ), 0, this, false, "Viewers:Front view");
+ tr( "MNU_FRONT_VIEW" ), 0, this, false, "/#Viewers/View/Set X-");
anAction->setStatusTip(tr("DSC_FRONT_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onFrontView()));
this->addAction(anAction);
anAction = new QtxAction(tr("MNU_BACK_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_BACK" ) ),
- tr( "MNU_BACK_VIEW" ), 0, this, false, "Viewers:Back view");
+ tr( "MNU_BACK_VIEW" ), 0, this, false, "/#Viewers/View/Set X+");
anAction->setStatusTip(tr("DSC_BACK_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onBackView()));
this->addAction(anAction);
anAction = new QtxAction(tr("MNU_TOP_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_TOP" ) ),
- tr( "MNU_TOP_VIEW" ), 0, this, false, "Viewers:Top view");
+ tr( "MNU_TOP_VIEW" ), 0, this, false, "/#Viewers/View/Set Z-");
anAction->setStatusTip(tr("DSC_TOP_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onTopView()));
this->addAction(anAction);
anAction = new QtxAction(tr("MNU_BOTTOM_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_BOTTOM" ) ),
- tr( "MNU_BOTTOM_VIEW" ), 0, this, false, "Viewers:Bottom view");
+ tr( "MNU_BOTTOM_VIEW" ), 0, this, false, "/#Viewers/View/Set Z+");
anAction->setStatusTip(tr("DSC_BOTTOM_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onBottomView()));
this->addAction(anAction);
anAction = new QtxAction(tr("MNU_LEFT_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_LEFT" ) ),
- tr( "MNU_LEFT_VIEW" ), 0, this, false, "Viewers:Left view");
+ tr( "MNU_LEFT_VIEW" ), 0, this, false, "/#Viewers/View/Set Y+");
anAction->setStatusTip(tr("DSC_LEFT_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onLeftView()));
this->addAction(anAction);
anAction = new QtxAction(tr("MNU_RIGHT_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_RIGHT" ) ),
- tr( "MNU_RIGHT_VIEW" ), 0, this, false, "Viewers:Right view");
+ tr( "MNU_RIGHT_VIEW" ), 0, this, false, "/#Viewers/View/Set Y-");
anAction->setStatusTip(tr("DSC_RIGHT_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onRightView()));
this->addAction(anAction);
// rotate anticlockwise
anAction = new QtxAction(tr("MNU_ANTICLOCKWISE_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_ANTICLOCKWISE" ) ),
- tr( "MNU_ANTICLOCKWISE_VIEW" ), 0, this, false, "Viewers:Rotate anticlockwise");
+ tr( "MNU_ANTICLOCKWISE_VIEW" ), 0, this, false, "/#Viewers/View/Rotate anticlockwise");
anAction->setStatusTip(tr("DSC_ANTICLOCKWISE_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onAntiClockWiseView()));
this->addAction(anAction);
// rotate clockwise
anAction = new QtxAction(tr("MNU_CLOCKWISE_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_CLOCKWISE" ) ),
- tr( "MNU_CLOCKWISE_VIEW" ), 0, this, false, "Viewers:Rotate clockwise");
+ tr( "MNU_CLOCKWISE_VIEW" ), 0, this, false, "/#Viewers/View/Rotate clockwise");
anAction->setStatusTip(tr("DSC_CLOCKWISE_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onClockWiseView()));
this->addAction(anAction);
mgr->registerAction( anAction, ClockWiseId );
// Reset
- anAction = new QtxAction(tr("MNU_RESET_VIEW"),
+ anAction = new QtxAction(tr("MNU_RESET_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_RESET" ) ),
- tr( "MNU_RESET_VIEW" ), 0, this, false, "Viewers:Reset view");
+ tr( "MNU_RESET_VIEW" ), 0, this, false, "/#Viewers/View/Reset");
anAction->setStatusTip(tr("DSC_RESET_VIEW"));
connect(anAction, SIGNAL(triggered()), this, SLOT(onResetView()));
this->addAction(anAction);
mgr->registerAction( anAction, ResetId );
// onViewTrihedron: Shows - Hides Trihedron
- anAction = new QtxAction(tr("MNU_SHOW_TRIHEDRON"),
+ anAction = new QtxAction(tr("MNU_SHOW_TRIHEDRON"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_VTKVIEWER_VIEW_TRIHEDRON" ) ),
tr( "MNU_SHOW_TRIHEDRON" ), 0, this);
anAction->setCheckable( true );
anAction->setChecked( true );
-
+
anAction->setStatusTip(tr("DSC_SHOW_TRIHEDRON"));
connect(anAction, SIGNAL(toggled(bool)), this, SLOT(onViewTrihedron(bool)));
mgr->registerAction( anAction, ViewTrihedronId );
// onNonIsometric: Manage non-isometric params
- anAction = new QtxAction(tr("MNU_SVTK_SCALING"),
+ anAction = new QtxAction(tr("MNU_SVTK_SCALING"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_SCALING" ) ),
tr( "MNU_SVTK_SCALING" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_SCALING"));
mgr->registerAction( anAction, NonIsometric );
// onGraduatedAxes: Manage graduated axes params
- anAction = new QtxAction(tr("MNU_SVTK_GRADUATED_AXES"),
+ anAction = new QtxAction(tr("MNU_SVTK_GRADUATED_AXES"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_GRADUATED_AXES" ) ),
tr( "MNU_SVTK_GRADUATED_AXES" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_GRADUATED_AXES"));
mgr->registerAction( anAction, GraduatedAxes );
// onGraduatedAxes: Manage graduated axes params
- anAction = new QtxAction(tr("MNU_SVTK_UPDATE_RATE"),
+ anAction = new QtxAction(tr("MNU_SVTK_UPDATE_RATE"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_UPDATE_RATE" ) ),
tr( "MNU_SVTK_UPDATE_RATE" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_UPDATE_RATE"));
mgr->registerAction( anAction, UpdateRate );
// Set perspective mode group
- anAction = new QtxAction(tr("MNU_SVTK_PARALLEL_MODE"),
+ anAction = new QtxAction(tr("MNU_SVTK_PARALLEL_MODE"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_VIEW_PARALLEL" ) ),
tr( "MNU_SVTK_PARALLEL_MODE" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_PARALLEL_MODE"));
anAction->setCheckable(true);
mgr->registerAction( anAction, ParallelModeId );
- anAction = new QtxAction(tr("MNU_SVTK_PERSPECTIVE_MODE"),
+ anAction = new QtxAction(tr("MNU_SVTK_PERSPECTIVE_MODE"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_VIEW_PERSPECTIVE" ) ),
tr( "MNU_SVTK_PERSPECTIVE_MODE" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_PERSPECTIVE_MODE"));
connect(aPerspectiveGroup, SIGNAL(triggered(QAction*)), this, SLOT(onProjectionMode(QAction*)));
// View Parameters
- anAction = new QtxAction(tr("MNU_VIEWPARAMETERS_VIEW"),
+ anAction = new QtxAction(tr("MNU_VIEWPARAMETERS_VIEW"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_VIEW_PARAMETERS" ) ),
tr( "MNU_VIEWPARAMETERS_VIEW" ), 0, this);
anAction->setStatusTip(tr("DSC_VIEWPARAMETERS_VIEW"));
connect(anAction, SIGNAL(toggled(bool)), this, SLOT(onViewParameters(bool)));
mgr->registerAction( anAction, ViewParametersId );
- // Synchronize View
+ // Synchronize View
mgr->registerAction( synchronizeAction(), SynchronizeId );
// Switch between interaction styles
- anAction = new QtxAction(tr("MNU_SVTK_STYLE_SWITCH"),
+ anAction = new QtxAction(tr("MNU_SVTK_STYLE_SWITCH"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_STYLE_SWITCH" ) ),
tr( "MNU_SVTK_STYLE_SWITCH" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_STYLE_SWITCH"));
mgr->registerAction( anAction, SwitchInteractionStyleId );
// Switch between zooming styles
- anAction = new QtxAction(tr("MNU_SVTK_ZOOMING_STYLE_SWITCH"),
+ anAction = new QtxAction(tr("MNU_SVTK_ZOOMING_STYLE_SWITCH"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_ZOOMING_STYLE_SWITCH" ) ),
tr( "MNU_SVTK_ZOOMING_STYLE_SWITCH" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_ZOOMING_STYLE_SWITCH"));
QSignalMapper* aSignalMapper = new QSignalMapper( this );
connect(aSignalMapper, SIGNAL(mapped(int)), this, SLOT(onSwitchPreSelectionMode(int)));
- anAction = new QtxAction(tr("MNU_SVTK_PRESELECTION_STANDARD"),
+ anAction = new QtxAction(tr("MNU_SVTK_PRESELECTION_STANDARD"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_PRESELECTION_STANDARD" ) ),
tr( "MNU_SVTK_PRESELECTION_STANDARD" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_PRESELECTION_STANDARD"));
connect(anAction, SIGNAL(triggered()), aSignalMapper, SLOT(map()));
aSignalMapper->setMapping( anAction, Standard_Preselection );
mgr->registerAction( anAction, StandardPreselectionId );
-
- anAction = new QtxAction(tr("MNU_SVTK_PRESELECTION_DYNAMIC"),
+
+ anAction = new QtxAction(tr("MNU_SVTK_PRESELECTION_DYNAMIC"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_PRESELECTION_DYNAMIC" ) ),
tr( "MNU_SVTK_PRESELECTION_DYNAMIC" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_PRESELECTION_DYNAMIC"));
aSignalMapper->setMapping( anAction, Dynamic_Preselection );
mgr->registerAction( anAction, DynamicPreselectionId );
- anAction = new QtxAction(tr("MNU_SVTK_PRESELECTION_DISABLED"),
+ anAction = new QtxAction(tr("MNU_SVTK_PRESELECTION_DISABLED"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_PRESELECTION_DISABLED" ) ),
tr( "MNU_SVTK_PRESELECTION_DISABLED" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_PRESELECTION_DISABLED"));
mgr->registerAction( aPreselectionAction, PreselectionId );
// Selection
- anAction = new QtxAction(tr("MNU_SVTK_ENABLE_SELECTION"),
+ anAction = new QtxAction(tr("MNU_SVTK_ENABLE_SELECTION"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_SELECTION" ) ),
tr( "MNU_SVTK_ENABLE_SELECTION" ), 0, this);
anAction->setStatusTip(tr("DSC_SVTK_ENABLE_SELECTION"));
mgr->registerAction( anAction, EnableSelectionId );
// Start recording
- myStartAction = new QtxAction(tr("MNU_SVTK_RECORDING_START"),
+ myStartAction = new QtxAction(tr("MNU_SVTK_RECORDING_START"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_RECORDING_START" ) ),
tr( "MNU_SVTK_RECORDING_START" ), 0, this);
myStartAction->setStatusTip(tr("DSC_SVTK_RECORDING_START"));
mgr->registerAction( myStartAction, StartRecordingId );
// Play recording
- myPlayAction = new QtxAction(tr("MNU_SVTK_RECORDING_PLAY"),
+ myPlayAction = new QtxAction(tr("MNU_SVTK_RECORDING_PLAY"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_RECORDING_PLAY" ) ),
tr( "MNU_SVTK_RECORDING_PLAY" ), 0, this);
myPlayAction->setStatusTip(tr("DSC_SVTK_RECORDING_PLAY"));
mgr->registerAction( myPlayAction, PlayRecordingId );
// Pause recording
- myPauseAction = new QtxAction(tr("MNU_SVTK_RECORDING_PAUSE"),
+ myPauseAction = new QtxAction(tr("MNU_SVTK_RECORDING_PAUSE"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_RECORDING_PAUSE" ) ),
tr( "MNU_SVTK_RECORDING_PAUSE" ), 0, this);
myPauseAction->setStatusTip(tr("DSC_SVTK_RECORDING_PAUSE"));
mgr->registerAction( myPauseAction, PauseRecordingId );
// Stop recording
- myStopAction = new QtxAction(tr("MNU_SVTK_RECORDING_STOP"),
+ myStopAction = new QtxAction(tr("MNU_SVTK_RECORDING_STOP"),
theResourceMgr->loadPixmap( "VTKViewer", tr( "ICON_SVTK_RECORDING_STOP" ) ),
tr( "MNU_SVTK_RECORDING_STOP" ), 0, this);
myStopAction->setStatusTip(tr("DSC_SVTK_RECORDING_STOP"));
void SVTK_ViewWindow::createToolBar()
{
QtxActionToolMgr* mgr = toolMgr();
-
+
mgr->append( DumpId, myToolBar );
mgr->append( SwitchInteractionStyleId, myToolBar );
mgr->append( SwitchZoomingStyleId, myToolBar );
mgr->append( mgr->separator(), myToolBar );
-
+
mgr->append( PreselectionId, myToolBar );
mgr->append( EnableSelectionId, myToolBar );
/*!
Custom show event handler
*/
-void SVTK_ViewWindow::showEvent( QShowEvent * theEvent )
+void SVTK_ViewWindow::showEvent( QShowEvent * theEvent )
{
emit Show( theEvent );
}
/*!
Custom hide event handler
*/
-void SVTK_ViewWindow::hideEvent( QHideEvent * theEvent )
+void SVTK_ViewWindow::hideEvent( QHideEvent * theEvent )
{
emit Hide( theEvent );
}
vtkCamera* aCamera = getRenderer()->GetActiveCamera();
if ( !aCamera )
return aProps;
-
+
aProps.setDimension( SUIT_CameraProperties::Dim3D );
if ( toolMgr()->action( ParallelModeId ) ) {
if ( toolMgr()->action( ParallelModeId )->isChecked() )
aCamera->GetFocalPoint( aFocalPoint );
aCamera->GetPosition( aPosition );
aCamera->GetViewUp( aViewUp );
-
+
aProps.setFocalPoint( aFocalPoint[0], aFocalPoint[1], aFocalPoint[2] );
aProps.setPosition( aPosition[0], aPosition[1], aPosition[2] );
aProps.setViewUp( aViewUp[0], aViewUp[1], aViewUp[2] );
GetRenderer()->GetScale( anAxialScale );
aProps.setAxialScale( anAxialScale[0], anAxialScale[1], anAxialScale[2] );
-
+
return aProps;
}
// get camera
vtkCamera* aCamera = getRenderer()->GetActiveCamera();
-
+
double aFocalPoint[3];
double aPosition[3];
double aViewUp[3];
aProps.getPosition( aPosition[0], aPosition[1], aPosition[2] );
aProps.getFocalPoint( aFocalPoint[0], aFocalPoint[1], aFocalPoint[2] );
aProps.getAxialScale( anAxialScale[0], anAxialScale[1], anAxialScale[2] );
-
+
// restore properties to the camera
aCamera->SetViewUp( aViewUp );
aCamera->SetPosition( aPosition );