diff options
Diffstat (limited to 'src/itemview.cpp')
-rw-r--r-- | src/itemview.cpp | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/src/itemview.cpp b/src/itemview.cpp new file mode 100644 index 0000000..452d33c --- /dev/null +++ b/src/itemview.cpp @@ -0,0 +1,581 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "cnitem.h" +#include "connector.h" +#include "docmanager.h" +#include "drawpart.h" +#include "ecnode.h" +#include "itemdocument.h" +#include "itemview.h" +#include "ktechlab.h" +#include "core/ktlconfig.h" + +#include <kaccel.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kurldrag.h> + +#include <cmath> +#include <qcursor.h> +#include <qtimer.h> +#include <qwmatrix.h> + + +//BEGIN class ItemView +ItemView::ItemView( ItemDocument * itemDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : View( itemDocument, viewContainer, viewAreaId, name ) +{ + KActionCollection * ac = actionCollection(); + + KStdAction::selectAll( itemDocument, SLOT(selectAll()), ac ); + KStdAction::zoomIn( this, SLOT(zoomIn()), ac ); + KStdAction::zoomOut( this, SLOT(zoomOut()), ac ); + KStdAction::actualSize( this, SLOT(actualSize()), ac )->setEnabled(false); + + + KAccel *pAccel = new KAccel(this); + pAccel->insert( "Cancel", i18n("Cancel"), i18n("Cancel the current operation"), Qt::Key_Escape, itemDocument, SLOT(cancelCurrentOperation()) ); + pAccel->readSettings(); + + new KAction( i18n("Delete"), "editdelete", Qt::Key_Delete, itemDocument, SLOT(deleteSelection()), ac, "edit_delete" ); + new KAction( i18n("Export as Image..."), 0, 0, itemDocument, SLOT(exportToImage()), ac, "file_export_image"); + + //BEGIN Item Alignment actions + new KAction( i18n("Align Horizontally"), 0, 0, itemDocument, SLOT(alignHorizontally()), ac, "align_horizontally" ); + new KAction( i18n("Align Vertically"), 0, 0, itemDocument, SLOT(alignVertically()), ac, "align_vertically" ); + new KAction( i18n("Distribute Horizontally"), 0, 0, itemDocument, SLOT(distributeHorizontally()), ac, "distribute_horizontally" ); + new KAction( i18n("Distribute Vertically"), 0, 0, itemDocument, SLOT(distributeVertically()), ac, "distribute_vertically" ); + //END Item Alignment actions + + + //BEGIN Draw actions + KToolBarPopupAction * pa = new KToolBarPopupAction( i18n("Draw"), "paintbrush", 0, 0, 0, ac, "edit_draw" ); + pa->setDelayed(false); + + KPopupMenu * m = pa->popupMenu(); + m->insertTitle( i18n("Draw") ); + + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_text", KIcon::Small ), i18n("Text"), DrawPart::da_text ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_line", KIcon::Small ), i18n("Line"), DrawPart::da_line ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_arrow", KIcon::Small ), i18n("Arrow"), DrawPart::da_arrow ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_ellipse", KIcon::Small ), i18n("Ellipse"), DrawPart::da_ellipse ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_rectangle", KIcon::Small ), i18n("Rectangle"), DrawPart::da_rectangle ); + connect( m, SIGNAL(activated(int)), itemDocument, SLOT(slotSetDrawAction(int)) ); + //END Draw actions + + + //BEGIN Item Control actions + new KAction( i18n("Raise Selection"), "1uparrow", Qt::Key_PageUp, itemDocument, SLOT(raiseZ()), ac, "edit_raise" ); + new KAction( i18n("Lower Selection"), "1downarrow", Qt::Key_PageDown, itemDocument, SLOT(lowerZ()), ac, "edit_lower" ); + //END Item Control actions + + + KAction * na = new KAction( "", 0, 0, 0, 0, ac, "null_action" ); + na->setEnabled(false); + + setXMLFile( "ktechlabitemviewui.rc" ); + + m_pUpdateStatusTmr = new QTimer(this); + connect( m_pUpdateStatusTmr, SIGNAL(timeout()), this, SLOT(updateStatus()) ); + connect( this, SIGNAL(viewUnfocused()), this, SLOT(stopUpdatingStatus()) ); + + p_itemDocument = itemDocument; + m_zoomLevel = 1.; + m_CVBEditor = new CVBEditor( p_itemDocument->canvas(), this, "cvbEditor" ); + m_CVBEditor->setLineWidth(1); + + m_layout->insertWidget( 0, m_CVBEditor ); + + setAcceptDrops(true); +} + + +ItemView::~ItemView() +{ +} + + +bool ItemView::canZoomIn() const +{ + return true; +} +bool ItemView::canZoomOut() const +{ + return int(std::floor((100*m_zoomLevel)+0.5)) > 25; +} + + +void ItemView::zoomIn() +{ + int currentZoomPercent = int(std::floor((100*m_zoomLevel)+0.5)); + int newZoom = currentZoomPercent; + + if ( currentZoomPercent < 100 ) + newZoom += 25; + else if ( currentZoomPercent < 200 ) + newZoom += 50; + else + newZoom += 100; + + m_zoomLevel = newZoom/100.; + + QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 ); + m_CVBEditor->setWorldMatrix(m); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + updateZoomActions(); +} + + +void ItemView::zoomOut() +{ + int currentZoomPercent = int(std::floor((100*m_zoomLevel)+0.5)); + int newZoom = currentZoomPercent; + + if ( currentZoomPercent <= 25 ) + return; + if ( currentZoomPercent <= 100 ) + newZoom -= 25; + else if ( currentZoomPercent <= 200 ) + newZoom -= 50; + else + newZoom -= 100; + + m_zoomLevel = newZoom/100.; + + QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 ); + m_CVBEditor->setWorldMatrix(m); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + updateZoomActions(); +} + + +void ItemView::actualSize() +{ + m_zoomLevel = 1.0; + QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 ); + m_CVBEditor->setWorldMatrix(m); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + updateZoomActions(); +} + + +void ItemView::updateZoomActions() +{ + action("view_zoom_in")->setEnabled( canZoomIn() ); + action("view_zoom_out")->setEnabled( canZoomOut() ); + action("view_actual_size")->setEnabled( m_zoomLevel != 1.0 ); +} + + +void ItemView::dropEvent( QDropEvent *event ) +{ + KURL::List urls; + if ( KURLDrag::decode( event, urls ) ) + { + // Then it is URLs that we can decode :) + const KURL::List::iterator end = urls.end(); + for ( KURL::List::iterator it = urls.begin(); it != end; ++it ) + { + DocManager::self()->openURL(*it); + } + return; + } + + if ( !QString(event->format()).startsWith("ktechlab/") ) + return; + + QString text; + QDataStream stream( event->encodedData(event->format()), IO_ReadOnly ); + stream >> text; + + QPoint position = event->pos(); + position.setX( int((position.x() + m_CVBEditor->contentsX())/m_zoomLevel) ); + position.setY( int((position.y() + m_CVBEditor->contentsY())/m_zoomLevel) ); + + // Get a new component item + p_itemDocument->addItem( text, position, true ); + + setFocus(); +} + + +void ItemView::scrollToMouse( const QPoint &pos ) +{ + QPoint position = pos * m_zoomLevel; + + int left = m_CVBEditor->contentsX(); + int top = m_CVBEditor->contentsY(); + int right = left + m_CVBEditor->visibleWidth(); + int bottom = top + m_CVBEditor->visibleHeight(); + + if( position.x() < left ) m_CVBEditor->scrollBy( position.x() - left, 0 ); + else if( position.x() > right ) m_CVBEditor->scrollBy( position.x() - right, 0 ); + + if( position.y() < top ) m_CVBEditor->scrollBy( 0, position.y() - top ); + else if( position.y() > bottom ) m_CVBEditor->scrollBy( 0, position.y() - bottom); +} + + +void ItemView::contentsMousePressEvent( QMouseEvent *e ) +{ + if (!e) + return; + + e->accept(); + + // For some reason, when we are initially unfocused, we only receive the + // release event if the user drags the mouse - not very often. So see if we + // were initially unfocused, and if so, do unclick as well. + bool wasFocused = isFocused(); + setFocused(); + + if ( !p_itemDocument ) + return; + + p_itemDocument->canvas()->setMessage( QString::null ); + p_itemDocument->m_cmManager->mousePressEvent( EventInfo( this, e ) ); + + if ( !wasFocused ) + p_itemDocument->m_cmManager->mouseReleaseEvent( EventInfo( this, e ) ); +} + + +void ItemView::contentsMouseDoubleClickEvent( QMouseEvent *e ) +{ + if (!e) + return; + + e->accept(); + + //HACK: Pass this of as a single press event if widget underneath + QCanvasItem * atTop = p_itemDocument->itemAtTop( e->pos()/zoomLevel() ); + if ( atTop && atTop->rtti() == ItemDocument::RTTI::Widget ) + contentsMousePressEvent(e); + else + p_itemDocument->m_cmManager->mouseDoubleClickEvent( EventInfo( this, e ) ); +} + + +void ItemView::contentsMouseMoveEvent( QMouseEvent *e ) +{ + if ( !e || !p_itemDocument ) + return; + + e->accept(); + + p_itemDocument->m_cmManager->mouseMoveEvent( EventInfo( this, e ) ); + if ( !m_pUpdateStatusTmr->isActive() ) + startUpdatingStatus(); +} + + +void ItemView::contentsMouseReleaseEvent( QMouseEvent *e ) +{ + if (!e) + return; + + e->accept(); + + p_itemDocument->m_cmManager->mouseReleaseEvent( EventInfo( this, e ) ); +} + + +void ItemView::contentsWheelEvent( QWheelEvent *e ) +{ + if (!e) + return; + + e->accept(); + + p_itemDocument->m_cmManager->wheelEvent( EventInfo( this, e ) ); +} + + +void ItemView::dragEnterEvent( QDragEnterEvent *event ) +{ + startUpdatingStatus(); + + KURL::List urls; + if ( KURLDrag::decode( event, urls ) ) + { + event->accept(true); + // Then it is URLs that we can decode later :) + return; + } +} + + +void ItemView::enterEvent( QEvent * e ) +{ + Q_UNUSED(e); + startUpdatingStatus(); +} + + +void ItemView::leaveEvent( QEvent * e ) +{ + Q_UNUSED(e); + stopUpdatingStatus(); + + // Cleanup + setCursor(Qt::ArrowCursor); + + if (p_ktechlab) + p_ktechlab->slotChangeStatusbar(QString::null); + + if ( p_itemDocument ) + p_itemDocument->m_canvasTip->setVisible(false); +} + + +void ItemView::slotUpdateConfiguration() +{ +// m_CVBEditor->setEraseColor( KTLConfig::bgColor() ); + m_CVBEditor->setEraseColor( Qt::white ); + + if ( m_pUpdateStatusTmr->isActive() ) + startUpdatingStatus(); +} + + +void ItemView::startUpdatingStatus() +{ + m_pUpdateStatusTmr->stop(); + m_pUpdateStatusTmr->start( int(1000./KTLConfig::refreshRate()) ); +} + + +void ItemView::stopUpdatingStatus() +{ + m_pUpdateStatusTmr->stop(); +} + + +void ItemView::updateStatus() +{ + QPoint pos = (m_CVBEditor->mapFromGlobal( QCursor::pos() ) + QPoint( m_CVBEditor->contentsX(), m_CVBEditor->contentsY() )) / zoomLevel(); + + ItemDocument * itemDocument = static_cast<ItemDocument*>(document()); + if ( !itemDocument ) + return; + + CMManager * cmManager = itemDocument->m_cmManager; + CanvasTip * canvasTip = itemDocument->m_canvasTip; + + bool displayTip = false; + QCursor cursor = Qt::ArrowCursor; + QString statusbar; + + if ( cmManager->cmState() & CMManager::cms_repeated_add ) + { + cursor = Qt::CrossCursor; + statusbar = i18n("Left click to add. Right click to resume normal editing"); + } + else if ( cmManager->cmState() & CMManager::cms_draw ) + { + cursor = Qt::CrossCursor; + statusbar = i18n("Click and hold to start drawing."); + } + else if ( cmManager->currentManipulator()) + { + switch ( cmManager->currentManipulator()->type() ) + { + case CanvasManipulator::RepeatedItemAdd: + cursor = Qt::CrossCursor; + statusbar = i18n("Left click to add. Right click to resume normal editing"); + break; + case CanvasManipulator::ManualConnector: + statusbar = i18n("Right click to cancel the connector"); + // no break + case CanvasManipulator::AutoConnector: + cursor = Qt::CrossCursor; + break; + case CanvasManipulator::ItemMove: + case CanvasManipulator::MechItemMove: + cursor = Qt::SizeAllCursor; + break; + case CanvasManipulator::Draw: + cursor = Qt::CrossCursor; + break; + default: + break; + } + + } + else if ( QCanvasItem *qcanvasItem = itemDocument->itemAtTop(pos) ) + { + switch( qcanvasItem->rtti() ) + { + case ItemDocument::RTTI::Connector: + { + cursor = Qt::CrossCursor; + if ( itemDocument->type() != Document::dt_circuit ) + break; + + canvasTip->displayVI( static_cast<Connector*>(qcanvasItem), pos ); + displayTip = true; + break; + } + case ItemDocument::RTTI::Node: + { + cursor = Qt::CrossCursor; + ECNode * ecnode = dynamic_cast<ECNode*>(qcanvasItem); + if ( !ecnode ) + break; + + canvasTip->displayVI( ecnode, pos ); + displayTip = true; + break; + } + case ItemDocument::RTTI::CNItem: + { + statusbar = (static_cast<CNItem*>(qcanvasItem))->name(); + break; + } + default: + { + break; + } + } + } + setCursor(cursor); + + if (p_ktechlab) + p_ktechlab->slotChangeStatusbar(statusbar); + + canvasTip->setVisible(displayTip); +} + +//END class ItemView + + + +//BEGIN class CVBEditor +CVBEditor::CVBEditor( QCanvas *canvas, ItemView *itemView, const char *name ) + : QCanvasView( canvas, itemView, name, WNoAutoErase | WStaticContents ) +{ + b_ignoreEvents = false; + b_passEventsToView = true; + p_itemView = itemView; + viewport()->setMouseTracking(true); + setAcceptDrops(true); + setFrameShape(NoFrame); +// setEraseColor( KTLConfig::bgColor() ); + setEraseColor( Qt::white ); + setPaletteBackgroundColor( Qt::white ); + viewport()->setEraseColor( Qt::white ); + viewport()->setPaletteBackgroundColor( Qt::white ); +} + + +void CVBEditor::contentsMousePressEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMousePressEvent(e); + else + QCanvasView::contentsMousePressEvent(e); +} + + +void CVBEditor::contentsMouseReleaseEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMouseReleaseEvent(e); + else + QCanvasView::contentsMouseReleaseEvent(e); +} + + +void CVBEditor::contentsMouseDoubleClickEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMouseDoubleClickEvent(e); + else + QCanvasView::contentsMouseDoubleClickEvent(e); +} + + +void CVBEditor::contentsMouseMoveEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMouseMoveEvent(e); + else + QCanvasView::contentsMouseMoveEvent(e); +} + + +void CVBEditor::dragEnterEvent( QDragEnterEvent* e ) +{ + if (b_passEventsToView) + p_itemView->dragEnterEvent(e); + else + QCanvasView::dragEnterEvent(e); +} + + +void CVBEditor::dropEvent( QDropEvent* e ) +{ + if (b_passEventsToView) + p_itemView->dropEvent(e); + else + QCanvasView::dropEvent(e); +} + + +void CVBEditor::enterEvent( QEvent * e ) +{ + if (b_passEventsToView) + p_itemView->enterEvent(e); + else + QCanvasView::enterEvent(e); +} + + +void CVBEditor::leaveEvent( QEvent* e ) +{ + if (b_passEventsToView) + p_itemView->leaveEvent(e); + else + QCanvasView::leaveEvent(e); +} + + +void CVBEditor::contentsWheelEvent( QWheelEvent *e ) +{ + if (b_ignoreEvents) + { + e->ignore(); + return; + } + + if (b_passEventsToView) + p_itemView->contentsWheelEvent(e); + else + { + b_ignoreEvents = true; + QCanvasView::wheelEvent(e); + b_ignoreEvents = false; + } +} + +void CVBEditor::viewportResizeEvent( QResizeEvent * e ) +{ + QCanvasView::viewportResizeEvent(e); + p_itemView->p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); +} +//END class CVBEditor + +#include "itemview.moc" |