Logo Search packages:      
Sourcecode: ktechlab version File versions

itemview.cpp

/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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();
}


00164 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 );
}


00183 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 ) );
}


00307 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);
}


00344 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"

Generated by  Doxygen 1.6.0   Back to index