You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/karbon/dockers/vdocumentdocker.cc

1461 lines
42 KiB

/* 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 <qhbuttongroup.h>
#include <qinputdialog.h>
#include <qlayout.h>
#include <qcheckbox.h>
#include <qlistview.h>
#include <qptrvector.h>
#include <qtoolbutton.h>
#include <qpainter.h>
#include <qtabwidget.h>
#include <qlabel.h>
#include <qcursor.h>
#include <klocale.h>
#include <kglobal.h>
#include <KoMainWindow.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <kinputdialog.h>
#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 <visitors/vselectiondesc.h>
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<QMouseEvent*>( 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<VObjectListViewItem> *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<VObjectListViewItem*>(i);
if( ! objectItem ) return 0;
return m_key < objectItem->m_key ? -1 : 1;
}
VLayerListViewItem::VLayerListViewItem( QListView* parent, VLayer* layer, VDocument *doc, QPtrDict<VLayerListViewItem> *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<VLayerListViewItem*>(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<VLayer> 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<VLayerListViewItem> 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<VObjectListViewItem *>( it.current() );
if( ! objectItem ) continue;
if( dynamic_cast<VGroup*>( 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<VLayerListViewItem *>( 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<VGroup*>( 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<VObjectListViewItem *>( 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<VLayerListViewItem *>( 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<VLayerListViewItem *>( 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<VLayerListViewItem *>( 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<QListViewItem> 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<VLayer> 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<VGroup *>( 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<VGroup *>( itr.current() ) )
updateObjects( itr.current(), objectItem );
}
item->sort();
}
void
VLayersTab::removeDeletedObjectsFromList()
{
QPtrDictIterator<VObjectListViewItem> 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<VLayerListViewItem*>( it.current()->parent() );
if( layerItem )
{
VGroup *group = dynamic_cast<VGroup*>( 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<VObjectListViewItem*>( it.current()->parent() );
if( objectItem )
{
VGroup *group = dynamic_cast<VGroup*>( 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<VLayerListViewItem> 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<VLayerCmd*>( command )
|| dynamic_cast<VDeleteCmd*>( command )
|| dynamic_cast<VGroupCmd*>( command )
|| dynamic_cast<VUnGroupCmd*>( command )
|| dynamic_cast<VZOrderCmd*>( 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<VCommand> 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"