• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kviewshell

marklist.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 Wilfried Huss <Wilfried.Huss@gmx.at>
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 <config.h>
00021 
00022 #include <qcheckbox.h>
00023 #include <qimage.h>
00024 #include <qlabel.h>
00025 #include <qlayout.h>
00026 #include <qtooltip.h>
00027 #include <qlabel.h>
00028 #include <qwhatsthis.h>
00029 #include <qpainter.h>
00030 #include <qtimer.h>
00031 
00032 #include <kapplication.h>
00033 #include <kglobalsettings.h>
00034 #include <klocale.h>
00035 #include <kpopupmenu.h>
00036 #include <kiconloader.h>
00037 #include <kdebug.h>
00038 
00039 #include "documentPageCache.h"
00040 #include "kvsprefs.h"
00041 #include "marklist.h"
00042 
00043 
00044 #include "marklist.moc"
00045 
00046 
00047 namespace {
00048 
00050 QPixmap* waitIcon = 0;
00051 
00052 } // namespace anon
00053 
00054 
00055 /****** ThumbnailWidget ******/
00056 
00057 ThumbnailWidget::ThumbnailWidget(MarkListWidget* _parent, const PageNumber& _pageNumber, DocumentPageCache* _pageCache)
00058   : QWidget(_parent), pageNumber(_pageNumber), pageCache(_pageCache), parent(_parent)
00059 {
00060   setBackgroundMode(Qt::NoBackground);
00061 
00062   needsUpdating = true;
00063 
00064   if (!waitIcon)
00065   {
00066     waitIcon = new QPixmap(KGlobal::iconLoader()->loadIcon("gear", KIcon::NoGroup, KIcon::SizeMedium));
00067   }
00068 }
00069 
00070 void ThumbnailWidget::paintEvent(QPaintEvent* e)
00071 {
00072   // Only repaint if the widget is really visible. We need to check this because Qt
00073   // sends paintEvents to all widgets that have ever been visible in the Scrollview
00074   // whenever the ScrollView is resized. This also increases the percieved performance
00075   // only thumbnails that are really needed are rendered.
00076   if (!parent->isVisible())
00077   {
00078     //kdDebug() << "Abort Thumbnail drawing for page " << pageNumber << endl;
00079     return;
00080   }
00081 
00082   QPainter p(this);
00083   p.setClipRect(e->rect());
00084 
00085   // Paint a black border around the widget
00086   p.setRasterOp(Qt::CopyROP);
00087   p.setBrush(NoBrush);
00088   p.setPen(Qt::black);
00089   p.drawRect(rect());
00090 
00091   // Remove 1 pixel from all sides of the rectangle, to eliminate overdraw with
00092   // the black border.
00093   QRect thumbRect = rect();
00094   thumbRect.addCoords(1,1,-1,-1);
00095 
00096   // If the thumbnail is empty or has been marked for updating generate a new thumbnail.
00097   if (thumbnail.isNull() || needsUpdating)
00098   {
00099     if (KVSPrefs::changeColors() && KVSPrefs::renderMode() == KVSPrefs::EnumRenderMode::Paper)
00100       p.fillRect(thumbRect, KVSPrefs::paperColor());
00101     else
00102       p.fillRect(thumbRect, Qt::white);
00103 
00104     // Draw busy indicator.
00105     // Im not really sure if this is a good idea.
00106     // While it is nice to see an indication that something is happening for pages which
00107     // take long to redraw, it gets quite annoing for fast redraws.
00108     // TODO: Disable or find something less distractiong.
00109     p.drawPixmap(10, 10, *waitIcon);
00110 
00111     QTimer::singleShot(50, this, SLOT(setThumbnail()));
00112     return;
00113   }
00114 
00115   // Safety check
00116   if (thumbnail.isNull())
00117   {
00118     kdDebug(1223) << "No Thumbnail for page " << pageNumber << " created." << endl;
00119     return;
00120   }
00121 
00122 
00123   // The actual page starts at point (1,1) because of the outline.
00124   // Therefore we need to shift the destination rectangle.
00125   QRect pixmapRect = thumbRect;
00126   pixmapRect.moveBy(-1,-1);
00127 
00128   // Paint widget
00129   bitBlt (this, thumbRect.topLeft(), &thumbnail, pixmapRect, CopyROP);
00130 }
00131 
00132 void ThumbnailWidget::resizeEvent(QResizeEvent*)
00133 {
00134   thumbnail.resize(width(), height());
00135   // Generate a new thumbnail in the next paintEvent.
00136   needsUpdating = true;
00137 }
00138 
00139 void ThumbnailWidget::setThumbnail()
00140 {
00141   if (!parent->isVisible())
00142   {
00143     // We only want to calculate the thumbnail for widgets that are currently visible.
00144     // When we are fast scrolling thru the document. Many paint events are created, that
00145     // are often not needed anymore at the time the eventloop executes them.
00146     //kdDebug() << "Delayed request Abort Thumbnail drawing for page " << pageNumber << endl;
00147     kapp->processEvents();
00148     return;
00149   }
00150 
00151   needsUpdating = false;
00152 
00153   // Draw Thumbnail
00154   thumbnail = pageCache->createThumbnail(pageNumber, width() - 2);
00155 
00156   if (thumbnail.height() != height() + 2)
00157     setFixedHeight(thumbnail.height() + 2);
00158 
00159   update();
00160   kapp->processEvents();
00161 }
00162 
00163 
00164 /****** MarkListWidget ******/
00165 
00166 
00167 MarkListWidget::MarkListWidget(QWidget* _parent, MarkList* _markList, const PageNumber& _pageNumber,
00168                                DocumentPageCache* _pageCache, bool _showThumbnail)
00169   : QWidget(_parent), showThumbnail(_showThumbnail), pageNumber(_pageNumber),
00170     pageCache(_pageCache), markList(_markList)
00171 {
00172   QBoxLayout* layout = new QVBoxLayout(this, margin);
00173 
00174   thumbnailWidget = 0;
00175   if (showThumbnail)
00176   {
00177     thumbnailWidget = new ThumbnailWidget(this, pageNumber, pageCache);
00178     layout->addWidget(thumbnailWidget, 1, Qt::AlignTop);
00179   }
00180 
00181   QBoxLayout* bottomLayout = new QHBoxLayout(layout);
00182 
00183   checkBox = new QCheckBox(QString::null, this );
00184   checkBox->setFocusPolicy(QWidget::NoFocus);
00185   QToolTip::add(checkBox, i18n("Select for printing"));
00186   bottomLayout->addWidget(checkBox, 0, Qt::AlignAuto);
00187 
00188   pageLabel = new QLabel(QString("%1").arg(pageNumber), this);
00189   bottomLayout->addWidget(pageLabel, 1);
00190 
00191   _backgroundColor = KGlobalSettings::baseColor();
00192 
00193   // Alternate between colors.
00194   if ((pageNumber % 2 == 0) && KGlobalSettings::alternateBackgroundColor().isValid())
00195     _backgroundColor = KGlobalSettings::alternateBackgroundColor();
00196 
00197   setPaletteBackgroundColor( _backgroundColor );
00198 
00199   show();
00200 }
00201 
00202 bool MarkListWidget::isChecked() const
00203 {
00204     return checkBox->isChecked();
00205 }
00206 
00207 void MarkListWidget::toggle()
00208 {
00209     checkBox->toggle();
00210 }
00211 
00212 void MarkListWidget::setChecked( bool checked )
00213 {
00214     checkBox->setChecked(checked);
00215 }
00216 
00217 void MarkListWidget::setSelected( bool selected )
00218 {
00219     if (selected)
00220       setPaletteBackgroundColor( QApplication::palette().active().highlight() );
00221     else
00222       setPaletteBackgroundColor( _backgroundColor );
00223 }
00224 
00225 int MarkListWidget::setNewWidth(int width)
00226 {
00227   int height = QMAX(checkBox->height(), pageLabel->height()) + 2*margin;
00228   if (showThumbnail)
00229   {
00230     // Calculate size of Thumbnail
00231     int thumbnailWidth = QMIN(width, KVSPrefs::maxThumbnailWidth());
00232     int thumbnailHeight = (int)((thumbnailWidth - 2*margin - 2) / pageCache->sizeOfPage(pageNumber).aspectRatio() + 0.5) + 2;
00233 
00234     // Resize Thumbnail if necessary
00235     if (thumbnailWidget->size() != QSize(thumbnailWidth, thumbnailHeight))
00236       thumbnailWidget->setFixedSize(thumbnailWidth - 2*margin, thumbnailHeight);
00237 
00238     height += thumbnailHeight + 2*margin;
00239   }
00240 
00241   setFixedSize(width, height);
00242   return height;
00243 }
00244 
00245 bool MarkListWidget::isVisible()
00246 {
00247   QRect visibleRect(markList->contentsX(), markList->contentsY(),
00248                    markList->visibleWidth(), markList->visibleHeight());
00249   QRect widgetRect(markList->childX(this), markList->childY(this), width(), height());
00250 
00251   if (widgetRect.intersects(visibleRect))
00252     return true;
00253 
00254   return false;
00255 }
00256 
00257 
00258 void MarkListWidget::mousePressEvent(QMouseEvent* e)
00259 {
00260   // Select Page
00261   if (e->button() == LeftButton)
00262   {
00263     emit selected(pageNumber);
00264   }
00265   else if (e->button() == RightButton)
00266   {
00267     emit showPopupMenu(pageNumber, e->globalPos());
00268   }
00269 }
00270 
00271 
00272 /****** MarkList ******/
00273 
00274 
00275 MarkList::MarkList(QWidget* parent, const char* name)
00276   : QScrollView(parent, name), clickedThumbnail(0), showThumbnails(true), contextMenu(0)
00277 {
00278   currentPage = PageNumber::invalidPage;
00279   widgetList.setAutoDelete(true);
00280   setFocusPolicy( QWidget::StrongFocus );
00281   //viewport()->setFocusPolicy( QWidget::WheelFocus );
00282   setResizePolicy(QScrollView::Manual);
00283 
00284   setVScrollBarMode(QScrollView::AlwaysOn);
00285   setHScrollBarMode(QScrollView::AlwaysOff);
00286 
00287   setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
00288 
00289   viewport()->setBackgroundMode(Qt::PaletteBase);
00290   enableClipper(true);
00291 }
00292 
00293 MarkList::~MarkList()
00294 {
00295   delete contextMenu;
00296 }
00297 
00298 void MarkList::setPageCache(DocumentPageCache* _pageCache)
00299 {
00300   pageCache = _pageCache;
00301 }
00302 
00303 QValueList<int> MarkList::selectedPages() const
00304 {
00305   QValueList<int> list;
00306   MarkListWidget* item;
00307   for(unsigned int i = 0; i < widgetList.count(); i++)
00308   {
00309     item = widgetList[i];
00310     if (item->isChecked()) 
00311         list << (i + 1);
00312   }
00313   return list;
00314 }
00315 
00316 void MarkList::setNumberOfPages(int numberOfPages, bool _showThumbnails)
00317 {
00318   showThumbnails = _showThumbnails;
00319 
00320   widgetList.resize(numberOfPages);
00321 
00322   int y = 0;
00323 
00324   for (int page = 1; page <= numberOfPages; page++)
00325   {
00326     MarkListWidget* item = new MarkListWidget(viewport(), this, page, pageCache, showThumbnails);
00327 
00328     connect(item, SIGNAL(selected(const PageNumber&)), this, SLOT(thumbnailSelected(const PageNumber&)));
00329     connect(item, SIGNAL(showPopupMenu(const PageNumber&, const QPoint&)), this, SLOT(showPopupMenu(const PageNumber&, const QPoint&)));
00330 
00331     widgetList.insert(page - 1, item);
00332 
00333     int height = item->setNewWidth(visibleWidth());
00334     addChild(item, 0, y);
00335 
00336     y += height;
00337   }
00338   resizeContents(visibleWidth(), y);
00339   viewport()->update();
00340 }
00341 
00342 void MarkList::thumbnailSelected(const PageNumber& pageNumber)
00343 {
00344   // This variable is set to remember that the next call to setCurrentPageNumber
00345   // has been initiated with a left click on the thumbnail of page pageNumber.
00346   clickedThumbnail = pageNumber;
00347   emit selected(pageNumber);
00348 }
00349 
00350 void MarkList::setCurrentPageNumber(const PageNumber& pageNumber)
00351 {
00352   if (!pageNumber.isValid() || pageNumber > (int)widgetList.count())
00353   {
00354     clickedThumbnail = 0;
00355     return;
00356   }
00357 
00358   if (currentPage == pageNumber)
00359     return;
00360 
00361   MarkListWidget* item;
00362 
00363   // Clear old selection
00364   if (currentPage.isValid() && currentPage <= (int)widgetList.count())
00365   {
00366     item = widgetList[currentPage - 1];
00367     item->setSelected(false);
00368   }
00369 
00370   // Draw new selection
00371   item = widgetList[pageNumber - 1];
00372   item->setSelected(true);
00373 
00374   // Make selected page visible if the current page has not been set with a mouseclick
00375   // in the thumbnail list. (We use this because it is a bit confusing if the element that
00376   // you have just clicked on, is scrolled away under the mouse cursor)
00377   if (clickedThumbnail != pageNumber)
00378     ensureVisible(childX(item), childY(item), 0, item->height());
00379 
00380   clickedThumbnail = 0;
00381 
00382   currentPage = pageNumber;
00383 }
00384 
00385 void MarkList::clear()
00386 {
00387   currentPage = PageNumber::invalidPage;
00388   widgetList.resize(0);
00389 }
00390 
00391 void MarkList::selectAll()
00392 {
00393   MarkListWidget* item;
00394   for (unsigned int i = 0; i < widgetList.count(); i++)
00395   {
00396     item = widgetList[i];
00397     item->setChecked(true);
00398   }
00399 }
00400 
00401 void MarkList::selectEven()
00402 {
00403   MarkListWidget* item;
00404   for (unsigned int i = 1; i < widgetList.count(); i = i + 2)
00405   {
00406     item = widgetList[i];
00407     item->setChecked(true);
00408   }
00409 }
00410 
00411 void MarkList::selectOdd()
00412 {
00413   MarkListWidget* item;
00414   for (unsigned int i = 0; i < widgetList.count(); i = i + 2)
00415   {
00416     item = widgetList[i];
00417     item->setChecked(true);
00418   }
00419 }
00420 
00421 void MarkList::toggleSelection()
00422 {
00423   MarkListWidget* item;
00424   for (unsigned int i = 0; i < widgetList.count(); i++)
00425   {
00426     item = widgetList[i];
00427     item->toggle();
00428   }
00429 }
00430 
00431 void MarkList::removeSelection()
00432 {
00433   MarkListWidget* item;
00434   for (unsigned int i = 0; i < widgetList.count(); i++)
00435   {
00436     item = widgetList[i];
00437     item->setChecked(false);
00438   }
00439 }
00440 
00441 void MarkList::viewportResizeEvent(QResizeEvent*)
00442 {
00443   MarkListWidget* item;
00444 
00445   int yold = contentsHeight();
00446   int y = 0;
00447 
00448   for (unsigned int i = 0; i < widgetList.count(); i++)
00449   {
00450     item = widgetList[i];
00451     int height = item->setNewWidth(visibleWidth());
00452     moveChild(item, 0, y);
00453 
00454     y += height;
00455   }
00456   resizeContents(visibleWidth(), y);
00457 
00458   // If the height of the content has changed
00459   if (yold != contentsHeight())
00460   {
00461     // Make sure the selected item is still visible.
00462     if (currentPage.isValid() && currentPage <= (int)widgetList.count())
00463     {
00464       item = widgetList[currentPage-1];
00465       ensureVisible(childX(item), childY(item), 0, item->height());
00466     }
00467   }
00468 
00469   viewport()->update();
00470 }
00471 
00472 
00473 void MarkList::updateWidgetSize(const PageNumber& pageNumber)
00474 {
00475   // safety checks
00476   if (!pageNumber.isValid() || pageNumber > widgetList.count())
00477   {
00478     kdError() << "MarkList::updateWidgetSize called with invalid pageNumber " << pageNumber << endl;
00479     return;
00480   }
00481 
00482   MarkListWidget* item;
00483 
00484   // Resize the changed widget
00485   item = widgetList[pageNumber - 1];
00486   int height = item->setNewWidth(visibleWidth());
00487   int y = childY(item) + height;
00488 
00489   // Move the rest of the widgets
00490   for (unsigned int i = pageNumber; i < widgetList.count(); i++)
00491   {
00492     item = widgetList[i];
00493     int height = item->height();
00494     moveChild(item, 0, y);
00495 
00496     y += height;
00497   }
00498   resizeContents(contentsWidth(), y);
00499 
00500   viewport()->update();
00501 }
00502 
00503 void MarkList::mousePressEvent(QMouseEvent* e)
00504 {
00505   if (e->button() == RightButton)
00506   {
00507     // We call showPopupMenu with an invalid pageNumber to indicate that
00508     // the mouse does not point at a thumbnailWidget.
00509     showPopupMenu(PageNumber::invalidPage, e->globalPos());
00510   }
00511 }
00512 
00513 void MarkList::slotShowThumbnails(bool show)
00514 {
00515   if (show != showThumbnails)
00516   {
00517     int numOfPages = widgetList.count();
00518 
00519     if (numOfPages == 0)
00520       return;
00521 
00522     // Save current page.
00523     PageNumber _currentPage = currentPage;
00524 
00525     // Save page selections.
00526     QValueVector<bool> selections;
00527     selections.resize(widgetList.count());
00528     for (unsigned int i = 0; i < widgetList.count(); i++)
00529       selections[i] = widgetList[i]->isChecked();
00530 
00531     // Rebuild thumbnail widgets.
00532     clear();
00533     setNumberOfPages(numOfPages, show);
00534 
00535     // Restore current page.
00536     setCurrentPageNumber(_currentPage);
00537 
00538     // Restore page selections
00539     for (unsigned int i = 0; i < widgetList.count(); i++)
00540       widgetList[i]->setChecked(selections[i]);
00541   }
00542 }
00543 
00544 
00545 void MarkList::repaintThumbnails()
00546 {
00547   bool show = showThumbnails;
00548   int numOfPages = widgetList.count();
00549 
00550   // Rebuild thumbnail widgets.
00551   clear();
00552   setNumberOfPages(numOfPages, show);
00553 }
00554 
00555 
00556 void MarkList::showPopupMenu(const PageNumber& pageNumber, const QPoint& position)
00557 {
00558   if (contextMenu == 0)
00559   {
00560     // Initialize Contextmenu
00561     contextMenu = new KPopupMenu(this, "markListContext");
00562 
00563     contextMenu->insertItem(i18n("Select &Current Page"), 0);
00564     contextMenu->insertItem(i18n("Select &All Pages"), 1);
00565     contextMenu->insertItem(i18n("Select &Even Pages"), 2);
00566     contextMenu->insertItem(i18n("Select &Odd Pages"), 3);
00567     contextMenu->insertItem(i18n("&Invert Selection"), 4);
00568     contextMenu->insertItem(i18n("&Deselect All Pages"), 5);
00569   }
00570 
00571   if (widgetList.count() == 0)
00572   {
00573     for (int i = 0; i <= 5; i++)
00574       contextMenu->setItemEnabled(i, false);
00575   }
00576   else
00577   {
00578     for (int i = 0; i <= 5; i++)
00579       contextMenu->setItemEnabled(i, true);
00580   }
00581 
00582   // Only allow to select the current page if we got a valid pageNumber.
00583   if (pageNumber.isValid() && pageNumber <= (int)widgetList.count())
00584     contextMenu->setItemEnabled(0, true);
00585   else
00586     contextMenu->setItemEnabled(0, false);
00587 
00588   // Show Contextmenu
00589   switch(contextMenu->exec(position))
00590   {
00591     case 0:
00592       widgetList[pageNumber - 1]->toggle();
00593       break;
00594 
00595     case 1:
00596       selectAll();
00597       break;
00598 
00599     case 2:
00600       selectEven();
00601       break;
00602 
00603     case 3:
00604       selectOdd();
00605       break;
00606 
00607     case 4:
00608       toggleSelection();
00609       break;
00610 
00611     case 5:
00612       removeSelection();
00613       break;
00614   }
00615 }
00616 

kviewshell

Skip menu "kviewshell"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kviewshell
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal