1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "QtxShortcutEdit.h"
26 #include <QToolButton>
28 #include <QTableWidgetItem>
29 #include <QMessageBox>
32 #include <QKeySequence>
34 #define COLUMN_SIZE 500
36 static const char* delete_icon[] = {
61 \param parent parent widget
63 QtxShortcutEdit::QtxShortcutEdit( QWidget* parent )
67 myShortcut->installEventFilter(this);
73 QtxShortcutEdit::~QtxShortcutEdit()
78 \brief Sets custom shortcut
79 \param seq a key sequence describes a combination of keys
82 void QtxShortcutEdit::setShortcut( const QKeySequence& seq )
84 QString txt = seq.toString();
85 myPrevShortcutText = txt;
86 myShortcut->setText( txt );
90 \brief Gets custom shortcut
91 \return a key sequence describes a combination of keys
94 QKeySequence QtxShortcutEdit::shortcut()
96 return QKeySequence::fromString( myShortcut->text() );
100 \brief Gets the key sequence from keys that were pressed
102 \return a string representation of the key sequence
104 QString QtxShortcutEdit::parseEvent( QKeyEvent* e )
106 bool isShiftPressed = e->modifiers() & Qt::ShiftModifier;
107 bool isControlPressed = e->modifiers() & Qt::ControlModifier;
108 bool isAltPressed = e->modifiers() & Qt::AltModifier;
109 bool isMetaPressed = e->modifiers() & Qt::MetaModifier;
110 bool isModifiersPressed = isShiftPressed || isControlPressed || isAltPressed || isMetaPressed;
112 if( isControlPressed )
122 if ( ( isValidKey( aKey ) && isModifiersPressed ) || ( ( aKey >= Qt::Key_F1 ) && ( aKey <= Qt::Key_F12 ) ) )
125 return QKeySequence( result ).toString();
129 \brief Check if the key event contains a 'valid' key
130 \param aKey the code of the key
131 \return \c true if the key is 'valid'
134 bool QtxShortcutEdit::isValidKey( int aKey )
136 if ( aKey == Qt::Key_Underscore || aKey == Qt::Key_Escape ||
137 ( aKey >= Qt::Key_Backspace && aKey <= Qt::Key_Delete ) ||
138 ( aKey >= Qt::Key_Home && aKey <= Qt::Key_PageDown ) ||
139 ( aKey >= Qt::Key_F1 && aKey <= Qt::Key_F12 ) ||
140 ( aKey >= Qt::Key_Space && aKey <= Qt::Key_Asterisk ) ||
141 ( aKey >= Qt::Key_Comma && aKey <= Qt::Key_Question ) ||
142 ( aKey >= Qt::Key_A && aKey <= Qt::Key_AsciiTilde ) )
148 \brief Called when "Clear" button is clicked.
150 void QtxShortcutEdit::onCliked()
152 myShortcut->setText( "" );
156 \brief Called when myShortcut loses focus.
158 void QtxShortcutEdit::onEditingFinished()
160 if ( myShortcut->text().endsWith("+") )
161 myShortcut->setText( myPrevShortcutText );
165 \brief Custom event filter.
166 \param obj event receiver object
168 \return \c true if further event processing should be stopped
170 bool QtxShortcutEdit::eventFilter(QObject* obj, QEvent* event)
172 if ( obj == myShortcut ) {
173 if (event->type() == QEvent::KeyPress ) {
174 QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
175 QString text = parseEvent( keyEvent );
176 if ( keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace )
179 myShortcut->setText( text );
182 if ( event->type() == QEvent::KeyRelease ) {
183 if ( myShortcut->text().endsWith("+") )
184 myShortcut->setText( myPrevShortcutText );
185 else myPrevShortcutText = myShortcut->text();
194 \brief Perform internal intialization.
196 void QtxShortcutEdit::initialize()
198 myPrevShortcutText = QString();
200 QHBoxLayout* base = new QHBoxLayout( this );
201 base->setMargin( 0 );
202 base->setSpacing( 5 );
204 base->addWidget( myShortcut = new QLineEdit( this ) );
206 QToolButton* deleteBtn = new QToolButton();
207 deleteBtn->setIcon( QPixmap( delete_icon ) );
208 base->addWidget( deleteBtn );
210 myShortcut->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
211 deleteBtn->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
213 connect( deleteBtn, SIGNAL( clicked() ), this, SLOT( onCliked() ) );
214 connect( myShortcut, SIGNAL( editingFinished() ), this, SLOT( onEditingFinished() ) );
219 \param parent parent widget
221 QtxShortcutTree::QtxShortcutTree( QWidget * parent ) : QTreeWidget( parent )
224 setSelectionMode( QAbstractItemView::SingleSelection );
225 setColumnWidth ( 0, COLUMN_SIZE);
226 setSortingEnabled(false);
227 headerItem()->setHidden ( true );
229 this->installEventFilter(this);
230 connect( this, SIGNAL( currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( onCurrentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem* ) ) );
237 QtxShortcutTree::~QtxShortcutTree(){}
240 \brief Custom event filter.
241 \param obj event receiver object
243 \return \c true if further event processing should be stopped
245 bool QtxShortcutTree::eventFilter(QObject* obj, QEvent* event)
247 if ( currentItem() && currentItem()->isSelected() ) {
249 if (event->type() == QEvent::KeyPress ) {
250 QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
251 QString text = QtxShortcutEdit::parseEvent( keyEvent );
252 if ( keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace )
253 currentItem()->setText( 1, "" );
255 if ( text.endsWith( "+" ) || checkUniqueness( currentItem(), text ) )
256 currentItem()->setText( 1, text );
260 if ( event->type() == QEvent::KeyRelease ) {
261 if ( currentItem()->text( 1 ).endsWith( "+" ) )
262 currentItem()->setText( 1, myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] );
263 else myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] = currentItem()->text( 1 );
272 \brief Called when the current item changes.
273 \param cur the current item
274 \param prev the previous current item
276 void QtxShortcutTree::onCurrentItemChanged( QTreeWidgetItem* cur, QTreeWidgetItem* prev )
278 if ( prev && prev->text( 1 ).endsWith( "+" ) )
279 prev->setText( 1, myPrevBindings[ prev->parent()->text( 0 ) ][ prev->text( 0 ) ] );
283 \brief Set key bindings to the tree
284 \param title the name of top-level item
285 \param theShortcutMap map of key bindings
287 void QtxShortcutTree::setBindings( const QString& title, const ShortcutMap& theShortcutMap )
289 QTreeWidgetItem* item= new QTreeWidgetItem();
290 QFont font = item->font(0);
293 if ( findItems( title, Qt::MatchFixedString ).isEmpty() ) {
294 item->setText( 0, title );
295 item->setFont( 0, font );
296 addTopLevelItem( item );
297 item->setFlags( Qt::ItemIsEnabled );
299 item = findItems( title, Qt::MatchFixedString ).first();
300 item->takeChildren();
302 for( ShortcutMap::const_iterator it = theShortcutMap.constBegin(); it != theShortcutMap.constEnd(); ++it )
303 item->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
304 myPrevBindings.insert( title, theShortcutMap);
308 \brief Get all sections names.
309 \return list of section names
311 QStringList QtxShortcutTree::sections() const
314 for( int i = 0; i < topLevelItemCount(); i++ )
315 lst << topLevelItem( i )->text( 0 );
319 ShortcutMap* QtxShortcutTree::bindings( const QString& sec ) const
321 ShortcutMap* aMap = new ShortcutMap();
322 QTreeWidgetItem* item = findItems( sec, Qt::MatchFixedString ).first();
323 int nbChildren = item->childCount();
325 for( int i = 0; i < nbChildren; i++ ) {
326 QTreeWidgetItem* child = item->child(i);
327 aMap->insert( child->text( 0 ), child->text( 1 ) );
333 void QtxShortcutTree::focusOutEvent ( QFocusEvent* event )
335 QWidget::focusOutEvent( event );
336 if ( currentItem() && currentItem()->isSelected() )
337 currentItem()->setText( 1, myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] );
341 \brief Set the list of shortcuts general sections.
343 Key combinations in general sections should not intersect
344 with any other key combinations.
346 \param sectionsList list of common section names
348 void QtxShortcutTree::setGeneralSections( const QStringList& sectionsList )
350 myGeneralSections = sectionsList;
354 \brief Check uniqueness of the shortcut.
355 \param item current item of the shortcut tree
356 \param shortcut shortcut appointed for the current item
357 \return \c true if the given shortcut is allowed
359 bool QtxShortcutTree::checkUniqueness( QTreeWidgetItem* item, const QString& shortcut )
361 // List of sections to check shortcut intersections
362 QStringList sectionsList;
365 QString currentSection = currentItem()->parent()->text( 0 );
367 // If the current section is general
368 if ( myGeneralSections.contains(currentSection) ) {
369 sectionsList = sections();
370 int currentSectionIndex = sectionsList.indexOf(currentSection);
371 sectionsList.move( currentSectionIndex, 0);
374 sectionsList = myGeneralSections;
375 sectionsList.prepend(currentSection);
378 // Iterate on sections
379 QStringList::const_iterator it;
380 for( it = sectionsList.constBegin(); it != sectionsList.constEnd(); ++it ) {
381 QString section = *it;
383 // Iterate on actual section
384 QTreeWidgetItem* sectionRoot = findItems( section, Qt::MatchFixedString ).first();
385 int nbChildren = sectionRoot->childCount();
387 for( int i = 0; i < nbChildren; i++ ) {
388 QTreeWidgetItem* child = sectionRoot->child(i);
390 if ( (child != item) && (shortcut == child->text( 1 )) ) {
391 bool res = QMessageBox::warning( parentWidget(), tr("Warning"),
392 tr("The \"%1\" shortcut has already used by the \"%2\" action.\n")
393 .arg(shortcut, section + ":" + child->text( 0 ) ) +
394 tr("Do you want to reassign it from that action to the current one?"),
395 QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
397 child->setText( 1, "" );