/* This file is part of the KDE project Copyright (C) 2001, 2002, 2003 The Karbon Developers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "karbon_part.h" #include "karbon_view.h" #include "karbon_factory.h" #include "karbon_resourceserver.h" #include "vdocument.h" #include "vkopainter.h" #include "vlayer.h" #include "vlayercmd.h" #include "vdeletecmd.h" #include "vzordercmd.h" #include "vgroupcmd.h" #include "vungroupcmd.h" #include "vselection.h" #include "vstroke.h" #include "vcanvas.h" #include "vdocumentdocker.h" #include static long g_lastKey = 0; /************************************************************************* * Document tab * *************************************************************************/ VDocumentPreview::VDocumentPreview( KarbonView* view, QWidget* parent ) : QWidget( parent, "DocumentPreview" ), m_document( &view->part()->document() ), m_view( view ) { update(); installEventFilter( this ); setBackgroundMode( Qt::NoBackground ); setMouseTracking( true ); m_dragging = false; m_docpixmap = 0L; } // VDocumentPreview::VDocumentPreview VDocumentPreview::~VDocumentPreview() { delete m_docpixmap; } // VDocumentPreview::~VDocumentPreview void VDocumentPreview::reset() { delete m_docpixmap; m_docpixmap = 0L; } bool VDocumentPreview::eventFilter( QObject* object, QEvent* event ) { double scaleFactor; double xoffset = 0.; double yoffset = 0.; if ( ( height() - 4 ) / m_document->height() > ( width() - 4 ) / m_document->width() ) { scaleFactor = ( width() - 4 ) / m_document->width(); yoffset = ( ( height() - 4 ) / scaleFactor - m_document->height() ) / 2; } else { scaleFactor = ( height() - 4 ) / m_document->height(); xoffset = ( ( width() - 4 ) / scaleFactor - m_document->width() ) / 2; } KoRect rect = m_view->canvasWidget()->boundingBox(); QMouseEvent* mouseEvent = static_cast( event ); if( event->type() == QEvent::MouseButtonPress ) { m_firstPoint.setX( mouseEvent->pos().x() ); m_firstPoint.setY( mouseEvent->pos().y() ); m_lastPoint = m_firstPoint; KoPoint p3( m_firstPoint.x() / scaleFactor - xoffset, ( height() - m_firstPoint.y() ) / scaleFactor - yoffset ); m_dragging = rect.contains( p3 ); } else if( event->type() == QEvent::MouseButtonRelease ) { if( m_dragging ) { m_lastPoint.setX( mouseEvent->pos().x() ); m_lastPoint.setY( mouseEvent->pos().y() ); double dx = m_lastPoint.x() - m_firstPoint.x(); double dy = m_lastPoint.y() - m_firstPoint.y(); scaleFactor /= m_view->zoom(); m_view->canvasWidget()->scrollBy( int( dx / scaleFactor ), int( dy / scaleFactor ) ); m_firstPoint = m_lastPoint; m_dragging = false; update(); } } else if( event->type() == QEvent::MouseMove ) { if( m_dragging ) { m_lastPoint.setX( mouseEvent->pos().x() ); m_lastPoint.setY( mouseEvent->pos().y() ); update(); /*double dx = m_lastPoint.x() - m_firstPoint.x(); double dy = m_lastPoint.y() - m_firstPoint.y(); scaleFactor /= m_view->zoom(); m_view->canvasWidget()->scrollBy( int( dx / scaleFactor ), int( dy / scaleFactor ) ); m_firstPoint = m_lastPoint;*/ } else { KoPoint p3( mouseEvent->pos().x() / scaleFactor - xoffset, ( height() - mouseEvent->pos().y() ) / scaleFactor - yoffset ); setCursor( rect.contains( p3 ) ? QCursor::SizeAllCursor : QCursor( Qt::arrowCursor ) ); } } return QWidget::eventFilter( object, event ); } void VDocumentPreview::paintEvent( QPaintEvent* ) { // TODO : use NotROP, otherwise too slow QPixmap pixmap( width(), height() ); double xoffset = 0.; double yoffset = 0.; double scaleFactor; if ( ( height() - 4 ) / m_document->height() > ( width() - 4 ) / m_document->width() ) { scaleFactor = ( width() - 4 ) / m_document->width(); yoffset = ( ( height() - 4 ) / scaleFactor - m_document->height() ) / 2; } else { scaleFactor = ( height() - 4 ) / m_document->height(); xoffset = ( ( width() - 4 ) / scaleFactor - m_document->width() ) / 2; } xoffset += 2 / scaleFactor; yoffset += 2 / scaleFactor; if( !m_docpixmap || m_docpixmap->width() != width() || m_docpixmap->height() != height() ) { delete m_docpixmap; m_docpixmap = new QPixmap( width(), height() ); VKoPainter p( m_docpixmap, width(), height() ); p.clear( QColor( 195, 194, 193 ) ); p.setWorldMatrix( QWMatrix( 1, 0, 0, -1, xoffset * scaleFactor, height() - yoffset * scaleFactor ) ); p.setZoomFactor( scaleFactor ); KoRect rect( -xoffset, -yoffset, m_document->width() + xoffset, m_document->height() + yoffset ); // draw doc outline VColor c( Qt::black ); VStroke stroke( c, 0L, 1.0 / scaleFactor ); p.setPen( stroke ); p.setBrush( Qt::white ); p.drawRect( KoRect( 2, 2, m_document->width() - 2, m_document->height() - 2 ) ); m_document->draw( &p, &rect ); p.end(); } bitBlt( &pixmap, 0, 0, m_docpixmap, 0, 0, width(), height() ); // draw viewport rect { QPainter p( &pixmap ); p.setWorldMatrix( QWMatrix( scaleFactor, 0, 0, -scaleFactor, xoffset * scaleFactor, height() - yoffset * scaleFactor ) ); p.setPen( Qt::red ); double dx = ( m_lastPoint.x() - m_firstPoint.x() ) * m_view->zoom(); double dy = ( m_lastPoint.y() - m_firstPoint.y() ) * m_view->zoom(); KoPoint p1( dx / scaleFactor, dy / scaleFactor ); p1 = m_view->canvasWidget()->toContents( p1 ); KoPoint p2( dx / scaleFactor + m_view->canvasWidget()->width(), dy / scaleFactor + m_view->canvasWidget()->height() ); p2 = m_view->canvasWidget()->toContents( p2 ); p.drawRect( int( p1.x() ), int( p1.y() ), int( p2.x() - p1.x() ), int( p2.y() - p1.y() ) ); } QPainter pw( &pixmap ); pw.setPen( colorGroup().light() ); pw.drawLine( 1, 1, 1, height() - 2 ); pw.drawLine( 1, 1, width() - 2, 1 ); pw.drawLine( width() - 1, height() - 1, 0, height() - 1 ); pw.drawLine( width() - 1, height() - 1, width() - 1, 0 ); pw.setPen( colorGroup().dark() ); pw.drawLine( 0, 0, width() - 1, 0 ); pw.drawLine( 0, 0, 0, height() - 1 ); pw.drawLine( width() - 2, height() - 2, width() - 2, 1 ); pw.drawLine( width() - 2, height() - 2, 1, height() - 2 ); pw.end(); bitBlt( this, 0, 0, &pixmap, 0, 0, width(), height() ); } // VDocumentPreview::paintEvent VDocumentTab::VDocumentTab( KarbonView* view, QWidget* parent ) : QWidget( parent, "DocumentTab" ), m_view( view ) { QFrame* frame; QGridLayout* layout = new QGridLayout( this ); layout->setMargin( 3 ); layout->setSpacing( 2 ); layout->addMultiCellWidget( m_documentPreview = new VDocumentPreview( m_view, this ), 0, 7, 2, 2 ); layout->addWidget( new QLabel( i18n( "document width", "Width:" ), this ), 0, 0 ); layout->addWidget( new QLabel( i18n( "Height:" ), this ), 1, 0 ); layout->addMultiCellWidget( frame = new QFrame( this ), 2, 2, 0, 1 ); frame->setFrameShape( QFrame::HLine ); layout->addWidget( new QLabel( i18n( "Layers:" ), this ), 3, 0 ); layout->addWidget( new QLabel( i18n( "Format:" ), this ), 4, 0 ); layout->addMultiCellWidget( frame = new QFrame( this ), 5, 5, 0, 1 ); frame->setFrameShape( QFrame::HLine ); //layout->addMultiCellWidget( new QLabel( i18n( "Zoom factor:" ), this ), 6, 6, 0, 1 ); layout->addWidget( m_width = new QLabel( this ), 0, 1 ); layout->addWidget( m_height = new QLabel( this ), 1, 1 ); layout->addWidget( m_layers = new QLabel( this ), 3, 1 ); layout->addWidget( m_format = new QLabel( this ), 4, 1 ); layout->setRowStretch( 7, 1 ); layout->setColStretch( 0, 0 ); layout->setColStretch( 1, 0 ); layout->setColStretch( 2, 2 ); //layout->addWidget( m_width->setAlignment( AlignRight ); m_height->setAlignment( AlignRight ); m_layers->setAlignment( AlignRight ); m_format->setAlignment( AlignRight ); connect( view->part()->commandHistory(), SIGNAL( commandAdded( VCommand* ) ), this, SLOT( slotCommandAdded( VCommand* ) ) ); connect( view->part()->commandHistory(), SIGNAL( commandExecuted() ), this, SLOT( slotCommandExecuted() ) ); connect( view, SIGNAL( pageLayoutChanged() ), this, SLOT( slotCommandExecuted() ) ); connect( view->canvasWidget(), SIGNAL( viewportChanged() ), this, SLOT( slotViewportChanged() ) ); updateDocumentInfo(); } // VDocumentTab::VDocumentTab VDocumentTab::~VDocumentTab() { } // VDocumentTab::~VDocumentTab void VDocumentTab::updateDocumentInfo() { m_width->setText( KoUnit::toUserStringValue( m_view->part()->document().width(), m_view->part()->unit() ) + m_view->part()->unitName() ); m_height->setText( KoUnit::toUserStringValue( m_view->part()->document().height(), m_view->part()->unit() ) + m_view->part()->unitName() ); m_layers->setText( QString::number( m_view->part()->document().layers().count() ) ); } // VDocumentTab::updateDocumentInfo void VDocumentTab::slotCommandAdded( VCommand * ) { m_documentPreview->reset(); m_documentPreview->update(); } void VDocumentTab::slotZoomChanged( double ) { m_documentPreview->update(); } void VDocumentTab::slotViewportChanged() { m_documentPreview->update(); updateDocumentInfo(); } void VDocumentTab::slotCommandExecuted() { m_documentPreview->reset(); m_documentPreview->update(); } /************************************************************************* * Layers tab * *************************************************************************/ VObjectListViewItem::VObjectListViewItem( QListViewItem* parent, VObject* object, VDocument *doc, uint key, QPtrDict *map ) : QListViewItem( parent, 0L ), m_object( object ), m_document( doc ), m_key( key ), m_map( map ) { update(); // add itself to object list item map m_map->insert( object, this ); } VObjectListViewItem::~VObjectListViewItem() { // remove itself from object list item map m_map->take( m_object ); } QString VObjectListViewItem::key( int, bool ) const { return QString( "%1" ).arg( m_key ); } void VObjectListViewItem::update() { // text description VSelectionDescription selectionDesc; selectionDesc.visit( *m_object ); setText( 0, QString( "%1" ).arg( selectionDesc.shortDescription() ) ); // draw thumb preview (16x16) QPixmap preview; preview.resize( 16, 16 ); VKoPainter p( &preview, 16, 16, false ); // Y mirroring QWMatrix mat; mat.scale( 1, -1 ); KoRect bbox = m_object->boundingBox(); mat.translate( 0, -16 ); double factor = 16. / kMax( bbox.width(), bbox.height() ); mat.translate( -bbox.x() * factor, -bbox.y() * factor ); p.setWorldMatrix( mat ); // TODO: When the document will support page size, change the following line. p.setZoomFactor( factor ); m_object->draw( &p ); p.setZoomFactor( 1 ); p.setWorldMatrix( QWMatrix() ); p.setPen( Qt::black ); p.setBrush( Qt::NoBrush ); p.drawRect( KoRect( 0, 0, 16, 16 ) ); p.end(); // set thumb preview, lock and visible pixmaps setPixmap( 0, preview ); QString s = ( m_object->state() == VObject::normal_locked || m_object->state() == VObject::hidden_locked ) ? "locked" : "unlocked"; setPixmap( 1, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); s = ( m_object->state() == VObject::hidden || m_object->state() == VObject::hidden_locked ) ? "14_layer_novisible" : "14_layer_visible"; setPixmap( 2, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); } int VObjectListViewItem::compare( QListViewItem *i, int /*col*/, bool /*ascending*/ ) const { VObjectListViewItem *objectItem = dynamic_cast(i); if( ! objectItem ) return 0; return m_key < objectItem->m_key ? -1 : 1; } VLayerListViewItem::VLayerListViewItem( QListView* parent, VLayer* layer, VDocument *doc, QPtrDict *map ) : QCheckListItem( parent, 0L, CheckBox ), m_layer( layer ), m_document( doc), m_map( map ) { update(); // add itself to layer list item map m_map->insert( layer, this ); } // VLayerListViewItem::VLayerListViewItem VLayerListViewItem::~VLayerListViewItem() { // remove itself from layer list item map m_map->take( m_layer ); } void VLayerListViewItem::update() { // draw thumb preview (16x16) QPixmap preview; preview.resize( 16, 16 ); VKoPainter p( &preview, 16, 16, false ); // Y mirroring QWMatrix mat; mat.scale( 1, -1 ); mat.translate( 0, -16 ); p.setWorldMatrix( mat ); // TODO: When the document will support page size, change the following line. p.setZoomFactor( 16. / 800. ); m_layer->draw( &p ); p.setZoomFactor( 1 ); p.setWorldMatrix( QWMatrix() ); p.setPen( Qt::black ); p.setBrush( Qt::NoBrush ); p.drawRect( KoRect( 0, 0, 16, 16 ) ); p.end(); // text description setOn( m_layer->selected() ); setText( 0, m_layer->name() ); // set thumb preview, lock and visible pixmaps setPixmap( 0, preview ); QString s = ( m_layer->state() == VObject::normal_locked || m_layer->state() == VObject::hidden_locked ) ? "locked" : "unlocked"; setPixmap( 1, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); s = ( m_layer->state() == VObject::normal || m_layer->state() == VObject::normal_locked ) ? "14_layer_visible" : "14_layer_novisible"; setPixmap( 2, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); } // VLayerListViewItem::update void VLayerListViewItem::stateChange( bool on ) { m_layer->setSelected( on ); } // VLayerListViewItem::stateChange int VLayerListViewItem::pos() { VLayerListViewItem* item; if( !( item = (VLayerListViewItem*)itemAbove() ) ) return 0; else return 1 + item->pos(); } // VLayerListViewItem::pos QString VLayerListViewItem::key( int, bool ) const { return QString( "%1" ).arg( m_key ); } int VLayerListViewItem::compare( QListViewItem *i, int /*col*/, bool /*ascending*/ ) const { VLayerListViewItem *layerItem = dynamic_cast(i); if( ! layerItem ) return 0; return m_key < layerItem->m_key ? -1 : 1; } VLayersTab::VLayersTab( KarbonView* view, QWidget* parent ) : QWidget( parent, "LayersTab" ), m_view( view ), m_document( &view->part()->document() ) { QToolButton* button; QVBoxLayout* layout = new QVBoxLayout( this, 1 ); layout->addWidget( m_layersListView = new QListView( this ), 1 ); m_buttonGroup = new QHButtonGroup( this ); m_buttonGroup->setInsideMargin( 3 ); button = new QToolButton( m_buttonGroup ); button->setIconSet( SmallIcon( "14_layer_newlayer" ) ); button->setTextLabel( i18n( "New" ) ); m_buttonGroup->insert( button ); button = new QToolButton( m_buttonGroup ); button->setIconSet( SmallIcon( "14_layer_raiselayer" ) ); button->setTextLabel( i18n( "Raise" ) ); m_buttonGroup->insert( button ); button = new QToolButton( m_buttonGroup ); button->setIconSet( SmallIcon( "14_layer_lowerlayer" ) ); button->setTextLabel( i18n( "Lower" ) ); m_buttonGroup->insert( button ); button = new QToolButton( m_buttonGroup ); button->setIconSet( SmallIcon( "14_layer_deletelayer" ) ); button->setTextLabel( i18n( "Delete" ) ); m_buttonGroup->insert( button ); layout->addWidget( m_buttonGroup, 0); layout->setSpacing( 0 ); layout->setMargin( 3 ); m_layersListView->setAllColumnsShowFocus( true ); m_layersListView->addColumn( i18n( "Item" ), 120 ); m_layersListView->addColumn( i18n( "L" ), 20 ); m_layersListView->addColumn( i18n( "V" ), 20 ); m_layersListView->setColumnWidthMode( 0, QListView::Maximum ); m_layersListView->setColumnAlignment( 1, Qt::AlignCenter ); m_layersListView->setColumnAlignment( 2, Qt::AlignCenter ); m_layersListView->setResizeMode( QListView::NoColumn ); m_layersListView->setSorting( 0, false ); m_layersListView->setRootIsDecorated( true ); m_layersListView->setSelectionMode( QListView::Extended ); connect( m_layersListView, SIGNAL( clicked( QListViewItem*, const QPoint&, int ) ), this, SLOT( itemClicked( QListViewItem*, const QPoint&, int ) ) ); connect( m_layersListView, SIGNAL( rightButtonClicked( QListViewItem*, const QPoint&, int ) ), this, SLOT( renameItem( QListViewItem*, const QPoint&, int ) ) ); connect( m_layersListView, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedFromList() ) ); connect( m_view, SIGNAL( selectionChange() ), this, SLOT( selectionChangedFromTool() ) ); connect( m_buttonGroup, SIGNAL( clicked( int ) ), this, SLOT( slotButtonClicked( int ) ) ); connect( view->part()->commandHistory(), SIGNAL( commandExecuted( VCommand*) ), this, SLOT( slotCommandExecuted( VCommand* ) ) ); layout->activate(); updateLayers(); } // VLayersTab::VLayersTab VLayersTab::~VLayersTab() { } // VLayersTab::~VLayersTab void VLayersTab::slotButtonClicked( int ID ) { switch( ID ) { case 0: addLayer(); break; case 1: raiseItem(); break; case 2: lowerItem(); break; case 3: deleteItem(); break; } } // VLayersTab::slotButtonClicked void VLayersTab::resetSelection() { QListViewItemIterator it( m_layersListView ); // iterates over all list items and deselects them manually // to avoid the list views selectionChanged signal for(; it.current(); ++it ) { it.current()->setSelected( false ); it.current()->repaint(); } } void VLayersTab::selectActiveLayer() { if( ! m_layers[ m_document->activeLayer() ] ) { QPtrVector vector; m_document->layers().toVector( &vector ); // find another layer to set active for( int i = vector.count() - 1; i >= 0; i-- ) if ( vector[i]->state() != VObject::deleted ) { m_document->setActiveLayer( vector[i] ); break; } } // deselect all other layers QPtrDictIterator it( m_layers ); for(; it.current(); ++it ) { it.current()->setSelected( false ); it.current()->repaint(); } VLayerListViewItem *layerItem = m_layers[ m_document->activeLayer() ]; if( layerItem ) { layerItem->setSelected( true ); layerItem->repaint(); kdDebug(38000) << "selecting active layer: " << layerItem->text() << endl; } } void VLayersTab::selectionChangedFromTool() { resetSelection(); removeDeletedObjectsFromList(); // TODO : use some kind of mapping... VObjectListIterator itr = m_document->selection()->objects(); for( ; itr.current(); ++itr ) if( itr.current()->state() != VObject::deleted ) { VObject *obj = itr.current(); VObjectListViewItem *item = m_objects[ obj ]; if( ! item ) { VLayerListViewItem *layerItem = m_layers[ obj->parent() ]; if( layerItem ) updateObjects( layerItem->layer(), layerItem ); else { VObjectListViewItem *objectItem = m_objects[ obj->parent() ]; if( objectItem ) updateObjects( objectItem->object(), objectItem ); else continue; } item = m_objects[ obj ]; } if( ! item ) continue; item->setSelected( true ); item->update(); } selectActiveLayer(); } void VLayersTab::updateChildItems( QListViewItem *item ) { QListViewItemIterator it( item ); // iterator points to item, so make the next item current first for( ++it; it.current(); ++it ) { VObjectListViewItem *objectItem = dynamic_cast( it.current() ); if( ! objectItem ) continue; if( dynamic_cast( objectItem->object() ) ) updateChildItems( objectItem ); objectItem->update(); objectItem->repaint(); } } void VLayersTab::toggleState( VObject *obj, int col ) { switch( col ) { case 1: // toggle visibility if( obj->state() == VObject::hidden_locked ) obj->setState( VObject::hidden ); else if( obj->state() == VObject::normal_locked ) obj->setState( VObject::selected ); else if( obj->state() == VObject::normal || obj->state() >= VObject::selected ) obj->setState( VObject::normal_locked ); else if( obj->state() == VObject::hidden ) obj->setState( VObject::hidden_locked ); break; case 2: // toggle locking if( obj->state() == VObject::hidden_locked ) obj->setState( VObject::normal_locked ); else if( obj->state() == VObject::normal_locked ) obj->setState( VObject::hidden_locked ); else if( obj->state() == VObject::normal || obj->state() >= VObject::selected ) obj->setState( VObject::hidden ); else if( obj->state() == VObject::hidden ) obj->setState( VObject::selected ); break; default: return; } if( obj->state() < VObject::selected ) m_document->selection()->take( *obj ); else m_document->selection()->append( obj ); } void VLayersTab::itemClicked( QListViewItem* item, const QPoint &, int col ) { if( item ) { VLayerListViewItem *layerItem = dynamic_cast( item ); if( layerItem ) { if( col == 0 ) { m_document->setActiveLayer( layerItem->layer() ); selectActiveLayer(); } if( col > 0 ) { toggleState( layerItem->layer(), col ); layerItem->update(); layerItem->repaint(); updateChildItems( layerItem ); m_view->part()->repaintAllViews(); } } else { VObjectListViewItem *objectItem = dynamic_cast< VObjectListViewItem *>( item ); if( col == 0 ) { VObject *obj = objectItem->object(); if( obj->state() == VObject::normal ) obj->setState( VObject::selected ); } if( col > 0 ) { toggleState( objectItem->object(), col ); if( objectItem->object()->state() == VObject::selected ) objectItem->setSelected( true ); else objectItem->setSelected( false ); objectItem->update(); objectItem->repaint(); if( dynamic_cast( objectItem->object() ) ) updateChildItems( objectItem ); m_view->part()->repaintAllViews(); } } } } // VLayersTab::itemClicked void VLayersTab::selectionChangedFromList() { m_document->selection()->clear(); QListViewItemIterator it( m_layersListView ); // iterate over all list items and add their corresponding object // to the documents selection if the list item is selected and not hidden or locked or both for(; it.current(); ++it ) { VObjectListViewItem *objectItem = dynamic_cast( it.current() ); if( ! objectItem ) continue; VObject::VState state = objectItem->object()->state(); if( state == VObject::deleted ) { delete objectItem; continue; } if( objectItem->isSelected() && (state != VObject::hidden) && (state != VObject::normal_locked ) && (state != VObject::hidden_locked) ) { m_document->selection()->append( objectItem->object() ); objectItem->repaint(); } } m_view->selectionChanged(); m_view->part()->repaintAllViews(); } void VLayersTab::renameItem( QListViewItem* item, const QPoint&, int col ) { if ( ( item ) && col == 0 ) { bool ok = true; VLayerListViewItem* layerItem = dynamic_cast( item ); if( !layerItem ) { VObjectListViewItem *objectItem = dynamic_cast< VObjectListViewItem *>( item ); VObject *obj = objectItem->object(); QString name = KInputDialog::getText( i18n( "Current Object" ), i18n( "Change the name of the object:" ), obj->name(), &ok, this ); if( ok ) { m_document->setObjectName( obj, name ); objectItem->update(); } } else { QString name = KInputDialog::getText( i18n( "Rename Layer" ), i18n( "Change the name of the current layer:" ), layerItem->layer()->name(), &ok, this ); if( ok ) { layerItem->layer()->setName( name ); layerItem->update(); } } } } // VLayersTab::renameItem void VLayersTab::addLayer() { bool ok = true; QString name = KInputDialog::getText( i18n( "New Layer" ), i18n( "Enter the name of the new layer:" ), i18n( "New layer" ), &ok, this ); if( ok ) { VLayer* layer = new VLayer( m_document ); layer->setName( name ); VLayerCmd* cmd = new VLayerCmd( m_document, i18n( "Add Layer" ), layer, VLayerCmd::addLayer ); m_view->part()->addCommand( cmd, true ); updateLayers(); } } // VLayersTab::addLayer void VLayersTab::raiseItem() { VCommand *cmd = 0L; //QListViewItem *newselection = 0L; QListViewItemIterator it( m_layersListView ); if( m_document->selection()->objects().count() ) { cmd = new VZOrderCmd( m_document, VZOrderCmd::up ); m_view->part()->addCommand( cmd, true ); } else { for(; it.current(); ++it ) { if( ! it.current()->isSelected() ) continue; VLayerListViewItem* layerItem = dynamic_cast( it.current() ); if( layerItem ) { VLayer *layer = layerItem->layer(); if( layer && m_document->canRaiseLayer( layer ) ) { cmd = new VLayerCmd( m_document, i18n( "Raise Layer" ), layerItem->layer(), VLayerCmd::raiseLayer ); m_view->part()->addCommand( cmd, true ); } } } } if( cmd ) updatePreviews(); } // VLayersTab::raiseItem void VLayersTab::lowerItem() { VCommand *cmd = 0L; QListViewItemIterator it( m_layersListView ); if( m_document->selection()->objects().count() ) { cmd = new VZOrderCmd( m_document, VZOrderCmd::down ); m_view->part()->addCommand( cmd, true ); } else { for(; it.current(); ++it ) { if( ! it.current()->isSelected() ) continue; VLayerListViewItem* layerItem = dynamic_cast( it.current() ); if( layerItem ) { VLayer *layer = layerItem->layer(); if( layer && m_document->canLowerLayer( layer ) ) { cmd = new VLayerCmd( m_document, i18n( "Lower Layer" ), layer, VLayerCmd::lowerLayer ); m_view->part()->addCommand( cmd, true ); } } } } if( cmd ) updatePreviews(); } // VLayersTab::lowerItem void VLayersTab::deleteItem() { VCommand *cmd = 0L; QListViewItemIterator it( m_layersListView ); QPtrList deleteItems; deleteItems.setAutoDelete( false ); // collect all selected items because they get deselected // when the first item is removed for(; it.current(); ++it ) { if( ! it.current()->isSelected() ) continue; deleteItems.append( it.current() ); } for( ;deleteItems.first(); ) { VLayerListViewItem* layerItem = dynamic_cast< VLayerListViewItem *>( deleteItems.current() ); if( layerItem ) { VLayer *layer = layerItem->layer(); if( layer && m_layers.count() > 1 ) { cmd = new VLayerCmd( m_document, i18n( "Delete Layer" ), layer, VLayerCmd::deleteLayer ); VObjectListIterator itr = layer->objects(); // iterate over this layers child objects and remove them from the internal // object list and the list of the to be deleted items for( ; itr.current(); ++itr ) { VObjectListViewItem *objectItem = m_objects.take( itr.current() ); deleteItems.remove( objectItem ); } delete layerItem; m_view->part()->addCommand( cmd ); selectActiveLayer(); } } else { VObjectListViewItem* item = dynamic_cast< VObjectListViewItem *>( deleteItems.current() ); if( item ) { cmd = new VDeleteCmd( m_document, item->object() ); delete item; m_view->part()->addCommand( cmd ); } } // remove first item, next item becomes current deleteItems.removeFirst(); } if( cmd ) { updatePreviews(); m_view->part()->repaintAllViews(); } } // VLayersTab::deleteItem void VLayersTab::updatePreviews() { // TODO: Optimization: call update() on each view item... updateLayers(); } // VLayersTab::updatePreviews void VLayersTab::updateLayers() { removeDeletedObjectsFromList(); QPtrVector vector; m_document->layers().toVector( &vector ); VLayerListViewItem* item = 0L; for( int i = vector.count() - 1; i >= 0; i-- ) { if ( vector[i]->state() != VObject::deleted ) { if( !m_layers[ vector[i] ] ) { item = new VLayerListViewItem( m_layersListView, vector[i], m_document, &m_layers ); item->setOpen( true ); } else item = m_layers[ vector[i] ]; item->setKey(i); updateObjects( vector[i], item ); } } selectActiveLayer(); m_layersListView->sort(); } // VLayersTab::updateLayers void VLayersTab::updateObjects( VObject *object, QListViewItem *item ) { VObjectListIterator itr = dynamic_cast( object )->objects(); for( uint objcount = 1; itr.current(); ++itr, objcount++ ) if( itr.current()->state() != VObject::deleted ) { VObjectListViewItem *objectItem = m_objects[ itr.current() ]; if( ! objectItem ) { // object not found -> insert objectItem = new VObjectListViewItem( item, itr.current(), m_document, objcount, &m_objects ); objectItem->update(); } else if( objectItem->parent() != item ) { // object found, but has false parent -> reparent objectItem->parent()->takeItem( objectItem ); item->insertItem( objectItem ); } objectItem->setKey( objcount ); if( dynamic_cast( itr.current() ) ) updateObjects( itr.current(), objectItem ); } item->sort(); } void VLayersTab::removeDeletedObjectsFromList() { QPtrDictIterator it( m_objects ); // iterate over all object items and delete the following items: // - items representing deleted objects // - items with objects objects that changed parents // BEWARE: when deleting an item, the iterator is automatically incremented for(; it.current(); ) { VLayerListViewItem *layerItem = dynamic_cast( it.current()->parent() ); if( layerItem ) { VGroup *group = dynamic_cast( layerItem->layer() ); // check if object of item is still child of object of parent item if( group && ! group->objects().contains( it.current()->object() ) ) { layerItem->takeItem( it.current() ); delete it.current(); continue; } } else { VObjectListViewItem *objectItem = dynamic_cast( it.current()->parent() ); if( objectItem ) { VGroup *group = dynamic_cast( objectItem->object() ); // check if object of item is still child of object of parent item if( group && ! group->objects().contains( it.current()->object() ) ) { objectItem->takeItem( it.current() ); delete it.current(); continue; } } else { delete it.current(); continue; } } if( it.current()->object()->state() == VObject::deleted ) { delete it.current(); continue; } ++it; } QPtrDictIterator itr( m_layers ); // iterate over all layer items and delete the following items: // - items representing deleted layers // BEWARE: when deleting an item, the iterator is automatically incremented for(; itr.current(); ) { if( itr.current()->layer()->state() == VObject::deleted ) { m_layersListView->takeItem( itr.current() ); delete itr.current(); continue; } ++itr; } } void VLayersTab::slotCommandExecuted( VCommand* command ) { // sync listview on changing layers or deleting/undeleting or grouping/ungrouping objects if( dynamic_cast( command ) || dynamic_cast( command ) || dynamic_cast( command ) || dynamic_cast( command ) || dynamic_cast( command ) ) updateLayers(); } /************************************************************************* * History tab * *************************************************************************/ VHistoryGroupItem::VHistoryGroupItem( VHistoryItem* item, QListView* parent, QListViewItem* after ) : QListViewItem( parent, after ) { setPixmap( 0, *item->pixmap( 0 ) ); setText( 0, item->text( 0 ) ); parent->takeItem( item ); insertItem( item ); m_key = item->key( 0, true ); } // VHistoryItem::VHistoryItem VHistoryGroupItem::~VHistoryGroupItem() { } // VHistoryGroupItem::~VHistoryGroupItem void VHistoryGroupItem::paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ) { int e = 0; int n = 0; VHistoryItem* item = (VHistoryItem*)firstChild(); while ( item ) { if ( item->command()->success() ) e++; else n++; item = (VHistoryItem*)item->nextSibling(); } if ( e > 0 ) { p->fillRect( 0, 0, width, height(), cg.base() ); if ( n > 0 ) p->fillRect( 0, 0, width, height(), QBrush( cg.base().dark( 140 ), QBrush::BDiagPattern ) ); } else p->fillRect( 0, 0, width, height(), cg.base().dark( 140 ) ); const QPixmap* pixmap = this->pixmap( column ); int xstart; if ( pixmap ) { int pw = pixmap->width(); int ph = pixmap->height(); p->drawPixmap( ( height() - pw ) / 2, ( height() - ph ) / 2, *pixmap ); xstart = height(); } else xstart = 4; p->setPen( cg.text() ); p->drawText( xstart, 0, width - xstart, height(), align | Qt::AlignVCenter, text( column ) ); } // VHistoryGroupItem::paintCell void VHistoryGroupItem::paintFocus( QPainter*, const QColorGroup&, const QRect& ) { // Do not paint any focus rectangle // It makes the list and the selected item look messy } // VHistoryGroupItem::paintFocus VHistoryItem::VHistoryItem( VCommand* command, QListView* parent, QListViewItem* after ) : QListViewItem( parent, after ), m_command( command ) { init(); } // VHistoryItem::VHistoryItem VHistoryItem::VHistoryItem( VCommand* command, VHistoryGroupItem* parent, QListViewItem* after ) : QListViewItem( parent, after ), m_command( command ) { init(); } // VHistoryItem::VHistoryItem void VHistoryItem::init() { kdDebug(38000) << "In VHistoryItem::init() : " << m_command->name() << endl; char buffer[70]; sprintf( buffer, "%064ld", ++g_lastKey ); m_key = buffer; setPixmap( 0, QPixmap( KGlobal::iconLoader()->iconPath( m_command->icon(), KIcon::Small ) ) ); setText( 0, m_command->name() ); } // VHistoryITem::init VHistoryItem::~VHistoryItem() { } // VHistoryItem::~VHistoryItem void VHistoryItem::paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ) { p->fillRect( 0, 0, width, height(), ( m_command->success() ? cg.base() : cg.base().dark( 140 ) ) ); const QPixmap* pixmap = this->pixmap( column ); int xstart; if ( pixmap ) { int pw = pixmap->width(); int ph = pixmap->height(); p->drawPixmap( ( height() - pw ) / 2, ( height() - ph ) / 2, *pixmap ); xstart = height(); } else xstart = 4; p->setPen( cg.text() ); p->drawText( xstart, 0, width - xstart, height(), align | Qt::AlignVCenter, text( column ) ); } // VHistoryItem::paintCell void VHistoryItem::paintFocus( QPainter*, const QColorGroup&, const QRect& ) { // Do not paint any focus rectangle // It makes the list and the selected item look messy } // VHistoryItem::paintFocus VHistoryTab::VHistoryTab( KarbonPart* part, QWidget* parent ) : QWidget( parent ), m_part( part ) { QVBoxLayout* layout = new QVBoxLayout( this ); layout->setMargin( 3 ); layout->setSpacing( 2 ); layout->add( m_history = new QListView( this ) ); m_history->setVScrollBarMode( QListView::AlwaysOn ); m_history->setSelectionMode( QListView::NoSelection ); m_history->addColumn( i18n( "Commands" ) ); m_history->setResizeMode( QListView::AllColumns ); m_history->setRootIsDecorated( true ); layout->add( m_groupCommands = new QCheckBox( i18n( "Group commands" ), this ) ); m_history->setSorting( 0, true ); VHistoryGroupItem* group = 0; VHistoryItem* last = 0; QPtrVector cmds; part->commandHistory()->commands()->toVector( &cmds ); int c = cmds.count(); for ( int i = 0; i < c; i++ ) { if ( ( i > 0 ) && ( cmds[ i ]->name() == cmds[ i - 1 ]->name() ) ) if ( group ) { QListViewItem* prev = group->firstChild(); while ( prev && prev->nextSibling() ) prev = prev->nextSibling(); new VHistoryItem( cmds[ i ], group, prev ); } else { group = new VHistoryGroupItem( last, m_history, last ); new VHistoryItem( cmds[ i ], group, last ); } else { last = new VHistoryItem( cmds[ i ], m_history, last ); group = 0; } } m_history->sort(); connect( m_history, SIGNAL( mouseButtonClicked( int, QListViewItem*, const QPoint&, int ) ), this, SLOT( commandClicked( int, QListViewItem*, const QPoint&, int ) ) ); connect( m_groupCommands, SIGNAL( stateChanged( int ) ), this, SLOT( groupingChanged( int ) ) ); connect( part->commandHistory(), SIGNAL( historyCleared() ), this, SLOT( historyCleared() ) ); connect( part->commandHistory(), SIGNAL( commandAdded( VCommand* ) ), this, SLOT( slotCommandAdded( VCommand* ) ) ); connect( part->commandHistory(), SIGNAL( commandExecuted( VCommand* ) ), this, SLOT( commandExecuted( VCommand* ) ) ); connect( part->commandHistory(), SIGNAL( firstCommandRemoved() ), this, SLOT( removeFirstCommand() ) ); connect( part->commandHistory(), SIGNAL( lastCommandRemoved() ), this, SLOT( removeLastCommand() ) ); connect( this, SIGNAL( undoCommand( VCommand* ) ), part->commandHistory(), SLOT( undo( VCommand* ) ) ); connect( this, SIGNAL( redoCommand( VCommand* ) ), part->commandHistory(), SLOT( redo( VCommand* ) ) ); connect( this, SIGNAL( undoCommandsTo( VCommand* ) ), part->commandHistory(), SLOT( undoAllTo( VCommand* ) ) ); connect( this, SIGNAL( redoCommandsTo( VCommand* ) ), part->commandHistory(), SLOT( redoAllTo( VCommand* ) ) ); } // VHistoryTab::VHistoryTab VHistoryTab::~VHistoryTab() { } // VHistoryTab::~VHistoryTab bool VHistoryTab::groupingEnabled() { return m_groupCommands->isChecked(); } // VHistoryTab::groupingEnabled void VHistoryTab::historyCleared() { m_history->clear(); } // VHistoryTab::historyCleared void VHistoryTab::commandExecuted( VCommand* command ) { QListViewItem* item = m_history->firstChild(); bool found = false; while ( !found && item ) { if ( item->rtti() == 1001 ) { QListViewItem* child = item->firstChild(); while ( !found && child ) { found = ( ( (VHistoryItem*)child )->command() == command ); if ( !found ) child = child->nextSibling(); else item = child; } } found = ( item && ( (VHistoryItem*)item )->command() == command ); if ( !found ) item = item->nextSibling(); } if ( found ) { m_history->repaintItem( item ); if ( item->parent() ) m_history->repaintItem( item->parent() ); m_history->ensureItemVisible( item ); } } // VHistoryTab::commandExecuted void VHistoryTab::slotCommandAdded( VCommand* command ) { if ( !command ) return; QListViewItem* last = m_history->firstChild(); while ( last && last->nextSibling() ) last = last->nextSibling(); if( groupingEnabled() ) { if( ( last ) && last->text( 0 ) == command->name() ) { if( last->rtti() == 1002 ) { QListViewItem* prevSibling; if( m_history->childCount() > 1 ) { prevSibling = m_history->firstChild(); while ( prevSibling->nextSibling() != last ) prevSibling = prevSibling->nextSibling(); } else prevSibling = m_history->firstChild(); last = new VHistoryGroupItem( (VHistoryItem*)last, m_history, prevSibling ); } QListViewItem* prev = last->firstChild(); while ( prev && prev->nextSibling() ) prev = prev->nextSibling(); m_history->setCurrentItem( new VHistoryItem( command, (VHistoryGroupItem*)last, prev ) ); } else m_history->setCurrentItem( new VHistoryItem( command, m_history, last ) ); } else m_history->setCurrentItem( new VHistoryItem( command, m_history, last ) ); m_history->sort(); m_history->ensureItemVisible( m_history->currentItem() ); m_history->update(); } // VHistoryTab::slotCommandAdded void VHistoryTab::removeFirstCommand() { if ( m_history->childCount() > 0 ) if ( m_history->firstChild()->rtti() == 1002 ) delete m_history->firstChild(); else { VHistoryGroupItem* group = (VHistoryGroupItem*)m_history->firstChild(); delete group->firstChild(); if ( group->childCount() == 1 ) { new VHistoryItem( ( (VHistoryItem*)group->firstChild() )->command(), m_history, 0 ); delete group; } } } // VHistoryTab::removeFirstCommand void VHistoryTab::removeLastCommand() { if ( m_history->childCount() > 0 ) { QListViewItem* last = m_history->firstChild(); while ( last && last->nextSibling() ) last = last->nextSibling(); if ( last->rtti() == 1002 ) delete last; else { VHistoryGroupItem* group = (VHistoryGroupItem*)last; last = group->firstChild(); while ( last && last->nextSibling() ) last = last->nextSibling(); delete last; if ( group->childCount() == 1 ) { new VHistoryItem( ( (VHistoryItem*)group->firstChild() )->command(), m_history, group ); delete group; } } } } // VHistoryTab::removeLastCommand void VHistoryTab::commandClicked( int button, QListViewItem* item, const QPoint&, int ) { if ( !item || item->rtti() == 1001 ) return; VCommand* cmd = ( (VHistoryItem*)item )->command(); if ( cmd->success() ) if ( button == 1 ) emit undoCommandsTo( ( (VHistoryItem*)item )->command() ); else emit undoCommand( ( (VHistoryItem*)item )->command() ); else if ( button == 1 ) emit redoCommandsTo( ( (VHistoryItem*)item )->command() ); else emit redoCommand( ( (VHistoryItem*)item )->command() ); } // VHistoryTab::commandClicked void VHistoryTab::groupingChanged( int ) { if ( m_groupCommands->isChecked() && m_history->childCount() > 1 ) { QListViewItem* s2last = 0; QListViewItem* last = m_history->firstChild(); QListViewItem* item = last->nextSibling(); while ( item ) if ( last->text( 0 ) == item->text( 0 ) ) { if ( last->rtti() == 1002 ) last = new VHistoryGroupItem( (VHistoryItem*)last, m_history, s2last ); m_history->takeItem( item ); last->insertItem( item ); item = last->nextSibling(); } else { s2last = last; last = item; item = last->nextSibling(); } } else { QListViewItem* item = m_history->firstChild(); while ( item ) if ( item->rtti() == 1001 ) { QListViewItem* child; while ( ( child = item->firstChild() ) ) { item->takeItem( child ); m_history->insertItem( child ); } child = item; item = item->nextSibling(); delete child; } else item = item->nextSibling(); } m_history->sort(); m_history->update(); } // VHistoryTab::groupingChanged #include "vdocumentdocker.moc"