kpresenter

KPrSideBar.cpp

00001 // -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4; -*-
00002 /* This file is part of the KDE project
00003    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00004    Copyright (C) 2001 Lukas Tinkl <lukas@kde.org>
00005    Copyright (C) 2002 Ariya Hidayat <ariya@kde.org>
00006    Copyright (C) 2005 Laurent Montel <montel@kde.org>
00007    Copyright (C) 2005 Thorsten Zachmann <zachmann@kde.org>
00008 
00009    This library is free software; you can redistribute it and/or
00010    modify it under the terms of the GNU Library General Public
00011    License as published by the Free Software Foundation; either
00012    version 2 of the License, or (at your option) any later version.
00013 
00014    This library is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017    Library General Public License for more details.
00018 
00019    You should have received a copy of the GNU Library General Public License
00020    along with this library; see the file COPYING.LIB.  If not, write to
00021    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022  * Boston, MA 02110-1301, USA.
00023 */
00024 
00025 #include <qheader.h>
00026 #include <qtimer.h>
00027 #include <qpopupmenu.h>
00028 #include <qimage.h>
00029 #include <qtabwidget.h>
00030 #include <qtooltip.h>
00031 
00032 #include <kwordwrap.h>
00033 #include <kmessagebox.h>
00034 #include <klocale.h>
00035 #include <kinputdialog.h>
00036 #include <knotifyclient.h>
00037 #include <kiconview.h>
00038 #include <kdebug.h>
00039 
00040 #include "KPrSideBar.h"
00041 #include "KPrView.h"
00042 #include "KPrDocument.h"
00043 #include "KPrCanvas.h"
00044 #include "KPrPage.h"
00045 #include "KPrObject.h"
00046 #include <qapplication.h>
00047 #include "KPrCommand.h"
00048 #include <qvalidator.h>
00049 #include "KPrFreehandObject.h"
00050 #include "KPrBezierCurveObject.h"
00051 #include "KPrTextObject.h"
00052 #include "KPrPolylineObject.h"
00053 #include "KPrClosedLineObject.h"
00054 #include "KPrGroupObject.h"
00055 
00056 
00057 QValidator::State KPrRenamePageValidator::validate( QString & input, int& ) const
00058 {
00059   QString str = input.stripWhiteSpace();
00060   if ( str.isEmpty() ) // we want to allow empty titles. Empty == automatic.
00061     return Acceptable;
00062 
00063   if ( mStringList.find( str ) == mStringList.end() )
00064     return Acceptable;
00065   else
00066     return Intermediate;
00067 }
00068 
00069 class ThumbToolTip : public QToolTip
00070 {
00071 public:
00072     ThumbToolTip( KPrThumbBar *parent )
00073         : QToolTip( parent->viewport() )
00074         , m_thumbBar( parent )
00075         {}
00076 
00077 protected:
00078     void maybeTip(const QPoint &pos)
00079     {
00080         QString title;
00081         QRect r( m_thumbBar->tip( pos, title ) );
00082         if (!r.isValid())
00083             return;
00084 
00085         tip(r, title);
00086     }
00087 private:
00088     KPrThumbBar *m_thumbBar;
00089 };
00090 
00091 
00092 class OutlineSlideItem: public KListViewItem
00093 {
00094 public:
00095     OutlineSlideItem( KListView * parent, KPrPage* page, bool _masterPage );
00096     OutlineSlideItem( KListView * parent, OutlineSlideItem *after, KPrPage* page, bool _masterPage );
00097 
00098     KPrPage* page() const { return m_page; }
00099 
00100     void setPage( KPrPage* p );
00101 
00102     void update();
00103     void updateTitle();
00104 
00105 private:
00106     KPrPage* m_page;
00107     bool m_masterPage;
00108 };
00109 
00110 class OutlineObjectItem: public KListViewItem
00111 {
00112 public:
00113     OutlineObjectItem( OutlineSlideItem * parent, KPrObject* object,
00114                        const QString& name = QString::null );
00115 
00116     KPrObject* object() const { return m_object; }
00117 
00118     void setObject( KPrObject* o );
00119 
00120 private:
00121     KPrObject* m_object;
00122 };
00123 
00124 class ThumbItem : public QIconViewItem
00125 {
00126 public:
00127     ThumbItem( QIconView *parent, const QString & text, const QPixmap & icon )
00128         : QIconViewItem( parent, text, icon )
00129         { uptodate = true; }
00130     ThumbItem( QIconView *parent, QIconViewItem *after, const QString & text, const QPixmap & icon )
00131         : QIconViewItem( parent, after, text, icon )
00132         { uptodate = true; }
00133 
00134     virtual bool isUptodate() { return uptodate; };
00135     virtual void setUptodate( bool _uptodate) { uptodate = _uptodate; };
00136 
00137 private:
00138     bool uptodate;
00139 };
00140 
00141 KPrSideBar::KPrSideBar(QWidget *parent, KPrDocument *d, KPrView *v)
00142     :QTabWidget(parent), m_doc(d), m_view(v)
00143 {
00144     setTabPosition(QTabWidget::Top);
00145     setTabShape(QTabWidget::Triangular);
00146 
00147     m_outline = new KPrOutline(this, m_doc, m_view);
00148     addTab(m_outline, i18n("Structure of the presentation", "Outline"));
00149 
00150     m_thb = new KPrThumbBar(this, m_doc, m_view);
00151     addTab(m_thb,i18n("Preview"));
00152 
00153 
00154     //TODO find a better way
00155     connect(m_outline, SIGNAL(showPage(int)),
00156             this, SIGNAL(showPage(int)));
00157 
00158     connect(m_thb, SIGNAL(showPage(int)),
00159             this, SIGNAL(showPage(int)));
00160 
00161     connect(m_outline, SIGNAL(movePage(int,int)),
00162             this, SIGNAL(movePage(int,int)));
00163 
00164     connect(m_outline, SIGNAL(selectPage(int,bool)),
00165             this, SIGNAL(selectPage(int,bool)));
00166 
00167     connect(this, SIGNAL(currentChanged(QWidget *)),
00168             this, SLOT(currentChanged(QWidget *)));
00169 
00170 }
00171 
00172 void KPrSideBar::currentChanged(QWidget *tab)
00173 {
00174     if (tab == m_thb) {
00175         if (!m_thb->uptodate && m_thb->isVisible())
00176             m_thb->rebuildItems();
00177         else
00178             m_thb->refreshItems();
00179     }
00180 }
00181 
00182 void KPrSideBar::addItem( int pos )
00183 {
00184     m_outline->addItem( pos );
00185     m_thb->addItem( pos );
00186 }
00187 
00188 void KPrSideBar::moveItem( int oldPos, int newPos )
00189 {
00190     m_outline->moveItem( oldPos, newPos );
00191     m_thb->moveItem( oldPos, newPos );
00192 }
00193 
00194 void KPrSideBar::removeItem( int pos )
00195 {
00196     m_outline->removeItem( pos );
00197     m_thb->removeItem( pos );
00198 }
00199 
00200 void KPrSideBar::updateItem( KPrPage *page )
00201 {
00202     bool sticky = false;
00203     int pos = 0;
00204     if ( page == m_doc->masterPage() )
00205     {
00206         pos = -1;
00207         sticky = true;
00208     }
00209     else
00210     {
00211         pos = m_doc->pageList().findRef( page );
00212     }
00213 
00214     m_outline->updateItem( pos, sticky );
00215     m_thb->updateItem( pos, sticky );
00216 }
00217 
00218 void KPrSideBar::setViewMasterPage( bool _masterPage )
00219 {
00220     m_outline->setViewMasterPage( _masterPage );
00221     m_thb->setViewMasterPage( _masterPage );
00222     m_outline->rebuildItems();
00223     m_thb->rebuildItems();
00224 }
00225 
00226 KPrSideBarBase::KPrSideBarBase(KPrDocument *_doc, KPrView *_view)
00227     : m_doc( _doc ), m_view( _view ), m_viewMasterPage( false )
00228 {
00229 }
00230 
00231 void KPrSideBarBase::setViewMasterPage( bool _b )
00232 {
00233     m_viewMasterPage = _b;
00234 }
00235 
00236 KPrThumbBar::KPrThumbBar(QWidget *parent, KPrDocument *d, KPrView *v)
00237     :KIconView(parent), KPrSideBarBase( d,v)
00238 {
00239     uptodate = false;
00240     m_offsetX = 0;
00241     m_offsetY = 0;
00242 
00243     setArrangement(QIconView::LeftToRight);
00244     setAutoArrange(true);
00245     setSorting(false);
00246     setItemsMovable(false);
00247     setResizeMode(QIconView::Adjust);
00248 
00249     m_thumbTip = new ThumbToolTip(this);
00250 
00251     connect(this, SIGNAL(currentChanged(QIconViewItem *)),
00252             this, SLOT(itemClicked(QIconViewItem *)));
00253     connect(this, SIGNAL(contentsMoving(int, int)),
00254             this, SLOT(slotContentsMoving(int, int)));
00255 }
00256 
00257 KPrThumbBar::~KPrThumbBar()
00258 {
00259     delete m_thumbTip;
00260 }
00261 
00262 void KPrThumbBar::setCurrentPage( int pg )
00263 {
00264     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
00265     {
00266         if ( it->text().toInt() - 1 == pg ) {
00267             blockSignals( true );
00268             setCurrentItem( it );
00269             setSelected( it, FALSE ); // to avoid the blue "selected"-mark
00270             ensureItemVisible(it);
00271             refreshItems();
00272             blockSignals( false );
00273             return;
00274         }
00275     }
00276 }
00277 
00278 QRect KPrThumbBar::tip(const QPoint &pos, QString &title)
00279 {
00280     QIconViewItem *item = findItem(viewportToContents(pos));
00281     if (!item)
00282         return QRect(0, 0, -1, -1);
00283 
00284     int pagenr =  item->index();
00285     title = m_doc->pageList().at(pagenr)->pageTitle();
00286 
00287     QRect r = item->pixmapRect(FALSE);
00288     r = QRect(contentsToViewport(QPoint(r.x(), r.y())), QSize(r.width(), r.height()));
00289     return r;
00290 }
00291 
00292 void KPrThumbBar::rebuildItems()
00293 {
00294     kdDebug()<<" void KPrThumbBar::rebuildItems() beofre \n";
00295     if( !isVisible())
00296         return;
00297     kdDebug(33001) << "KPrThumbBar::rebuildItems" << endl;
00298 
00299     QApplication::setOverrideCursor( Qt::waitCursor );
00300 
00301     clear();
00302     if ( m_viewMasterPage )
00303     {
00304     }
00305     else
00306     {
00307         for ( unsigned int i = 0; i < m_doc->getPageNums(); i++ ) {
00308             // calculate the size of the thumb
00309             QRect rect = m_doc->pageList().at(i)->getZoomPageRect( );
00310 
00311             int w = rect.width();
00312             int h = rect.height();
00313             if ( w > h ) {
00314                 w = 130;
00315                 float diff = (float)rect.width() / (float)w;
00316                 h = (int) (rect.height() / diff);
00317                 if ( h > 120 ) {
00318                     h = 120;
00319                     float diff = (float)rect.height() / (float)h;
00320                     w = (int) (rect.width() / diff);
00321                 }
00322             }
00323             else if ( w < h ) {
00324                 h = 130;
00325                 float diff = (float)rect.height() / (float)h;
00326                 w = (int) (rect.width() / diff);
00327                 if ( w > 120 ) {
00328                     w = 120;
00329                     float diff = (float)rect.width() / (float)w;
00330                     h = (int) (rect.height() / diff);
00331                 }
00332             }
00333             else if ( w == h ) {
00334                 w = 130;
00335                 h = 130;
00336             }
00337 
00338             // draw an empty thumb
00339             QPixmap pix(w, h);
00340             pix.fill( Qt::white );
00341 
00342             QPainter p(&pix);
00343             p.setPen(Qt::black);
00344             p.drawRect(pix.rect());
00345 
00346             ThumbItem *item = new ThumbItem(static_cast<QIconView *>(this), QString::number(i+1), pix);
00347             item->setUptodate( false );
00348             item->setDragEnabled(false);  //no dragging for now
00349         }
00350 
00351         QTimer::singleShot( 10, this, SLOT( slotRefreshItems() ) );
00352     }
00353     uptodate = true;
00354 
00355     QApplication::restoreOverrideCursor();
00356 }
00357 
00358 void KPrThumbBar::refreshItems(bool offset)
00359 {
00360     QRect vRect = visibleRect();
00361     if ( offset )
00362         vRect.moveBy( m_offsetX, m_offsetY );
00363     else
00364         vRect.moveBy( contentsX(), contentsY() );
00365 
00366     QIconViewItem *it = findFirstVisibleItem( vRect );
00367     while ( it )
00368     {
00369         kdDebug(33001) << "visible page = " << it->text().toInt() << endl;
00370         if ( ! dynamic_cast<ThumbItem *>(it)->isUptodate( ) ){
00371             //todo refresh picture
00372             it->setPixmap( getSlideThumb( it->text().toInt() - 1 ) );
00373             static_cast<ThumbItem *>(it)->setUptodate( true );
00374         }
00375 
00376         if ( it == findLastVisibleItem( vRect ) )
00377             break;
00378         it = it->nextItem();
00379     }
00380 
00381     m_offsetX = 0;
00382     m_offsetY = 0;
00383 }
00384 
00385 void KPrThumbBar::updateItem( int pagenr /* 0-based */, bool sticky )
00386 {
00387     if ( m_viewMasterPage )
00388         return;
00389     if ( !uptodate )
00390         return;
00391     int pagecnt = 0;
00392     // calculate rect of visible objects
00393     QRect vRect = visibleRect();
00394     vRect.moveBy( contentsX(), contentsY() );
00395 
00396     // Find icon
00397     QIconViewItem *it = firstItem();
00398     do
00399     {
00400         if ( it == findFirstVisibleItem( vRect ) ) {
00401             do
00402             {
00403                 if ( sticky || it->text().toInt() == pagenr + 1 ) {
00404                     it->setPixmap(getSlideThumb( pagecnt ));
00405                     static_cast<ThumbItem *>(it)->setUptodate( true );
00406 
00407                     if ( !sticky )
00408                         return;
00409                 }
00410                 if ( it == findLastVisibleItem( vRect ) )
00411                     break;
00412                 pagecnt++;
00413                 it = it->nextItem();
00414             } while ( true );
00415         }
00416         else if ( sticky || it->text().toInt() == pagenr + 1 ) {
00417             static_cast<ThumbItem *>(it)->setUptodate( false );
00418             if ( !sticky )
00419                 return;
00420         }
00421         pagecnt++;
00422         it = it->nextItem();
00423     } while ( it );
00424 
00425     if ( ! sticky )
00426         kdWarning(33001) << "Item for page " << pagenr << " not found" << endl;
00427 }
00428 
00429 // add a thumb item without recreating all thumbs
00430 void KPrThumbBar::addItem( int pos )
00431 {
00432     kdDebug(33001)<< "KPrThumbBar::addItem" << endl;
00433     int page = 0;
00434     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00435         // find page which should move
00436         // do stuff because a item can not be insert at the beginning
00437         if ( pos == 0 && page == pos ){
00438             ThumbItem *item = new ThumbItem(static_cast<QIconView *>(this), it, QString::number(2), getSlideThumb(1));
00439             item->setDragEnabled(false);  //no dragging for now
00440             it->setPixmap(getSlideThumb( 0 ));
00441             // move on to next item as we have inserted one
00442             it = it->nextItem();
00443         }
00444         else if ( (page + 1) == pos ) {
00445             ThumbItem *item = new ThumbItem(static_cast<QIconView *>(this), it, QString::number(pos+1), getSlideThumb(pos));
00446             item->setDragEnabled(false);  //no dragging for now
00447             it = it->nextItem();
00448         }
00449         // update page numbers
00450         if ( page >= pos )
00451             it->setText( QString::number(page+2) );
00452         page++;
00453     }
00454 }
00455 
00456 // moves a item without recreating all pages
00457 void KPrThumbBar::moveItem( int oldPos, int newPos )
00458 {
00459     kdDebug(33001)<< "KPrThumbBar::moveItem " << oldPos << " to " << newPos << endl;
00460     int page = 0;
00461     QIconViewItem *after = 0;
00462     QIconViewItem *take = 0;
00463     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00464         // find page which should move
00465         if ( page == oldPos )
00466             take = it;
00467         // find position where page should be insert
00468         // as a page can not be insert at the beginning get the first one
00469         // the page to get depends on if a page is moved forward / backwards
00470         if ( page == newPos )
00471             after = page == 0 ? it : newPos > oldPos ? it : it->prevItem();
00472         page++;
00473     }
00474 
00475     if ( ! take )
00476         return;
00477 
00478     // workaround for a bug in qt 3.1.1 insertItem dose not work.
00479     // TODO remove workaround when qt 3.1.2 comes out tz
00480     //takeItem( take );
00481     //insertItem( take, after);
00482     ThumbItem *item = new ThumbItem( static_cast<QIconView *>(this), after, QString::number( newPos ), *(take->pixmap()) );
00483     item->setDragEnabled(false);  //no dragging for now
00484     delete take;
00485     // update the thumbs if new pos was 0
00486     // because it was insert after the first one
00487     if ( newPos == 0 ) {
00488         //todo do not recreate the pics
00489         after->setPixmap(getSlideThumb( 0 ));
00490         //take->setPixmap(getSlideThumb( 1 ));
00491         item->setPixmap(getSlideThumb( 1 ));
00492     }
00493 
00494     //write the new page numbers
00495     int lowPage = oldPos > newPos ? newPos : oldPos;
00496     int highPage = oldPos < newPos ? newPos : oldPos;
00497     page = 0;
00498     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00499         if ( page >= lowPage && page <= highPage)
00500             it->setText( QString::number(page+1) );
00501         page++;
00502     }
00503 }
00504 
00505 void KPrThumbBar::removeItem( int pos )
00506 {
00507     kdDebug(33001)<< "KPrThumbBar::removeItem" << endl;
00508     int page = 0;
00509     bool change = false;
00510     QIconViewItem *itemToDelete = 0;
00511 
00512     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00513         if ( page == pos ) {
00514             itemToDelete = it;
00515             if ( it->nextItem() )
00516                 it = it->nextItem();
00517             change = true;
00518         }
00519         if ( change )
00520             it->setText( QString::number( page + 1 ) );
00521         page++;
00522     }
00523     delete itemToDelete;
00524 }
00525 
00526 QPixmap KPrThumbBar::getSlideThumb(int slideNr) const
00527 {
00528     //kdDebug(33001) << "KPrThumbBar::getSlideThumb: " << slideNr << endl;
00529     QPixmap pix( 10, 10 );
00530 
00531     m_view->getCanvas()->drawPageInPix( pix, slideNr, 60 );
00532 
00533     int w = pix.width();
00534     int h = pix.height();
00535 
00536     if ( w > h ) {
00537         w = 130;
00538         h = 120;
00539     }
00540     else if ( w < h ) {
00541         w = 120;
00542         h = 130;
00543     }
00544     else if ( w == h ) {
00545         w = 130;
00546         h = 130;
00547     }
00548 
00549     const QImage img(pix.convertToImage().smoothScale( w, h, QImage::ScaleMin ));
00550     pix.convertFromImage(img);
00551 
00552     // draw a frame around the thumb to show its size
00553     QPainter p(&pix);
00554     p.setPen(Qt::black);
00555     p.drawRect(pix.rect());
00556 
00557     return pix;
00558 }
00559 
00560 void KPrThumbBar::itemClicked(QIconViewItem *i)
00561 {
00562     if ( !i )
00563         return;
00564     emit showPage( i->index() );
00565 }
00566 
00567 void KPrThumbBar::slotContentsMoving(int x, int y)
00568 {
00569     m_offsetX = x;
00570     m_offsetY = y;
00571     kdDebug(33001) << "offset x,y = " << x << ", " << y << endl;
00572     refreshItems( true );
00573 }
00574 
00575 void KPrThumbBar::slotRefreshItems()
00576 {
00577     refreshItems();
00578 }
00579 
00580 OutlineSlideItem::OutlineSlideItem( KListView* parent, KPrPage* _page, bool _masterPage )
00581     : KListViewItem( parent ), m_page( _page ), m_masterPage( _masterPage )
00582 {
00583     setDragEnabled(true);
00584     setPage( _page );
00585     setPixmap( 0, KPBarIcon( "slide" ) );
00586 }
00587 
00588 OutlineSlideItem::OutlineSlideItem( KListView* parent, OutlineSlideItem * after, KPrPage* _page, bool _masterPage )
00589     : KListViewItem( parent, after ), m_page( _page ), m_masterPage( _masterPage )
00590 {
00591     setDragEnabled(true);
00592     setPage( _page );
00593     setPixmap( 0, KPBarIcon( "slide" ) );
00594 }
00595 
00596 void OutlineSlideItem::setPage( KPrPage* p )
00597 {
00598     if( !p ) return;
00599     m_page = p;
00600     update();
00601 }
00602 
00603 void OutlineSlideItem::update()
00604 {
00605     if( !m_page ) return;
00606     KPrDocument *doc = m_page->kPresenterDoc();
00607     updateTitle();
00608 
00609     // add all objects
00610     OutlineObjectItem *ooi = 0;
00611     while ( ( ooi = dynamic_cast<OutlineObjectItem*>( this->firstChild() ) ) )
00612         delete ooi;
00613 
00614     // keep selected object
00615     ooi = 0;
00616 
00617     QPtrListIterator<KPrObject> it( m_page->objectList() );
00618 
00619     if ( !m_masterPage )
00620     {
00621         for ( ; it.current(); ++it ) {
00622             OutlineObjectItem *item = new OutlineObjectItem( this, it.current() );
00623             item->setDragEnabled( false );
00624             if ( it.current()->isSelected() )
00625                 ooi = item;
00626         }
00627     }
00628     else
00629     {
00630         KPrObject* header = 0;
00631         KPrObject* footer = 0;
00632 
00633         // add sticky objects, exclude header and footer
00634         it = doc->masterPage()->objectList();
00635         for ( ; it.current() ; ++it )
00636         {
00637             KPrObject* object = it.current();
00638 
00639             if( m_page->hasHeader() && doc->isHeader( object ) )
00640                 header = object;
00641             else if( m_page->hasFooter() && doc->isFooter( object ) )
00642                 footer = object;
00643             else if( !doc->isHeader( object ) && !doc->isFooter( object ) ) {
00644                 OutlineObjectItem *item = new OutlineObjectItem( this, object );
00645                 if ( object->isSelected() )
00646                     ooi = item;
00647             }
00648 
00649         }
00650 
00651         // add header and footer (if any)
00652         if ( footer ) {
00653             OutlineObjectItem *item = new OutlineObjectItem( this, footer, i18n("Footer") );
00654             if ( footer->isSelected() )
00655                 ooi = item;
00656         }
00657 
00658         if ( header ) {
00659             OutlineObjectItem *item = new OutlineObjectItem( this, header, i18n("Header") );
00660             if ( header->isSelected() )
00661                 ooi = item;
00662         }
00663     }
00664 
00665     // select selected object the page is necessary that a
00666     // sticky object is selected on the active page
00667     if ( ooi && doc->activePage() == m_page )
00668         (ooi->listView())->setSelected( ooi, true );
00669 }
00670 
00671 void OutlineSlideItem::updateTitle()
00672 {
00673     QString title = m_page->pageTitle();
00674     if ( ! m_page->isSlideSelected() )
00675         title = i18n( "(%1)" ).arg( title );
00676     setText( 0, title );
00677 }
00678 
00679 OutlineObjectItem::OutlineObjectItem( OutlineSlideItem* parent, KPrObject* _object,
00680                                       const QString& name )
00681     : KListViewItem( parent ), m_object( _object )
00682 {
00683     setObject( m_object );
00684     setDragEnabled( false );
00685 
00686     QString objectName = name.isEmpty() ? m_object->getObjectName() : name;
00687     //if( sticky ) objectName += i18n(" (Sticky)" );
00688     setText( 0, objectName );
00689 }
00690 
00691 void OutlineObjectItem::setObject( KPrObject* object )
00692 {
00693     if( !object ) return;
00694     m_object = object;
00695 
00696     switch ( m_object->getType() ) {
00697     case OT_PICTURE:
00698         setPixmap( 0, KPBarIcon( "frame_image" ) );
00699         break;
00700     case OT_LINE:
00701         setPixmap( 0, KPBarIcon( "mini_line" ) );
00702         break;
00703     case OT_RECT:
00704         setPixmap( 0, KPBarIcon( "mini_rect" ) );
00705         break;
00706     case OT_ELLIPSE:
00707         setPixmap( 0, KPBarIcon( "mini_circle" ) );
00708         break;
00709     case OT_TEXT:
00710         setPixmap( 0, KPBarIcon( "frame_text" ) );
00711         break;
00712     case OT_AUTOFORM:
00713         setPixmap( 0, KPBarIcon( "mini_autoform" ) );
00714         break;
00715     case OT_CLIPART:
00716         setPixmap( 0, KPBarIcon( "mini_clipart" ) );
00717         break;
00718     case OT_PIE:
00719         setPixmap( 0, KPBarIcon( "mini_pie" ) );
00720         break;
00721     case OT_PART:
00722         setPixmap( 0, KPBarIcon( "frame_query" ) );
00723         break;
00724     case OT_FREEHAND:
00725         setPixmap( 0, KPBarIcon( "freehand" ) );
00726         break;
00727     case OT_POLYLINE:
00728         setPixmap( 0, KPBarIcon( "polyline" ) );
00729         break;
00730     case OT_QUADRICBEZIERCURVE:
00731         setPixmap( 0, KPBarIcon( "quadricbeziercurve" ) );
00732         break;
00733     case OT_CUBICBEZIERCURVE:
00734         setPixmap( 0, KPBarIcon( "cubicbeziercurve" ) );
00735         break;
00736     case OT_POLYGON:
00737         setPixmap( 0, KPBarIcon( "mini_polygon" ) );
00738         break;
00739     case OT_CLOSED_LINE: {
00740         QString name = m_object->getTypeString();
00741         if ( name == i18n( "Closed Freehand" ) )
00742             setPixmap( 0, KPBarIcon( "closed_freehand" ) );
00743         else if ( name == i18n( "Closed Polyline" ) )
00744             setPixmap( 0, KPBarIcon( "closed_polyline" ) );
00745         else if ( name == i18n( "Closed Quadric Bezier Curve" ) )
00746             setPixmap( 0, KPBarIcon( "closed_quadricbeziercurve" ) );
00747         else if ( name == i18n( "Closed Cubic Bezier Curve" ) )
00748             setPixmap( 0, KPBarIcon( "closed_cubicbeziercurve" ) );
00749     } break;
00750     case OT_GROUP:
00751         setPixmap( 0, KPBarIcon( "group" ) );
00752         break;
00753     default:
00754         break;
00755     }
00756 }
00757 
00758 KPrOutline::KPrOutline( QWidget *parent, KPrDocument *d, KPrView *v )
00759     : KListView( parent ), KPrSideBarBase( d, v)
00760 {
00761     rebuildItems();
00762     setSorting( -1 );
00763     header()->hide();
00764     addColumn( i18n( "Slide" ) );
00765     setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) );
00766 
00767     connect( this, SIGNAL( currentChanged( QListViewItem * ) ), this, SLOT( itemClicked( QListViewItem * ) ) );
00768     connect( this, SIGNAL( rightButtonPressed( QListViewItem *, const QPoint &, int ) ),
00769              this, SLOT( rightButtonPressed( QListViewItem *, const QPoint &, int ) ) );
00770     connect( this, SIGNAL( contextMenu( KListView*, QListViewItem*, const QPoint& ) ),
00771              this, SLOT( slotContextMenu( KListView*, QListViewItem*, const QPoint&) ) );
00772 
00773     connect( this, SIGNAL( doubleClicked ( QListViewItem * )),
00774              this, SLOT(renamePageTitle()));
00775     connect( this, SIGNAL( dropped( QDropEvent*, QListViewItem*, QListViewItem* ) ),
00776              this, SLOT( slotDropped( QDropEvent*, QListViewItem*, QListViewItem*  ) ));
00777 
00778     setItemsMovable( false );
00779     setDragEnabled( true );
00780     setAcceptDrops( true );
00781     setDropVisualizer( true );
00782     setFullWidth( true );
00783     this->setRootIsDecorated( true );
00784 }
00785 
00786 KPrOutline::~KPrOutline()
00787 {
00788 }
00789 
00790 void KPrOutline::rebuildItems()
00791 {
00792     clear();
00793     if ( m_viewMasterPage )
00794     {
00795         KPrPage *page=m_doc->masterPage();
00796         new OutlineSlideItem( this, page, true );
00797     }
00798     else
00799     {
00800         // Rebuild all the items
00801         for ( int i = m_doc->getPageNums() - 1; i >= 0; --i ) {
00802             KPrPage *page=m_doc->pageList().at( i );
00803             new OutlineSlideItem( this, page, false );
00804         }
00805     }
00806 }
00807 
00808 // given the page number (0-based), find associated slide item
00809 // returns 0 upon stupid things (e.g. invalid page number)
00810 OutlineSlideItem* KPrOutline::slideItem( int pageNumber )
00811 {
00812     QListViewItem* item = firstChild();
00813     for( int index = 0; item; ++index, item = item->nextSibling() ) {
00814         if( index == pageNumber )
00815             return dynamic_cast<OutlineSlideItem*>( item );
00816     }
00817 
00818     return 0;
00819 }
00820 
00821 
00822 // update the KPrOutline item, the title may have changed
00823 void KPrOutline::updateItem( int pagenr /* 0-based */, bool sticky )
00824 {
00825     if ( ! sticky ) {
00826         OutlineSlideItem *item = slideItem( pagenr );
00827         if( item ) {
00828             blockSignals(true);
00829             item->update();
00830             blockSignals(false);
00831         }
00832     } else {
00833         blockSignals(true);
00834         for( QListViewItem *item = this->firstChild(); item; item = item->nextSibling() )
00835             dynamic_cast<OutlineSlideItem*>(item)->update();
00836         blockSignals(false);
00837     }
00838 }
00839 
00840 void KPrOutline::addItem( int pos )
00841 {
00842     kdDebug(33001)<< "KPrOutline::addItem" << endl;
00843 
00844     KPrPage *page=m_doc->pageList().at( pos );
00845     OutlineSlideItem *item;
00846     if ( pos == 0 ) {
00847         item = new OutlineSlideItem( this, page,m_viewMasterPage );
00848     }
00849     else {
00850         OutlineSlideItem *after = slideItem( pos - 1 );
00851         item = new OutlineSlideItem( this, after, page,m_viewMasterPage );
00852     }
00853 
00854     item = dynamic_cast<OutlineSlideItem*>( item->nextSibling() );
00855     // update title
00856     for( ; item; item = dynamic_cast<OutlineSlideItem*>( item->nextSibling() ) )
00857         item->updateTitle();
00858 }
00859 
00860 // move an KPrOutline Item so that not the hole list has to be recreated
00861 void KPrOutline::moveItem( int oldPos, int newPos )
00862 {
00863     kdDebug(33001)<< "KPrOutline::moveItem " << oldPos << " to " << newPos << endl;
00864 
00865     int lowPage = oldPos > newPos ? newPos : oldPos;
00866     int highPage = oldPos < newPos ? newPos : oldPos;
00867 
00868     OutlineSlideItem *item = dynamic_cast<OutlineSlideItem*>( firstChild() );
00869     QListViewItem *itemToMove = 0;
00870     QListViewItem *itemAfter = 0;
00871 
00872     // moving backwards
00873     if ( newPos < oldPos )
00874         newPos--;
00875 
00876     for ( int index = 0; item; ++index, item = dynamic_cast<OutlineSlideItem*>( item->nextSibling() ) )
00877     {
00878         if ( index == oldPos )
00879             itemToMove = item;
00880         if ( index == newPos )
00881             itemAfter = item;
00882         if ( index >= lowPage && index <= highPage )
00883             item->updateTitle();
00884     }
00885 
00886     KListView::moveItem( itemToMove, 0, itemAfter );
00887 }
00888 
00889 void KPrOutline::removeItem( int pos )
00890 {
00891     kdDebug(33001)<< "KPrOutline::removeItem" << endl;
00892 
00893     OutlineSlideItem* item = slideItem( pos );
00894     if( !item ) return;
00895     OutlineSlideItem* temp = dynamic_cast<OutlineSlideItem*>(item->nextSibling());
00896 
00897     delete item;
00898 
00899     for ( item = temp; item; item = dynamic_cast<OutlineSlideItem*>( item->nextSibling() ) )
00900         item->updateTitle();
00901 }
00902 
00903 void KPrOutline::itemClicked( QListViewItem *item )
00904 {
00905     if( !item ) return;
00906 
00907     // check if we need to show chosen slide
00908     OutlineSlideItem* slideItem = dynamic_cast<OutlineSlideItem*>(item);
00909     if( slideItem )
00910     {
00911         KPrPage* page = slideItem->page();
00912         if( !page ) return;
00913         if ( !m_viewMasterPage )
00914             emit showPage( m_doc->pageList().findRef( page ) );
00915     }
00916 
00917     // check if we need to show chosen object
00918     OutlineObjectItem* objectItem = dynamic_cast<OutlineObjectItem*>(item);
00919     if( objectItem )
00920     {
00921         KPrObject *object = objectItem->object();
00922         if( !object ) return;
00923 
00924         // ensure the owner slide is shown first
00925         OutlineSlideItem* slideItem = dynamic_cast<OutlineSlideItem*>(objectItem->parent());
00926         if( slideItem && m_doc->activePage() != slideItem->page() )
00927         {
00928             KPrPage* page = slideItem->page();
00929             if( !page ) return;
00930             if ( !m_viewMasterPage )
00931                 emit showPage( m_doc->pageList().findRef( page ) );
00932         }
00933 
00934         // select the object, make sure it's visible
00935         m_doc->deSelectAllObj();
00936         m_view->getCanvas()->selectObj( object );
00937         m_view->showObjectRect( object );
00938         m_doc->repaint( false );
00939     }
00940 }
00941 
00949 void KPrOutline::slotDropped( QDropEvent * /* e */, QListViewItem *parent, QListViewItem *target )
00950 {
00951     kdDebug(33001) << "slotDropped" << endl;
00952     /* slide doesn't have parent (always 0)
00953      * Only slides can move at the moment, objects can't. */
00954     if ( parent )
00955         return;
00956 
00957     // This code is taken from KListView
00958     for (QListViewItem *i = firstChild(), *iNext = 0; i != 0; i = iNext)
00959     {
00960         iNext = i->itemBelow();
00961         if ( !i->isSelected() )
00962             continue;
00963 
00964         // don't drop an item after itself, or else
00965         // it moves to the top of the list
00966         if ( i == target )
00967             continue;
00968 
00969         i->setSelected( false );
00970 
00971         // don't move the item as it is allready
00972         moveItem(i, parent, target );
00973 
00974         // Only one item can be moved
00975         break;
00976     }
00977 }
00978 
00979 // We have to overwrite this method as it checks if an item is movable
00980 // and we have disabled it.
00981 bool KPrOutline::acceptDrag( QDropEvent* e ) const
00982 {
00983     return acceptDrops() && (e->source()==viewport());
00984 }
00985 
00986 
00987 void KPrOutline::setCurrentPage( int pg )
00988 {
00989     OutlineSlideItem *item = slideItem( pg );
00990     if( item && ( item!=currentItem()->parent() ) )
00991     {
00992         blockSignals( true );
00993         setCurrentItem( item );
00994         setSelected( item, true );
00995         ensureItemVisible( item );
00996         blockSignals( false );
00997     }
00998 }
00999 
01000 void KPrOutline::contentsDropEvent( QDropEvent *e )
01001 {
01002     disconnect( this, SIGNAL( currentChanged( QListViewItem * ) ), this, SLOT( itemClicked( QListViewItem * ) ) );
01003     KListView::contentsDropEvent( e );
01004     connect( this, SIGNAL( currentChanged( QListViewItem * ) ), this, SLOT( itemClicked( QListViewItem * ) ) );
01005 }
01006 
01007 void KPrOutline::moveItem( QListViewItem *i, QListViewItem *, QListViewItem *newAfter )
01008 {
01009     OutlineSlideItem* srcItem = dynamic_cast<OutlineSlideItem*>( i );
01010     if ( !srcItem )
01011         return;
01012 
01013     int num = m_doc->pageList().findRef( srcItem->page() );
01014 
01015     int numNow = 0;
01016     if ( newAfter )
01017     {
01018         OutlineSlideItem* dstItem = dynamic_cast<OutlineSlideItem*>( newAfter );
01019         if( !dstItem )
01020             return;
01021 
01022         numNow = m_doc->pageList().findRef( dstItem->page() );
01023         if ( numNow < num )
01024             numNow++;
01025     }
01026 
01027     if ( num!=numNow )
01028         m_doc->movePage( num, numNow );
01029 }
01030 
01031 void KPrOutline::rightButtonPressed( QListViewItem *, const QPoint &pnt, int )
01032 {
01033     if ( !m_doc->isReadWrite() || m_viewMasterPage ) return;
01034 
01035     QListViewItem *item = QListView::selectedItem();
01036     if( !item ) return;
01037 
01038     OutlineSlideItem* slideItem = dynamic_cast<OutlineSlideItem*>(item);
01039 
01040     if( slideItem ) {
01041         m_view->openPopupMenuSideBar(pnt);
01042     } else {
01043         OutlineObjectItem* objectItem = dynamic_cast<OutlineObjectItem*>(item);
01044         if( objectItem ) 
01045         {
01046             KPrObject * kpobject = objectItem->object();
01047 
01048             if( !kpobject ) {
01049                 return;
01050             }
01051 
01052             KPrCanvas* canvas = static_cast<KPrCanvas*>(m_view->canvas());
01053             canvas->deSelectAllObj();
01054             canvas->selectObj( kpobject );
01055 
01056             canvas->objectPopup( kpobject, pnt );
01057         }
01058     }
01059 }
01060 
01061 void KPrOutline::slotContextMenu( KListView*, QListViewItem* item, const QPoint& p )
01062 {
01063     rightButtonPressed( item, p, 0 );
01064 }
01065 
01066 void KPrOutline::renamePageTitle()
01067 {
01068     QListViewItem *item = QListView::selectedItem();
01069     if( !item || m_viewMasterPage) return;
01070 
01071     OutlineSlideItem* slideItem = dynamic_cast<OutlineSlideItem*>(item);
01072     if( !slideItem ) return;
01073 
01074     KPrPage* page = slideItem->page();
01075     if( !page ) return;
01076 
01077     bool ok = false;
01078     QString activeTitle = item->text( 0 );
01079 
01080     QStringList page_titles;
01081     KPrPage *it;
01082     for ( it = m_doc->pageList().first(); it; it = m_doc->pageList().next() )
01083       if ( it->pageTitle() != activeTitle )
01084         page_titles.append( it->pageTitle() );
01085 
01086     KPrRenamePageValidator validator( page_titles );
01087     QString newTitle = KInputDialog::getText( i18n("Rename Slide"),
01088                                               i18n("Slide title:"), activeTitle, &ok, this, 0,
01089                                               &validator );
01090 
01091     // Have a different name ?
01092     if ( ok ) { // User pushed an OK button.
01093         if ( newTitle != activeTitle ) { // Title changed.
01094             KPrChangeTitlePageNameCommand *cmd=new KPrChangeTitlePageNameCommand( i18n("Rename Slide"),
01095                                                                                   m_doc, activeTitle, newTitle.stripWhiteSpace(), page  );
01096             cmd->execute();
01097             m_doc->addCommand(cmd);
01098         }
01099     }
01100 }
01101 
01102 QDragObject* KPrOutline::dragObject()
01103 {
01104     if( !selectedItem()->dragEnabled() ) {
01105       return 0;
01106     }
01107 
01108     return KListView::dragObject();
01109 }
01110 
01111 #include "KPrSideBar.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys