File indexing completed on 2024-05-12 16:35:45

0001 /* This file is part of the KDE project
0002    Copyright 2006 Robert Knight <robertknight@gmail.com>
0003    Copyright 2006 Inge Wallin <inge@lysator.liu.se>
0004    Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0005    Copyright 1999-2002,2004 Laurent Montel <montel@kde.org>
0006    Copyright 2002-2005 Ariya Hidayat <ariya@kde.org>
0007    Copyright 1999-2004 David Faure <faure@kde.org>
0008    Copyright 2004-2005 Meni Livne <livne@kde.org>
0009    Copyright 2001-2003 Philipp Mueller <philipp.mueller@gmx.de>
0010    Copyright 2002-2003 Norbert Andres <nandres@web.de>
0011    Copyright 2003 Hamish Rodda <rodda@kde.org>
0012    Copyright 2003 Joseph Wenninger <jowenn@kde.org>
0013    Copyright 2003 Lukas Tinkl <lukas@kde.org>
0014    Copyright 2000-2002 Werner Trobin <trobin@kde.org>
0015    Copyright 2002 Harri Porten <porten@kde.org>
0016    Copyright 2002 John Dailey <dailey@vt.edu>
0017    Copyright 2002 Daniel Naber <daniel.naber@t-online.de>
0018    Copyright 1999-2000 Torben Weis <weis@kde.org>
0019    Copyright 1999-2000 Stephan Kulow <coolo@kde.org>
0020    Copyright 2000 Bernd Wuebben <wuebben@kde.org>
0021    Copyright 2000 Wilco Greven <greven@kde.org>
0022    Copyright 2000 Simon Hausmann <hausmann@kde.org
0023    Copyright 1999 Michael Reiher <michael.reiher@gmx.de>
0024    Copyright 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at>
0025    Copyright 1999 Reginald Stadlbauer <reggie@kde.org>
0026 
0027    This library is free software; you can redistribute it and/or
0028    modify it under the terms of the GNU Library General Public
0029    License as published by the Free Software Foundation; either
0030    version 2 of the License, or (at your option) any later version.
0031 
0032    This library is distributed in the hope that it will be useful,
0033    but WITHOUT ANY WARRANTY; without even the implied warranty of
0034    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0035    Library General Public License for more details.
0036 
0037    You should have received a copy of the GNU Library General Public License
0038    along with this library; see the file COPYING.LIB.  If not, write to
0039    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0040    Boston, MA 02110-1301, USA.
0041 */
0042 
0043 // Local
0044 #include "Headers.h"
0045 
0046 // Qt
0047 #include <QApplication>
0048 #include <QLabel>
0049 #include <QPainter>
0050 #include <QTextLayout>
0051 #include <QToolTip>
0052 
0053 // KF5
0054 #include <KLocalizedString>
0055 #include <kmessagebox.h>
0056 
0057 // Calligra
0058 #include <KoCanvasController.h>
0059 #include <KoToolProxy.h>
0060 #include <KoZoomHandler.h>
0061 #include <KoPointerEvent.h>
0062 #include <KoGlobal.h>
0063 
0064 // Sheets
0065 #include "CanvasBase.h"
0066 #include "Cell.h"
0067 #include "Doc.h"
0068 #include "calligra_sheets_limits.h"
0069 #include "RowColumnFormat.h"
0070 #include "RowFormatStorage.h"
0071 #include "Sheet.h"
0072 #include "ElapsedTime_p.h"
0073 
0074 // commands
0075 #include "commands/RowColumnManipulators.h"
0076 
0077 // ui
0078 #include "ui/Selection.h"
0079 
0080 using namespace Calligra::Sheets;
0081 
0082 /****************************************************************
0083  *
0084  * RowHeader
0085  *
0086  ****************************************************************/
0087 
0088 RowHeader::RowHeader(CanvasBase *_canvas)
0089         : m_pCanvas(_canvas), m_bSelection(false),
0090         m_iSelectionAnchor(1), m_bResize(false), m_lSize(0), m_bMousePressed(false),
0091         m_cellToolIsActive(true), m_font(KoGlobal::defaultFont())
0092 {
0093 }
0094 
0095 
0096 RowHeader::~RowHeader()
0097 {
0098 }
0099 
0100 void RowHeader::mousePress(KoPointerEvent * _ev)
0101 {
0102     if (!m_cellToolIsActive)
0103         return;
0104 
0105     register Sheet * const sheet = m_pCanvas->activeSheet();
0106     if (!sheet)
0107         return;
0108 
0109     if (_ev->button() == Qt::LeftButton) {
0110         m_bMousePressed = true;
0111         m_pCanvas->enableAutoScroll();
0112     }
0113 
0114     double ev_PosY = m_pCanvas->zoomHandler()->unzoomItY(_ev->pos().y()) + m_pCanvas->yOffset();
0115     double dHeight = m_pCanvas->zoomHandler()->unzoomItY(height());
0116     m_bResize = false;
0117     m_bSelection = false;
0118 
0119     // We were editing a cell -> save value and get out of editing mode
0120     m_pCanvas->selection()->emitCloseEditor(true); // save changes
0121 
0122     // Find the first visible row and the y position of this row.
0123     qreal y;
0124     int row = sheet->topRow(m_pCanvas->yOffset(), y);
0125 
0126     // Did the user click between two rows?
0127     while (y < (dHeight + m_pCanvas->yOffset()) && (!m_bResize) && row <= KS_rowMax) {
0128         double h = sheet->rowFormats()->rowHeight(row);
0129         row++;
0130         if (row > KS_rowMax)
0131             row = KS_rowMax;
0132         if ((ev_PosY >= y + h - 2) &&
0133                 (ev_PosY <= y + h + 1) &&
0134                 !(sheet->rowFormats()->isHiddenOrFiltered(row) && row == 1))
0135             m_bResize = true;
0136         y += h;
0137     }
0138 
0139     //if row is hide and it's the first row
0140     //you mustn't resize it.
0141     qreal tmp2;
0142     int tmpRow = sheet->topRow(ev_PosY - 1, tmp2);
0143     if (sheet->rowFormats()->isHiddenOrFiltered(tmpRow) && tmpRow == 1)
0144         m_bResize = false;
0145 
0146     // So the user clicked between two rows ?
0147     if (m_bResize) {
0148         // Determine row to resize
0149         qreal tmp;
0150         m_iResizedRow = sheet->topRow(ev_PosY - 1, tmp);
0151         if (!sheet->isProtected())
0152             paintSizeIndicator(_ev->pos().y());
0153     } else {
0154         if (_ev->button() != Qt::RightButton) {
0155             m_bSelection = true;
0156         }
0157 
0158         qreal tmp;
0159         int hit_row = sheet->topRow(ev_PosY, tmp);
0160         if (hit_row > KS_rowMax)
0161             return;
0162 
0163         m_iSelectionAnchor = hit_row;
0164 
0165         if (!m_pCanvas->selection()->contains(QPoint(1, hit_row)) ||
0166                 !(_ev->button() == Qt::RightButton) ||
0167                 !m_pCanvas->selection()->isRowSelected()) {
0168             QPoint newMarker(1, hit_row);
0169             QPoint newAnchor(KS_colMax, hit_row);
0170             if (_ev->modifiers() == Qt::ControlModifier) {
0171                 m_pCanvas->selection()->extend(QRect(newAnchor, newMarker));
0172             } else if (_ev->modifiers() == Qt::ShiftModifier) {
0173                 m_pCanvas->selection()->update(newMarker);
0174             } else {
0175                 m_pCanvas->selection()->initialize(QRect(newAnchor, newMarker));
0176             }
0177         }
0178 
0179         if (_ev->button() == Qt::RightButton) {
0180             m_pCanvas->mousePressed(_ev);
0181         }
0182     }
0183 }
0184 
0185 void RowHeader::mouseRelease(KoPointerEvent * _ev)
0186 {
0187     if (!m_cellToolIsActive)
0188         return;
0189     m_pCanvas->disableAutoScroll();
0190     if (m_lSize)
0191         m_lSize->hide();
0192 
0193     m_bMousePressed = false;
0194 
0195     register Sheet * const sheet = m_pCanvas->activeSheet();
0196     if (!sheet)
0197         return;
0198 
0199     double ev_PosY = m_pCanvas->zoomHandler()->unzoomItY(_ev->pos().y()) + m_pCanvas->yOffset();
0200 
0201     if (m_bResize) {
0202         // Remove size indicator painted by paintSizeIndicator
0203         removeSizeIndicator();
0204 
0205         QRect rect;
0206         rect.setCoords(1, m_iResizedRow, KS_colMax, m_iResizedRow);
0207         if (m_pCanvas->selection()->isRowSelected()) {
0208             if (m_pCanvas->selection()->contains(QPoint(1, m_iResizedRow))) {
0209                 rect = m_pCanvas->selection()->lastRange();
0210             }
0211         }
0212 
0213         double height = 0.0;
0214         double y = sheet->rowPosition(m_iResizedRow);
0215         if (ev_PosY - y <= 0.0)
0216             height = 0.0;
0217         else
0218             height = ev_PosY - y;
0219 
0220         if (height != 0.0) {
0221             ResizeRowManipulator* command = new ResizeRowManipulator();
0222             command->setSheet(sheet);
0223             command->setSize(height);
0224             command->add(Region(rect, sheet));
0225             if (!command->execute())
0226                 delete command;
0227         } else { // hide
0228             HideShowManipulator* command = new HideShowManipulator();
0229             command->setSheet(sheet);
0230             command->setManipulateRows(true);
0231             command->add(Region(rect, sheet));
0232             if (!command->execute())
0233                 delete command;
0234         }
0235         delete m_lSize;
0236         m_lSize = 0;
0237     } else if (m_bSelection) {
0238         QRect rect = m_pCanvas->selection()->lastRange();
0239 
0240         // TODO: please don't remove. Right now it's useless, but it's for a future feature
0241         // Norbert
0242         bool m_frozen = false;
0243         if (m_frozen) {
0244             debugSheets << "selected: T" << rect.top() << " B" << rect.bottom();
0245 
0246             int i;
0247             QList<int> hiddenRows;
0248 
0249             for (i = rect.top(); i <= rect.bottom(); ++i) {
0250                 if (sheet->rowFormats()->isHidden(i)) {
0251                     hiddenRows.append(i);
0252                 }
0253             }
0254 
0255             if (hiddenRows.count() > 0) {
0256                 if (m_pCanvas->selection()->isColumnSelected()) {
0257                     KMessageBox::error(/* XXX TODO this*/0, i18n("Area is too large."));
0258                     return;
0259                 }
0260 
0261                 HideShowManipulator* command = new HideShowManipulator();
0262                 command->setSheet(sheet);
0263                 command->setManipulateRows(true);
0264                 command->setReverse(true);
0265                 command->add(*m_pCanvas->selection());
0266                 command->execute();
0267             }
0268         }
0269     }
0270 
0271     m_bSelection = false;
0272     m_bResize = false;
0273 }
0274 
0275 void RowHeader::equalizeRow(double resize)
0276 {
0277     if (resize != 0.0) {
0278         ResizeRowManipulator* command = new ResizeRowManipulator();
0279         command->setSheet(m_pCanvas->activeSheet());
0280         command->setSize(qMax(2.0, resize));
0281         command->add(*m_pCanvas->selection());
0282         if (!command->execute())
0283             delete command;
0284     } else { // hide
0285         HideShowManipulator* command = new HideShowManipulator();
0286         command->setSheet(m_pCanvas->activeSheet());
0287         command->setManipulateRows(true);
0288         command->add(*m_pCanvas->selection());
0289         if (!command->execute())
0290             delete command;
0291     }
0292 }
0293 
0294 void RowHeader::mouseDoubleClick(KoPointerEvent*)
0295 {
0296     if (!m_cellToolIsActive)
0297         return;
0298     register Sheet * const sheet = m_pCanvas->activeSheet();
0299     if (!sheet)
0300         return;
0301 
0302     if (sheet->isProtected())
0303         return;
0304 
0305     AdjustColumnRowManipulator* command = new AdjustColumnRowManipulator();
0306     command->setSheet(sheet);
0307     command->setAdjustRow(true);
0308     command->add(*m_pCanvas->selection());
0309     command->execute();
0310 }
0311 
0312 
0313 void RowHeader::mouseMove(KoPointerEvent* _ev)
0314 {
0315     if (!m_cellToolIsActive) {
0316         setCursor(Qt::ArrowCursor);
0317         return;
0318     }
0319 
0320     register Sheet * const sheet = m_pCanvas->activeSheet();
0321     if (!sheet)
0322         return;
0323 
0324     qreal ev_PosY = m_pCanvas->zoomHandler()->unzoomItY(_ev->pos().y()) + m_pCanvas->yOffset();
0325     qreal dHeight = m_pCanvas->zoomHandler()->unzoomItY(height());
0326 
0327     // The button is pressed and we are resizing ?
0328     if (m_bResize) {
0329         if (!sheet->isProtected())
0330             paintSizeIndicator(_ev->pos().y());
0331     }
0332     // The button is pressed and we are selecting ?
0333     else if (m_bSelection) {
0334         qreal y;
0335         int row = sheet->topRow(ev_PosY, y);
0336         if (row > KS_rowMax || row <= 0)
0337             return;
0338 
0339         QPoint newAnchor = m_pCanvas->selection()->anchor();
0340         QPoint newMarker = m_pCanvas->selection()->marker();
0341         newMarker.setY(row);
0342         newAnchor.setY(m_iSelectionAnchor);
0343         m_pCanvas->selection()->update(newMarker);
0344 
0345         if (_ev->pos().y() < 0)
0346             m_pCanvas->setVertScrollBarPos(qMax<qreal>(0, ev_PosY));
0347         else if (_ev->pos().y() > m_pCanvas->height()) {
0348             if (row < KS_rowMax) {
0349                 const qreal rowHeight = sheet->rowFormats()->rowHeight(row + 1);
0350                 y = sheet->rowPosition(row + 1);
0351                 m_pCanvas->setVertScrollBarPos(ev_PosY + rowHeight - dHeight);
0352             }
0353         }
0354     }
0355     // No button is pressed and the mouse is just moved
0356     else {
0357 
0358         //What is the internal size of 1 pixel
0359         const double unzoomedPixel = m_pCanvas->zoomHandler()->unzoomItY(1.0);
0360         qreal y;
0361         int tmpRow = sheet->topRow(m_pCanvas->yOffset(), y);
0362 
0363         while (y < dHeight + m_pCanvas->yOffset() && tmpRow <= KS_rowMax) {
0364             double h = sheet->rowFormats()->visibleHeight(tmpRow);
0365             //if col is hide and it's the first column
0366             //you mustn't resize it.
0367             if (ev_PosY >= y + h - 2 * unzoomedPixel &&
0368                     ev_PosY <= y + h + unzoomedPixel &&
0369                     !(sheet->rowFormats()->isHiddenOrFiltered(tmpRow) && tmpRow == 1)) {
0370                 setCursor(Qt::SplitVCursor);
0371                 return;
0372             }
0373             y += h;
0374             tmpRow++;
0375         }
0376         setCursor(Qt::ArrowCursor);
0377     }
0378 }
0379 
0380 void RowHeader::paint(QPainter* painter, const QRectF& painterRect)
0381 {
0382     register Sheet * const sheet = m_pCanvas->activeSheet();
0383     if (!sheet)
0384         return;
0385 
0386 //     ElapsedTime et( "Painting vertical header", ElapsedTime::PrintOnlyTime );
0387 
0388     // FIXME Stefan: Make use of clipping. Find the repaint call after the scrolling.
0389     // debugSheetsRender << event->rect();
0390 
0391     // painting rectangle
0392     const QRectF paintRect = m_pCanvas->zoomHandler()->viewToDocument(painterRect);
0393 
0394     // the painter
0395     painter->setRenderHint(QPainter::TextAntialiasing);
0396 
0397     // fonts
0398     QFont normalFont(m_font);
0399     QFont boldFont(normalFont);
0400     boldFont.setBold(true);
0401 
0402     // background brush/color
0403     const QBrush backgroundBrush(palette().window());
0404     const QColor backgroundColor(backgroundBrush.color());
0405 
0406     // selection brush/color
0407     QColor selectionColor(palette().highlight().color());
0408     selectionColor.setAlpha(127);
0409     const QBrush selectionBrush(selectionColor);
0410 
0411     qreal yPos;
0412     // Get the top row and the current y-position
0413     int y = sheet->topRow(qMax<qreal>(0, paintRect.y() + m_pCanvas->yOffset()), yPos);
0414     // Align to the offset
0415     yPos = yPos - m_pCanvas->yOffset();
0416 
0417     const KoViewConverter *converter = m_pCanvas->zoomHandler();
0418     const qreal width = this->width() - 1;
0419 
0420     QSet<int> selectedRows;
0421     QSet<int> affectedRows;
0422     if (!m_pCanvas->selection()->referenceSelectionMode() && m_cellToolIsActive) {
0423         selectedRows = m_pCanvas->selection()->rowsSelected();
0424         affectedRows = m_pCanvas->selection()->rowsAffected();
0425     }
0426     // Loop through the rows, until we are out of range
0427     while (yPos <= paintRect.bottom() && y <= KS_rowMax) {
0428         const bool selected = (selectedRows.contains(y));
0429         const bool highlighted = (!selected && affectedRows.contains(y));
0430 
0431         if (sheet->rowFormats()->isHiddenOrFiltered(y)) {
0432             ++y;
0433             continue;
0434         }
0435         const qreal rawHeight = sheet->rowFormats()->rowHeight(y);
0436         const qreal height = converter->documentToViewY(rawHeight);
0437         const QRectF rect(0, converter->documentToViewY(yPos), width, height);
0438 
0439         if (selected || highlighted) {
0440             painter->setPen(QPen(selectionColor.dark(150), 0));
0441             painter->setBrush(selectionBrush);
0442         } else {
0443             painter->setPen(QPen(backgroundColor.dark(150), 0));
0444             painter->setBrush(backgroundBrush);
0445         }
0446         painter->drawRect(rect);
0447 
0448         const QString rowText = QString::number(y);
0449 
0450         // Reset painter
0451         painter->setFont(normalFont);
0452         painter->setPen(palette().text().color());
0453 
0454         if (selected)
0455             painter->setPen(palette().highlightedText().color());
0456         else if (highlighted)
0457             painter->setFont(boldFont);
0458 
0459         QFontMetricsF fm(painter->font());
0460 #if 0
0461         if (height < fm.ascent() - fm.descent()) {
0462             // try to scale down the font to make it fit
0463             QFont font = painter->font();
0464             qreal maxSize = font.pointSizeF();
0465             qreal minSize = maxSize / 2;
0466             while (minSize > 1) {
0467                 font.setPointSizeF(minSize);
0468                 const QFontMetricsF fm2(font);
0469                 if (height >= fm2.ascent() - fm2.descent())
0470                     break;
0471                 minSize /= 2;
0472             }
0473             while (minSize < 0.99 * maxSize) {
0474                 qreal middle = (maxSize + minSize) / 2;
0475                 font.setPointSizeF(middle);
0476                 const QFontMetricsF fm2(font);
0477                 if (height >= fm2.ascent() - fm2.descent()) {
0478                     minSize = middle;
0479                 } else {
0480                     maxSize = middle;
0481                 }
0482             }
0483             painter->setFont(font);
0484             fm = QFontMetricsF(font);
0485         }
0486 #endif
0487         if (height >= fm.ascent() - fm.descent()) {
0488             painter->drawText(rect, Qt::AlignCenter, rowText);
0489         }
0490 
0491         yPos += rawHeight;
0492         y++;
0493     }
0494 }
0495 
0496 
0497 void RowHeader::focusOut(QFocusEvent*)
0498 {
0499     m_pCanvas->disableAutoScroll();
0500     m_bMousePressed = false;
0501 }
0502 
0503 void RowHeader::doToolChanged(const QString& toolId)
0504 {
0505     m_cellToolIsActive = toolId.startsWith(QLatin1String("KSpread"));
0506     update();
0507 }
0508 
0509 void RowHeader::setHeaderFont(const QFont &font)
0510 {
0511     m_font = font;
0512     update();
0513 }
0514 
0515 QFont RowHeader::headerFont() const
0516 {
0517     return m_font;
0518 }
0519 
0520 /****************************************************************
0521  *
0522  * ColumnHeader
0523  *
0524  ****************************************************************/
0525 
0526 ColumnHeader::ColumnHeader(CanvasBase *_canvas)
0527     : m_pCanvas(_canvas), m_bSelection(false),
0528     m_iSelectionAnchor(1), m_bResize(false), m_lSize(0), m_bMousePressed(false),
0529     m_cellToolIsActive(true), m_font(KoGlobal::defaultFont())
0530 {
0531 }
0532 
0533 
0534 ColumnHeader::~ColumnHeader()
0535 {
0536 }
0537 
0538 void ColumnHeader::mousePress(KoPointerEvent * _ev)
0539 {
0540     if (!m_cellToolIsActive)
0541         return;
0542 
0543     if (_ev->button() == Qt::LeftButton) {
0544         m_bMousePressed = true;
0545         m_pCanvas->enableAutoScroll();
0546     }
0547 
0548     const register Sheet * const sheet = m_pCanvas->activeSheet();
0549     if (!sheet)
0550         return;
0551 
0552     // We were editing a cell -> save value and get out of editing mode
0553     m_pCanvas->selection()->emitCloseEditor(true); // save changes
0554 
0555     double ev_PosX;
0556     double dWidth = m_pCanvas->zoomHandler()->unzoomItX(width());
0557     if (sheet->layoutDirection() == Qt::RightToLeft)
0558         ev_PosX = dWidth - m_pCanvas->zoomHandler()->unzoomItX(_ev->pos().x()) + m_pCanvas->xOffset();
0559     else
0560         ev_PosX = m_pCanvas->zoomHandler()->unzoomItX(_ev->pos().x()) + m_pCanvas->xOffset();
0561     m_bResize = false;
0562     m_bSelection = false;
0563 
0564     // Find the first visible column and the x position of this column.
0565     qreal x;
0566 
0567     const double unzoomedPixel = m_pCanvas->zoomHandler()->unzoomItX(1.0);
0568     if (sheet->layoutDirection() == Qt::RightToLeft) {
0569         int tmpCol = sheet->leftColumn(m_pCanvas->xOffset(), x);
0570 
0571         debugSheets << "evPos:" << ev_PosX << ", x:" << x << ", COL:" << tmpCol;
0572         while (ev_PosX > x && (!m_bResize) && tmpCol <= KS_colMax) {
0573             double w = sheet->columnFormat(tmpCol)->width();
0574 
0575             debugSheets << "evPos:" << ev_PosX << ", x:" << x << ", w:" << w << ", COL:" << tmpCol;
0576 
0577             ++tmpCol;
0578             if (tmpCol > KS_colMax)
0579                 tmpCol = KS_colMax;
0580             //if col is hide and it's the first column
0581             //you mustn't resize it.
0582 
0583             if (ev_PosX >= x + w - unzoomedPixel &&
0584                     ev_PosX <= x + w + unzoomedPixel &&
0585                     !(sheet->columnFormat(tmpCol)->isHiddenOrFiltered() && tmpCol == 1)) {
0586                 m_bResize = true;
0587             }
0588             x += w;
0589         }
0590 
0591         //if col is hide and it's the first column
0592         //you mustn't resize it.
0593         qreal tmp2;
0594         tmpCol = sheet->leftColumn(dWidth - ev_PosX + 1, tmp2);
0595         if (sheet->columnFormat(tmpCol)->isHiddenOrFiltered() && tmpCol == 0) {
0596             debugSheets << "No resize:" << tmpCol << "," << sheet->columnFormat(tmpCol)->isHiddenOrFiltered();
0597             m_bResize = false;
0598         }
0599 
0600         debugSheets << "Resize:" << m_bResize;
0601     } else {
0602         int col = sheet->leftColumn(m_pCanvas->xOffset(), x);
0603 
0604         // Did the user click between two columns?
0605         while (x < (dWidth + m_pCanvas->xOffset()) && (!m_bResize) && col <= KS_colMax) {
0606             double w = sheet->columnFormat(col)->width();
0607             col++;
0608             if (col > KS_colMax)
0609                 col = KS_colMax;
0610             if ((ev_PosX >= x + w - unzoomedPixel) &&
0611                     (ev_PosX <= x + w + unzoomedPixel) &&
0612                     !(sheet->columnFormat(col)->isHiddenOrFiltered() && col == 1))
0613                 m_bResize = true;
0614             x += w;
0615         }
0616 
0617         //if col is hide and it's the first column
0618         //you mustn't resize it.
0619         qreal tmp2;
0620         int tmpCol = sheet->leftColumn(ev_PosX - 1, tmp2);
0621         if (sheet->columnFormat(tmpCol)->isHiddenOrFiltered() && tmpCol == 1)
0622             m_bResize = false;
0623     }
0624 
0625     // So the user clicked between two rows ?
0626     if (m_bResize) {
0627         // Determine the column to resize
0628         qreal tmp;
0629         if (sheet->layoutDirection() == Qt::RightToLeft) {
0630             m_iResizedColumn = sheet->leftColumn(ev_PosX - 1, tmp);
0631             // debugSheets <<"RColumn:" << m_iResizedColumn <<", PosX:" << ev_PosX;
0632 
0633             if (!sheet->isProtected())
0634                 paintSizeIndicator(_ev->pos().x());
0635         } else {
0636             m_iResizedColumn = sheet->leftColumn(ev_PosX - 1, tmp);
0637 
0638             if (!sheet->isProtected())
0639                 paintSizeIndicator(_ev->pos().x());
0640         }
0641 
0642         // debugSheets <<"Column:" << m_iResizedColumn;
0643     } else {
0644         if (_ev->button() != Qt::RightButton) {
0645             m_bSelection = true;
0646         }
0647 
0648         qreal tmp;
0649         int hit_col = sheet->leftColumn(ev_PosX, tmp);
0650         if (hit_col > KS_colMax)
0651             return;
0652 
0653         m_iSelectionAnchor = hit_col;
0654 
0655         if (!m_pCanvas->selection()->contains(QPoint(hit_col, 1)) ||
0656                 !(_ev->button() == Qt::RightButton) ||
0657                 !m_pCanvas->selection()->isColumnSelected()) {
0658             QPoint newMarker(hit_col, 1);
0659             QPoint newAnchor(hit_col, KS_rowMax);
0660             if (_ev->modifiers() == Qt::ControlModifier) {
0661                 m_pCanvas->selection()->extend(QRect(newAnchor, newMarker));
0662             } else if (_ev->modifiers() == Qt::ShiftModifier) {
0663                 m_pCanvas->selection()->update(newMarker);
0664             } else {
0665                 m_pCanvas->selection()->initialize(QRect(newAnchor, newMarker));
0666             }
0667         }
0668 
0669         if (_ev->button() == Qt::RightButton) {
0670             m_pCanvas->mousePressed(_ev);
0671         }
0672     }
0673 }
0674 
0675 void ColumnHeader::mouseRelease(KoPointerEvent * _ev)
0676 {
0677     if (!m_cellToolIsActive)
0678         return;
0679     m_pCanvas->disableAutoScroll();
0680     if (m_lSize)
0681         m_lSize->hide();
0682 
0683     m_bMousePressed = false;
0684 
0685     register Sheet * const sheet = m_pCanvas->activeSheet();
0686     if (!sheet)
0687         return;
0688 
0689     if (m_bResize) {
0690         double dWidth = m_pCanvas->zoomHandler()->unzoomItX(width());
0691         double ev_PosX;
0692 
0693         // Remove size indicator painted by paintSizeIndicator
0694         removeSizeIndicator();
0695 
0696         QRect rect;
0697         rect.setCoords(m_iResizedColumn, 1, m_iResizedColumn, KS_rowMax);
0698         if (m_pCanvas->selection()->isColumnSelected()) {
0699             if (m_pCanvas->selection()->contains(QPoint(m_iResizedColumn, 1))) {
0700                 rect  = m_pCanvas->selection()->lastRange();
0701             }
0702         }
0703 
0704         double width = 0.0;
0705         double x;
0706 
0707         if (sheet->layoutDirection() == Qt::RightToLeft)
0708             ev_PosX = dWidth - m_pCanvas->zoomHandler()->unzoomItX(_ev->pos().x()) + m_pCanvas->xOffset();
0709         else
0710             ev_PosX = m_pCanvas->zoomHandler()->unzoomItX(_ev->pos().x()) + m_pCanvas->xOffset();
0711 
0712         x = sheet->columnPosition(m_iResizedColumn);
0713 
0714         if (ev_PosX - x <= 0.0)
0715             width = 0.0;
0716         else
0717             width = ev_PosX - x;
0718 
0719         if (width != 0.0) {
0720             ResizeColumnManipulator* command = new ResizeColumnManipulator();
0721             command->setSheet(sheet);
0722             command->setSize(width);
0723             command->add(Region(rect, sheet));
0724             if (!command->execute())
0725                 delete command;
0726         } else { // hide
0727             HideShowManipulator* command = new HideShowManipulator();
0728             command->setSheet(sheet);
0729             command->setManipulateColumns(true);
0730             command->add(Region(rect, sheet));
0731             if (!command->execute())
0732                 delete command;
0733         }
0734         delete m_lSize;
0735         m_lSize = 0;
0736     } else if (m_bSelection) {
0737         QRect rect = m_pCanvas->selection()->lastRange();
0738 
0739         // TODO: please don't remove. Right now it's useless, but it's for a future feature
0740         // Norbert
0741         bool m_frozen = false;
0742         if (m_frozen) {
0743             debugSheets << "selected: L" << rect.left() << " R" << rect.right();
0744 
0745             int i;
0746             QList<int> hiddenCols;
0747 
0748             for (i = rect.left(); i <= rect.right(); ++i) {
0749                 if (sheet->columnFormat(i)->isHidden()) {
0750                     hiddenCols.append(i);
0751                 }
0752             }
0753 
0754             if (hiddenCols.count() > 0) {
0755                 if (m_pCanvas->selection()->isRowSelected()) {
0756                     KMessageBox::error(0 /* XXX TODO this */, i18n("Area is too large."));
0757                     return;
0758                 }
0759 
0760                 HideShowManipulator* command = new HideShowManipulator();
0761                 command->setSheet(sheet);
0762                 command->setManipulateColumns(true);
0763                 command->setReverse(true);
0764                 command->add(*m_pCanvas->selection());
0765                 command->execute();
0766             }
0767         }
0768     }
0769 
0770     m_bSelection = false;
0771     m_bResize = false;
0772 }
0773 
0774 void ColumnHeader::equalizeColumn(double resize)
0775 {
0776     if (resize != 0.0) {
0777         ResizeColumnManipulator* command = new ResizeColumnManipulator();
0778         command->setSheet(m_pCanvas->activeSheet());
0779         command->setSize(qMax(2.0, resize));
0780         command->add(*m_pCanvas->selection());
0781         if (!command->execute())
0782             delete command;
0783     } else { // hide
0784         HideShowManipulator* command = new HideShowManipulator();
0785         command->setSheet(m_pCanvas->activeSheet());
0786         command->setManipulateColumns(true);
0787         command->add(*m_pCanvas->selection());
0788         if (!command->execute())
0789             delete command;
0790     }
0791 }
0792 
0793 void ColumnHeader::mouseDoubleClick(KoPointerEvent*)
0794 {
0795     if (!m_cellToolIsActive)
0796         return;
0797     register Sheet * const sheet = m_pCanvas->activeSheet();
0798     if (!sheet)
0799         return;
0800 
0801     if (sheet->isProtected())
0802         return;
0803 
0804     AdjustColumnRowManipulator* command = new AdjustColumnRowManipulator();
0805     command->setSheet(sheet);
0806     command->setAdjustColumn(true);
0807     command->add(*m_pCanvas->selection());
0808     command->execute();
0809 }
0810 
0811 void ColumnHeader::mouseMove(KoPointerEvent* _ev)
0812 {
0813     if (!m_cellToolIsActive)
0814         return;
0815 
0816     register Sheet * const sheet = m_pCanvas->activeSheet();
0817 
0818     if (!sheet)
0819         return;
0820 
0821     double dWidth = m_pCanvas->zoomHandler()->unzoomItX(width());
0822     double ev_PosX;
0823     if (sheet->layoutDirection() == Qt::RightToLeft)
0824         ev_PosX = dWidth - m_pCanvas->zoomHandler()->unzoomItX(_ev->pos().x()) + m_pCanvas->xOffset();
0825     else
0826         ev_PosX = m_pCanvas->zoomHandler()->unzoomItX(_ev->pos().x()) + m_pCanvas->xOffset();
0827 
0828     // The button is pressed and we are resizing ?
0829     if (m_bResize) {
0830         if (!sheet->isProtected())
0831             paintSizeIndicator(_ev->pos().x());
0832     }
0833     // The button is pressed and we are selecting ?
0834     else if (m_bSelection) {
0835         qreal x;
0836         int col = sheet->leftColumn(ev_PosX, x);
0837 
0838         if (col > KS_colMax || col <= 0)
0839             return;
0840 
0841         QPoint newMarker = m_pCanvas->selection()->marker();
0842         QPoint newAnchor = m_pCanvas->selection()->anchor();
0843         newMarker.setX(col);
0844         newAnchor.setX(m_iSelectionAnchor);
0845         m_pCanvas->selection()->update(newMarker);
0846 
0847         if (sheet->layoutDirection() == Qt::RightToLeft) {
0848             if (_ev->pos().x() < width() - m_pCanvas->width()) {
0849                 const ColumnFormat *cl = sheet->columnFormat(col + 1);
0850                 x = sheet->columnPosition(col + 1);
0851                 m_pCanvas->setHorizScrollBarPos(- (int)((ev_PosX + cl->width()) - dWidth));
0852             } else if (_ev->pos().x() > width())
0853                 m_pCanvas->setHorizScrollBarPos(- (ev_PosX - dWidth + m_pCanvas->zoomHandler()->unzoomItX(m_pCanvas->width())));
0854         } else {
0855             if (_ev->pos().x() < 0)
0856                 m_pCanvas->setHorizScrollBarPos(ev_PosX);
0857             else if (_ev->pos().x() > m_pCanvas->width()) {
0858                 if (col < KS_colMax) {
0859                     const ColumnFormat *cl = sheet->columnFormat(col + 1);
0860                     x = sheet->columnPosition(col + 1);
0861                     m_pCanvas->setHorizScrollBarPos(ev_PosX + cl->width() - dWidth);
0862                 }
0863             }
0864         }
0865 
0866     }
0867     // No button is pressed and the mouse is just moved
0868     else {
0869         //What is the internal size of 1 pixel
0870         const double unzoomedPixel = m_pCanvas->zoomHandler()->unzoomItX(1.0);
0871         qreal x;
0872 
0873         if (sheet->layoutDirection() == Qt::RightToLeft) {
0874             int tmpCol = sheet->leftColumn(m_pCanvas->xOffset(), x);
0875 
0876             while (ev_PosX > x && tmpCol <= KS_colMax) {
0877                 double w = sheet->columnFormat(tmpCol)->visibleWidth();
0878                 ++tmpCol;
0879 
0880                 //if col is hide and it's the first column
0881                 //you mustn't resize it.
0882                 if (ev_PosX >= x + w - unzoomedPixel &&
0883                         ev_PosX <= x + w + unzoomedPixel &&
0884                         !(sheet->columnFormat(tmpCol)->isHiddenOrFiltered() && tmpCol == 0)) {
0885                     setCursor(Qt::SplitHCursor);
0886                     return;
0887                 }
0888                 x += w;
0889             }
0890             setCursor(Qt::ArrowCursor);
0891         } else {
0892             int tmpCol = sheet->leftColumn(m_pCanvas->xOffset(), x);
0893 
0894             while (x < m_pCanvas->zoomHandler()->unzoomItY(width()) + m_pCanvas->xOffset() && tmpCol <= KS_colMax) {
0895                 double w = sheet->columnFormat(tmpCol)->visibleWidth();
0896                 //if col is hide and it's the first column
0897                 //you mustn't resize it.
0898                 if (ev_PosX >= x + w - unzoomedPixel &&
0899                         ev_PosX <= x + w + unzoomedPixel &&
0900                         !(sheet->columnFormat(tmpCol)->isHiddenOrFiltered() && tmpCol == 1)) {
0901                     setCursor(Qt::SplitHCursor);
0902                     return;
0903                 }
0904                 x += w;
0905                 tmpCol++;
0906             }
0907             setCursor(Qt::ArrowCursor);
0908         }
0909     }
0910 }
0911 
0912 void ColumnHeader::resize(const QSizeF& size, const QSizeF& oldSize)
0913 {
0914     register Sheet * const sheet = m_pCanvas->activeSheet();
0915     if (!sheet)
0916         return;
0917 
0918     // workaround to allow horizontal resizing and zoom changing when sheet
0919     // direction and interface direction don't match (e.g. an RTL sheet on an
0920     // LTR interface)
0921     if (sheet->layoutDirection() == Qt::RightToLeft && !QApplication::isRightToLeft()) {
0922         int dx = size.width() - oldSize.width();
0923         scroll(dx, 0);
0924     } else if (sheet->layoutDirection() == Qt::LeftToRight && QApplication::isRightToLeft()) {
0925         int dx = size.width() - oldSize.width();
0926         scroll(-dx, 0);
0927     }
0928 }
0929 
0930 void ColumnHeader::paint(QPainter* painter, const QRectF& painterRect)
0931 {
0932     register Sheet * const sheet = m_pCanvas->activeSheet();
0933     if (!sheet)
0934         return;
0935 
0936 //     ElapsedTime et( "Painting horizontal header", ElapsedTime::PrintOnlyTime );
0937 
0938     // FIXME Stefan: Make use of clipping. Find the repaint call after the scrolling.
0939     // debugSheetsRender << event->rect();
0940 
0941     // painting rectangle
0942     const QRectF paintRect = m_pCanvas->zoomHandler()->viewToDocument(painterRect);
0943 
0944     // the painter
0945     painter->setRenderHint(QPainter::TextAntialiasing);
0946 
0947     // fonts
0948     QFont normalFont(m_font);
0949     QFont boldFont(normalFont);
0950     boldFont.setBold(true);
0951 
0952     // background brush/color
0953     const QBrush backgroundBrush(palette().window());
0954     const QColor backgroundColor(backgroundBrush.color());
0955 
0956     // selection brush/color
0957     QColor selectionColor(palette().highlight().color());
0958     selectionColor.setAlpha(127);
0959     const QBrush selectionBrush(selectionColor);
0960 
0961     qreal xPos;
0962     int x;
0963 
0964     if (sheet->layoutDirection() == Qt::RightToLeft) {
0965         //Get the left column and the current x-position
0966         x = sheet->leftColumn(int(m_pCanvas->zoomHandler()->unzoomItX(width()) - paintRect.x() + m_pCanvas->xOffset()), xPos);
0967         //Align to the offset
0968         xPos = m_pCanvas->zoomHandler()->unzoomItX(width()) - xPos + m_pCanvas->xOffset();
0969     } else {
0970         //Get the left column and the current x-position
0971         x = sheet->leftColumn(int(paintRect.x() + m_pCanvas->xOffset()), xPos);
0972         //Align to the offset
0973         xPos = xPos - m_pCanvas->xOffset();
0974     }
0975 
0976     const KoViewConverter *converter = m_pCanvas->zoomHandler();
0977     const qreal height = this->height() - 1;
0978 
0979     QSet<int> selectedColumns;
0980     QSet<int> affectedColumns;
0981     if (!m_pCanvas->selection()->referenceSelectionMode() && m_cellToolIsActive) {
0982         selectedColumns = m_pCanvas->selection()->columnsSelected();
0983         affectedColumns = m_pCanvas->selection()->columnsAffected();
0984     }
0985 
0986     int deltaX = 1;
0987     if (sheet->layoutDirection() == Qt::RightToLeft) {
0988         if (x > KS_colMax)
0989             x = KS_colMax;
0990 
0991         xPos -= sheet->columnFormat(x)->width();
0992         deltaX = -1;
0993     }
0994 
0995     //Loop through the columns, until we are out of range
0996     while (xPos <= paintRect.right() && x <= KS_colMax) {
0997         bool selected = (selectedColumns.contains(x));
0998         bool highlighted = (!selected && affectedColumns.contains(x));
0999 
1000         const ColumnFormat *columnFormat = sheet->columnFormat(x);
1001         if (columnFormat->isHiddenOrFiltered()) {
1002             ++x;
1003             continue;
1004         }
1005         const qreal width = converter->documentToViewX(columnFormat->width());
1006         const QRectF rect(converter->documentToViewX(xPos), 0, width, height);
1007 
1008         if (selected || highlighted) {
1009             painter->setPen(QPen(selectionColor.dark(150), 0));
1010             painter->setBrush(selectionBrush);
1011         } else {
1012             painter->setPen(QPen(backgroundColor.dark(150), 0));
1013             painter->setBrush(backgroundBrush);
1014         }
1015         painter->drawRect(rect);
1016 
1017         // Reset painter
1018         painter->setFont(normalFont);
1019         painter->setPen(palette().text().color());
1020 
1021         if (selected)
1022             painter->setPen(palette().highlightedText().color());
1023         else if (highlighted)
1024             painter->setFont(boldFont);
1025 
1026         QString colText = sheet->getShowColumnNumber() ? QString::number(x) : Cell::columnName(x);
1027         QFontMetricsF fm(painter->font());
1028 #if 0
1029         if (width < fm.width(colText)) {
1030             // try to scale down the font to make it fit
1031             QFont font = painter->font();
1032             qreal maxSize = font.pointSizeF();
1033             qreal minSize = maxSize / 2;
1034             while (minSize > 1) {
1035                 font.setPointSizeF(minSize);
1036                 const QFontMetricsF fm2(font);
1037                 if (width >= fm2.width(colText))
1038                     break;
1039                 minSize /= 2;
1040             }
1041             while (minSize < 0.99 * maxSize) {
1042                 qreal middle = (maxSize + minSize) / 2;
1043                 font.setPointSizeF(middle);
1044                 const QFontMetricsF fm2(font);
1045                 if (width >= fm2.width(colText)) {
1046                     minSize = middle;
1047                 } else {
1048                     maxSize = middle;
1049                 }
1050             }
1051             painter->setFont(font);
1052             fm = QFontMetricsF(font);
1053         }
1054 #endif
1055         if (width >= fm.width(colText)) {
1056 #if 0
1057             switch (x % 3) {
1058             case 0: colText = QString::number(height) + 'h'; break;
1059             case 1: colText = QString::number(fm.ascent()) + 'a'; break;
1060             case 2: colText = QString::number(fm.descent()) + 'd'; break;
1061             }
1062 #endif
1063             painter->drawText(rect, Qt::AlignCenter, colText);
1064         }
1065 
1066         xPos += columnFormat->width();
1067 
1068         x += deltaX;
1069     }
1070 }
1071 
1072 void ColumnHeader::focusOut(QFocusEvent*)
1073 {
1074     m_pCanvas->disableAutoScroll();
1075     m_bMousePressed = false;
1076 }
1077 
1078 void ColumnHeader::doToolChanged(const QString& toolId)
1079 {
1080     m_cellToolIsActive = toolId.startsWith(QLatin1String("KSpread"));
1081     update();
1082 }
1083 
1084 void ColumnHeader::setHeaderFont(const QFont &font)
1085 {
1086     m_font = font;
1087     update();
1088 }
1089 
1090 QFont ColumnHeader::headerFont() const
1091 {
1092     return m_font;
1093 }
1094 
1095 /****************************************************************
1096  *
1097  * SelectAllButton
1098  *
1099  ****************************************************************/
1100 
1101 SelectAllButton::SelectAllButton(CanvasBase* canvasBase)
1102         : m_canvasBase(canvasBase)
1103         , m_mousePressed(false)
1104         , m_cellToolIsActive(true)
1105 {
1106 }
1107 
1108 SelectAllButton::~SelectAllButton()
1109 {
1110 }
1111 
1112 void SelectAllButton::paint(QPainter* painter, const QRectF& painterRect)
1113 {
1114     // the painter
1115     painter->setClipRect(painterRect);
1116 
1117     // if all cells are selected
1118     if (m_canvasBase->selection()->isAllSelected() &&
1119             !m_canvasBase->selection()->referenceSelectionMode() && m_cellToolIsActive) {
1120         // selection brush/color
1121         QColor selectionColor(palette().highlight().color());
1122         selectionColor.setAlpha(127);
1123         const QBrush selectionBrush(selectionColor);
1124 
1125         painter->setPen(QPen(selectionColor.dark(150), 0));
1126         painter->setBrush(selectionBrush);
1127     } else {
1128         // background brush/color
1129         const QBrush backgroundBrush(palette().window());
1130         const QColor backgroundColor(backgroundBrush.color());
1131 
1132         painter->setPen(QPen(backgroundColor.dark(150), 0));
1133         painter->setBrush(backgroundBrush);
1134     }
1135     painter->drawRect(painterRect.adjusted(0, 0, -1, -1));
1136 }
1137 
1138 void SelectAllButton::mousePress(KoPointerEvent* event)
1139 {
1140     if (!m_cellToolIsActive)
1141         return;
1142     if (event->button() == Qt::LeftButton)
1143         m_mousePressed = true;
1144 }
1145 
1146 void SelectAllButton::mouseRelease(KoPointerEvent* event)
1147 {
1148     if (!m_cellToolIsActive)
1149         return;
1150     Q_UNUSED(event);
1151     if (!m_mousePressed)
1152         return;
1153     m_mousePressed = false;
1154     m_canvasBase->selection()->selectAll();
1155 }
1156 
1157 void SelectAllButton::doToolChanged(const QString& toolId)
1158 {
1159     m_cellToolIsActive = toolId.startsWith(QLatin1String("KSpread"));
1160     update();
1161 }