Warning, file /office/calligra/libs/widgets/KoRuler.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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