lib

KoView.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <KoView.h>
00021 #include <KoDocument.h>
00022 #include <KoMainWindow.h>
00023 #include <KoFrame.h>
00024 #include <KoViewIface.h>
00025 #include <KoDocumentChild.h>
00026 
00027 #include <klocale.h>
00028 #include <kglobal.h>
00029 #include <kdebug.h>
00030 #include <kparts/partmanager.h>
00031 #include <kparts/event.h>
00032 #include <kcursor.h>
00033 #include <assert.h>
00034 #include <kstatusbar.h>
00035 #include <kapplication.h>
00036 #include <qtimer.h>
00037 
00038 class KoViewPrivate
00039 {
00040 public:
00041   KoViewPrivate()
00042   {
00043     m_inOperation = false;
00044     m_zoom = 1.0;
00045     m_children.setAutoDelete( true );
00046     m_manager = 0L;
00047     m_tempActiveWidget = 0L;
00048     m_dcopObject = 0;
00049     m_registered=false;
00050     m_documentDeleted=false;
00051   }
00052   ~KoViewPrivate()
00053   {
00054   }
00055 
00056   QGuardedPtr<KoDocument> m_doc; // our KoDocument
00057   QGuardedPtr<KParts::PartManager> m_manager;
00058   double m_zoom;
00059   QPtrList<KoViewChild> m_children;
00060   QWidget *m_tempActiveWidget;
00061   KoViewIface *m_dcopObject;
00062   bool m_registered;  // are we registered at the part manager?
00063   bool m_documentDeleted; // true when m_doc gets deleted [can't use m_doc==0
00064                           // since this only happens in ~QObject, and views
00065                           // get deleted by ~KoDocument].
00066   QTimer *m_scrollTimer;
00067 
00068   // Hmm sorry for polluting the private class with such a big inner class.
00069   // At the beginning it was a little struct :)
00070   class StatusBarItem {
00071   public:
00072       StatusBarItem() // for QValueList
00073           : m_widget(0), m_visible(false)
00074       {}
00075       StatusBarItem( QWidget * widget, int stretch, bool permanent )
00076           : m_widget(widget), m_stretch(stretch), m_permanent(permanent), m_visible(false)
00077       {}
00078 
00079       QWidget * widget() const { return m_widget; }
00080 
00081       void ensureItemShown( KStatusBar * sb )
00082       {
00083             if ( !m_visible )
00084             {
00085                 sb->addWidget( m_widget, m_stretch, m_permanent );
00086                 m_visible = true;
00087                 m_widget->show();
00088             }
00089       }
00090       void ensureItemHidden( KStatusBar * sb )
00091       {
00092             if ( m_visible )
00093             {
00094                 sb->removeWidget( m_widget );
00095                 m_visible = false;
00096                 m_widget->hide();
00097             }
00098       }
00099   private:
00100       QWidget * m_widget;
00101       int m_stretch;
00102       bool m_permanent;
00103       bool m_visible;  // true when the item has been added to the statusbar
00104   };
00105   QValueList<StatusBarItem> m_statusBarItems; // Our statusbar items
00106   bool m_inOperation; //in the middle of an operation (no screen refreshing)?
00107 };
00108 
00109 KoView::KoView( KoDocument *document, QWidget *parent, const char *name )
00110  : QWidget( parent, name )
00111 {
00112   Q_ASSERT( document );
00113 
00114   //kdDebug(30003) << "KoView::KoView " << this << endl;
00115   d = new KoViewPrivate;
00116   d->m_doc = document;
00117   KParts::PartBase::setPartObject( this );
00118 
00119   setFocusPolicy( StrongFocus );
00120 
00121   setMouseTracking( true );
00122 
00123   connect( d->m_doc, SIGNAL( childChanged( KoDocumentChild * ) ),
00124            this, SLOT( slotChildChanged( KoDocumentChild * ) ) );
00125 
00126   connect( d->m_doc, SIGNAL( sigBeginOperation() ),
00127            this, SLOT( beginOperation() ) );
00128 
00129   connect( d->m_doc, SIGNAL( sigEndOperation() ),
00130            this, SLOT( endOperation() ) );
00131 
00132 
00133   actionCollection()->setWidget( this );
00134   setupGlobalActions();
00135   KActionCollection *coll = actionCollection();
00136   /**** not needed anymore, according to David (Werner)
00137   QValueList<KAction*> docActions = document->actionCollection()->actions();
00138   QValueList<KAction*>::ConstIterator it = docActions.begin();
00139   QValueList<KAction*>::ConstIterator end = docActions.end();
00140   for (; it != end; ++it )
00141       coll->insert( *it );
00142   */
00143 
00144   KStatusBar * sb = statusBar();
00145   if ( sb ) // No statusbar in e.g. konqueror
00146   {
00147       coll->setHighlightingEnabled( true );
00148       connect( coll, SIGNAL( actionStatusText( const QString & ) ),
00149                this, SLOT( slotActionStatusText( const QString & ) ) );
00150       connect( coll, SIGNAL( clearStatusText() ),
00151                this, SLOT( slotClearStatusText() ) );
00152 
00153       connect( d->m_doc, SIGNAL( sigStatusBarMessage( const QString& ) ),
00154                this, SLOT( slotActionStatusText( const QString& ) ) );
00155       connect( d->m_doc, SIGNAL( sigClearStatusBarMessage() ),
00156                this, SLOT( slotClearStatusText() ) );
00157   }
00158   d->m_doc->setCurrent();
00159 
00160   d->m_scrollTimer = new QTimer( this );
00161   connect (d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ) );
00162 }
00163 
00164 KoView::~KoView()
00165 {
00166   kdDebug(30003) << "KoView::~KoView " << this << endl;
00167   delete d->m_scrollTimer;
00168   delete d->m_dcopObject;
00169   if (!d->m_documentDeleted)
00170   {
00171     if ( koDocument() && !koDocument()->isSingleViewMode() )
00172     {
00173       if ( d->m_manager && d->m_registered ) // if we aren't registered we mustn't unregister :)
00174         d->m_manager->removePart( koDocument() );
00175       d->m_doc->removeView(this);
00176       d->m_doc->setCurrent( false );
00177     }
00178   }
00179   delete d;
00180 }
00181 
00182 KoDocument *KoView::koDocument() const
00183 {
00184   return d->m_doc;
00185 }
00186 
00187 void KoView::setDocumentDeleted()
00188 {
00189     d->m_documentDeleted = true;
00190 }
00191 
00192 bool KoView::documentDeleted() const
00193 {
00194     return d->m_documentDeleted;
00195 }
00196 
00197 bool KoView::hasDocumentInWindow( KoDocument *doc )
00198 {
00199   return child( doc ) != 0L;
00200 }
00201 
00202 void KoView::setPartManager( KParts::PartManager *manager )
00203 {
00204   d->m_manager = manager;
00205   if ( !koDocument()->isSingleViewMode() &&
00206        manager->parts()->containsRef( koDocument() ) == 0 ) // is there another view registered?
00207   {
00208     d->m_registered = true; // no, so we have to register now and ungregister again in the DTOR
00209     manager->addPart( koDocument(), false );
00210   }
00211   else
00212     d->m_registered = false;  // There is already another view registered for that part...
00213 }
00214 
00215 KParts::PartManager *KoView::partManager() const
00216 {
00217   return d->m_manager;
00218 }
00219 
00220 KAction *KoView::action( const QDomElement &element ) const
00221 {
00222   static const QString &attrName = KGlobal::staticQString( "name" );
00223   QString name = element.attribute( attrName );
00224 
00225   KAction *act = KXMLGUIClient::action( name.utf8() );
00226 
00227   if ( !act )
00228     act = d->m_doc->KXMLGUIClient::action( name.utf8() );
00229 
00230   return act;
00231 }
00232 
00233 KoDocument *KoView::hitTest( const QPoint &viewPos )
00234 {
00235   KoViewChild *viewChild;
00236 
00237   QPoint pos = reverseViewTransformations( viewPos );
00238 
00239   KoDocumentChild *docChild = selectedChild();
00240   if ( docChild )
00241   {
00242     if ( ( viewChild = child( docChild->document() ) ) )
00243     {
00244       if ( viewChild->frameRegion().contains( pos ) )
00245         return 0;
00246     }
00247     else
00248       if ( docChild->frameRegion().contains( pos ) )
00249         return 0;
00250   }
00251 
00252   docChild = activeChild();
00253   if ( docChild )
00254   {
00255     if ( ( viewChild = child( docChild->document() ) ) )
00256     {
00257       if ( viewChild->frameRegion().contains( pos ) )
00258         return 0;
00259     }
00260     else
00261       if ( docChild->frameRegion().contains( pos ) )
00262         return 0;
00263   }
00264 
00265   return koDocument()->hitTest( pos );
00266 }
00267 
00268 int KoView::leftBorder() const
00269 {
00270   return 0;
00271 }
00272 
00273 int KoView::rightBorder() const
00274 {
00275   return 0;
00276 }
00277 
00278 int KoView::topBorder() const
00279 {
00280   return 0;
00281 }
00282 
00283 int KoView::bottomBorder() const
00284 {
00285   return 0;
00286 }
00287 
00288 void KoView::setZoom( double zoom )
00289 {
00290   d->m_zoom = zoom;
00291   update();
00292 }
00293 
00294 double KoView::zoom() const
00295 {
00296   return d->m_zoom;
00297 }
00298 
00299 QWidget *KoView::canvas() const
00300 {
00301     //dfaure: since the view plays two roles in this method (the const means "you can modify the canvas
00302     // but not the view", it's just coincidence that the view is the canvas by default ;)
00303    return const_cast<KoView *>(this);
00304 }
00305 
00306 int KoView::canvasXOffset() const
00307 {
00308   return 0;
00309 }
00310 
00311 int KoView::canvasYOffset() const
00312 {
00313   return 0;
00314 }
00315 
00316 void KoView::canvasAddChild( KoViewChild * )
00317 {
00318 }
00319 
00320 void KoView::customEvent( QCustomEvent *ev )
00321 {
00322   if ( KParts::PartActivateEvent::test( ev ) )
00323     partActivateEvent( (KParts::PartActivateEvent *)ev );
00324   else if ( KParts::PartSelectEvent::test( ev ) )
00325     partSelectEvent( (KParts::PartSelectEvent *)ev );
00326   else if( KParts::GUIActivateEvent::test( ev ) )
00327     guiActivateEvent( (KParts::GUIActivateEvent*)ev );
00328 }
00329 
00330 void KoView::partActivateEvent( KParts::PartActivateEvent *event )
00331 {
00332   if ( event->part() != (KParts::Part *)koDocument() )
00333   {
00334     assert( event->part()->inherits( "KoDocument" ) );
00335 
00336     KoDocumentChild *child = koDocument()->child( (KoDocument *)event->part() );
00337     if ( child && event->activated() )
00338     {
00339       if ( child->isRectangle() && !child->isTransparent() )
00340       {
00341         KoViewChild *viewChild = new KoViewChild( child, this );
00342         d->m_children.append( viewChild );
00343 
00344         QApplication::setOverrideCursor(waitCursor);
00345         // This is the long operation (due to toolbar layout stuff)
00346         d->m_manager->setActivePart( child->document(), viewChild->frame()->view() );
00347         QApplication::restoreOverrideCursor();
00348 
00349         // Now we can move the frame to the right place
00350         viewChild->setInitialFrameGeometry();
00351       }
00352       else
00353       {
00354         emit regionInvalidated( child->frameRegion( matrix() ), true );
00355       }
00356       emit childActivated( child );
00357     }
00358     else if ( child )
00359     {
00360       emit regionInvalidated( child->frameRegion( matrix() ), true );
00361       emit childDeactivated( child );
00362     }
00363     else
00364       emit invalidated();
00365   }
00366   else
00367     emit activated( event->activated() );
00368 }
00369 
00370 void KoView::partSelectEvent( KParts::PartSelectEvent *event )
00371 {
00372   if ( event->part() != (KParts::Part *)koDocument() )
00373   {
00374     assert( event->part()->inherits( "KoDocument" ) );
00375 
00376     KoDocumentChild *child = koDocument()->child( (KoDocument *)event->part() );
00377 
00378     if ( child && event->selected() )
00379     {
00380       QRegion r = child->frameRegion( matrix() );
00381       r.translate( - canvasXOffset(), - canvasYOffset() );
00382       emit regionInvalidated( r, true );
00383       emit childSelected( child );
00384     }
00385     else if ( child )
00386     {
00387       QRegion r = child->frameRegion( matrix() );
00388       r.translate( - canvasXOffset(), - canvasYOffset() );
00389       emit regionInvalidated( r, true );
00390       emit childUnselected( child );
00391     }
00392     else
00393       emit invalidated();
00394   }
00395   else
00396     emit selected( event->selected() );
00397 }
00398 
00399 void KoView::guiActivateEvent( KParts::GUIActivateEvent * ev )
00400 {
00401     showAllStatusBarItems( ev->activated() );
00402 }
00403 
00404 void KoView::showAllStatusBarItems( bool show )
00405 {
00406     KStatusBar * sb = statusBar();
00407     if ( !sb )
00408         return;
00409     QValueListIterator<KoViewPrivate::StatusBarItem> it = d->m_statusBarItems.begin();
00410     for ( ; it != d->m_statusBarItems.end() ; ++it )
00411         if ( show )
00412             (*it).ensureItemShown( sb );
00413         else
00414             (*it).ensureItemHidden( sb );
00415 }
00416 
00417 void KoView::addStatusBarItem( QWidget * widget, int stretch, bool permanent )
00418 {
00419     KoViewPrivate::StatusBarItem item( widget, stretch, permanent );
00420     d->m_statusBarItems.append(item);
00421     QValueListIterator<KoViewPrivate::StatusBarItem> it = d->m_statusBarItems.fromLast();
00422     KStatusBar * sb = statusBar();
00423     Q_ASSERT(sb);
00424     if (sb)
00425         (*it).ensureItemShown( sb );
00426 }
00427 
00428 void KoView::removeStatusBarItem( QWidget * widget )
00429 {
00430     KStatusBar * sb = statusBar();
00431     QValueListIterator<KoViewPrivate::StatusBarItem> it = d->m_statusBarItems.begin();
00432     for ( ; it != d->m_statusBarItems.end() ; ++it )
00433         if ( (*it).widget() == widget )
00434         {
00435             if ( sb )
00436                 (*it).ensureItemHidden( sb );
00437             d->m_statusBarItems.remove( it );
00438             break;
00439         }
00440     if ( it == d->m_statusBarItems.end() )
00441         kdWarning() << "KoView::removeStatusBarItem. Widget not found : " << widget << endl;
00442 }
00443 
00444 KoDocumentChild *KoView::selectedChild()
00445 {
00446   if ( !d->m_manager )
00447     return 0L;
00448 
00449   KParts::Part *selectedPart = d->m_manager->selectedPart();
00450 
00451   if ( !selectedPart || !selectedPart->inherits( "KoDocument" ) )
00452     return 0L;
00453 
00454   return koDocument()->child( (KoDocument *)selectedPart );
00455 }
00456 
00457 KoDocumentChild *KoView::activeChild()
00458 {
00459   if ( !d->m_manager )
00460     return 0L;
00461 
00462   KParts::Part *activePart = d->m_manager->activePart();
00463 
00464   if ( !activePart || !activePart->inherits( "KoDocument" ) )
00465     return 0L;
00466 
00467   return koDocument()->child( (KoDocument *)activePart );
00468 }
00469 
00470 void KoView::enableAutoScroll( )
00471 {
00472     d->m_scrollTimer->start( 50 );
00473 }
00474 
00475 void KoView::disableAutoScroll( )
00476 {
00477     d->m_scrollTimer->stop();
00478 }
00479 
00480 void KoView::paintEverything( QPainter &painter, const QRect &rect, bool transparent )
00481 {
00482   koDocument()->paintEverything( painter, rect, transparent, this );
00483 }
00484 
00485 KoViewChild *KoView::child( KoView *view )
00486 {
00487   QPtrListIterator<KoViewChild> it( d->m_children );
00488   for (; it.current(); ++it )
00489     if ( it.current()->frame()->view() == view )
00490       return it.current();
00491 
00492   return 0L;
00493 }
00494 
00495 KoViewChild *KoView::child( KoDocument *doc )
00496 {
00497   QPtrListIterator<KoViewChild> it( d->m_children );
00498   for (; it.current(); ++it )
00499     if ( it.current()->documentChild()->document() == doc )
00500       return it.current();
00501 
00502   return 0L;
00503 }
00504 
00505 QWMatrix KoView::matrix() const
00506 {
00507   QWMatrix m;
00508   m.scale( zoom(), zoom() );
00509   //m.translate(  canvasXOffset() ,  canvasYOffset() );
00510   return m;
00511 }
00512 
00513 void KoView::slotChildActivated( bool a )
00514 {
00515   // Only interested in deactivate events
00516   if ( a )
00517     return;
00518 
00519   KoViewChild* ch = child( (KoView*)sender() );
00520   if ( !ch )
00521     return;
00522 
00523   KoView* view = ch->frame()->view();
00524 
00525   QWidget *activeWidget = view->d->m_tempActiveWidget;
00526 
00527   if ( d->m_manager->activeWidget() )
00528     activeWidget = d->m_manager->activeWidget();
00529 
00530   if ( !activeWidget || !activeWidget->inherits( "KoView" ) )
00531     return;
00532 
00533   // Is the new active view a child of this one ?
00534   // In this case we may not delete!
00535   //  QObject *n = d->m_manager->activeWidget();
00536   QObject *n = activeWidget;
00537   while( n )
00538     if ( n == (QObject *)view )
00539       return;
00540     else
00541      n = n->parent();
00542 
00543 
00544   d->m_tempActiveWidget = activeWidget;
00545   QApplication::setOverrideCursor(waitCursor);
00546   d->m_manager->setActivePart( 0L );
00547 
00548   QGuardedPtr<KoDocumentChild> docChild = ch->documentChild();
00549   QGuardedPtr<KoFrame> chFrame = ch->frame();
00550   if ( docChild && chFrame && chFrame->view() )
00551   {
00552     docChild->setContentsPos( chFrame->view()->canvasXOffset(),
00553                               chFrame->view()->canvasYOffset() );
00554     docChild->document()->setViewBuildDocument( chFrame->view(), chFrame->view()->xmlguiBuildDocument() );
00555   }
00556 
00557   d->m_children.remove( ch );
00558 
00559   d->m_manager->addPart( docChild->document(), false ); // the destruction of the view removed the part from the partmanager. re-add it :)
00560 
00561   QApplication::restoreOverrideCursor();
00562 
00563   // #### HACK
00564   // We want to delete as many views as possible and this
00565   // trick is used to go upwards in the view-tree.
00566   emit activated( FALSE );
00567 }
00568 
00569 void KoView::slotChildChanged( KoDocumentChild *child )
00570 {
00571   QRegion region( child->oldPointArray( matrix() ) );
00572   emit regionInvalidated( child->frameRegion( matrix(), true ).unite( region ), true );
00573 }
00574 
00575 int KoView::autoScrollAcceleration( int offset ) const
00576 {
00577     if(offset < 40)
00578         return offset;
00579     else
00580         return offset*offset/40;
00581 }
00582 
00583 void KoView::slotAutoScroll(  )
00584 {
00585     QPoint scrollDistance;
00586     bool actuallyDoScroll = false;
00587     QPoint pos( mapFromGlobal( QCursor::pos() ) );
00588 
00589     //Provide progressive scrolling depending on the mouse position
00590     if ( pos.y() < topBorder() )
00591     {
00592         scrollDistance.setY ((int) - autoScrollAcceleration( - pos.y() + topBorder() ));
00593         actuallyDoScroll = true;
00594     }
00595     else if ( pos.y() > height() - bottomBorder() )
00596     {
00597         scrollDistance.setY ((int) autoScrollAcceleration(pos.y() - height() + bottomBorder() ));
00598         actuallyDoScroll = true;
00599     }
00600 
00601     if ( pos.x() < leftBorder() )
00602     {
00603         scrollDistance.setX ((int) - autoScrollAcceleration( - pos.x() + leftBorder() ));
00604         actuallyDoScroll = true;
00605     }
00606     else if ( pos.x() > width() - rightBorder() )
00607     {
00608         scrollDistance.setX ((int) autoScrollAcceleration( pos.x() - width() + rightBorder() ));
00609         actuallyDoScroll = true;
00610     }
00611 
00612     if ( actuallyDoScroll )
00613     {
00614         int state=0;
00615 #if KDE_IS_VERSION(3,4,0)
00616         state = kapp->keyboardMouseState();
00617 #endif
00618 
00619         pos = canvas()->mapFrom(this, pos);
00620         QMouseEvent * event = new QMouseEvent(QEvent::MouseMove, pos, 0, state);
00621 
00622         QApplication::postEvent( canvas(), event );
00623         emit autoScroll( scrollDistance );
00624     }
00625 }
00626 
00627 
00628 void KoView::setupGlobalActions() {
00629     actionNewView = new KAction( i18n( "&New View" ), "window_new", 0,
00630         this, SLOT( newView() ),
00631         actionCollection(), "view_newview" );
00632 }
00633 
00634 void KoView::setupPrinter( KPrinter & )
00635 {
00636     kdDebug() << "KoView::setupPrinter not implemented by the application!" << endl;
00637 }
00638 
00639 void KoView::print( KPrinter & )
00640 {
00641     kdDebug() << "KoView::print not implemented by the application!" << endl;
00642 }
00643 
00644 void KoView::newView() {
00645     assert( ( d!=0L && d->m_doc ) );
00646 
00647     KoDocument *thisDocument = d->m_doc;
00648     KoMainWindow *shell = new KoMainWindow( thisDocument->instance() );
00649     shell->setRootDocument(thisDocument);
00650     shell->show();
00651 }
00652 
00653 bool KoView::isInOperation() const
00654 {
00655    return d->m_inOperation;
00656 }
00657 
00658 void KoView::beginOperation()
00659 {
00660    d->m_inOperation = true;
00661    canvas()->setUpdatesEnabled(FALSE);
00662 }
00663 
00664 void KoView::endOperation()
00665 {
00666    canvas()->setUpdatesEnabled(TRUE);
00667    d->m_inOperation = false;
00668 
00669 //   canvas()->update();
00670 }
00671 
00672 KoMainWindow * KoView::shell() const
00673 {
00674     return dynamic_cast<KoMainWindow *>( topLevelWidget() );
00675 }
00676 
00677 KMainWindow * KoView::mainWindow() const
00678 {
00679     return dynamic_cast<KMainWindow *>( topLevelWidget() );
00680 }
00681 
00682 KStatusBar * KoView::statusBar() const
00683 {
00684     KoMainWindow *mw = shell();
00685     return mw ? mw->statusBar() : 0L;
00686 }
00687 
00688 void KoView::slotActionStatusText( const QString &text )
00689 {
00690   KStatusBar *sb = statusBar();
00691   if ( sb )
00692       sb->message( text );
00693 }
00694 
00695 void KoView::slotClearStatusText()
00696 {
00697   KStatusBar *sb = statusBar();
00698   if ( sb )
00699       sb->clear();
00700 }
00701 
00702 DCOPObject *KoView::dcopObject()
00703 {
00704     if ( !d->m_dcopObject )
00705         d->m_dcopObject = new KoViewIface( this );
00706     return d->m_dcopObject;
00707 }
00708 
00709 class KoViewChild::KoViewChildPrivate
00710 {
00711 public:
00712   KoViewChildPrivate()
00713   {
00714   }
00715   ~KoViewChildPrivate()
00716   {
00717   }
00718 };
00719 
00720 KoViewChild::KoViewChild( KoDocumentChild *child, KoView *_parentView )
00721 {
00722   d = new KoViewChildPrivate;
00723   m_parentView = _parentView;
00724   m_child = child;
00725 
00726   m_frame = new KoFrame( parentView()->canvas() );
00727   KoView *view = child->document()->createView( m_frame );
00728   view->setXMLGUIBuildDocument( child->document()->viewBuildDocument( view ) );
00729 
00730   view->setPartManager( parentView()->partManager() );
00731 
00732   // hack? (Werner)
00733   view->setZoom( parentView()->zoom() * QMAX(child->xScaling(), child->yScaling()) );
00734 
00735   m_frame->setView( view );
00736   m_frame->show();
00737   m_frame->raise();
00738 
00739   parentView()->canvasAddChild( this );
00740 
00741 
00742   /*
00743    KoViewChild has basically three geometries to keep in sync.
00744    - The KoDocumentChild geometry (i.e. the embedded object's geometry, unzoomed)
00745    - Its own geometry (used for hit-test etc.)
00746    - The KoFrame geometry (the graphical widget for moving the object when active)
00747 
00748    So we need to subtract the scrollview's offset for the frame geometry, since it's a widget.
00749 
00750    The rules are
00751    (R1) frameGeometry = viewGeometry(childGeometry) "+" m_frame->{left|right|top|bottom}Border() - scrollview offset,
00752    (R2) frameGeometry = myGeometry "+" active_frame_border - scrollview offset.
00753 
00754    So: (R3, unused) myGeometry = viewGeometry(childGeometry) "+" m_frame->{left|right|top|bottom}Border() "-" active_frame_border
00755 
00756    Notes: active_frame_border is m_frame->border() (0 when inactive, 5 when active).
00757           {left|right|top|bottom}Border are the borders used in kspread (0 when inactive, big when active).
00758           "+" border means we add a border, so it's a subtraction on x, y and an addition on width, height.
00759 
00760           viewGeometry() applies the zoom as well as any other translation the app might want to do
00761    */
00762 
00763   // Setting the frameGeometry is done in setInitialFrameGeometry, which is
00764   // also called right after activation.
00765 
00766   connect( view, SIGNAL( activated( bool ) ),
00767            parentView(), SLOT( slotChildActivated( bool ) ) );
00768 }
00769 
00770 KoViewChild::~KoViewChild()
00771 {
00772   if ( m_frame )
00773   {
00774     slotFrameGeometryChanged();
00775     delete static_cast<KoFrame *>( m_frame );
00776   }
00777   delete d;
00778 }
00779 
00780 void KoViewChild::slotFrameGeometryChanged()
00781 {
00782   // Set our geometry from the frame geometry (R2 reversed)
00783   QRect geom = m_frame->geometry();
00784   int b = m_frame->border();
00785   QRect borderRect( geom.x() + b + parentView()->canvasXOffset(),
00786                     geom.y() + b + parentView()->canvasYOffset(),
00787                     geom.width() - b * 2,
00788                     geom.height() - b * 2 );
00789   setGeometry( borderRect );
00790 
00791   if(m_child)
00792   {
00793     // Set the child geometry from the frame geometry (R1 reversed)
00794     QRect borderLessRect( geom.x() + m_frame->leftBorder() + parentView()->canvasXOffset(),
00795                           geom.y() + m_frame->topBorder() + parentView()->canvasYOffset(),
00796                           geom.width() - m_frame->leftBorder() - m_frame->rightBorder(),
00797                           geom.height() - m_frame->topBorder() - m_frame->bottomBorder() );
00798 
00799     // We don't want to trigger slotDocGeometryChanged again
00800     lock();
00801     QRect childGeom = parentView()->reverseViewTransformations( borderLessRect );
00802     kdDebug() << "KoChild::slotFrameGeometryChanged child geometry "
00803               << ( geometry() == childGeom ? "already " : "set to " )
00804               << childGeom << endl;
00805     m_child->setGeometry( childGeom );
00806     unlock();
00807   }
00808 }
00809 
00810 void KoViewChild::slotDocGeometryChanged()
00811 {
00812   if ( locked() )
00813       return;
00814   // Set frame geometry from child geometry (R1)
00815   // The frame's resizeEvent will call slotFrameGeometryChanged.
00816   QRect geom = parentView()->applyViewTransformations( m_child->geometry() );
00817   QRect borderRect( geom.x() - m_frame->leftBorder() - parentView()->canvasXOffset(),
00818                     geom.y() - m_frame->topBorder() - parentView()->canvasYOffset(),
00819                     geom.width() + m_frame->leftBorder() + m_frame->rightBorder(),
00820                     geom.height() + m_frame->topBorder() + m_frame->bottomBorder() );
00821   kdDebug() << "KoViewChild::slotDocGeometryChanged frame geometry "
00822             << ( m_frame->geometry() == borderRect ? "already " : "set to " )
00823             << borderRect << endl;
00824 
00825   m_frame->setGeometry( borderRect );
00826 }
00827 
00828 QPoint KoView::applyViewTransformations( const QPoint& p ) const
00829 {
00830   return QPoint( qRound( p.x() * zoom() ), qRound( p.y() * zoom() ) );
00831 }
00832 
00833 QPoint KoView::reverseViewTransformations( const QPoint& v ) const
00834 {
00835   return QPoint( qRound( v.x() / zoom() ), qRound( v.y() / zoom() ) );
00836 }
00837 
00838 QRect KoView::applyViewTransformations( const QRect& r ) const
00839 {
00840   return QRect( applyViewTransformations( r.topLeft() ),
00841                 applyViewTransformations( r.bottomRight() ) );
00842 }
00843 
00844 QRect KoView::reverseViewTransformations( const QRect& r ) const
00845 {
00846   return QRect( reverseViewTransformations( r.topLeft() ),
00847                 reverseViewTransformations( r.bottomRight() ) );
00848 }
00849 
00850 void KoViewChild::setInitialFrameGeometry()
00851 {
00852     kdDebug() << k_funcinfo << endl;
00853 
00854     // Connect only now, so that the GUI building doesn't move us around.
00855     connect( m_frame, SIGNAL( geometryChanged() ),
00856              this, SLOT( slotFrameGeometryChanged() ) );
00857     connect( m_child, SIGNAL( changed( KoChild * ) ),
00858              this, SLOT( slotDocGeometryChanged() ) );
00859 
00860     // Set frameGeometry from childGeometry
00861     slotDocGeometryChanged();
00862     // Set myGeometry from frameGeometry
00863     slotFrameGeometryChanged();
00864 
00865 }
00866 
00867 #include "KoView.moc"
00868 
KDE Home | KDE Accessibility Home | Description of Access Keys