File indexing completed on 2024-04-28 04:42:11
0001 /* This file is part of the KDE project 0002 Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org> 0003 Copyright (C) 2006 Peter Simonsson <peter.simonsson@gmail.com> 0004 Copyright (C) 2007 C. Boemann <cbo@boemann.dk> 0005 Copyright (C) 2007-2008 Jan Hambrecht <jaham@gmx.net> 0006 Copyright (C) 2007 Thomas Zander <zander@kde.org> 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #include "KReportRuler_p.h" 0025 #include "KReportDesign_p.h" 0026 #include "KReportZoomHandler_p.h" 0027 0028 #include <QPainter> 0029 #include <QMenu> 0030 #include <QMouseEvent> 0031 #include <QFontDatabase> 0032 0033 // the distance in pixels of a mouse position considered outside the rule 0034 static const int OutsideRulerThreshold = 20; 0035 // 0036 static const int fullStepMarkerLength = 6; 0037 static const int halfStepMarkerLength = 6; 0038 static const int quarterStepMarkerLength = 3; 0039 static const int measurementTextAboveBelowMargin = 1; 0040 0041 class RulerTabChooser : public QWidget 0042 { 0043 public: 0044 RulerTabChooser(QWidget *parent) : QWidget(parent), m_type(QTextOption::LeftTab), m_showTabs(false) {} 0045 ~RulerTabChooser() override {} 0046 0047 inline QTextOption::TabType type() {return m_type;} 0048 void setShowTabs(bool showTabs) { if (m_showTabs == showTabs) return; m_showTabs = showTabs; update(); } 0049 void mousePressEvent(QMouseEvent *) override; 0050 0051 void paintEvent(QPaintEvent *) override; 0052 0053 private: 0054 QTextOption::TabType m_type; 0055 bool m_showTabs :1; 0056 }; 0057 0058 // ---- 0059 0060 class PaintingStrategy 0061 { 0062 public: 0063 /// constructor 0064 PaintingStrategy() {} 0065 /// destructor 0066 virtual ~PaintingStrategy() {} 0067 0068 /** 0069 * Draw the background of the ruler. 0070 * @param ruler the ruler to draw on. 0071 * @param painter the painter we can paint with. 0072 */ 0073 virtual QRectF drawBackground(const KReportRuler::Private *ruler, QPainter *painter) = 0; 0074 0075 /** 0076 * Draw the indicators for text-tabs. 0077 * @param ruler the ruler to draw on. 0078 * @param painter the painter we can paint with. 0079 */ 0080 virtual void drawTabs(const KReportRuler::Private *ruler, QPainter *painter) = 0; 0081 0082 /** 0083 * Draw the indicators for the measurements which typically are drawn every [unit]. 0084 * @param ruler the ruler to draw on. 0085 * @param painter the painter we can paint with. 0086 * @param rectangle 0087 */ 0088 virtual void drawMeasurements(const KReportRuler::Private *ruler, QPainter *painter, const QRectF &rectangle) = 0; 0089 0090 /** 0091 * Draw the indicators for the indents of a text paragraph 0092 * @param ruler the ruler to draw on. 0093 * @param painter the painter we can paint with. 0094 */ 0095 virtual void drawIndents(const KReportRuler::Private *ruler, QPainter *painter) = 0; 0096 0097 /** 0098 *returns the size suggestion for a ruler with this strategy. 0099 */ 0100 virtual QSize sizeHint() = 0; 0101 }; 0102 0103 // ---- 0104 0105 class HorizontalPaintingStrategy : public PaintingStrategy 0106 { 0107 public: 0108 HorizontalPaintingStrategy() : lengthInPixel(1) {} 0109 0110 QRectF drawBackground(const KReportRuler::Private *ruler, QPainter *painter) override; 0111 void drawTabs(const KReportRuler::Private *ruler, QPainter *painter) override; 0112 void drawMeasurements(const KReportRuler::Private *ruler, QPainter *painter, const QRectF &rectangle) override; 0113 void drawIndents(const KReportRuler::Private *ruler, QPainter *painter) override; 0114 QSize sizeHint() override; 0115 0116 private: 0117 qreal lengthInPixel; 0118 }; 0119 0120 // ---- 0121 0122 class VerticalPaintingStrategy : public PaintingStrategy 0123 { 0124 public: 0125 VerticalPaintingStrategy() : lengthInPixel(1) {} 0126 0127 QRectF drawBackground(const KReportRuler::Private *ruler, QPainter *painter) override; 0128 void drawTabs(const KReportRuler::Private *, QPainter *) override {} 0129 void drawMeasurements(const KReportRuler::Private *ruler, QPainter *painter, const QRectF &rectangle) override; 0130 void drawIndents(const KReportRuler::Private *, QPainter *) override {} 0131 QSize sizeHint() override; 0132 0133 private: 0134 qreal lengthInPixel; 0135 }; 0136 0137 class HorizontalDistancesPaintingStrategy : public HorizontalPaintingStrategy 0138 { 0139 public: 0140 HorizontalDistancesPaintingStrategy() {} 0141 0142 void drawMeasurements(const KReportRuler::Private *ruler, QPainter *painter, const QRectF &rectangle) override; 0143 0144 private: 0145 void drawDistanceLine(const KReportRuler::Private *d, QPainter *painter, qreal start, qreal end); 0146 }; 0147 0148 // ---- 0149 0150 class KReportRuler::Private 0151 { 0152 public: 0153 Private(KReportRuler *parent, const KReportZoomHandler &zoomHandler, Qt::Orientation orientation); 0154 ~Private(); 0155 0156 void emitTabChanged(); 0157 0158 KReportUnit unit; 0159 const Qt::Orientation orientation; 0160 const KReportZoomHandler * const viewConverter; 0161 0162 int offset; 0163 qreal rulerLength; 0164 qreal activeRangeStart; 0165 qreal activeRangeEnd; 0166 qreal activeOverrideRangeStart; 0167 qreal activeOverrideRangeEnd; 0168 0169 int mouseCoordinate; 0170 int showMousePosition; 0171 0172 bool showSelectionBorders; 0173 qreal firstSelectionBorder; 0174 qreal secondSelectionBorder; 0175 0176 bool showIndents; 0177 qreal firstLineIndent; 0178 qreal paragraphIndent; 0179 qreal endIndent; 0180 0181 bool showTabs; 0182 bool relativeTabs; 0183 bool tabMoved; // set to true on first move of a selected tab 0184 QList<KReportRuler::Tab> tabs; 0185 int originalIndex; //index of selected tab before we started dragging it. 0186 int currentIndex; //index of selected tab or selected HotSpot - only valid when selected indicates tab or hotspot 0187 KReportRuler::Tab deletedTab; 0188 qreal tabDistance; 0189 0190 struct HotSpotData { 0191 qreal position; 0192 int id; 0193 }; 0194 QList<HotSpotData> hotspots; 0195 0196 bool rightToLeft; 0197 enum class Selection { 0198 None, 0199 Tab, 0200 FirstLineIndent, 0201 ParagraphIndent, 0202 EndIndent, 0203 HotSpot 0204 }; 0205 Selection selected; 0206 int selectOffset; 0207 0208 QList<QAction*> popupActions; 0209 0210 RulerTabChooser *tabChooser; 0211 0212 // Cached painting strategies 0213 PaintingStrategy * normalPaintingStrategy; 0214 PaintingStrategy * distancesPaintingStrategy; 0215 0216 // Current painting strategy 0217 PaintingStrategy * paintingStrategy; 0218 0219 KReportRuler *ruler; 0220 0221 qreal numberStepForUnit() const; 0222 /// @return The rounding of value to the nearest multiple of stepValue 0223 qreal doSnapping(qreal value) const; 0224 Selection selectionAtPosition(const QPoint &pos, int *selectOffset = nullptr); 0225 int hotSpotIndex(const QPoint &pos); 0226 qreal effectiveActiveRangeStart() const; 0227 qreal effectiveActiveRangeEnd() const; 0228 0229 friend class VerticalPaintingStrategy; 0230 friend class HorizontalPaintingStrategy; 0231 }; 0232 0233 // ---- 0234 0235 void RulerTabChooser::mousePressEvent(QMouseEvent *) 0236 { 0237 if (! m_showTabs) { 0238 return; 0239 } 0240 0241 switch(m_type) { 0242 case QTextOption::LeftTab: 0243 m_type = QTextOption::RightTab; 0244 break; 0245 case QTextOption::RightTab: 0246 m_type = QTextOption::CenterTab; 0247 break; 0248 case QTextOption::CenterTab: 0249 m_type = QTextOption::DelimiterTab; 0250 break; 0251 case QTextOption::DelimiterTab: 0252 m_type = QTextOption::LeftTab; 0253 break; 0254 } 0255 update(); 0256 } 0257 0258 void RulerTabChooser::paintEvent(QPaintEvent *) 0259 { 0260 if (! m_showTabs) { 0261 return; 0262 } 0263 0264 QPainter painter(this); 0265 QPolygonF polygon; 0266 0267 painter.setPen(palette().color(QPalette::Text)); 0268 painter.setBrush(palette().color(QPalette::Text)); 0269 painter.setRenderHint( QPainter::Antialiasing ); 0270 0271 qreal x = qreal(width())/2.0; 0272 painter.translate(0,-height()/2+5); 0273 0274 switch (m_type) { 0275 case QTextOption::LeftTab: 0276 polygon << QPointF(x+0.5, height() - 8.5) 0277 << QPointF(x+6.5, height() - 2.5) 0278 << QPointF(x+0.5, height() - 2.5); 0279 painter.drawPolygon(polygon); 0280 break; 0281 case QTextOption::RightTab: 0282 polygon << QPointF(x+0.5, height() - 8.5) 0283 << QPointF(x-5.5, height() - 2.5) 0284 << QPointF(x+0.5, height() - 2.5); 0285 painter.drawPolygon(polygon); 0286 break; 0287 case QTextOption::CenterTab: 0288 polygon << QPointF(x+0.5, height() - 8.5) 0289 << QPointF(x-5.5, height() - 2.5) 0290 << QPointF(x+6.5, height() - 2.5); 0291 painter.drawPolygon(polygon); 0292 break; 0293 case QTextOption::DelimiterTab: 0294 polygon << QPointF(x-5.5, height() - 2.5) 0295 << QPointF(x+6.5, height() - 2.5); 0296 painter.drawPolyline(polygon); 0297 polygon << QPointF(x+0.5, height() - 2.5) 0298 << QPointF(x+0.5, height() - 8.5); 0299 painter.drawPolyline(polygon); 0300 break; 0301 default: 0302 break; 0303 } 0304 } 0305 0306 static int compareTabs(const KReportRuler::Tab &tab1, const KReportRuler::Tab &tab2) 0307 { 0308 return tab1.position < tab2.position; 0309 } 0310 0311 QRectF HorizontalPaintingStrategy::drawBackground(const KReportRuler::Private *d, QPainter *painter) 0312 { 0313 lengthInPixel = d->viewConverter->documentToViewX(d->rulerLength); 0314 QRectF rectangle; 0315 rectangle.setX(qMax(0, d->offset)); 0316 rectangle.setY(0); 0317 rectangle.setWidth(qMin(qreal(d->ruler->width() - 1.0 - rectangle.x()), 0318 (d->offset >= 0) ? lengthInPixel : lengthInPixel + d->offset)); 0319 rectangle.setHeight(d->ruler->height() - 1); 0320 QRectF activeRangeRectangle; 0321 activeRangeRectangle.setX(qMax(rectangle.x() + 1, 0322 d->viewConverter->documentToViewX(d->effectiveActiveRangeStart()) + d->offset)); 0323 activeRangeRectangle.setY(rectangle.y() + 1); 0324 activeRangeRectangle.setRight(qMin(rectangle.right() - 1, 0325 d->viewConverter->documentToViewX(d->effectiveActiveRangeEnd()) + d->offset)); 0326 activeRangeRectangle.setHeight(rectangle.height() - 2); 0327 0328 painter->setPen(d->ruler->palette().color(QPalette::Mid)); 0329 painter->drawRect(rectangle); 0330 0331 if(d->effectiveActiveRangeStart() != d->effectiveActiveRangeEnd()) 0332 painter->fillRect(activeRangeRectangle, d->ruler->palette().brush(QPalette::Base)); 0333 0334 if(d->showSelectionBorders) { 0335 // Draw first selection border 0336 if(d->firstSelectionBorder > 0) { 0337 qreal border = d->viewConverter->documentToViewX(d->firstSelectionBorder) + d->offset; 0338 painter->drawLine(QPointF(border, rectangle.y() + 1), QPointF(border, rectangle.bottom() - 1)); 0339 } 0340 // Draw second selection border 0341 if(d->secondSelectionBorder > 0) { 0342 qreal border = d->viewConverter->documentToViewX(d->secondSelectionBorder) + d->offset; 0343 painter->drawLine(QPointF(border, rectangle.y() + 1), QPointF(border, rectangle.bottom() - 1)); 0344 } 0345 } 0346 0347 return rectangle; 0348 } 0349 0350 void HorizontalPaintingStrategy::drawTabs(const KReportRuler::Private *d, QPainter *painter) 0351 { 0352 if (! d->showTabs) 0353 return; 0354 QPolygonF polygon; 0355 0356 const QColor tabColor = d->ruler->palette().color(QPalette::Text); 0357 painter->setPen(tabColor); 0358 painter->setBrush(tabColor); 0359 painter->setRenderHint( QPainter::Antialiasing ); 0360 0361 qreal position = -10000; 0362 0363 foreach (const KReportRuler::Tab & t, d->tabs) { 0364 qreal x; 0365 if (d->rightToLeft) { 0366 x = d->viewConverter->documentToViewX(d->effectiveActiveRangeEnd() 0367 - (d->relativeTabs ? d->paragraphIndent : 0) - t.position) + d->offset; 0368 } else { 0369 x = d->viewConverter->documentToViewX(d->effectiveActiveRangeStart() 0370 + (d->relativeTabs ? d->paragraphIndent : 0) + t.position) + d->offset; 0371 } 0372 position = qMax(position, t.position); 0373 0374 polygon.clear(); 0375 switch (t.type) { 0376 case QTextOption::LeftTab: 0377 polygon << QPointF(x+0.5, d->ruler->height() - 6.5) 0378 << QPointF(x+6.5, d->ruler->height() - 0.5) 0379 << QPointF(x+0.5, d->ruler->height() - 0.5); 0380 painter->drawPolygon(polygon); 0381 break; 0382 case QTextOption::RightTab: 0383 polygon << QPointF(x+0.5, d->ruler->height() - 6.5) 0384 << QPointF(x-5.5, d->ruler->height() - 0.5) 0385 << QPointF(x+0.5, d->ruler->height() - 0.5); 0386 painter->drawPolygon(polygon); 0387 break; 0388 case QTextOption::CenterTab: 0389 polygon << QPointF(x+0.5, d->ruler->height() - 6.5) 0390 << QPointF(x-5.5, d->ruler->height() - 0.5) 0391 << QPointF(x+6.5, d->ruler->height() - 0.5); 0392 painter->drawPolygon(polygon); 0393 break; 0394 case QTextOption::DelimiterTab: 0395 polygon << QPointF(x-5.5, d->ruler->height() - 0.5) 0396 << QPointF(x+6.5, d->ruler->height() - 0.5); 0397 painter->drawPolyline(polygon); 0398 polygon << QPointF(x+0.5, d->ruler->height() - 0.5) 0399 << QPointF(x+0.5, d->ruler->height() - 6.5); 0400 painter->drawPolyline(polygon); 0401 break; 0402 default: 0403 break; 0404 } 0405 } 0406 0407 // and also draw the regular interval tab that are non editable 0408 if (d->tabDistance > 0.0) { 0409 // first possible position 0410 position = qMax(position, d->relativeTabs ? 0 : d->paragraphIndent); 0411 if (position < 0) { 0412 position = int(position / d->tabDistance) * d->tabDistance; 0413 } else { 0414 position = (int(position / d->tabDistance) + 1) * d->tabDistance; 0415 } 0416 while (position < d->effectiveActiveRangeEnd() - d->effectiveActiveRangeStart() 0417 - d->endIndent) { 0418 qreal x; 0419 if (d->rightToLeft) { 0420 x = d->viewConverter->documentToViewX(d->effectiveActiveRangeEnd() 0421 - (d->relativeTabs ? d->paragraphIndent : 0) - position) + d->offset; 0422 } else { 0423 x = d->viewConverter->documentToViewX(d->effectiveActiveRangeStart() 0424 + (d->relativeTabs ? d->paragraphIndent : 0) + position) + d->offset; 0425 } 0426 0427 polygon.clear(); 0428 polygon << QPointF(x+0.5, d->ruler->height() - 3.5) 0429 << QPointF(x+4.5, d->ruler->height() - 0.5) 0430 << QPointF(x+0.5, d->ruler->height() - 0.5); 0431 painter->drawPolygon(polygon); 0432 0433 position += d->tabDistance; 0434 } 0435 } 0436 } 0437 0438 void HorizontalPaintingStrategy::drawMeasurements(const KReportRuler::Private *d, QPainter *painter, const QRectF &rectangle) 0439 { 0440 qreal numberStep = d->numberStepForUnit(); // number step in unit 0441 // QRectF activeRangeRectangle; 0442 int numberStepPixel = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue(numberStep))); 0443 // const bool adjustMillimeters = (d->unit.type() == KReportUnit::Millimeter); 0444 0445 const QFont font = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); 0446 const QFontMetrics fontMetrics(font); 0447 painter->setFont(font); 0448 0449 if (numberStepPixel == 0 || numberStep == 0) 0450 return; 0451 0452 // Calc the longest text length 0453 int textLength = 0; 0454 for(int i = 0; i < lengthInPixel; i += numberStepPixel) { 0455 int number = qRound((i / numberStepPixel) * numberStep); 0456 0457 textLength = qMax(textLength, fontMetrics.horizontalAdvance(QString::number(number))); 0458 } 0459 textLength += 4; // Add some padding 0460 0461 // Change number step so all digits fits 0462 while(textLength > numberStepPixel) { 0463 numberStepPixel += numberStepPixel; 0464 numberStep += numberStep; 0465 } 0466 0467 int start=0; 0468 // Calc the first number step 0469 if(d->offset < 0) 0470 start = qAbs(d->offset); 0471 0472 // make a little hack so rulers shows correctly inversed number aligned 0473 const qreal lengthInUnit = d->unit.toUserValue(d->rulerLength); 0474 const qreal hackyLength = lengthInUnit - fmod(lengthInUnit, numberStep); 0475 if(d->rightToLeft) { 0476 start -= int(d->viewConverter->documentToViewX(fmod(d->rulerLength, 0477 d->unit.fromUserValue(numberStep)))); 0478 } 0479 0480 int stepCount = (start / numberStepPixel) + 1; 0481 int halfStepCount = (start / qRound(numberStepPixel * 0.5)) + 1; 0482 int quarterStepCount = (start / qRound(numberStepPixel * 0.25)) + 1; 0483 0484 const QPen numberPen(d->ruler->palette().color(QPalette::Text)); 0485 const QPen markerPen(d->ruler->palette().color(QPalette::Inactive, QPalette::Text)); 0486 painter->setPen(markerPen); 0487 0488 if(d->offset > 0) 0489 painter->translate(d->offset, 0); 0490 0491 const int len = qRound(rectangle.width()) + start; 0492 int nextStep = qRound(d->viewConverter->documentToViewX( 0493 d->unit.fromUserValue(numberStep * stepCount))); 0494 int nextHalfStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0495 numberStep * 0.5 * halfStepCount))); 0496 int nextQuarterStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0497 numberStep * 0.25 * quarterStepCount))); 0498 0499 for(int i = start; i < len; ++i) { 0500 const int pos = i - start; 0501 0502 if(i == nextStep) { 0503 if(pos != 0) 0504 painter->drawLine(QPointF(pos, rectangle.bottom()-1), 0505 QPointF(pos, rectangle.bottom() - fullStepMarkerLength)); 0506 0507 int number = qRound(stepCount * numberStep); 0508 0509 QString numberText = QString::number(number); 0510 int x = pos; 0511 if (d->rightToLeft) { // this is done in a hacky way with the fine tuning done above 0512 numberText = QString::number(hackyLength - stepCount * numberStep); 0513 } 0514 painter->setPen(numberPen); 0515 painter->drawText(QPointF(x-fontMetrics.horizontalAdvance(numberText)/2.0, 0516 rectangle.bottom() -fullStepMarkerLength -measurementTextAboveBelowMargin), 0517 numberText); 0518 painter->setPen(markerPen); 0519 0520 ++stepCount; 0521 nextStep = qRound(d->viewConverter->documentToViewX( 0522 d->unit.fromUserValue(numberStep * stepCount))); 0523 ++halfStepCount; 0524 nextHalfStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0525 numberStep * 0.5 * halfStepCount))); 0526 ++quarterStepCount; 0527 nextQuarterStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0528 numberStep * 0.25 * quarterStepCount))); 0529 } 0530 else if(i == nextHalfStep) { 0531 if(pos != 0) 0532 painter->drawLine(QPointF(pos, rectangle.bottom()-1), 0533 QPointF(pos, rectangle.bottom() - halfStepMarkerLength)); 0534 0535 ++halfStepCount; 0536 nextHalfStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0537 numberStep * 0.5 * halfStepCount))); 0538 ++quarterStepCount; 0539 nextQuarterStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0540 numberStep * 0.25 * quarterStepCount))); 0541 } 0542 else if(i == nextQuarterStep) { 0543 if(pos != 0) 0544 painter->drawLine(QPointF(pos, rectangle.bottom()-1), 0545 QPointF(pos, rectangle.bottom() - quarterStepMarkerLength)); 0546 0547 ++quarterStepCount; 0548 nextQuarterStep = qRound(d->viewConverter->documentToViewX(d->unit.fromUserValue( 0549 numberStep * 0.25 * quarterStepCount))); 0550 } 0551 } 0552 0553 // Draw the mouse indicator 0554 const int mouseCoord = d->mouseCoordinate - start; 0555 if (d->selected == KReportRuler::Private::Selection::None 0556 || d->selected == KReportRuler::Private::Selection::HotSpot) 0557 { 0558 const qreal top = rectangle.y() + 1; 0559 const qreal bottom = rectangle.bottom() -1; 0560 if (d->selected == KReportRuler::Private::Selection::None && d->showMousePosition 0561 && mouseCoord > 0 && mouseCoord < rectangle.width()) 0562 { 0563 painter->drawLine(QPointF(mouseCoord, top), QPointF(mouseCoord, bottom)); 0564 } 0565 foreach (const KReportRuler::Private::HotSpotData & hp, d->hotspots) { 0566 const qreal x = d->viewConverter->documentToViewX(hp.position) + d->offset; 0567 painter->drawLine(QPointF(x, top), QPointF(x, bottom)); 0568 } 0569 } 0570 } 0571 0572 void HorizontalPaintingStrategy::drawIndents(const KReportRuler::Private *d, QPainter *painter) 0573 { 0574 QPolygonF polygon; 0575 0576 painter->setBrush(d->ruler->palette().brush(QPalette::Base)); 0577 painter->setRenderHint( QPainter::Antialiasing ); 0578 0579 qreal x; 0580 // Draw first line start indent 0581 if (d->rightToLeft) 0582 x = d->effectiveActiveRangeEnd() - d->firstLineIndent - d->paragraphIndent; 0583 else 0584 x = d->effectiveActiveRangeStart() + d->firstLineIndent + d->paragraphIndent; 0585 // convert and use the +0.5 to go to nearest integer so that the 0.5 added below ensures sharp lines 0586 x = int(d->viewConverter->documentToViewX(x) + d->offset + 0.5); 0587 polygon << QPointF(x+6.5, 0.5) 0588 << QPointF(x+0.5, 8.5) 0589 << QPointF(x-5.5, 0.5) 0590 << QPointF(x+5.5, 0.5); 0591 painter->drawPolygon(polygon); 0592 0593 // draw the hanging indent. 0594 if (d->rightToLeft) 0595 x = d->effectiveActiveRangeStart() + d->endIndent; 0596 else 0597 x = d->effectiveActiveRangeStart() + d->paragraphIndent; 0598 // convert and use the +0.5 to go to nearest integer so that the 0.5 added below ensures sharp lines 0599 x = int(d->viewConverter->documentToViewX(x) + d->offset + 0.5); 0600 const int bottom = d->ruler->height(); 0601 polygon.clear(); 0602 polygon << QPointF(x+6.5, bottom - 0.5) 0603 << QPointF(x+0.5, bottom - 8.5) 0604 << QPointF(x-5.5, bottom - 0.5) 0605 << QPointF(x+5.5, bottom - 0.5); 0606 painter->drawPolygon(polygon); 0607 0608 // Draw end-indent or paragraph indent if mode is rightToLeft 0609 qreal diff; 0610 if (d->rightToLeft) 0611 diff = d->viewConverter->documentToViewX(d->effectiveActiveRangeEnd() 0612 - d->paragraphIndent) + d->offset - x; 0613 else 0614 diff = d->viewConverter->documentToViewX(d->effectiveActiveRangeEnd() - d->endIndent) 0615 + d->offset - x; 0616 polygon.translate(diff, 0); 0617 painter->drawPolygon(polygon); 0618 } 0619 0620 QSize HorizontalPaintingStrategy::sizeHint() 0621 { 0622 // assumes that digits for the number only use glyphs which do not go below the baseline 0623 const QFontMetrics fm(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0624 const int digitsHeight = fm.ascent() + 1; // +1 for baseline 0625 const int minimum = digitsHeight + fullStepMarkerLength + 2*measurementTextAboveBelowMargin; 0626 0627 return QSize(0, minimum); 0628 } 0629 0630 QRectF VerticalPaintingStrategy::drawBackground(const KReportRuler::Private *d, QPainter *painter) 0631 { 0632 lengthInPixel = d->viewConverter->documentToViewY(d->rulerLength); 0633 QRectF rectangle; 0634 rectangle.setX(0); 0635 rectangle.setY(qMax(0, d->offset)); 0636 rectangle.setWidth(d->ruler->width() - 1.0); 0637 rectangle.setHeight(qMin(qreal(d->ruler->height() - 1.0 - rectangle.y()), 0638 (d->offset >= 0) ? lengthInPixel : lengthInPixel + d->offset)); 0639 0640 QRectF activeRangeRectangle; 0641 activeRangeRectangle.setX(rectangle.x() + 1); 0642 activeRangeRectangle.setY(qMax(rectangle.y() + 1, 0643 d->viewConverter->documentToViewY(d->effectiveActiveRangeStart()) + d->offset)); 0644 activeRangeRectangle.setWidth(rectangle.width() - 2); 0645 activeRangeRectangle.setBottom(qMin(rectangle.bottom() - 1, 0646 d->viewConverter->documentToViewY(d->effectiveActiveRangeEnd()) + d->offset)); 0647 0648 painter->setPen(d->ruler->palette().color(QPalette::Mid)); 0649 painter->drawRect(rectangle); 0650 0651 if(d->effectiveActiveRangeStart() != d->effectiveActiveRangeEnd()) 0652 painter->fillRect(activeRangeRectangle, d->ruler->palette().brush(QPalette::Base)); 0653 0654 if(d->showSelectionBorders) { 0655 // Draw first selection border 0656 if(d->firstSelectionBorder > 0) { 0657 qreal border = d->viewConverter->documentToViewY(d->firstSelectionBorder) + d->offset; 0658 painter->drawLine(QPointF(rectangle.x() + 1, border), QPointF(rectangle.right() - 1, border)); 0659 } 0660 // Draw second selection border 0661 if(d->secondSelectionBorder > 0) { 0662 qreal border = d->viewConverter->documentToViewY(d->secondSelectionBorder) + d->offset; 0663 painter->drawLine(QPointF(rectangle.x() + 1, border), QPointF(rectangle.right() - 1, border)); 0664 } 0665 } 0666 0667 return rectangle; 0668 } 0669 0670 void VerticalPaintingStrategy::drawMeasurements(const KReportRuler::Private *d, QPainter *painter, const QRectF &rectangle) 0671 { 0672 qreal numberStep = d->numberStepForUnit(); // number step in unit 0673 int numberStepPixel = qRound(d->viewConverter->documentToViewY( d->unit.fromUserValue(numberStep))); 0674 if (numberStepPixel <= 0) 0675 return; 0676 0677 const QFont font = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); 0678 const QFontMetrics fontMetrics(font); 0679 painter->setFont(font); 0680 0681 // Calc the longest text length 0682 int textLength = 0; 0683 0684 for(int i = 0; i < lengthInPixel; i += numberStepPixel) { 0685 int number = qRound((i / numberStepPixel) * numberStep); 0686 textLength = qMax(textLength, fontMetrics.horizontalAdvance(QString::number(number))); 0687 } 0688 textLength += 4; // Add some padding 0689 0690 if (numberStepPixel == 0 || numberStep == 0) 0691 return; 0692 // Change number step so all digits will fit 0693 while(textLength > numberStepPixel) { 0694 numberStepPixel += numberStepPixel; 0695 numberStep += numberStep; 0696 } 0697 0698 // Calc the first number step 0699 const int start = d->offset < 0 ? qAbs(d->offset) : 0; 0700 0701 // make a little hack so rulers shows correctly inversed number aligned 0702 int stepCount = (start / numberStepPixel) + 1; 0703 int halfStepCount = (start / qRound(numberStepPixel * 0.5)) + 1; 0704 int quarterStepCount = (start / qRound(numberStepPixel * 0.25)) + 1; 0705 0706 const QPen numberPen(d->ruler->palette().color(QPalette::Text)); 0707 const QPen markerPen(d->ruler->palette().color(QPalette::Inactive, QPalette::Text)); 0708 painter->setPen(markerPen); 0709 0710 if(d->offset > 0) 0711 painter->translate(0, d->offset); 0712 0713 const int len = qRound(rectangle.height()) + start; 0714 int nextStep = qRound(d->viewConverter->documentToViewY( 0715 d->unit.fromUserValue(numberStep * stepCount))); 0716 int nextHalfStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0717 numberStep * 0.5 * halfStepCount))); 0718 int nextQuarterStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0719 numberStep * 0.25 * quarterStepCount))); 0720 0721 for(int i = start; i < len; ++i) { 0722 const int pos = i - start; 0723 0724 if(i == nextStep) { 0725 painter->save(); 0726 painter->translate(rectangle.right()-fullStepMarkerLength, pos); 0727 if(pos != 0) 0728 painter->drawLine(QPointF(0, 0), QPointF(fullStepMarkerLength-1, 0)); 0729 0730 painter->rotate(-90); 0731 int number = qRound(stepCount * numberStep); 0732 QString numberText = QString::number(number); 0733 painter->setPen(numberPen); 0734 painter->drawText(QPointF(-fontMetrics.horizontalAdvance(numberText) / 2.0, -measurementTextAboveBelowMargin), numberText); 0735 painter->restore(); 0736 0737 ++stepCount; 0738 nextStep = qRound(d->viewConverter->documentToViewY( 0739 d->unit.fromUserValue(numberStep * stepCount))); 0740 ++halfStepCount; 0741 nextHalfStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0742 numberStep * 0.5 * halfStepCount))); 0743 ++quarterStepCount; 0744 nextQuarterStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0745 numberStep * 0.25 * quarterStepCount))); 0746 } else if(i == nextHalfStep) { 0747 if(pos != 0) 0748 painter->drawLine(QPointF(rectangle.right() - halfStepMarkerLength, pos), 0749 QPointF(rectangle.right() - 1, pos)); 0750 0751 ++halfStepCount; 0752 nextHalfStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0753 numberStep * 0.5 * halfStepCount))); 0754 ++quarterStepCount; 0755 nextQuarterStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0756 numberStep * 0.25 * quarterStepCount))); 0757 } else if(i == nextQuarterStep) { 0758 if(pos != 0) 0759 painter->drawLine(QPointF(rectangle.right() - quarterStepMarkerLength, pos), 0760 QPointF(rectangle.right() - 1, pos)); 0761 0762 ++quarterStepCount; 0763 nextQuarterStep = qRound(d->viewConverter->documentToViewY(d->unit.fromUserValue( 0764 numberStep * 0.25 * quarterStepCount))); 0765 } 0766 } 0767 0768 // Draw the mouse indicator 0769 const int mouseCoord = d->mouseCoordinate - start; 0770 if (d->selected == KReportRuler::Private::Selection::None 0771 || d->selected == KReportRuler::Private::Selection::HotSpot) 0772 { 0773 const qreal left = rectangle.left() + 1; 0774 const qreal right = rectangle.right() -1; 0775 if (d->selected == KReportRuler::Private::Selection::None && d->showMousePosition 0776 && mouseCoord > 0 && mouseCoord < rectangle.height()) 0777 { 0778 painter->drawLine(QPointF(left, mouseCoord), QPointF(right, mouseCoord)); 0779 } 0780 foreach (const KReportRuler::Private::HotSpotData & hp, d->hotspots) { 0781 const qreal y = d->viewConverter->documentToViewY(hp.position) + d->offset; 0782 painter->drawLine(QPointF(left, y), QPointF(right, y)); 0783 } 0784 } 0785 } 0786 0787 QSize VerticalPaintingStrategy::sizeHint() 0788 { 0789 // assumes that digits for the number only use glyphs which do not go below the baseline 0790 const QFontMetrics fm(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0791 const int digitsHeight = fm.ascent() + 1; // +1 for baseline 0792 const int minimum = digitsHeight + fullStepMarkerLength + 2*measurementTextAboveBelowMargin; 0793 0794 return QSize(minimum, 0); 0795 } 0796 0797 0798 void HorizontalDistancesPaintingStrategy::drawDistanceLine(const KReportRuler::Private *d, 0799 QPainter *painter, qreal start, 0800 qreal end) 0801 { 0802 0803 // Don't draw too short lines 0804 if (qMax(start, end) - qMin(start, end) < 1) 0805 return; 0806 0807 painter->save(); 0808 painter->translate(d->offset, d->ruler->height() / 2); 0809 painter->setPen(d->ruler->palette().color(QPalette::Text)); 0810 painter->setBrush(d->ruler->palette().color(QPalette::Text)); 0811 0812 QLineF line(QPointF(d->viewConverter->documentToViewX(start), 0), 0813 QPointF(d->viewConverter->documentToViewX(end), 0)); 0814 QPointF midPoint = line.pointAt(0.5); 0815 0816 // Draw the label text 0817 const QFont font = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); 0818 const QFontMetrics fontMetrics(font); 0819 QString label = d->unit.toUserStringValue( 0820 d->viewConverter->viewToDocumentX(line.length())) + QLatin1String("") + d->unit.symbol(); 0821 QPointF labelPosition = QPointF(midPoint.x() - fontMetrics.horizontalAdvance(label)/2, 0822 midPoint.y() + fontMetrics.ascent()/2); 0823 painter->setFont(font); 0824 painter->drawText(labelPosition, label); 0825 0826 // Draw the arrow lines 0827 qreal arrowLength = (line.length() - fontMetrics.horizontalAdvance(label)) / 2 - 2; 0828 arrowLength = qMax(qreal(0.0), arrowLength); 0829 QLineF startArrow(line.p1(), line.pointAt(arrowLength / line.length())); 0830 QLineF endArrow(line.p2(), line.pointAt(1.0 - arrowLength / line.length())); 0831 painter->drawLine(startArrow); 0832 painter->drawLine(endArrow); 0833 0834 // Draw the arrow heads 0835 QPolygonF arrowHead; 0836 arrowHead << line.p1() << QPointF(line.x1()+3, line.y1()-3) 0837 << QPointF(line.x1()+3, line.y1()+3); 0838 painter->drawPolygon(arrowHead); 0839 arrowHead.clear(); 0840 arrowHead << line.p2() << QPointF(line.x2()-3, line.y2()-3) 0841 << QPointF(line.x2()-3, line.y2()+3); 0842 painter->drawPolygon(arrowHead); 0843 0844 painter->restore(); 0845 } 0846 0847 void HorizontalDistancesPaintingStrategy::drawMeasurements(const KReportRuler::Private *d, 0848 QPainter *painter, const QRectF&) 0849 { 0850 QList<qreal> points; 0851 points << 0.0; 0852 points << d->effectiveActiveRangeStart() + d->paragraphIndent + d->firstLineIndent; 0853 points << d->effectiveActiveRangeStart() + d->paragraphIndent; 0854 points << d->effectiveActiveRangeEnd() - d->endIndent; 0855 points << d->effectiveActiveRangeStart(); 0856 points << d->effectiveActiveRangeEnd(); 0857 points << d->rulerLength; 0858 std::sort(points.begin(), points.end()); 0859 QListIterator<qreal> i(points); 0860 i.next(); 0861 while (i.hasNext() && i.hasPrevious()) { 0862 drawDistanceLine(d, painter, i.peekPrevious(), i.peekNext()); 0863 i.next(); 0864 } 0865 } 0866 0867 KReportRuler::Private::Private(KReportRuler *parent, 0868 const KReportZoomHandler &zoomHandler, Qt::Orientation o) 0869 : unit(DEFAULT_UNIT), 0870 orientation(o), 0871 viewConverter(&zoomHandler), 0872 offset(0), 0873 rulerLength(0), 0874 activeRangeStart(0), 0875 activeRangeEnd(0), 0876 activeOverrideRangeStart(0), 0877 activeOverrideRangeEnd(0), 0878 mouseCoordinate(-1), 0879 showMousePosition(0), 0880 showSelectionBorders(false), 0881 firstSelectionBorder(0), 0882 secondSelectionBorder(0), 0883 showIndents(false), 0884 firstLineIndent(0), 0885 paragraphIndent(0), 0886 endIndent(0), 0887 showTabs(false), 0888 relativeTabs(false), 0889 tabMoved(false), 0890 originalIndex(-1), 0891 currentIndex(0), 0892 tabDistance(0.0), 0893 rightToLeft(false), 0894 selected(Selection::None), 0895 selectOffset(0), 0896 tabChooser(nullptr), 0897 normalPaintingStrategy(o == Qt::Horizontal ? 0898 static_cast<PaintingStrategy*>(new HorizontalPaintingStrategy()) 0899 : static_cast<PaintingStrategy*>(new VerticalPaintingStrategy())), 0900 distancesPaintingStrategy(new HorizontalDistancesPaintingStrategy()), 0901 paintingStrategy(normalPaintingStrategy), 0902 ruler(parent) 0903 { 0904 } 0905 0906 KReportRuler::Private::~Private() 0907 { 0908 delete normalPaintingStrategy; 0909 delete distancesPaintingStrategy; 0910 } 0911 0912 qreal KReportRuler::Private::numberStepForUnit() const 0913 { 0914 switch(unit.type()) { 0915 case KReportUnit::Type::Inch: 0916 case KReportUnit::Type::Centimeter: 0917 case KReportUnit::Type::Decimeter: 0918 case KReportUnit::Type::Millimeter: 0919 return 1.0; 0920 case KReportUnit::Type::Pica: 0921 case KReportUnit::Type::Cicero: 0922 return 10.0; 0923 case KReportUnit::Type::Point: 0924 default: 0925 return 100.0; 0926 } 0927 } 0928 0929 qreal KReportRuler::Private::doSnapping(qreal value) const 0930 { 0931 qreal numberStep = unit.fromUserValue(numberStepForUnit()/4.0); 0932 return numberStep * qRound(value / numberStep); 0933 } 0934 0935 KReportRuler::Private::Selection KReportRuler::Private::selectionAtPosition(const QPoint & pos, int *selectOffset ) 0936 { 0937 const int height = ruler->height(); 0938 if (rightToLeft) { 0939 int x = int(viewConverter->documentToViewX(effectiveActiveRangeEnd() - firstLineIndent - paragraphIndent) + offset); 0940 if (pos.x() >= x - 8 && pos.x() <= x +8 && pos.y() < height / 2) { 0941 if (selectOffset) 0942 *selectOffset = x - pos.x(); 0943 return KReportRuler::Private::Selection::FirstLineIndent; 0944 } 0945 0946 x = int(viewConverter->documentToViewX(effectiveActiveRangeEnd() - paragraphIndent) + offset); 0947 if (pos.x() >= x - 8 && pos.x() <= x +8 && pos.y() > height / 2) { 0948 if (selectOffset) 0949 *selectOffset = x - pos.x(); 0950 return KReportRuler::Private::Selection::ParagraphIndent; 0951 } 0952 0953 x = int(viewConverter->documentToViewX(effectiveActiveRangeStart() + endIndent) + offset); 0954 if (pos.x() >= x - 8 && pos.x() <= x + 8) { 0955 if (selectOffset) 0956 *selectOffset = x - pos.x(); 0957 return KReportRuler::Private::Selection::EndIndent; 0958 } 0959 } 0960 else { 0961 int x = int(viewConverter->documentToViewX(effectiveActiveRangeStart() + firstLineIndent + paragraphIndent) + offset); 0962 if (pos.x() >= x -8 && pos.x() <= x + 8 && pos.y() < height / 2) { 0963 if (selectOffset) 0964 *selectOffset = x - pos.x(); 0965 return KReportRuler::Private::Selection::FirstLineIndent; 0966 } 0967 0968 x = int(viewConverter->documentToViewX(effectiveActiveRangeStart() + paragraphIndent) + offset); 0969 if (pos.x() >= x - 8 && pos.x() <= x + 8 && pos.y() > height/2) { 0970 if (selectOffset) 0971 *selectOffset = x - pos.x(); 0972 return KReportRuler::Private::Selection::ParagraphIndent; 0973 } 0974 0975 x = int(viewConverter->documentToViewX(effectiveActiveRangeEnd() - endIndent) + offset); 0976 if (pos.x() >= x - 8 && pos.x() <= x + 8) { 0977 if (selectOffset) 0978 *selectOffset = x - pos.x(); 0979 return KReportRuler::Private::Selection::EndIndent; 0980 } 0981 } 0982 0983 return KReportRuler::Private::Selection::None; 0984 } 0985 0986 int KReportRuler::Private::hotSpotIndex(const QPoint & pos) 0987 { 0988 for(int counter = 0; counter < hotspots.count(); counter++) { 0989 bool hit; 0990 if (orientation == Qt::Horizontal) 0991 hit = qAbs(viewConverter->documentToViewX(hotspots[counter].position) - pos.x() + offset) < 3; 0992 else 0993 hit = qAbs(viewConverter->documentToViewY(hotspots[counter].position) - pos.y() + offset) < 3; 0994 0995 if (hit) 0996 return counter; 0997 } 0998 return -1; 0999 } 1000 1001 qreal KReportRuler::Private::effectiveActiveRangeStart() const 1002 { 1003 if (activeOverrideRangeStart != activeOverrideRangeEnd) { 1004 return activeOverrideRangeStart; 1005 } else { 1006 return activeRangeStart; 1007 } 1008 } 1009 1010 qreal KReportRuler::Private::effectiveActiveRangeEnd() const 1011 { 1012 if (activeOverrideRangeStart != activeOverrideRangeEnd) { 1013 return activeOverrideRangeEnd; 1014 } else { 1015 return activeRangeEnd; 1016 } 1017 } 1018 1019 void KReportRuler::Private::emitTabChanged() 1020 { 1021 KReportRuler::Tab tab; 1022 if (currentIndex >= 0) 1023 tab = tabs[currentIndex]; 1024 emit ruler->tabChanged(originalIndex, currentIndex >= 0 ? &tab : nullptr); 1025 } 1026 1027 1028 KReportRuler::KReportRuler(QWidget* parent, Qt::Orientation orientation, 1029 const KReportZoomHandler &zoomHandler) 1030 : QWidget(parent) 1031 , d(new KReportRuler::Private(this, zoomHandler, orientation)) 1032 { 1033 setMouseTracking( true ); 1034 } 1035 1036 KReportRuler::~KReportRuler() 1037 { 1038 delete d; 1039 } 1040 1041 KReportUnit KReportRuler::unit() const 1042 { 1043 return d->unit; 1044 } 1045 1046 void KReportRuler::setUnit(const KReportUnit &unit) 1047 { 1048 d->unit = unit; 1049 update(); 1050 } 1051 1052 qreal KReportRuler::rulerLength() const 1053 { 1054 return d->rulerLength; 1055 } 1056 1057 Qt::Orientation KReportRuler::orientation() const 1058 { 1059 return d->orientation; 1060 } 1061 1062 void KReportRuler::setOffset(int offset) 1063 { 1064 d->offset = offset; 1065 update(); 1066 } 1067 1068 void KReportRuler::setRulerLength(qreal length) 1069 { 1070 d->rulerLength = length; 1071 update(); 1072 } 1073 1074 void KReportRuler::paintEvent(QPaintEvent* event) 1075 { 1076 QPainter painter(this); 1077 painter.setClipRegion(event->region()); 1078 painter.save(); 1079 QRectF rectangle = d->paintingStrategy->drawBackground(d, &painter); 1080 painter.restore(); 1081 painter.save(); 1082 d->paintingStrategy->drawMeasurements(d, &painter, rectangle); 1083 painter.restore(); 1084 if (d->showIndents) { 1085 painter.save(); 1086 d->paintingStrategy->drawIndents(d, &painter); 1087 painter.restore(); 1088 } 1089 d->paintingStrategy->drawTabs(d, &painter); 1090 } 1091 1092 QSize KReportRuler::minimumSizeHint() const 1093 { 1094 return d->paintingStrategy->sizeHint(); 1095 } 1096 1097 QSize KReportRuler::sizeHint() const 1098 { 1099 return d->paintingStrategy->sizeHint(); 1100 } 1101 1102 void KReportRuler::setActiveRange(qreal start, qreal end) 1103 { 1104 d->activeRangeStart = start; 1105 d->activeRangeEnd = end; 1106 update(); 1107 } 1108 1109 void KReportRuler::setOverrideActiveRange(qreal start, qreal end) 1110 { 1111 d->activeOverrideRangeStart = start; 1112 d->activeOverrideRangeEnd = end; 1113 update(); 1114 } 1115 1116 void KReportRuler::updateMouseCoordinate(int coordinate) 1117 { 1118 if(d->mouseCoordinate == coordinate) 1119 return; 1120 d->mouseCoordinate = coordinate; 1121 update(); 1122 } 1123 1124 void KReportRuler::setShowMousePosition(bool show) 1125 { 1126 d->showMousePosition = show; 1127 update(); 1128 } 1129 1130 void KReportRuler::setRightToLeft(bool isRightToLeft) 1131 { 1132 d->rightToLeft = isRightToLeft; 1133 update(); 1134 } 1135 1136 void KReportRuler::setShowIndents(bool show) 1137 { 1138 d->showIndents = show; 1139 update(); 1140 } 1141 1142 void KReportRuler::setFirstLineIndent(qreal indent) 1143 { 1144 d->firstLineIndent = indent; 1145 if (d->showIndents) { 1146 update(); 1147 } 1148 } 1149 1150 void KReportRuler::setParagraphIndent(qreal indent) 1151 { 1152 d->paragraphIndent = indent; 1153 if (d->showIndents) { 1154 update(); 1155 } 1156 } 1157 1158 void KReportRuler::setEndIndent(qreal indent) 1159 { 1160 d->endIndent = indent; 1161 if (d->showIndents) { 1162 update(); 1163 } 1164 } 1165 1166 qreal KReportRuler::firstLineIndent() const 1167 { 1168 return d->firstLineIndent; 1169 } 1170 1171 qreal KReportRuler::paragraphIndent() const 1172 { 1173 return d->paragraphIndent; 1174 } 1175 1176 qreal KReportRuler::endIndent() const 1177 { 1178 return d->endIndent; 1179 } 1180 1181 QWidget *KReportRuler::tabChooser() 1182 { 1183 if ((d->tabChooser == nullptr) && (d->orientation == Qt::Horizontal)) { 1184 d->tabChooser = new RulerTabChooser(parentWidget()); 1185 d->tabChooser->setShowTabs(d->showTabs); 1186 } 1187 1188 return d->tabChooser; 1189 } 1190 1191 void KReportRuler::setShowSelectionBorders(bool show) 1192 { 1193 d->showSelectionBorders = show; 1194 update(); 1195 } 1196 1197 void KReportRuler::updateSelectionBorders(qreal first, qreal second) 1198 { 1199 d->firstSelectionBorder = first; 1200 d->secondSelectionBorder = second; 1201 1202 if(d->showSelectionBorders) 1203 update(); 1204 } 1205 1206 void KReportRuler::setShowTabs(bool show) 1207 { 1208 if (d->showTabs == show) { 1209 return; 1210 } 1211 1212 d->showTabs = show; 1213 if (d->tabChooser) { 1214 d->tabChooser->setShowTabs(show); 1215 } 1216 update(); 1217 } 1218 1219 void KReportRuler::setRelativeTabs(bool relative) 1220 { 1221 d->relativeTabs = relative; 1222 if (d->showTabs) { 1223 update(); 1224 } 1225 } 1226 1227 void KReportRuler::updateTabs(const QList<KReportRuler::Tab> &tabs, qreal tabDistance) 1228 { 1229 d->tabs = tabs; 1230 d->tabDistance = tabDistance; 1231 if (d->showTabs) { 1232 update(); 1233 } 1234 } 1235 1236 QList<KReportRuler::Tab> KReportRuler::tabs() const 1237 { 1238 QList<Tab> answer = d->tabs; 1239 std::sort(answer.begin(), answer.end(), compareTabs); 1240 1241 return answer; 1242 } 1243 1244 void KReportRuler::setPopupActionList(const QList<QAction*> &popupActionList) 1245 { 1246 d->popupActions = popupActionList; 1247 } 1248 1249 QList<QAction*> KReportRuler::popupActionList() const 1250 { 1251 return d->popupActions; 1252 } 1253 1254 void KReportRuler::mousePressEvent ( QMouseEvent* ev ) 1255 { 1256 d->tabMoved = false; 1257 d->selected = KReportRuler::Private::Selection::None; 1258 if (ev->button() == Qt::RightButton && !d->popupActions.isEmpty()) 1259 QMenu::exec(d->popupActions, ev->globalPos()); 1260 if (ev->button() != Qt::LeftButton) { 1261 ev->ignore(); 1262 return; 1263 } 1264 1265 QPoint pos = ev->pos(); 1266 1267 if (d->showTabs) { 1268 int i = 0; 1269 int x; 1270 foreach (const Tab & t, d->tabs) { 1271 if (d->rightToLeft) { 1272 x = d->viewConverter->documentToViewX(d->effectiveActiveRangeEnd() 1273 - (d->relativeTabs ? d->paragraphIndent : 0) - t.position) + d->offset; 1274 } else { 1275 x = d->viewConverter->documentToViewX(d->effectiveActiveRangeStart() 1276 + (d->relativeTabs ? d->paragraphIndent : 0) + t.position) + d->offset; 1277 } 1278 if (pos.x() >= x-6 && pos.x() <= x+6) { 1279 d->selected = KReportRuler::Private::Selection::Tab; 1280 d->selectOffset = x - pos.x(); 1281 d->currentIndex = i; 1282 break; 1283 } 1284 i++; 1285 } 1286 d->originalIndex = d->currentIndex; 1287 } 1288 1289 if (d->selected == KReportRuler::Private::Selection::None) 1290 d->selected = d->selectionAtPosition(ev->pos(), &d->selectOffset); 1291 if (d->selected == KReportRuler::Private::Selection::None) { 1292 int hotSpotIndex = d->hotSpotIndex(ev->pos()); 1293 if (hotSpotIndex >= 0) { 1294 d->selected = KReportRuler::Private::Selection::HotSpot; 1295 update(); 1296 } 1297 } 1298 1299 if (d->showTabs && d->selected == KReportRuler::Private::Selection::None) { 1300 // still haven't found something so let assume the user wants to add a tab 1301 qreal tabpos; 1302 if (d->rightToLeft) { 1303 tabpos = d->viewConverter->viewToDocumentX(pos.x() - d->offset) 1304 + d->effectiveActiveRangeEnd() + (d->relativeTabs ? d->paragraphIndent : 0); 1305 } else { 1306 tabpos = d->viewConverter->viewToDocumentX(pos.x() - d->offset) 1307 - d->effectiveActiveRangeStart() - (d->relativeTabs ? d->paragraphIndent : 0); 1308 } 1309 Tab t(tabpos, d->tabChooser ? d->tabChooser->type() : 1310 d->rightToLeft ? QTextOption::RightTab : 1311 QTextOption::LeftTab); 1312 d->tabs.append(t); 1313 d->selectOffset = 0; 1314 d->selected = KReportRuler::Private::Selection::Tab; 1315 d->currentIndex = d->tabs.count() - 1; 1316 d->originalIndex = -1; // new! 1317 update(); 1318 } 1319 if (d->orientation == Qt::Horizontal && (ev->modifiers() & Qt::ShiftModifier) && 1320 (d->selected == KReportRuler::Private::Selection::FirstLineIndent || 1321 d->selected == KReportRuler::Private::Selection::ParagraphIndent || 1322 d->selected == KReportRuler::Private::Selection::Tab || 1323 d->selected == KReportRuler::Private::Selection::EndIndent)) 1324 d->paintingStrategy = d->distancesPaintingStrategy; 1325 1326 if (d->selected != KReportRuler::Private::Selection::None) 1327 emit aboutToChange(); 1328 } 1329 1330 void KReportRuler::mouseReleaseEvent ( QMouseEvent* ev ) 1331 { 1332 ev->accept(); 1333 if (d->selected == KReportRuler::Private::Selection::Tab) { 1334 if (d->originalIndex >= 0 && !d->tabMoved) { 1335 int type = d->tabs[d->currentIndex].type; 1336 type++; 1337 if (type > 3) 1338 type = 0; 1339 d->tabs[d->currentIndex].type = static_cast<QTextOption::TabType> (type); 1340 update(); 1341 } 1342 d->emitTabChanged(); 1343 } 1344 else if( d->selected != KReportRuler::Private::Selection::None) 1345 emit indentsChanged(true); 1346 else 1347 ev->ignore(); 1348 1349 d->paintingStrategy = d->normalPaintingStrategy; 1350 d->selected = KReportRuler::Private::Selection::None; 1351 } 1352 1353 void KReportRuler::mouseMoveEvent ( QMouseEvent* ev ) 1354 { 1355 QPoint pos = ev->pos(); 1356 1357 qreal activeLength = d->effectiveActiveRangeEnd() - d->effectiveActiveRangeStart(); 1358 1359 switch (d->selected) { 1360 case KReportRuler::Private::Selection::FirstLineIndent: 1361 if (d->rightToLeft) 1362 d->firstLineIndent = d->effectiveActiveRangeEnd() - d->paragraphIndent - 1363 d->viewConverter->viewToDocumentX(pos.x() + d->selectOffset - d->offset); 1364 else 1365 d->firstLineIndent = d->viewConverter->viewToDocumentX(pos.x() + d->selectOffset 1366 - d->offset) - d->effectiveActiveRangeStart() - d->paragraphIndent; 1367 if( ! (ev->modifiers() & Qt::ShiftModifier)) { 1368 d->firstLineIndent = d->doSnapping(d->firstLineIndent); 1369 d->paintingStrategy = d->normalPaintingStrategy; 1370 } else { 1371 if (d->orientation == Qt::Horizontal) 1372 d->paintingStrategy = d->distancesPaintingStrategy; 1373 } 1374 1375 emit indentsChanged(false); 1376 break; 1377 case KReportRuler::Private::Selection::ParagraphIndent: 1378 if (d->rightToLeft) 1379 d->paragraphIndent = d->effectiveActiveRangeEnd() - 1380 d->viewConverter->viewToDocumentX(pos.x() + d->selectOffset - d->offset); 1381 else 1382 d->paragraphIndent = d->viewConverter->viewToDocumentX(pos.x() + d->selectOffset 1383 - d->offset) - d->effectiveActiveRangeStart(); 1384 if( ! (ev->modifiers() & Qt::ShiftModifier)) { 1385 d->paragraphIndent = d->doSnapping(d->paragraphIndent); 1386 d->paintingStrategy = d->normalPaintingStrategy; 1387 } else { 1388 if (d->orientation == Qt::Horizontal) 1389 d->paintingStrategy = d->distancesPaintingStrategy; 1390 } 1391 1392 if (d->paragraphIndent + d->endIndent > activeLength) 1393 d->paragraphIndent = activeLength - d->endIndent; 1394 emit indentsChanged(false); 1395 break; 1396 case KReportRuler::Private::Selection::EndIndent: 1397 if (d->rightToLeft) 1398 d->endIndent = d->viewConverter->viewToDocumentX(pos.x() 1399 + d->selectOffset - d->offset) - d->effectiveActiveRangeStart(); 1400 else 1401 d->endIndent = d->effectiveActiveRangeEnd() - d->viewConverter->viewToDocumentX(pos.x() 1402 + d->selectOffset - d->offset); 1403 if (!(ev->modifiers() & Qt::ShiftModifier)) { 1404 d->endIndent = d->doSnapping(d->endIndent); 1405 d->paintingStrategy = d->normalPaintingStrategy; 1406 } else { 1407 if (d->orientation == Qt::Horizontal) 1408 d->paintingStrategy = d->distancesPaintingStrategy; 1409 } 1410 1411 if (d->paragraphIndent + d->endIndent > activeLength) 1412 d->endIndent = activeLength - d->paragraphIndent; 1413 emit indentsChanged(false); 1414 break; 1415 case KReportRuler::Private::Selection::Tab: 1416 d->tabMoved = true; 1417 if (d->currentIndex < 0) { // tab is deleted. 1418 if (ev->pos().y() < height()) { // reinstante it. 1419 d->currentIndex = d->tabs.count(); 1420 d->tabs.append(d->deletedTab); 1421 } else { 1422 break; 1423 } 1424 } 1425 if (d->rightToLeft) 1426 d->tabs[d->currentIndex].position = d->effectiveActiveRangeEnd() - 1427 d->viewConverter->viewToDocumentX(pos.x() + d->selectOffset - d->offset); 1428 else 1429 d->tabs[d->currentIndex].position = d->viewConverter->viewToDocumentX(pos.x() + d->selectOffset 1430 - d->offset) - d->effectiveActiveRangeStart(); 1431 if (!(ev->modifiers() & Qt::ShiftModifier)) 1432 d->tabs[d->currentIndex].position = d->doSnapping(d->tabs[d->currentIndex].position); 1433 if (d->tabs[d->currentIndex].position < 0) 1434 d->tabs[d->currentIndex].position = 0; 1435 if (d->tabs[d->currentIndex].position > activeLength) 1436 d->tabs[d->currentIndex].position = activeLength; 1437 1438 if (ev->pos().y() > height() + OutsideRulerThreshold ) { // moved out of the ruler, delete it. 1439 d->deletedTab = d->tabs.takeAt(d->currentIndex); 1440 d->currentIndex = -1; 1441 // was that a temporary added tab? 1442 if ( d->originalIndex == -1 ) 1443 emit guideLineCreated(d->orientation, 1444 d->orientation == Qt::Horizontal 1445 ? d->viewConverter->viewToDocumentY(ev->pos().y()) 1446 : d->viewConverter->viewToDocumentX(ev->pos().x())); 1447 } 1448 1449 d->emitTabChanged(); 1450 break; 1451 case KReportRuler::Private::Selection::HotSpot: 1452 qreal newPos; 1453 if (d->orientation == Qt::Horizontal) 1454 newPos= d->viewConverter->viewToDocumentX(pos.x() - d->offset); 1455 else 1456 newPos= d->viewConverter->viewToDocumentY(pos.y() - d->offset); 1457 d->hotspots[d->currentIndex].position = newPos; 1458 emit hotSpotChanged(d->hotspots[d->currentIndex].id, newPos); 1459 break; 1460 case KReportRuler::Private::Selection::None: 1461 d->mouseCoordinate = (d->orientation == Qt::Horizontal ? pos.x() : pos.y()) - d->offset; 1462 int hotSpotIndex = d->hotSpotIndex(pos); 1463 if (hotSpotIndex >= 0) { 1464 setCursor(QCursor( d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor )); 1465 break; 1466 } 1467 unsetCursor(); 1468 1469 KReportRuler::Private::Selection selection = d->selectionAtPosition(pos); 1470 QString text; 1471 switch(selection) { 1472 case KReportRuler::Private::Selection::FirstLineIndent: text = tr("First line indent"); break; 1473 case KReportRuler::Private::Selection::ParagraphIndent: text = tr("Left indent"); break; 1474 case KReportRuler::Private::Selection::EndIndent: text = tr("Right indent"); break; 1475 case KReportRuler::Private::Selection::None: 1476 if (ev->buttons() & Qt::LeftButton) { 1477 if (d->orientation == Qt::Horizontal && ev->pos().y() > height() + OutsideRulerThreshold) 1478 emit guideLineCreated(d->orientation, d->viewConverter->viewToDocumentY(ev->pos().y())); 1479 else if (d->orientation == Qt::Vertical && ev->pos().x() > width() + OutsideRulerThreshold) 1480 emit guideLineCreated(d->orientation, d->viewConverter->viewToDocumentX(ev->pos().x())); 1481 } 1482 break; 1483 default: 1484 break; 1485 } 1486 setToolTip(text); 1487 } 1488 update(); 1489 } 1490 1491 void KReportRuler::clearHotSpots() 1492 { 1493 if (d->hotspots.isEmpty()) 1494 return; 1495 d->hotspots.clear(); 1496 update(); 1497 } 1498 1499 void KReportRuler::setHotSpot(qreal position, int id) 1500 { 1501 int hotspotCount = d->hotspots.count(); 1502 for (int i = 0; i < hotspotCount; ++i) { 1503 KReportRuler::Private::HotSpotData & hs = d->hotspots[i]; 1504 if (hs.id == id) { 1505 hs.position = position; 1506 update(); 1507 return; 1508 } 1509 } 1510 // not there yet, then insert it. 1511 KReportRuler::Private::HotSpotData hs; 1512 hs.position = position; 1513 hs.id = id; 1514 d->hotspots.append(hs); 1515 } 1516 1517 bool KReportRuler::removeHotSpot(int id) 1518 { 1519 QList<KReportRuler::Private::HotSpotData>::Iterator iter = d->hotspots.begin(); 1520 while(iter != d->hotspots.end()) { 1521 if (iter->id == id) { 1522 d->hotspots.erase(iter); 1523 update(); 1524 return true; 1525 } 1526 } 1527 return false; 1528 }