00001
00002
00003
00004
00005
00006
00007
00008
00009
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
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 }
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
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
00113
00114 indexOfUnderlinedLink = -1;
00115
00116
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);
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
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);
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
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 if (!isVisible())
00188 {
00189
00190 kapp->processEvents();
00191 return;
00192 }
00193
00194 QPainter p(this);
00195 p.setClipRegion(e->region());
00196
00197
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
00206 QColor backgroundColor = colorGroup().mid();
00207
00208
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
00227 for(int i=0; i<4; i++)
00228 {
00229 p.setPen(backgroundColor.light(shadow_strip[i]));
00230
00231 p.drawLine(pageSize().width()+i+2, 8, pageSize().width()+i+2, pageSize().height()+2);
00232
00233 p.drawLine(8, pageSize().height()+i+2, pageSize().width()+2, pageSize().height()+i+2);
00234 }
00235
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
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
00253
00254
00255
00256
00257 p.drawPixmap(10, 10, *busyIcon);
00258
00259 if (!pixmapRequested)
00260 {
00261
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
00280 QRect destRect = damagedRects[i].intersect(pageRect());
00281
00282
00283
00284 QRect pixmapRect = destRect;
00285 pixmapRect.moveBy(-1,-1);
00286
00287 if (KVSPrefs::changeColors() && KVSPrefs::renderMode() != KVSPrefs::EnumRenderMode::Paper)
00288 {
00289
00290 bitBlt ( this, destRect.topLeft(), &pageData->accessiblePixmap(), pixmapRect, CopyROP);
00291 }
00292 else
00293 {
00294
00295 bitBlt ( this, destRect.topLeft(), pageData, pixmapRect, CopyROP);
00296 }
00297 }
00298
00299 if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::Enabled ||
00300 KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover)
00301 {
00302 int h = 2;
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
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
00332 TextSelection selection = documentCache->selectedText();
00333 if ((selection.getPageNumber() != 0) && (selection.getPageNumber() == pageNr))
00334 {
00335 if (selectionNeedsUpdating)
00336 {
00337
00338
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
00354 if (scrollGuide >= 0)
00355 {
00356
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
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
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
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
00400
00401 if (pageNr == 0)
00402 return;
00403
00404
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
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
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
00436
00437 e->ignore();
00438
00439
00440
00441 if (pageNr == 0)
00442 return;
00443
00444
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
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
00470
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
00485
00486 e->ignore();
00487
00488 if (e->button() == RightButton || (!moveTool && e->button() == LeftButton))
00489 {
00490
00491 if (firstSelectedPoint == e->pos())
00492 {
00493 if (pageNr == 0)
00494 return;
00495
00496
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
00510
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
00523
00524 if (pageNr == 0)
00525 return;
00526
00527
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
00535 if (e->state() == 0) {
00536
00537 int lastUnderlinedLink = indexOfUnderlinedLink;
00538
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
00555 newUnderline.addCoords(0, 0, 0, 2);
00556
00557 update(newUnderline);
00558
00559 if (lastUnderlinedLink != -1 && lastUnderlinedLink < pageData->hyperLinkList.size())
00560 {
00561
00562 QRect oldUnderline = pageData->hyperLinkList[lastUnderlinedLink].box;
00563 oldUnderline.addCoords(0, 0, 0, 2);
00564 update(oldUnderline);
00565 }
00566 }
00567 return;
00568 }
00569 }
00570
00571 indexOfUnderlinedLink = -1;
00572 if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover &&
00573 lastUnderlinedLink != -1 && lastUnderlinedLink < pageData->hyperLinkList.size())
00574 {
00575
00576 QRect oldUnderline = pageData->hyperLinkList[lastUnderlinedLink].box;
00577
00578 oldUnderline.addCoords(0, 0, 0, 2);
00579
00580 update(oldUnderline);
00581 }
00582
00583
00584 setStandardCursor();
00585 }
00586
00587 if (!clearStatusBarTimer.isActive())
00588 clearStatusBarTimer.start(200, true);
00589
00590
00591 if ((e->state() & LeftButton) != 0 && moveTool)
00592 {
00593
00594
00595
00596 e->ignore();
00597 }
00598
00599
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
00614
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
00628 documentCache->deselectText();
00629 selectedRectangle = QRect();
00630 selectedRegion = QRegion();
00631 update();
00632 }
00633 else
00634 {
00635 if (pageNr == 0)
00636 return;
00637
00638
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
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
00684
00685
00686
00687
00688 pixmapRequested = false;
00689 kapp->processEvents();
00690 return;
00691 }
00692
00693 documentCache->getPage(pageNr);
00694 pixmapRequested = false;
00695 update();
00696
00697
00698
00699
00700
00701 kapp->processEvents();
00702 }
00703
00704 QSize DocumentWidget::pageSize() const
00705 {
00706
00707 return size() - QSize(6, 6);
00708 }
00709
00710 QRect DocumentWidget::pageRect() const
00711 {
00712 QRect boundingRect = rect();
00713
00714 boundingRect.addCoords(1,1,-5,-5);
00715 return boundingRect;
00716 }
00717
00718 void DocumentWidget::setPageSize(const QSize& pageSize)
00719 {
00720
00721
00722
00723
00724 selectionNeedsUpdating = true;
00725
00726
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"