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

kviewshell

documentWidget.cpp

Go to the documentation of this file.
00001 //
00002 // Class: DocumentWidget
00003 //
00004 // Widget for displaying TeX DVI files.
00005 // Part of KDVI- A previewer for TeX DVI files.
00006 //
00007 // (C) 2001 Stefan Kebekus
00008 // Copyright (C) 2004-2005 Wilfried Huss <Wilfried.Huss@gmx.at>
00009 // Distributed under the GPL
00010 //
00011 
00012 #include <config.h>
00013 
00014 #include <kaction.h>
00015 #include <kapplication.h>
00016 #include <kdebug.h>
00017 #include <kglobalsettings.h>
00018 #include <kiconloader.h>
00019 #include <klocale.h>
00020 #include <qclipboard.h>
00021 #include <qcursor.h>
00022 #include <qimage.h>
00023 #include <qpainter.h>
00024 #include <qpixmap.h>
00025 
00026 #include "documentWidget.h"
00027 #include "pageView.h"
00028 #include "documentPageCache.h"
00029 #include "hyperlink.h"
00030 #include "renderedDocumentPagePixmap.h"
00031 #include "textBox.h"
00032 
00033 #include "kvsprefs.h"
00034 
00035 //#define DEBUG_DOCUMENTWIDGET
00036 
00037 const int DocumentWidget::bottom_right_corner[16] =
00038   { 61, 71, 85, 95,
00039     71, 78, 89, 96,
00040     85, 89, 95, 98,
00041     95, 97, 98, 99 };
00042 
00043 const int DocumentWidget::bottom_left_corner[16] =
00044   { 95, 85, 71, 61,
00045     97, 89, 78, 71,
00046     98, 95, 89, 85,
00047     99, 98, 96, 95 };
00048 
00049 const int DocumentWidget::shadow_strip[4] =
00050   { 56, 67, 83, 94 };
00051 
00052 QColor DocumentWidget::backgroundColorForCorners;
00053 
00054 namespace {
00055 
00057 QPixmap* busyIcon = 0;
00058 
00061 QPixmap* URShadow = 0;
00062 QPixmap* BRShadow = 0;
00063 QPixmap* BLShadow = 0;
00064 
00065 } // namespace anon
00066 
00067 
00068 DocumentWidget::DocumentWidget(QWidget *parent, PageView *sv, DocumentPageCache *cache, const char *name )
00069   : QWidget( parent, name ), indexOfUnderlinedLink(-1)
00070 {
00071   moveTool = true;
00072 
00073   selectionNeedsUpdating = false;
00074 
00075   // Variables used in animation.
00076   animationCounter = 0;
00077   timerIdent       = 0;
00078   documentCache    = cache;
00079   scrollView       = sv;
00080 
00081   pixmapRequested = false;
00082 
00083   scrollGuide = -1;
00084 
00085   setMouseTracking(true);
00086   setFocusPolicy(QWidget::ClickFocus);
00087 
00088   connect(&clearStatusBarTimer, SIGNAL(timeout()), this, SLOT(clearStatusBar()));
00089   setBackgroundMode(Qt::NoBackground);
00090 
00091   if (!busyIcon)
00092   {
00093     busyIcon = new QPixmap(KGlobal::iconLoader()->loadIcon("gear", KIcon::NoGroup, KIcon::SizeMedium));
00094 
00095     URShadow = new QPixmap();
00096     BRShadow = new QPixmap();
00097     BLShadow = new QPixmap();
00098 
00099     URShadow->resize(4,4);
00100     BRShadow->resize(4,4);
00101     BLShadow->resize(4,4);
00102   }
00103 }
00104 
00105 
00106 void DocumentWidget::setPageNumber(Q_UINT16 nr)
00107 {
00108   pageNr = nr;
00109 
00110   selectionNeedsUpdating = true;
00111 
00112   // We have to reset this, because otherwise we might crash in the mouseMoveEvent
00113   // After switching pages in SinglePageMode or OverviewMode.
00114   indexOfUnderlinedLink = -1;
00115 
00116   // Resize Widget if the size of the new page is different than the size of the old page.
00117   QSize _pageSize = documentCache->sizeOfPageInPixel(pageNr);
00118   if (_pageSize != pageSize())
00119   {
00120     setPageSize(_pageSize);
00121   }
00122   update();
00123 }
00124 
00125 QRect DocumentWidget::linkFlashRect()
00126 {
00127   int width = pageSize().width()/(11 - animationCounter);
00128   int height = pageSize().height()/(60 - 4 * animationCounter);
00129   return QRect((pageSize().width()-width)/2, flashOffset - height/2, width, height);
00130 }
00131 
00132 void DocumentWidget::timerEvent( QTimerEvent *e )
00133 {
00134   if (animationCounter == 0) {
00135     killTimer(e->timerId());
00136     timerIdent = startTimer(50); // Proceed with the animation in 1/10s intervals
00137   }
00138 
00139   animationCounter++;
00140 
00141   QRect flashRect = linkFlashRect();
00142   flashRect.addCoords(-1, -1, 1, 1);
00143 
00144   if (animationCounter >= 10) {
00145     killTimer(e->timerId());
00146     timerIdent       = 0;
00147     animationCounter = 0;
00148   }
00149 
00150   repaint(flashRect, false);
00151 }
00152 
00153 
00154 void DocumentWidget::flash(int fo)
00155 {
00156   if (timerIdent != 0)
00157   {
00158     killTimer(timerIdent);
00159     // Delete old flash rectangle
00160     animationCounter = 10;
00161     QRect flashRect = linkFlashRect();
00162     flashRect.addCoords(-1, -1, 1, 1);
00163     repaint(flashRect, false);
00164   }
00165   animationCounter = 0;
00166   flashOffset      = fo;
00167   timerIdent       = startTimer(50); // Start the animation. The animation proceeds in 1/10s intervals
00168 }
00169 
00170 
00171 void DocumentWidget::paintEvent(QPaintEvent *e)
00172 {
00173 #ifdef DEBUG_DOCUMENTWIDGET
00174   kdDebug(1223) << "DocumentWidget::paintEvent() called" << endl;
00175 #endif
00176 
00177   // Check if this widget is really visible to the user. If not, there
00178   // is nothing to do. Remark: if we don't do this, then under QT
00179   // 3.2.3 the following happens: when the user changes the zoom
00180   // value, all those widgets are updated which the user has EVER
00181   // seen, not just those that are visible at the moment. If the
00182   // document contains several thousand pages, it is easily possible
00183   // that this means that a few hundred of these are re-painted (which
00184   // takes substantial time) although perhaps only three widgets are
00185   // visible and *should* be updated. I believe this is some error in
00186   // QT, but I am not positive about that ---Stefan Kebekus.
00187   if (!isVisible())
00188   {
00189     //kdDebug() << "widget of page " << pageNr << " is not visible. Abort rendering" << endl;
00190     kapp->processEvents();
00191     return;
00192   }
00193 
00194   QPainter p(this);
00195   p.setClipRegion(e->region());
00196 
00197   // Paint a black border around the widget
00198   p.setRasterOp(Qt::CopyROP);
00199   p.setBrush(NoBrush);
00200   p.setPen(Qt::black);
00201   QRect outlineRect = pageRect();
00202   outlineRect.addCoords(-1, -1, 1, 1);
00203   p.drawRect(outlineRect);
00204 
00205   // Paint page shadow
00206   QColor backgroundColor = colorGroup().mid();
00207 
00208   // (Re-)generate the Pixmaps for the shadow corners, if necessary
00209   if (backgroundColor != backgroundColorForCorners)
00210   {
00211     backgroundColorForCorners = backgroundColor;
00212     QImage tmp(4, 4, 32);
00213     for(int x=0; x<4; x++)
00214       for(int y=0; y<4; y++)
00215         tmp.setPixel(x, y, backgroundColor.light(bottom_right_corner[x+4*y]).rgb() );
00216     BRShadow->convertFromImage(tmp);
00217 
00218     for(int x=0; x<4; x++)
00219       for(int y=0; y<4; y++)
00220         tmp.setPixel(x, y, backgroundColor.light(bottom_left_corner[x+4*y]).rgb() );
00221     BLShadow->convertFromImage(tmp);
00222 
00223     URShadow->convertFromImage(tmp.mirror(true, true));
00224   }
00225 
00226   // Draw right and bottom shadows
00227   for(int i=0; i<4; i++)
00228   {
00229     p.setPen(backgroundColor.light(shadow_strip[i]));
00230     // Right shadow
00231     p.drawLine(pageSize().width()+i+2, 8, pageSize().width()+i+2, pageSize().height()+2);
00232     // Bottom shadow
00233     p.drawLine(8, pageSize().height()+i+2, pageSize().width()+2, pageSize().height()+i+2);
00234   }
00235   // Draw shadow corners
00236   p.drawPixmap(pageSize().width()+2, pageSize().height()+2, *BRShadow);
00237   p.drawPixmap(4, pageSize().height()+2, *BLShadow);
00238   p.drawPixmap(pageSize().width()+2, 4, *URShadow);
00239 
00240   // Draw corners
00241   p.fillRect(0, pageSize().height()+2, 4, 4, backgroundColor);
00242   p.fillRect(pageSize().width()+2, 0, 4, 4, backgroundColor);
00243 
00244   if (!documentCache->isPageCached(pageNr, pageSize()))
00245   {
00246     QRect destRect = e->rect().intersect(pageRect());
00247     if (KVSPrefs::changeColors() && KVSPrefs::renderMode() == KVSPrefs::EnumRenderMode::Paper)
00248       p.fillRect(destRect, KVSPrefs::paperColor());
00249     else
00250       p.fillRect(destRect, Qt::white);
00251 
00252     // Draw busy indicator.
00253     // Im not really sure if this is a good idea.
00254     // While it is nice to see an indication that something is happening for pages which
00255     // take long to redraw, it gets quite annoing for fast redraws.
00256     // TODO: Disable or find something less distractiong.
00257     p.drawPixmap(10, 10, *busyIcon);
00258 
00259     if (!pixmapRequested)
00260     {
00261       // Request page pixmap.
00262       pixmapRequested = true;
00263       QTimer::singleShot(50, this, SLOT(delayedRequestPage()));
00264     }
00265     return;
00266   }
00267 
00268   RenderedDocumentPagePixmap *pageData = documentCache->getPage(pageNr);
00269   if (pageData == 0) {
00270 #ifdef DEBUG_DOCUMENTWIDGET
00271     kdDebug(1223) << "DocumentWidget::paintEvent: no documentPage generated" << endl;
00272 #endif
00273     return;
00274   }
00275 
00276   QMemArray<QRect> damagedRects = e->region().rects();
00277   for (unsigned int i = 0; i < damagedRects.count(); i++)
00278   {
00279     // Paint the page where it intersects with the damaged area.
00280     QRect destRect = damagedRects[i].intersect(pageRect());
00281 
00282     // The actual page starts at point (1,1) because of the outline.
00283     // Therefore we need to shift the destination rectangle.
00284     QRect pixmapRect = destRect;
00285     pixmapRect.moveBy(-1,-1);
00286 
00287     if (KVSPrefs::changeColors() && KVSPrefs::renderMode() != KVSPrefs::EnumRenderMode::Paper)
00288     {
00289       // Paint widget contents with accessibility changes.
00290       bitBlt ( this, destRect.topLeft(), &pageData->accessiblePixmap(), pixmapRect, CopyROP);
00291     }
00292     else
00293     {
00294       // Paint widget contents
00295       bitBlt ( this, destRect.topLeft(), pageData, pixmapRect, CopyROP);
00296     }
00297   }
00298   // Underline hyperlinks
00299   if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::Enabled ||
00300       KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover)
00301   {
00302     int h = 2; // Height of line.
00303     for(int i = 0; i < (int)pageData->hyperLinkList.size(); i++) 
00304     {
00305       if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover && 
00306           i != indexOfUnderlinedLink)
00307         continue;
00308       int x = pageData->hyperLinkList[i].box.left();
00309       int w = pageData->hyperLinkList[i].box.width();
00310       int y = pageData->hyperLinkList[i].baseline;
00311 
00312       QRect hyperLinkRect(x, y, w, h);
00313       if (hyperLinkRect.intersects(e->rect()))
00314       {
00315 #ifdef DEBUG_DOCUMENTWIDGET
00316         kdDebug(1223) << "Underline hyperlink \"" << pageData->hyperLinkList[i].linkText << "\"" << endl;
00317 #endif
00318         p.fillRect(x, y, w, h, KGlobalSettings::linkColor());
00319       }
00320     }
00321   }
00322 
00323   // Paint flashing frame, if appropriate
00324   if (animationCounter > 0 && animationCounter < 10)
00325   {
00326     int gbChannel = 255 - (9-animationCounter)*28;
00327     p.setPen(QPen(QColor(255, gbChannel, gbChannel), 3));
00328     p.drawRect(linkFlashRect());
00329   }
00330 
00331   // Mark selected text.
00332   TextSelection selection = documentCache->selectedText();
00333   if ((selection.getPageNumber() != 0) && (selection.getPageNumber() == pageNr))
00334   {
00335     if (selectionNeedsUpdating)
00336     {
00337       //The zoom value has changed, therefore we need to recalculate
00338       //the selected region.
00339       selectedRegion = pageData->selectedRegion(selection);
00340       selectionNeedsUpdating = false;
00341     }
00342 
00343     p.setPen(NoPen);
00344     p.setBrush(white);
00345     p.setRasterOp(Qt::XorROP);
00346 
00347     QMemArray<QRect> selectionRects = selectedRegion.rects();
00348 
00349     for (unsigned int i = 0; i < selectionRects.count(); i++)
00350       p.drawRect(selectionRects[i]);
00351   }
00352 
00353   // Draw scroll Guide
00354   if (scrollGuide >= 0)
00355   {
00356     // Don't draw over the page shadow
00357     p.setClipRegion(e->region().intersect(pageRect()));
00358     p.setRasterOp(Qt::CopyROP);
00359     p.setPen(Qt::red);
00360     p.drawLine(1, scrollGuide, pageSize().width(), scrollGuide);
00361   }
00362 }
00363 
00364 void DocumentWidget::drawScrollGuide(int ycoord)
00365 {
00366   //kdDebug() << "draw scroll guide for page " << pageNr << " at y = " << ycoord << endl;
00367   scrollGuide = ycoord;
00368   update(QRect(1, scrollGuide, pageSize().width(), 1));
00369   QTimer::singleShot(1000, this, SLOT(clearScrollGuide()));
00370 }
00371 
00372 void DocumentWidget::clearScrollGuide()
00373 {
00374   //kdDebug() << "clear scroll guide for page " << pageNr << " at y = " << scrollGuide << endl;
00375   int temp = scrollGuide;
00376   scrollGuide = -1;
00377   update(QRect(1, temp, pageSize().width(), 1));
00378 }
00379 
00380 void DocumentWidget::select(const TextSelection& newSelection)
00381 {
00382   // Get a pointer to the page contents
00383   RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
00384   if (pageData == 0) {
00385     kdDebug(1223) << "DocumentWidget::select() pageData for page #" << pageNr << " is empty" << endl;
00386     return;
00387   }
00388 
00389   documentCache->selectText(newSelection);
00390 
00391   selectedRegion = pageData->selectedRegion(documentCache->selectedText());
00392   selectionNeedsUpdating = false;
00393 
00394   update();
00395 }
00396 
00397 void DocumentWidget::selectAll()
00398 {
00399   // pageNr == 0 indicated an invalid page (e.g. page number not yet
00400   // set)
00401   if (pageNr == 0)
00402     return;
00403 
00404   // Get a pointer to the page contents
00405   RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
00406   if (pageData == 0) {
00407     kdDebug(1223) << "DocumentWidget::selectAll() pageData for page #" << pageNr << " is empty" << endl;
00408     return;
00409   }
00410 
00411   TextSelection selection;
00412   // mark everything as selected
00413   QString selectedText("");
00414   for(unsigned int i = 0; i < pageData->textBoxList.size(); i++) {
00415     selectedText += pageData->textBoxList[i].text;
00416     selectedText += "\n";
00417   }
00418   selection.set(pageNr, 0, pageData->textBoxList.size()-1, selectedText);
00419 
00420   selectedRegion = pageData->selectedRegion(selection);
00421 
00422   documentCache->selectText(selection);
00423 
00424   // Re-paint
00425   update();
00426 }
00427 
00428 
00429 void DocumentWidget::mousePressEvent ( QMouseEvent * e )
00430 {
00431 #ifdef DEBUG_DOCUMENTWIDGET
00432   kdDebug(1223) << "DocumentWidget::mousePressEvent(...) called" << endl;
00433 #endif
00434   
00435   // Make sure the event is passed on to the higher-level widget;
00436   // otherwise QT gets the coordinated in the mouse move events wrong
00437   e->ignore();
00438 
00439   // pageNr == 0 indicated an invalid page (e.g. page number not yet
00440   // set)
00441   if (pageNr == 0)
00442     return;
00443 
00444   // Get a pointer to the page contents
00445   RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
00446   if (pageData == 0) {
00447     kdDebug(1223) << "DocumentWidget::selectAll() pageData for page #" << pageNr << " is empty" << endl;
00448     return;
00449   }
00450 
00451   // Check if the mouse is pressed on a regular hyperlink
00452   if (e->button() == LeftButton) {
00453     if (pageData->hyperLinkList.size() > 0)
00454       for(unsigned int i = 0; i < pageData->hyperLinkList.size(); i++) {
00455         if (pageData->hyperLinkList[i].box.contains(e->pos())) {
00456           emit(localLink(pageData->hyperLinkList[i].linkText));
00457           return;
00458         }
00459       }
00460     if (moveTool)
00461       setCursor(Qt::SizeAllCursor);
00462     else
00463       setCursor(Qt::IbeamCursor);
00464   }
00465 
00466   if (e->button() == RightButton || (!moveTool && e->button() == LeftButton))
00467   {
00468     setCursor(Qt::IbeamCursor);
00469     // If Shift is not pressed clear the current selection,
00470     // otherwise modify the existing selection.
00471     if (!(e->state() & ShiftButton))
00472     {
00473       firstSelectedPoint = e->pos();
00474       selectedRectangle = QRect();
00475       selectedRegion = QRegion();
00476       emit clearSelection();
00477     }
00478   }
00479 }
00480 
00481 
00482 void DocumentWidget::mouseReleaseEvent ( QMouseEvent *e )
00483 {
00484   // Make sure the event is passed on to the higher-level widget;
00485   // otherwise the mouse cursor in the centeringScrollview is wrong
00486   e->ignore();
00487 
00488   if (e->button() == RightButton || (!moveTool && e->button() == LeftButton))
00489   {
00490     // If the selectedRectangle is empty then there was only a single right click.
00491     if (firstSelectedPoint == e->pos())
00492     {
00493       if (pageNr == 0)
00494         return;
00495 
00496       // Get a pointer to the page contents
00497       RenderedDocumentPage* pageData = documentCache->getPage(pageNr);
00498       if (pageData == 0) 
00499       {
00500         kdDebug(1223) << "DocumentWidget::mouseReleaseEvent() pageData for page #" << pageNr << " is empty" << endl;
00501         return;
00502       }
00503 
00504       TextSelection newTextSelection = pageData->select(firstSelectedPoint);
00505       updateSelection(newTextSelection);
00506     }
00507   }
00508 
00509   //Reset the cursor to the usual arrow if we use the move tool, and
00510   // The textselection cursor if we use the selection tool.
00511   setStandardCursor();
00512 }
00513 
00514 
00515 void DocumentWidget::mouseMoveEvent ( QMouseEvent * e )
00516 {
00517 #ifdef DEBUG_DOCUMENTWIDGET
00518   kdDebug(1223) << "DocumentWidget::mouseMoveEvent(...) called" << endl;
00519 #endif
00520 
00521 
00522   // pageNr == 0 indicated an invalid page (e.g. page number not yet
00523   // set)
00524   if (pageNr == 0)
00525     return;
00526 
00527   // Get a pointer to the page contents
00528   RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
00529   if (pageData == 0) {
00530     kdDebug(1223) << "DocumentWidget::selectAll() pageData for page #" << pageNr << " is empty" << endl;
00531     return;
00532   }
00533 
00534   // If no mouse button pressed
00535   if (e->state() == 0) {
00536     // Remember the index of the underlined link.
00537     int lastUnderlinedLink = indexOfUnderlinedLink;
00538     // go through hyperlinks
00539     for(unsigned int i = 0; i < pageData->hyperLinkList.size(); i++) {
00540       if (pageData->hyperLinkList[i].box.contains(e->pos())) {
00541         clearStatusBarTimer.stop();
00542         setCursor(pointingHandCursor);
00543         QString link = pageData->hyperLinkList[i].linkText;
00544         if ( link.startsWith("#") )
00545           link = link.remove(0,1);
00546 
00547         emit setStatusBarText( i18n("Link to %1").arg(link) );
00548 
00549         indexOfUnderlinedLink = i;
00550         if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover &&
00551             indexOfUnderlinedLink != lastUnderlinedLink)
00552         {
00553           QRect newUnderline = pageData->hyperLinkList[i].box;
00554           // Increase Rectangle so that the whole line really lines in it.
00555           newUnderline.addCoords(0, 0, 0, 2);
00556           // Redraw widget
00557           update(newUnderline);
00558 
00559           if (lastUnderlinedLink != -1 && lastUnderlinedLink < pageData->hyperLinkList.size())
00560           {
00561             // Erase old underline
00562             QRect oldUnderline = pageData->hyperLinkList[lastUnderlinedLink].box;
00563             oldUnderline.addCoords(0, 0, 0, 2);
00564             update(oldUnderline);
00565           }
00566         }
00567         return;
00568       }
00569     }
00570     // Whenever we reach this the mouse hovers no link.
00571     indexOfUnderlinedLink = -1;
00572     if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover &&
00573         lastUnderlinedLink != -1 && lastUnderlinedLink < pageData->hyperLinkList.size())
00574     {
00575       // Erase old underline
00576       QRect oldUnderline = pageData->hyperLinkList[lastUnderlinedLink].box;
00577       // Increase Rectangle so that the whole line really lines in it.
00578       oldUnderline.addCoords(0, 0, 0, 2);
00579       // Redraw widget
00580       update(oldUnderline);
00581     }
00582     // Cursor not over hyperlink? Then let the cursor be the usual arrow if we use the move tool, and
00583     // The textselection cursor if we use the selection tool.
00584     setStandardCursor();
00585   }
00586 
00587   if (!clearStatusBarTimer.isActive())
00588     clearStatusBarTimer.start(200, true); // clear the statusbar after 200 msec.
00589 
00590   // Left mouse button pressed -> Text scroll function
00591   if ((e->state() & LeftButton) != 0 && moveTool)
00592   {
00593     // Pass the mouse event on to the owner of this widget ---under
00594     // normal circumstances that is the centeringScrollView which will
00595     // then scroll the scrollview contents
00596     e->ignore();
00597   }
00598 
00599   // Right mouse button pressed -> Text copy function
00600   if ((e->state() & RightButton) != 0 || (!moveTool && (e->state() & LeftButton != 0)))
00601   {
00602     if (selectedRectangle.isEmpty()) {
00603       firstSelectedPoint = e->pos();
00604       selectedRectangle.setRect(e->pos().x(),e->pos().y(),1,1);
00605     } else {
00606       int lx = e->pos().x() < firstSelectedPoint.x() ? e->pos().x() : firstSelectedPoint.x();
00607       int rx = e->pos().x() > firstSelectedPoint.x() ? e->pos().x() : firstSelectedPoint.x();
00608       int ty = e->pos().y() < firstSelectedPoint.y() ? e->pos().y() : firstSelectedPoint.y();
00609       int by = e->pos().y() > firstSelectedPoint.y() ? e->pos().y() : firstSelectedPoint.y();
00610       selectedRectangle.setCoords(lx,ty,rx,by);
00611     }
00612 
00613     // Now that we know the rectangle, we have to find out which words
00614     // intersect it!
00615     TextSelection newTextSelection = pageData->select(selectedRectangle);
00616 
00617     updateSelection(newTextSelection);
00618   }
00619 }
00620 
00621 void DocumentWidget::updateSelection(const TextSelection& newTextSelection)
00622 {
00623   if (newTextSelection != documentCache->selectedText())
00624   {
00625     if (newTextSelection.isEmpty())
00626     {
00627       // Clear selection
00628       documentCache->deselectText();
00629       selectedRectangle = QRect();
00630       selectedRegion = QRegion();
00631       update();
00632     }
00633     else
00634     {
00635       if (pageNr == 0)
00636         return;
00637 
00638       // Get a pointer to the page contents
00639       RenderedDocumentPage* pageData = documentCache->getPage(pageNr);
00640       if (pageData == 0) 
00641       {
00642         kdDebug(1223) << "DocumentWidget::mouseReleaseEvent() pageData for page #" << pageNr << " is empty" << endl;
00643         return;
00644       }
00645 
00646       documentCache->selectText(newTextSelection);
00647 
00648       QRegion newlySelectedRegion = pageData->selectedRegion(documentCache->selectedText());
00649 
00650       // Compute the region that needs to be updated
00651       QRegion updateRegion;
00652       if(!selectedRegion.isEmpty())
00653       {
00654         updateRegion = newlySelectedRegion.eor(selectedRegion);
00655       }
00656       else
00657       {
00658         updateRegion = newlySelectedRegion;
00659       }
00660 
00661       selectedRegion = newlySelectedRegion;
00662 
00663       QMemArray<QRect> rectangles = updateRegion.rects();
00664       for (unsigned int i = 0; i < rectangles.count(); i++)
00665       {
00666         repaint(rectangles[i]);
00667       }
00668     }
00669   }
00670 }
00671 
00672 
00673 void DocumentWidget::clearStatusBar()
00674 {
00675   emit setStatusBarText( QString::null );
00676 }
00677 
00678 
00679 void DocumentWidget::delayedRequestPage()
00680 {
00681   if (!isVisible())
00682   {
00683     // We only want to calculate the page pixmap for widgets that are currently visible.
00684     // When we are fast scrolling thru the document many paint events are created, that
00685     // are often not needed anymore at the time the eventloop executes them.
00686 
00687     //kdDebug() << "delayedRequest: widget of page " << pageNr << " is not visible. Abort rendering" << endl;
00688     pixmapRequested = false;
00689     kapp->processEvents();
00690     return;
00691   }
00692 
00693   documentCache->getPage(pageNr);
00694   pixmapRequested = false;
00695   update();
00696 
00697   // If more widgets need updateing at the some time, the next line allows them to be
00698   // displayed one after another. Widthout it all widgets are updated after all the rendering
00699   // is completed. This is especially noticable in overview mode. After the change to a seperate
00700   // rendering thread this will probably not be needed anymore.
00701   kapp->processEvents();
00702 }
00703 
00704 QSize DocumentWidget::pageSize() const
00705 {
00706   // Substract size of the shadow.
00707   return size() - QSize(6, 6);
00708 }
00709 
00710 QRect DocumentWidget::pageRect() const
00711 {
00712   QRect boundingRect = rect();
00713   // Substract the shadow.
00714   boundingRect.addCoords(1,1,-5,-5);
00715   return boundingRect;
00716 }
00717 
00718 void DocumentWidget::setPageSize(const QSize& pageSize)
00719 {
00720   // When the page size changes this means either the paper size
00721   // has been changed, or the zoomlevel has been changed.
00722   // If the zoomlevel changes we need to recalculate the selected
00723   // region. We do this always, just to be on the safe side.
00724   selectionNeedsUpdating = true;
00725 
00726   // Add size of the shadow.
00727   resize(pageSize + QSize(6,6));
00728 }
00729 
00730 void DocumentWidget::setPageSize(int width, int height)
00731 {
00732   setPageSize(QSize(width, height));
00733 }
00734 
00735 
00736 void DocumentWidget::slotEnableMoveTool(bool enable)
00737 {
00738   moveTool = enable;
00739 
00740   setStandardCursor();
00741 }
00742 
00743 
00744 void DocumentWidget::setStandardCursor()
00745 {
00746   if (moveTool)
00747   {
00748     setCursor(Qt::arrowCursor);
00749   }
00750   else
00751   {
00752     setCursor(Qt::IbeamCursor);
00753   }
00754 }
00755 
00756 
00757 bool DocumentWidget::isVisible()
00758 {
00759   QRect visibleRect(scrollView->contentsX(), scrollView->contentsY(), scrollView->visibleWidth(), scrollView->visibleHeight());
00760   QRect widgetRect(scrollView->childX(this), scrollView->childY(this), width(), height());
00761   return widgetRect.intersects(visibleRect);
00762 }
00763 
00764 #include "documentWidget.moc"

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