diff options
Diffstat (limited to 'tdevdesigner/designer/popupmenueditor.cpp')
-rw-r--r-- | tdevdesigner/designer/popupmenueditor.cpp | 1469 |
1 files changed, 1469 insertions, 0 deletions
diff --git a/tdevdesigner/designer/popupmenueditor.cpp b/tdevdesigner/designer/popupmenueditor.cpp new file mode 100644 index 00000000..da6289dd --- /dev/null +++ b/tdevdesigner/designer/popupmenueditor.cpp @@ -0,0 +1,1469 @@ +/********************************************************************** +** Copyright (C) 2003 Trolltech AS. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** See http://www.trolltech.com/pricing.html or email [email protected] for +** information about TQt Commercial License Agreements. +** +** Contact [email protected] if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include <tqapplication.h> +#include <tqcstring.h> +#include <tqdatastream.h> +#include <tqdragobject.h> +#include <tqlineedit.h> +#include <tqobjectlist.h> +#include <tqpainter.h> +#include <tqpopupmenu.h> +#include <tqrect.h> +#include <tqsize.h> +#include <tqstyle.h> +#include <tqtimer.h> +#include "actiondnd.h" +#include "actioneditorimpl.h" +#include "command.h" +#include "formfile.h" +#include "formwindow.h" +#include "mainwindow.h" +#include "metadatabase.h" +#include "pixmapchooser.h" +#include "popupmenueditor.h" +#include "menubareditor.h" + +#include <tdelocale.h> + +// Drag Object Declaration ------------------------------------------- + +class PopupMenuEditorItemPtrDrag : public TQStoredDrag +{ +public: + PopupMenuEditorItemPtrDrag( PopupMenuEditorItem * item, TQWidget * parent = 0, + const char * name = 0 ); + ~PopupMenuEditorItemPtrDrag() {}; + static bool canDecode( TQDragMoveEvent * e ); + static bool decode( TQDropEvent * e, PopupMenuEditorItem ** i ); +}; + +// Drag Object Implementation --------------------------------------- + +PopupMenuEditorItemPtrDrag::PopupMenuEditorItemPtrDrag( PopupMenuEditorItem * item, + TQWidget * parent, const char * name ) + : TQStoredDrag( "qt/popupmenueditoritemptr", parent, name ) +{ + TQByteArray data( sizeof( TQ_LONG ) ); + TQDataStream stream( data, IO_WriteOnly ); + stream << ( TQ_LONG ) item; + setEncodedData( data ); +} + +bool PopupMenuEditorItemPtrDrag::canDecode( TQDragMoveEvent * e ) +{ + return e->provides( "qt/popupmenueditoritemptr" ); +} + +bool PopupMenuEditorItemPtrDrag::decode( TQDropEvent * e, PopupMenuEditorItem ** i ) +{ + TQByteArray data = e->encodedData( "qt/popupmenueditoritemptr" ); + TQDataStream stream( data, IO_ReadOnly ); + + if ( !data.size() ) + return FALSE; + + TQ_LONG p = 0; + stream >> p; + *i = ( PopupMenuEditorItem *) p; + + return TRUE; +} + +// PopupMenuEditorItem Implementation ----------------------------------- + +PopupMenuEditorItem::PopupMenuEditorItem( PopupMenuEditor * menu, TQObject * parent, const char * name ) + : TQObject( parent, name ), + a( 0 ), + s( 0 ), + m( menu ), + separator( FALSE ), + removable( FALSE ) +{ + init(); + a = new TQAction( this ); + TQObject::connect( a, TQT_SIGNAL( destroyed() ), this, TQT_SLOT( selfDestruct() ) ); +} + + +PopupMenuEditorItem::PopupMenuEditorItem( TQAction * action, PopupMenuEditor * menu, + TQObject * parent, const char * name ) + : TQObject( parent, name ), + a( action ), + s( 0 ), + m( menu ), + separator( FALSE ), + removable( TRUE ) +{ + init(); + if ( /*a->name() == "qt_separator_action" ||*/ ::tqqt_cast<QSeparatorAction*>(a) ) + separator = TRUE; + if ( a && !a->childrenListObject().isEmpty() ) + a->installEventFilter( this ); +} + +PopupMenuEditorItem::PopupMenuEditorItem( PopupMenuEditorItem * item, PopupMenuEditor * menu, + TQObject * parent, const char * name ) + : TQObject( parent, name ), + a( item->a ), + s( 0 ), + m( menu ), + separator( item->separator ), + removable( item->removable ) +{ + init(); + if ( ::tqqt_cast<TQActionGroup*>(a) ) + a->installEventFilter( this ); +} + +PopupMenuEditorItem::~PopupMenuEditorItem() +{ + +} + +void PopupMenuEditorItem::init() +{ + if ( a ) { + TQObject::connect( a, TQT_SIGNAL( destroyed() ), this, TQT_SLOT( selfDestruct() ) ); + if ( m && !isSeparator() ) { + s = new PopupMenuEditor( m->formWindow(), m ); + TQString n = "PopupMenuEditor"; + m->formWindow()->unify( TQT_TQOBJECT(s), n, TRUE ); + s->setName( n ); + MetaDataBase::addEntry( TQT_TQOBJECT(s) ); + } + } +} + +PopupMenuEditorItem::ItemType PopupMenuEditorItem::type() const +{ + if ( separator ) + return Separator; + else if ( a ) + return Action; + return Unknown; +} + +void PopupMenuEditorItem::setVisible( bool enable ) +{ + if ( a ) + a->setVisible( enable ); +} + +bool PopupMenuEditorItem::isVisible() const +{ + TQActionGroup *g = ::tqqt_cast<TQActionGroup*>(a); + if ( g ) + return ( g->isVisible() && g->usesDropDown() ); + else if ( a ) + return a->isVisible(); + return FALSE; +} + +void PopupMenuEditorItem::showMenu( int x, int y ) +{ + if ( ( !separator ) && s ) { + s->move( x, y ); + s->show(); + s->raise(); + } +} + +void PopupMenuEditorItem::hideMenu() +{ + if ( s ) { + s->hideSubMenu(); + s->hide(); + } +} + +void PopupMenuEditorItem::focusOnMenu() +{ + if ( s ) { + s->showSubMenu(); + s->setFocus(); + } +} + +int PopupMenuEditorItem::count() const +{ + if ( s ) { + return s->count(); + } else if ( ::tqqt_cast<TQActionGroup*>(a) ) { + const TQObjectList l = a->childrenListObject(); + if ( !l.isEmpty() ) + return l.count(); + } + return 0; +} + +bool PopupMenuEditorItem::eventFilter( TQObject * o, TQEvent * event ) +{ + if ( ! ::tqqt_cast<TQActionGroup*>( o ) ) + return FALSE; + if ( event->type() == TQEvent::ChildInserted ) { + TQChildEvent * ce = ( TQChildEvent * ) event; + TQObject * c = TQT_TQOBJECT(ce->child()); + TQAction * action = ::tqqt_cast<TQAction*>( c ); + if ( s->find( action ) != -1 ) // avoid duplicates + return FALSE; + TQActionGroup * actionGroup = ::tqqt_cast<TQActionGroup*>( c ); + if ( actionGroup ) + s->insert( actionGroup ); + else if ( action ) + s->insert( action ); + } + return FALSE; +} + +void PopupMenuEditorItem::selfDestruct() +{ + hideMenu(); + int i = m->find( s ); + if ( i != -1 && i < m->count() ) + m->remove( i ); // remove this item + a = 0; // the selfDestruct call was caused by the deletion of the action + delete this; +} + +// PopupMenuEditor Implementation ----------------------------------- + +PopupMenuEditorItem * PopupMenuEditor::draggedItem = 0; +int PopupMenuEditor::clipboardOperation = 0; +PopupMenuEditorItem * PopupMenuEditor::clipboardItem = 0; + +PopupMenuEditor::PopupMenuEditor( FormWindow * fw, TQWidget * parent, const char * name ) + : TQWidget( 0, name, WStyle_Customize | WStyle_NoBorder | WRepaintNoErase | WResizeNoErase ), + formWnd( fw ), + parentMenu( parent ), + iconWidth( 0 ), + textWidth( 0 ), + accelWidth( 0 ), + arrowWidth( 30 ), + borderSize( 2 ), + currentField( 1 ), + currentIndex( 0 ) +{ + init(); +} + +PopupMenuEditor::PopupMenuEditor( FormWindow * fw, PopupMenuEditor * menu, + TQWidget * parent, const char * name ) + : TQWidget( 0, name, WStyle_Customize | WStyle_NoBorder | WRepaintNoErase ), + formWnd( fw ), + parentMenu( parent ), + iconWidth( menu->iconWidth ), + textWidth( menu->textWidth ), + accelWidth( menu->accelWidth ), + arrowWidth( menu->arrowWidth ), + borderSize( menu->borderSize ), + currentField( menu->currentField ), + currentIndex( menu->currentIndex ) +{ + init(); + PopupMenuEditorItem * i; + for ( i = menu->itemList.first(); i; i = menu->itemList.next() ) { + PopupMenuEditorItem * n = new PopupMenuEditorItem( i, this ); + itemList.append( n ); + } +} + +PopupMenuEditor::~PopupMenuEditor() +{ + itemList.setAutoDelete( TRUE ); +} + +void PopupMenuEditor::init() +{ + reparent( ( TQMainWindow * ) formWnd->mainContainer(), pos() ); + + addItem.action()->setMenuText( i18n("new item") ); + addSeparator.action()->setMenuText( i18n("new separator") ); + + setAcceptDrops( TRUE ); + setFocusPolicy( TQ_StrongFocus ); + + lineEdit = new TQLineEdit( this ); + lineEdit->hide(); + lineEdit->setFrameStyle(TQFrame::Plain | TQFrame::NoFrame); + lineEdit->polish(); + lineEdit->setBackgroundOrigin(ParentOrigin); + lineEdit->setBackgroundMode(PaletteButton); + lineEdit->installEventFilter( this ); + + dropLine = new TQWidget( this, 0, TQt::WStyle_NoBorder | WStyle_StaysOnTop ); + dropLine->setBackgroundColor( TQt::red ); + dropLine->hide(); + + hide(); +} + +void PopupMenuEditor::insert( PopupMenuEditorItem * item, int index ) +{ + if ( !item ) + return; + if ( index == -1 ) { + itemList.append( item ); + if ( isVisible() ) + currentIndex = itemList.count() - 1; + } else { + itemList.insert( index, item ); + if ( isVisible() ) + currentIndex = index; + } + item->m = this; + item->s->parentMenu = this; + resizeToContents(); + if ( isVisible() && parentMenu ) + parentMenu->update(); // draw arrow in parent menu + emit inserted( item->action() ); +} + +void PopupMenuEditor::insert( TQAction * action, int index ) +{ + if ( !action ) + return; + insert( new PopupMenuEditorItem( action, this, 0, action->name() ), index ); +} + +void PopupMenuEditor::insert( TQActionGroup * actionGroup, int index ) +{ + if ( !actionGroup ) + return; + bool dropdown = actionGroup->usesDropDown(); + PopupMenuEditorItem *i = new PopupMenuEditorItem( (TQAction *)actionGroup, this, 0, + TQString( actionGroup->name() ) + "Menu" ); + TQActionGroup *g = 0; + TQObjectList *l = actionGroup->queryList( TQACTION_OBJECT_NAME_STRING, 0, FALSE, FALSE ); + TQObjectListIterator it( *l ); + insert( i, index ); + for ( ; it.current(); ++it ) { + g = ::tqqt_cast<TQActionGroup*>(it.current()); + if ( g ) { + if ( dropdown ) + i->s->insert( g ); + else + insert( g ); + } else { + i->s->insert( (TQAction*)it.current() ); + } + } + delete l; +} + +int PopupMenuEditor::find( const TQAction * action ) +{ + PopupMenuEditorItem * i = itemList.first(); + while ( i ) { + if ( i->action() == action ) + return itemList.at(); + i = itemList.next(); + } + return -1; +} + +int PopupMenuEditor::find( PopupMenuEditor * menu ) +{ + PopupMenuEditorItem * i = itemList.first(); + while ( i ) { + if ( i->subMenu() == menu ) + return itemList.at(); + i = itemList.next(); + } + return -1; +} + +int PopupMenuEditor::count() +{ + return itemList.count(); +} + +PopupMenuEditorItem * PopupMenuEditor::at( int index ) +{ + return itemList.at( index ); +} + +void PopupMenuEditor::exchange( int a, int b ) +{ + PopupMenuEditorItem * ia = itemList.at( a ); + PopupMenuEditorItem * ib = itemList.at( b ); + if ( !ia || !ib || + ia == &addItem || ia == &addSeparator || + ib == &addItem || ib == &addSeparator ) + return; // do nothing + itemList.replace( b, ia ); + itemList.replace( a, ib ); +} + +void PopupMenuEditor::cut( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + + if ( clipboardItem && clipboardOperation == Cut ) + delete clipboardItem; + + clipboardOperation = Cut; + clipboardItem = itemList.at( idx ); + + if ( clipboardItem == &addItem || clipboardItem == &addSeparator ) { + clipboardOperation = None; + clipboardItem = 0; + return; // do nothing + } + + RemoveActionFromPopupCommand * cmd = + new RemoveActionFromPopupCommand( i18n( "Cut Item" ), formWnd, this, idx ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); +} + +void PopupMenuEditor::copy( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + + if ( clipboardItem && clipboardOperation == Cut ) + delete clipboardItem; + + clipboardOperation = Copy; + clipboardItem = itemList.at( idx ); + + if ( clipboardItem == &addItem || clipboardItem == &addSeparator ) { + clipboardOperation = None; + clipboardItem = 0; + } +} + +void PopupMenuEditor::paste( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + + if ( clipboardItem && clipboardOperation ) { + PopupMenuEditorItem * n = new PopupMenuEditorItem( clipboardItem, this ); + AddActionToPopupCommand * cmd = + new AddActionToPopupCommand( i18n( "Paste Item" ), formWnd, this, n, idx ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + } +} + +void PopupMenuEditor::insertedActions( TQPtrList<TQAction> & list ) +{ + TQAction * a = 0; + PopupMenuEditorItem * i = itemList.first(); + + while ( i ) { + a = i->action(); + if ( a ) + list.append( a ); + i = itemList.next(); + } +} + +void PopupMenuEditor::show() +{ + resizeToContents(); + TQWidget::show(); +} + +void PopupMenuEditor::choosePixmap( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + + PopupMenuEditorItem * i = 0; + TQAction * a = 0; + + if ( idx < (int)itemList.count() ) { + i = itemList.at( idx ); + a = i->action(); + } else { + createItem(); + } + + hide(); // qChoosePixmap hides the menu + TQIconSet icons( qChoosePixmap( 0, formWnd, 0, 0 ) ); + SetActionIconsCommand * cmd = + new SetActionIconsCommand( i18n( "Set Icon" ), formWnd, a, this, icons ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + show(); + setFocus(); +} + +void PopupMenuEditor::showLineEdit( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + + PopupMenuEditorItem * i = 0; + + if ( idx >= (int)itemList.count() ) + i = &addItem; + else + i = itemList.at( idx ); + + // open edit currentField for item name + lineEdit->setText( i->action()->menuText() ); + lineEdit->selectAll(); + lineEdit->setGeometry( borderSize + iconWidth, borderSize + itemPos( i ), + textWidth, itemHeight( i ) ); + lineEdit->show(); + lineEdit->setFocus(); +} + +void PopupMenuEditor::setAccelerator( int key, TQt::ButtonState state, int index ) +{ + // FIXME: make this a command + + int idx = ( index == -1 ? currentIndex : index ); + + if ( key == TQt::Key_Shift || + key == TQt::Key_Control || + key == TQt::Key_Alt || + key == TQt::Key_Meta || + key == TQt::Key_unknown ) + return; // ignore these keys when they are pressed + + PopupMenuEditorItem * i = 0; + + if ( idx >= (int)itemList.count() ) + i = createItem(); + else + i = itemList.at( idx ); + + int shift = ( state & TQt::ShiftButton ? TQt::SHIFT : 0 ); + int ctrl = ( state & TQt::ControlButton ? TQt::CTRL : 0 ); + int alt = ( state & TQt::AltButton ? TQt::ALT : 0 ); + int meta = ( state & TQt::MetaButton ? TQt::META : 0 ); + + TQAction * a = i->action(); + TQKeySequence ks = a->accel(); + int keys[4] = { ks[0], ks[1], ks[2], ks[3] }; + int n = 0; + while ( n < 4 && ks[n++] ); + n--; + if ( n < 4 ) + keys[n] = key | shift | ctrl | alt | meta; + a->setAccel( TQKeySequence( keys[0], keys[1], keys[2], keys[3] ) ); + MetaDataBase::setPropertyChanged( a, "accel", TRUE ); + resizeToContents(); +} + +void PopupMenuEditor::resizeToContents() +{ + TQSize s = contentsSize(); + dropLine->resize( s.width(), 2 ); + s.rwidth() += borderSize * 2; + s.rheight() += borderSize * 2; + resize( s ); +} + +void PopupMenuEditor::showSubMenu() +{ + if ( currentIndex < (int)itemList.count() ) { + itemList.at( currentIndex )->showMenu( pos().x() + width() - borderSize * 3, + pos().y() + itemPos( at( currentIndex ) ) + + borderSize * 2 ); + setFocus(); // Keep focus in this widget + } +} + +void PopupMenuEditor::hideSubMenu() +{ + if ( currentIndex < (int)itemList.count() ) + itemList.at( currentIndex )->hideMenu(); +} + +void PopupMenuEditor::focusOnSubMenu() +{ + if ( currentIndex < (int)itemList.count() ) + itemList.at( currentIndex )->focusOnMenu(); +} + +// This function has no undo. It is only here to remove an item when its action was +// removed from the action editor. +// Use removeItem to put the command on the command stack. +void PopupMenuEditor::remove( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + PopupMenuEditorItem * i = itemList.at( idx ); + if ( i && i->isRemovable() ) { + itemList.remove( idx ); + int n = itemList.count() + 1; + if ( currentIndex >= n ) + currentIndex = itemList.count() + 1; + emit removed( i->action() ); + resizeToContents(); + } +} + +PopupMenuEditorItem * PopupMenuEditor::createItem( TQAction * a ) +{ + ActionEditor * ae = (ActionEditor *) formWindow()->mainWindow()->child( 0, "ActionEditor" ); + if ( !a ) + a = ae->newActionEx(); + PopupMenuEditorItem * i = new PopupMenuEditorItem( a, this ); + TQString n = TQString( a->name() ) + "Item"; + formWindow()->unify( i, n, FALSE ); + i->setName( n ); + AddActionToPopupCommand * cmd = + new AddActionToPopupCommand( i18n( "Add Item" ), formWnd, this, i ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + return i; +} + +void PopupMenuEditor::removeItem( int index ) +{ + int idx = ( index == -1 ? currentIndex : index ); + if ( idx < (int)itemList.count() ) { + RemoveActionFromPopupCommand * cmd = new RemoveActionFromPopupCommand( i18n( "Remove Item" ), + formWnd, + this, + idx ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + if ( itemList.count() == 0 && parentMenu ) + parentMenu->update(); + resizeToContents(); + } +} + +PopupMenuEditorItem * PopupMenuEditor::currentItem() +{ + int count = itemList.count(); + if ( currentIndex < count ) + return itemList.at( currentIndex ); + else if ( currentIndex == count ) + return &addItem; + return &addSeparator; +} + +PopupMenuEditorItem * PopupMenuEditor::itemAt( int y ) +{ + PopupMenuEditorItem * i = itemList.first(); + int iy = 0; + + while ( i ) { + iy += itemHeight( i ); + if ( iy > y ) + return i; + i = itemList.next(); + } + iy += itemHeight( &addItem ); + if ( iy > y ) + return &addItem; + return &addSeparator; +} + +void PopupMenuEditor::setFocusAt( const TQPoint & pos ) +{ + hideSubMenu(); + lineEdit->hide(); + + currentIndex = 0; + int iy = 0; + PopupMenuEditorItem * i = itemList.first(); + + while ( i ) { + iy += itemHeight( i ); + if ( iy > pos.y() ) + break; + i = itemList.next(); + currentIndex++; + } + + iy += itemHeight( &addItem ); + if ( iy <= pos.y() ) + currentIndex++; + + if ( currentIndex < (int)itemList.count() ) { + if ( pos.x() < iconWidth ) + currentField = 0; + else if ( pos.x() < iconWidth + textWidth ) + currentField = 1; + else + currentField = 2; + } else { + currentField = 1; + } + + showSubMenu(); +} + +bool PopupMenuEditor::eventFilter( TQObject * o, TQEvent * e ) +{ + if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(lineEdit) && e->type() == TQEvent::FocusOut ) { + leaveEditMode( 0 ); + update(); + } + return TQWidget::eventFilter( o, e ); +} + +void PopupMenuEditor::paintEvent( TQPaintEvent * ) +{ + TQPainter p( this ); + p.save(); + TQRegion reg( rect() ); + TQRegion mid( borderSize, borderSize, + rect().width() - borderSize * 2, rect().height() - borderSize * 2 ); + reg -= mid; + p.setClipRegion( reg ); + style().tqdrawPrimitive( TQStyle::PE_PanelPopup, &p, rect(), colorGroup() ); + p.restore(); + drawItems( &p ); +} + +void PopupMenuEditor::mousePressEvent( TQMouseEvent * e ) +{ + mousePressPos = e->pos(); + setFocusAt( mousePressPos ); + e->accept(); + update(); +} + +void PopupMenuEditor::mouseDoubleClickEvent( TQMouseEvent * ) +{ + setFocusAt( mousePressPos ); + if ( currentItem() == &addSeparator ) { + PopupMenuEditorItem * i = createItem( new QSeparatorAction( 0 ) ); + i->setSeparator( TRUE ); + return; + } + if ( currentField == 0 ) { + choosePixmap(); + resizeToContents(); + } else if ( currentField == 1 ) { + showLineEdit(); + } +} + +void PopupMenuEditor::mouseMoveEvent( TQMouseEvent * e ) +{ + if ( e->state() & Qt::LeftButton ) { + if ( ( e->pos() - mousePressPos ).manhattanLength() > 3 ) { + draggedItem = itemAt( mousePressPos.y() ); + if ( draggedItem == &addItem ) { + draggedItem = createItem(); + RenameActionCommand cmd( i18n( "Rename Item" ), formWnd, draggedItem->action(), + this, "Unnamed" ); + cmd.execute(); + // FIXME: start rename after drop + } else if ( draggedItem == &addSeparator ) { + draggedItem = createItem( new QSeparatorAction( 0 ) ); + draggedItem->setSeparator( TRUE ); + } + + PopupMenuEditorItemPtrDrag * d = + new PopupMenuEditorItemPtrDrag( draggedItem, this ); + + hideSubMenu(); + + draggedItem->setVisible( FALSE ); + resizeToContents(); + + // If the item is dropped in the same list, + // we will have two instances of the same pointer + // in the list. We use node instead. + int idx = itemList.find( draggedItem ); + TQLNode * node = itemList.currentNode(); + + d->dragCopy(); // dragevents and stuff happens + + if ( draggedItem ) { // item was not dropped + draggedItem->setVisible( TRUE ); + draggedItem = 0; + if ( hasFocus() ) { + hideSubMenu(); + resizeToContents(); + showSubMenu(); + } + } else { // item was dropped + itemList.takeNode( node )->setVisible( TRUE ); + if ( currentIndex > 0 && currentIndex > idx ) + --currentIndex; + // the drop might happen in another menu, so we'll resize + // and show the submenu there + } + } + } +} + +void PopupMenuEditor::dragEnterEvent( TQDragEnterEvent * e ) +{ + if ( e->provides( "qt/popupmenueditoritemptr" ) || + e->provides( "application/x-designer-actions" ) || + e->provides( "application/x-designer-actiongroup" ) ) { + e->accept(); + dropLine->show(); + } +} + +void PopupMenuEditor::dragLeaveEvent( TQDragLeaveEvent * ) +{ + dropLine->hide(); +} + +void PopupMenuEditor::dragMoveEvent( TQDragMoveEvent * e ) +{ + TQPoint pos = e->pos(); + dropLine->move( borderSize, snapToItem( pos.y() ) ); + + if ( currentItem() != itemAt( pos.y() ) ) { + hideSubMenu(); + setFocusAt( pos ); + showSubMenu(); + } +} + +void PopupMenuEditor::dropEvent( TQDropEvent * e ) +{ + if ( !( e->provides( "qt/popupmenueditoritemptr" ) || + e->provides( "application/x-designer-actions" ) || + e->provides( "application/x-designer-actiongroup" ) ) ) + return; + + // Hide the sub menu of the current item, but do it later + if ( currentIndex < (int)itemList.count() ) { + PopupMenuEditor *s = itemList.at( currentIndex )->s; + TQTimer::singleShot( 0, s, TQT_SLOT( hide() ) ); + } + + draggedItem = 0; + PopupMenuEditorItem * i = 0; + + if ( e->provides( "qt/popupmenueditoritemptr" ) ) { + PopupMenuEditorItemPtrDrag::decode( e, &i ); + } else { + if ( e->provides( "application/x-designer-actiongroup" ) ) { + TQActionGroup * g = ::tqqt_cast<QDesignerActionGroup*>(ActionDrag::action()); + if ( g->usesDropDown() ) { + i = new PopupMenuEditorItem( g, this ); + TQString n = TQString( g->name() ) + "Item"; + formWindow()->unify( i, n, FALSE ); + i->setName( n ); + TQObjectList *l = g->queryList( TQACTION_OBJECT_NAME_STRING, 0, FALSE, FALSE ); + TQObjectListIterator it( *l ); + for ( ; it.current(); ++it ) { + g = ::tqqt_cast<TQActionGroup*>(it.current()); + if ( g ) + i->s->insert( g ); + else + i->s->insert( (TQAction*)it.current() ); + } + delete l; + } else { + dropInPlace( g, e->pos().y() ); + } + } else if ( e->provides( "application/x-designer-actions" ) ) { + TQAction *a = ::tqqt_cast<QDesignerAction*>(ActionDrag::action()); + i = new PopupMenuEditorItem( a, this ); + } + } + + if ( i ) { + dropInPlace( i, e->pos().y() ); + TQTimer::singleShot( 0, this, TQT_SLOT( resizeToContents() ) ); + } + + TQTimer::singleShot( 0, this, TQT_SLOT( showSubMenu() ) ); + TQTimer::singleShot( 0, this, TQT_SLOT( setFocus() ) ); + dropLine->hide(); + e->accept(); +} + +void PopupMenuEditor::keyPressEvent( TQKeyEvent * e ) +{ + if ( lineEdit->isHidden() ) { // In navigation mode + + switch ( e->key() ) { + + case TQt::Key_Delete: + hideSubMenu(); + removeItem(); + showSubMenu(); + break; + + case TQt::Key_Backspace: + clearCurrentField(); + break; + + case TQt::Key_Up: + navigateUp( e->state() & TQt::ControlButton ); + break; + + case TQt::Key_Down: + navigateDown( e->state() & TQt::ControlButton ); + break; + + case TQt::Key_Left: + navigateLeft(); + break; + + case TQt::Key_Right: + navigateRight(); + break; + + case TQt::Key_PageUp: + currentIndex = 0; + break; + + case TQt::Key_PageDown: + currentIndex = itemList.count(); + break; + + case TQt::Key_Enter: + case TQt::Key_Return: + case TQt::Key_F2: + enterEditMode( e ); + // move on + case TQt::Key_Alt: + case TQt::Key_Shift: + case TQt::Key_Control: + // do nothing + return; + + case TQt::Key_Escape: + currentField = 0; + navigateLeft(); + break; + + case TQt::Key_C: + if ( e->state() & TQt::ControlButton && + currentIndex < (int)itemList.count() ) { + copy( currentIndex ); + break; + } + + case TQt::Key_X: + if ( e->state() & TQt::ControlButton && + currentIndex < (int)itemList.count() ) { + hideSubMenu(); + cut( currentIndex ); + showSubMenu(); + break; + } + + case TQt::Key_V: + if ( e->state() & TQt::ControlButton ) { + hideSubMenu(); + paste( currentIndex < (int)itemList.count() ? currentIndex + 1: itemList.count() ); + showSubMenu(); + break; + } + + default: + if ( currentItem()->isSeparator() ) + return; + if ( currentField == 1 ) { + showLineEdit(); + TQApplication::sendEvent( lineEdit, e ); + e->accept(); + return; + } else if ( currentField == 2 ) { + setAccelerator( e->key(), e->state() ); + showSubMenu(); + } + break; + + } + + } else { // In edit mode + switch ( e->key() ) { + case TQt::Key_Enter: + case TQt::Key_Return: + case TQt::Key_Escape: + leaveEditMode( e ); + e->accept(); + return; + } + } + update(); +} + +void PopupMenuEditor::focusInEvent( TQFocusEvent * ) +{ + showSubMenu(); + update(); + parentMenu->update(); +} + +void PopupMenuEditor::focusOutEvent( TQFocusEvent * ) +{ + TQWidget * fw = tqApp->focusWidget(); + if ( !fw || ( !::tqqt_cast<PopupMenuEditor*>(fw) && fw != lineEdit ) ) { + hideSubMenu(); + if ( fw && ::tqqt_cast<MenuBarEditor*>(fw) ) + return; + TQWidget * w = this; + while ( w && w != fw && ::tqqt_cast<PopupMenuEditor*>(w) ) { // hide all popups + w->hide(); + w = ((PopupMenuEditor *)w)->parentEditor(); + } + } +} + +void PopupMenuEditor::drawItem( TQPainter * p, PopupMenuEditorItem * i, + const TQRect & r, int f ) const +{ + int x = r.x(); + int y = r.y(); + int h = r.height(); + + p->fillRect( r, colorGroup().brush( TQColorGroup::Background ) ); + + if ( i->isSeparator() ) { + style().tqdrawPrimitive( TQStyle::PE_Separator, p, + TQRect( r.x(), r.y() + 2, r.width(), 1 ), + colorGroup(), TQStyle::Style_Sunken | f ); + return; + } + + const TQAction * a = i->action(); + if ( a->isToggleAction() && a->isOn() ) { + style().tqdrawPrimitive( TQStyle::PE_CheckMark, p, + TQRect( x , y, iconWidth, h ), + colorGroup(), f ); + } else { + TQPixmap icon = a->iconSet().pixmap( TQIconSet::Automatic, TQIconSet::Normal ); + p->drawPixmap( x + ( iconWidth - icon.width() ) / 2, + y + ( h - icon.height() ) / 2, + icon ); + } + x += iconWidth; + p->drawText( x, y, textWidth, h, + TQPainter::AlignLeft | + TQPainter::AlignVCenter | + TQt::ShowPrefix | + TQt::SingleLine, + a->menuText() ); + + x += textWidth + borderSize * 3; + p->drawText( x, y, accelWidth, h, + TQPainter::AlignLeft | TQPainter::AlignVCenter, + a->accel() ); + if ( i->count() ) // Item has submenu + style().tqdrawPrimitive( TQStyle::PE_ArrowRight, p, + TQRect( r.width() - arrowWidth, r.y(), arrowWidth, r.height() ), + colorGroup(), f ); +} + +void PopupMenuEditor::drawWinFocusRect( TQPainter * p, const TQRect & r ) const +{ + if ( currentIndex < (int)itemList.count() && + ((PopupMenuEditor*)this)->itemList.at( currentIndex )->isSeparator() ) { + p->drawWinFocusRect( borderSize, r.y(), width() - borderSize * 2, r.height() ); + return; + } + int y = r.y(); + int h = r.height(); + if ( currentField == 0 ) + p->drawWinFocusRect( borderSize + 1, y, iconWidth - 2, h ); + else if ( currentField == 1 ) + p->drawWinFocusRect( borderSize + iconWidth, y, textWidth, h ); + else if ( currentField == 2 ) + p->drawWinFocusRect( borderSize + iconWidth + textWidth + + borderSize * 3, y, accelWidth, h ); +} + +void PopupMenuEditor::drawItems( TQPainter * p ) +{ + int flags = 0; + int idx = 0; + + TQColorGroup enabled = colorGroup(); + TQColorGroup disabled = palette().disabled(); + TQRect focus; + TQRect rect( borderSize, borderSize, width() - borderSize * 2, 0 ); + + PopupMenuEditorItem * i = itemList.first(); + while ( i ) { + if ( i->isVisible() ) { + rect.setHeight( itemHeight( i ) ); + if ( idx == currentIndex ) + focus = rect; + if ( i->action()->isEnabled() ) { + flags = TQStyle::Style_Enabled; + p->setPen( enabled.buttonText() ); + } else { + flags = TQStyle::Style_Default; + p->setPen( disabled.buttonText() ); + } + drawItem( p, i, rect, flags ); + rect.moveBy( 0, rect.height() ); + } + i = itemList.next(); + idx++; + } + + // Draw the "add item" and "add separator" items + p->setPen( darkBlue ); + rect.setHeight( itemHeight( &addItem ) ); + if ( idx == currentIndex ) + focus = rect; + drawItem( p, &addItem, rect, TQStyle::Style_Default ); + rect.moveBy( 0, rect.height() ); + idx++; + rect.setHeight( itemHeight( &addSeparator ) ); + if ( idx == currentIndex ) + focus = rect; + drawItem( p, &addSeparator, rect, TQStyle::Style_Default ); + idx++; + + if ( hasFocus() && !draggedItem ) + drawWinFocusRect( p, focus ); +} + +TQSize PopupMenuEditor::contentsSize() +{ + TQRect textRect = fontMetrics().boundingRect( addSeparator.action()->menuText() ); + textWidth = textRect.width(); + accelWidth = textRect.height(); // default size + iconWidth = textRect.height(); + + int w = 0; + int h = itemHeight( &addItem ) + itemHeight( &addSeparator ); + PopupMenuEditorItem * i = itemList.first(); + TQAction * a = 0; + while ( i ) { + if ( i->isVisible() ) { + if ( !i->isSeparator() ) { + a = i->action(); + w = a->iconSet().pixmap( TQIconSet::Automatic, TQIconSet::Normal ).rect().width() + + borderSize; // padding + iconWidth = TQMAX( iconWidth, w ); + w = fontMetrics().boundingRect( a->menuText() ).width(); + textWidth = TQMAX( textWidth, w ); + w = fontMetrics().boundingRect( a->accel() ).width() + 2; // added padding? + accelWidth = TQMAX( accelWidth, w ); + } + h += itemHeight( i ); + } + i = itemList.next(); + } + + int width = iconWidth + textWidth + borderSize * 3 + accelWidth + arrowWidth; + return TQSize( width, h ); +} + +int PopupMenuEditor::itemHeight( const PopupMenuEditorItem * item ) const +{ + if ( !item || ( item && !item->isVisible() ) ) + return 0; + if ( item->isSeparator() ) + return 4; // FIXME: hardcoded ( get from styles )r + int padding = + borderSize * 6; + TQAction * a = item->action(); + int h = a->iconSet().pixmap( TQIconSet::Automatic, TQIconSet::Normal ).rect().height(); + h = TQMAX( h, fontMetrics().boundingRect( a->menuText() ).height() + padding ); + h = TQMAX( h, fontMetrics().boundingRect( a->accel() ).height() + padding ); + return h; +} + +int PopupMenuEditor::itemPos( const PopupMenuEditorItem * item ) const +{ + PopupMenuEditor * that = ( PopupMenuEditor * ) this; + int y = 0; + PopupMenuEditorItem * i = that->itemList.first(); + while ( i ) { + if ( i == item ) + return y; + y += itemHeight( i ); + i = that->itemList.next(); + } + return y; +} + +int PopupMenuEditor::snapToItem( int y ) +{ + int iy = 0; + int dy = 0; + + PopupMenuEditorItem * i = itemList.first(); + + while ( i ) { + dy = itemHeight( i ); + if ( iy + dy / 2 > y ) + return iy; + iy += dy; + i = itemList.next(); + } + + return iy; +} + +void PopupMenuEditor::dropInPlace( PopupMenuEditorItem * i, int y ) +{ + int iy = 0; + int dy = 0; + int idx = 0; + + PopupMenuEditorItem * n = itemList.first(); + + while ( n ) { + dy = itemHeight( n ); + if ( iy + dy / 2 > y ) + break; + iy += dy; + idx++; + n = itemList.next(); + } + int same = itemList.findRef( i ); + AddActionToPopupCommand * cmd = new AddActionToPopupCommand( i18n( "Drop Item" ), formWnd, this, i, idx ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + currentIndex = ( same >= 0 && same < idx ) ? idx - 1 : idx; + currentField = 1; +} + +void PopupMenuEditor::dropInPlace( TQActionGroup * g, int y ) +{ + TQObjectList l = g->childrenListObject(); + if (l.isEmpty()) + return; + for ( int i = 0; i < (int)l.count(); ++i ) { + TQAction *a = ::tqqt_cast<TQAction*>(l.at(i)); + TQActionGroup *g = ::tqqt_cast<TQActionGroup*>(l.at(i)); + if ( g ) + dropInPlace( g, y ); + else if ( a ) + dropInPlace( new PopupMenuEditorItem( a, this ), y ); + } +} + +void PopupMenuEditor::safeDec() +{ + do { + currentIndex--; + } while ( currentIndex > 0 && !currentItem()->isVisible() ); + if ( currentIndex == 0 && + !currentItem()->isVisible() && + parentMenu ) { + parentMenu->setFocus(); + } +} + +void PopupMenuEditor::safeInc() +{ + int max = itemList.count() + 1; + if ( currentIndex < max ) { + do { + currentIndex++; + } while ( currentIndex < max && !currentItem()->isVisible() ); // skip invisible items + } +} + +void PopupMenuEditor::clearCurrentField() +{ + if ( currentIndex >= (int)itemList.count() ) + return; // currentIndex is addItem or addSeparator + PopupMenuEditorItem * i = currentItem(); + hideSubMenu(); + if ( i->isSeparator() ) + return; + if ( currentField == 0 ) { + TQIconSet icons( 0 ); + SetActionIconsCommand * cmd = new SetActionIconsCommand( i18n( "Remove Icon" ), + formWnd, + i->action(), + this, + icons ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + } else if ( currentField == 2 ) { + i->action()->setAccel( 0 ); + } + resizeToContents(); + showSubMenu(); + return; +} + +void PopupMenuEditor::navigateUp( bool ctrl ) +{ + if ( currentIndex > 0 ) { + hideSubMenu(); + if ( ctrl ) { + ExchangeActionInPopupCommand * cmd = + new ExchangeActionInPopupCommand( i18n( "Move Item Up" ), + formWnd, + this, + currentIndex, + currentIndex - 1 ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + safeDec(); + } else { + safeDec(); + } + showSubMenu(); + } else if ( parentMenu ) { + parentMenu->setFocus(); + parentMenu->update(); + } +} + +void PopupMenuEditor::navigateDown( bool ctrl ) +{ + hideSubMenu(); + if ( ctrl ) { + if ( currentIndex < ( (int)itemList.count() - 1 ) ) { // safe index + ExchangeActionInPopupCommand * cmd = + new ExchangeActionInPopupCommand( i18n( "Move Item Down" ), + formWnd, + this, + currentIndex, + currentIndex + 1 ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + safeInc(); + } + } else { // ! Ctrl + safeInc(); + } + if ( currentIndex >= (int)itemList.count() ) + currentField = 1; + showSubMenu(); +} + +void PopupMenuEditor::navigateLeft() +{ + if ( currentItem()->isSeparator() || + currentIndex >= (int)itemList.count() || + currentField == 0 ) { + if ( parentMenu ) { + hideSubMenu(); + parentMenu->setFocus(); + } else if ( !currentItem()->isSeparator() ) { + currentField = 2; + } + } else { + currentField--; + } +} + +void PopupMenuEditor::navigateRight() +{ + if ( !currentItem()->isSeparator() && + currentIndex < (int)itemList.count() ) { + if ( currentField == 2 ) { + focusOnSubMenu(); + } else { + currentField++; + currentField %= 3; + } + } +} + +void PopupMenuEditor::enterEditMode( TQKeyEvent * e ) +{ + PopupMenuEditorItem * i = currentItem(); + + if ( i == &addSeparator ) { + i = createItem( new QSeparatorAction( 0 ) ); + } else if ( i->isSeparator() ) { + return; + } else if ( currentField == 0 ) { + choosePixmap(); + } else if ( currentField == 1 ) { + showLineEdit(); + return; + } else {// currentField == 2 + setAccelerator( e->key(), e->state() ); + } + showSubMenu(); + return; +} + +void PopupMenuEditor::leaveEditMode( TQKeyEvent * e ) +{ + setFocus(); + lineEdit->hide(); + + PopupMenuEditorItem * i = 0; + if ( e && e->key() == TQt::Key_Escape ) { + update(); + return; + } + + if ( currentIndex >= (int)itemList.count() ) { + // new item was created + TQAction * a = formWnd->mainWindow()->actioneditor()->newActionEx(); + TQString actionText = lineEdit->text(); + actionText.replace("&&", "&"); + TQString menuText = lineEdit->text(); + a->setText( actionText ); + a->setMenuText( menuText ); + i = createItem( a ); + TQString n = constructName( i ); + formWindow()->unify( a, n, TRUE ); + a->setName( n ); + MetaDataBase::addEntry( a ); + MetaDataBase::setPropertyChanged( a, "menuText", TRUE ); + ActionEditor *ae = (ActionEditor*)formWindow()->mainWindow()->child( 0, "ActionEditor" ); + if ( ae ) + ae->updateActionName( a ); + } else { + i = itemList.at( currentIndex ); + RenameActionCommand * cmd = new RenameActionCommand( i18n( "Rename Item" ), + formWnd, + i->action(), + this, + lineEdit->text() ); + formWnd->commandHistory()->addCommand( cmd ); + cmd->execute(); + } + resizeToContents(); + + if ( !i ) + return; + + if ( i->isSeparator() ) + hideSubMenu(); + else + showSubMenu(); +} + +TQString PopupMenuEditor::constructName( PopupMenuEditorItem *item ) +{ + TQString s; + TQString name = item->action()->menuText(); + TQWidget *e = parentEditor(); + PopupMenuEditor *p = ::tqqt_cast<PopupMenuEditor*>(e); + if ( p ) { + int idx = p->find( item->m ); + PopupMenuEditorItem * i = ( idx > -1 ? p->at( idx ) : 0 ); + s = ( i ? TQString( i->action()->name() ).remove( "Action" ) : TQString( "" ) ); + } else { + MenuBarEditor *b = ::tqqt_cast<MenuBarEditor*>(e); + if ( b ) { + int idx = b->findItem( item->m ); + MenuBarEditorItem * i = ( idx > -1 ? b->item( idx ) : 0 ); + s = ( i ? i->menuText().lower() : TQString( "" ) ); + } + } + // replace illegal characters + + return ( RenameMenuCommand::makeLegal( s ) + + RenameMenuCommand::makeLegal( name ) + "Action" ); +} |