1 /* This file is part of the KDE project
2    Copyright 2006-2008 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
3    Copyright 2005-2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
4    Copyright 2002-2005 Ariya Hidayat <ariya@kde.org>
5    Copyright 1999-2003 Laurent Montel <montel@kde.org>
6    Copyright 2002-2003 Norbert Andres <nandres@web.de>
7    Copyright 2002-2003 Philipp Mueller <philipp.mueller@gmx.de>
8    Copyright 2002-2003 John Dailey <dailey@vt.edu>
9    Copyright 1999-2003 David Faure <faure@kde.org>
10    Copyright 1999-2001 Simon Hausmann <hausmann@kde.org>
11    Copyright 1998-2000 Torben Weis <weis@kde.org>
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Library General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or(at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Library General Public License for more details.
22 
23    You should have received a copy of the GNU Library General Public License
24    along with this library; see the file COPYING.LIB.  If not, write to
25    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26    Boston, MA 02110-1301, USA.
27 */
28 
29 #include "CellToolBase.h"
30 #include "CellToolBase_p.h"
31 
32 // Sheets
33 #include "ActionOptionWidget.h"
34 #include "ApplicationSettings.h"
35 #include "AutoFillStrategy.h"
36 #include "CalculationSettings.h"
37 #include "Cell.h"
38 #include "CellEditor.h"
39 #include "CellView.h"
40 #include "Damages.h"
41 #include "database/Database.h"
42 #include "database/FilterPopup.h"
43 #include "DragAndDropStrategy.h"
44 #include "ExternalEditor.h"
45 #include "HyperlinkStrategy.h"
46 #include "tests/inspector.h"
47 #include "LocationComboBox.h"
48 #include "Map.h"
49 #include "MergeStrategy.h"
50 #include "NamedAreaManager.h"
51 #include "PasteStrategy.h"
52 #include "RowFormatStorage.h"
53 #include "SelectionStrategy.h"
54 #include "Sheet.h"
55 #include "SheetView.h"
56 #include "StyleManager.h"
57 #include "CellStorage.h"
58 #include "Value.h"
59 #include "ValueConverter.h"
60 #include "odf/SheetsOdf.h"
61 
62 // commands
63 #include "commands/AutoFilterCommand.h"
64 #include "commands/BorderColorCommand.h"
65 #include "commands/CommentCommand.h"
66 #include "commands/ConditionCommand.h"
67 #include "commands/CopyCommand.h"
68 #include "commands/DataManipulators.h"
69 #include "commands/DeleteCommand.h"
70 #include "commands/IndentationCommand.h"
71 #include "commands/LinkCommand.h"
72 #include "commands/MergeCommand.h"
73 #include "commands/PageBreakCommand.h"
74 #include "commands/PasteCommand.h"
75 #include "commands/PrecisionCommand.h"
76 #include "commands/RowColumnManipulators.h"
77 #include "commands/SortManipulator.h"
78 #include "commands/SpellCheckCommand.h"
79 #include "commands/StyleCommand.h"
80 #include "commands/ValidityCommand.h"
81 
82 // dialogs
83 #include "dialogs/AddNamedAreaDialog.h"
84 #include "dialogs/AngleDialog.h"
85 #include "dialogs/AutoFormatDialog.h"
86 #include "dialogs/CharacterSelectDialog.h"
87 #include "dialogs/CommentDialog.h"
88 #include "dialogs/ConditionalDialog.h"
89 #include "dialogs/ConsolidateDialog.h"
90 #include "dialogs/CSVDialog.h"
91 #include "dialogs/DatabaseDialog.h"
92 #include "dialogs/DocumentSettingsDialog.h"
93 #include "dialogs/GoalSeekDialog.h"
94 #include "dialogs/GotoDialog.h"
95 #include "dialogs/InsertDialog.h"
96 #include "dialogs/LayoutDialog.h"
97 #include "dialogs/LinkDialog.h"
98 #include "dialogs/ListDialog.h"
99 #include "dialogs/NamedAreaDialog.h"
100 #include "dialogs/PasteInsertDialog.h"
101 #include "dialogs/Resize2Dialog.h"
102 #include "dialogs/SeriesDialog.h"
103 #include "dialogs/ShowColRowDialog.h"
104 #include "dialogs/SortDialog.h"
105 #include "dialogs/SpecialPasteDialog.h"
106 #include "dialogs/StyleManagerDialog.h"
107 #include "dialogs/SubtotalDialog.h"
108 #include "dialogs/ValidityDialog.h"
109 #include "dialogs/pivot.h"
110 
111 // Calligra
112 #include <KoCanvasBase.h>
113 #include <KoCanvasController.h>
114 #include <KoColorPopupAction.h>
115 #include <KoPointerEvent.h>
116 #include <KoSelection.h>
117 #include <KoShape.h>
118 #include <KoViewConverter.h>
119 #include <KoColor.h>
120 #include <KoIcon.h>
121 
122 // KF5
123 #include <kfind.h>
124 #include <kfontaction.h>
125 #include <kfontsizeaction.h>
126 #include <klocale.h>
127 #include <kmessagebox.h>
128 #include <kreplace.h>
129 #include <kstandardaction.h>
130 #include <ktoggleaction.h>
131 
132 // Qt
133 #include <QStandardPaths>
134 #include <QInputDialog>
135 #include <QBuffer>
136 #include <QHash>
137 #include <QMenu>
138 #include <QPainter>
139 #ifndef QT_NO_SQL
140 #include <QSqlDatabase>
141 #endif
142 
143 #ifndef NDEBUG
144 #include <QTableView>
145 #include "SheetModel.h"
146 #endif
147 
148 using namespace Calligra::Sheets;
149 
CellToolBase(KoCanvasBase * canvas)150 CellToolBase::CellToolBase(KoCanvasBase* canvas)
151         : KoInteractionTool(canvas)
152         , d(new Private(this))
153 {
154     d->cellEditor = 0;
155     d->externalEditor = 0;
156     d->formulaDialog = 0;
157     d->specialCharDialog = 0;
158     d->initialized = false;
159     d->popupListChoose = 0;
160     d->lastEditorWithFocus = EmbeddedEditor;
161 
162     d->findOptions = 0;
163     d->findLeftColumn = 0;
164     d->findRightColumn = 0;
165     d->findTopRow = 0;
166     d->findBottomRow = 0;
167     d->typeValue = FindOption::Value;
168     d->directionValue = FindOption::Row;
169     d->find = 0;
170     d->replace = 0;
171     d->replaceCommand = 0;
172 
173     d->searchInSheets.currentSheet = 0;
174     d->searchInSheets.firstSheet = 0;
175 
176     // Create the extra and ones with extended names for the context menu.
177     d->createPopupMenuActions();
178 
179     // Create the actions.
180     QAction* action = 0;
181 
182     // -- cell style actions --
183 
184     action = new QAction(koIcon("cell_layout"), i18n("Cell Format..."), this);
185     action->setIconText(i18n("Format"));
186     addAction("cellStyle", action);
187     action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_F));
188     connect(action, SIGNAL(triggered(bool)), this, SLOT(cellStyle()));
189     action->setToolTip(i18n("Set the cell formatting"));
190 
191     action = new QAction(i18n("Default"), this);
192     addAction("setDefaultStyle", action);
193     connect(action, SIGNAL(triggered(bool)), this, SLOT(setDefaultStyle()));
194     action->setToolTip(i18n("Resets to the default format"));
195 
196     action = new QAction(i18n("Style Manager..."), this);
197     addAction("styleDialog", action);
198     connect(action, SIGNAL(triggered(bool)), this, SLOT(styleDialog()));
199     action->setToolTip(i18n("Edit and organize cell styles"));
200 
201     action = new KSelectAction(i18n("Style"), this);
202     addAction("setStyle", action);
203     action->setToolTip(i18n("Apply a predefined style to the selected cells"));
204     connect(action, SIGNAL(triggered(QString)), this, SLOT(setStyle(QString)));
205 
206     action = new QAction(i18n("Create Style From Cell..."), this);
207     action->setIconText(i18n("Style From Cell"));
208     addAction("createStyleFromCell", action);
209     connect(action, SIGNAL(triggered(bool)), this, SLOT(createStyleFromCell()));
210     action->setToolTip(i18n("Create a new style based on the currently selected cell"));
211 
212     // -- font actions --
213 
214     action = new KToggleAction(koIcon("format-text-bold"), i18n("Bold"), this);
215     addAction("bold", action);
216     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
217     connect(action, SIGNAL(triggered(bool)), this, SLOT(bold(bool)));
218 
219     action = new KToggleAction(koIcon("format-text-italic"), i18n("Italic"), this);
220     addAction("italic", action);
221     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I));
222     connect(action, SIGNAL(triggered(bool)), this, SLOT(italic(bool)));
223 
224     action = new KToggleAction(koIcon("format-text-underline"), i18n("Underline"), this);
225     addAction("underline", action);
226     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
227     connect(action, SIGNAL(triggered(bool)), this, SLOT(underline(bool)));
228 
229     action = new KToggleAction(koIcon("format-text-strikethrough"), i18n("Strike Out"), this);
230     addAction("strikeOut", action);
231     connect(action, SIGNAL(triggered(bool)), this, SLOT(strikeOut(bool)));
232 
233     action = new KFontAction(i18n("Select Font..."), this);
234     action->setIconText(i18n("Font"));
235     addAction("font", action);
236     connect(action, SIGNAL(triggered(QString)), this, SLOT(font(QString)));
237 
238     action = new KFontSizeAction(i18n("Select Font Size"), this);
239     action->setIconText(i18n("Font Size"));
240     addAction("fontSize", action);
241     connect(action, SIGNAL(fontSizeChanged(int)), this, SLOT(fontSize(int)));
242 
243     action = new QAction(koIcon("format-font-size-more"), i18n("Increase Font Size"), this);
244     addAction("increaseFontSize", action);
245     connect(action, SIGNAL(triggered(bool)), this, SLOT(increaseFontSize()));
246 
247     action = new QAction(koIcon("format-font-size-less"), i18n("Decrease Font Size"), this);
248     addAction("decreaseFontSize", action);
249     connect(action, SIGNAL(triggered(bool)), this, SLOT(decreaseFontSize()));
250 
251     action = new KoColorPopupAction(this);
252     action->setIcon(koIcon("format-text-color"));
253     action->setText(i18n("Text Color"));
254     action->setToolTip(i18n("Set the text color"));
255     addAction("textColor", action);
256     connect(action, SIGNAL(colorChanged(KoColor)), this, SLOT(changeTextColor(KoColor)));
257 
258     // -- horizontal alignment actions --
259 
260     QActionGroup* groupAlign = new QActionGroup(this);
261     action = new KToggleAction(koIcon("format-justify-left"), i18n("Align Left"), this);
262     action->setIconText(i18n("Left"));
263     addAction("alignLeft", action);
264     connect(action, SIGNAL(triggered(bool)), this, SLOT(alignLeft(bool)));
265     action->setToolTip(i18n("Left justify the cell contents"));
266     action->setActionGroup(groupAlign);
267 
268     action = new KToggleAction(koIcon("format-justify-center"), i18n("Align Center"), this);
269     action->setIconText(i18n("Center"));
270     addAction("alignCenter", action);
271     connect(action, SIGNAL(triggered(bool)), this, SLOT(alignCenter(bool)));
272     action->setToolTip(i18n("Center the cell contents"));
273     action->setActionGroup(groupAlign);
274 
275     action = new KToggleAction(koIcon("format-justify-right"), i18n("Align Right"), this);
276     action->setIconText(i18n("Right"));
277     addAction("alignRight", action);
278     connect(action, SIGNAL(triggered(bool)), this, SLOT(alignRight(bool)));
279     action->setToolTip(i18n("Right justify the cell contents"));
280     action->setActionGroup(groupAlign);
281 
282     // -- vertical alignment actions --
283 
284     QActionGroup* groupPos = new QActionGroup(this);
285     action = new KToggleAction(koIcon("format-align-vertical-top"), i18n("Align Top"), this);
286     action->setIconText(i18n("Top"));
287     addAction("alignTop", action);
288     connect(action, SIGNAL(triggered(bool)), this, SLOT(alignTop(bool)));
289     action->setToolTip(i18n("Align cell contents along the top of the cell"));
290     action->setActionGroup(groupPos);
291 
292     action = new KToggleAction(koIcon("format-align-vertical-center"), i18n("Align Middle"), this);
293     action->setIconText(i18n("Middle"));
294     addAction("alignMiddle", action);
295     connect(action, SIGNAL(triggered(bool)), this, SLOT(alignMiddle(bool)));
296     action->setToolTip(i18n("Align cell contents centered in the cell"));
297     action->setActionGroup(groupPos);
298 
299     action = new KToggleAction(koIcon("format-align-vertical-bottom"), i18n("Align Bottom"), this);
300     action->setIconText(i18n("Bottom"));
301     addAction("alignBottom", action);
302     connect(action, SIGNAL(triggered(bool)), this, SLOT(alignBottom(bool)));
303     action->setToolTip(i18n("Align cell contents along the bottom of the cell"));
304     action->setActionGroup(groupPos);
305 
306     // -- border actions --
307 
308     action = new QAction(koIcon("format-border-set-left"), i18n("Border Left"), this);
309     action->setIconText(i18n("Left"));
310     addAction("borderLeft", action);
311     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderLeft()));
312     action->setToolTip(i18n("Set a left border to the selected area"));
313 
314     action = new QAction(koIcon("format-border-set-right"), i18n("Border Right"), this);
315     action->setIconText(i18n("Right"));
316     addAction("borderRight", action);
317     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderRight()));
318     action->setToolTip(i18n("Set a right border to the selected area"));
319 
320     action = new QAction(koIcon("format-border-set-top"), i18n("Border Top"), this);
321     action->setIconText(i18n("Top"));
322     addAction("borderTop", action);
323     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderTop()));
324     action->setToolTip(i18n("Set a top border to the selected area"));
325 
326     action = new QAction(koIcon("format-border-set-bottom"), i18n("Border Bottom"), this);
327     action->setIconText(i18n("Bottom"));
328     addAction("borderBottom", action);
329     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderBottom()));
330     action->setToolTip(i18n("Set a bottom border to the selected area"));
331 
332     action = new QAction(koIcon("format-border-set-all"), i18n("All Borders"), this);
333     action->setIconText(i18n("All"));
334     addAction("borderAll", action);
335     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderAll()));
336     action->setToolTip(i18n("Set a border around all cells in the selected area"));
337 
338     action = new QAction(koIcon("format-border-set-none"), i18n("No Borders"), this);
339     action->setIconText(i18n("None"));
340     addAction("borderRemove", action);
341     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderRemove()));
342     action->setToolTip(i18n("Remove all borders in the selected area"));
343 
344     action = new QAction(koIcon("format-border-set-external"), i18n("Border Outline"), this);
345     action->setIconText(i18n("Outline"));
346     addAction("borderOutline", action);
347     connect(action, SIGNAL(triggered(bool)), this, SLOT(borderOutline()));
348     action->setToolTip(i18n("Set a border to the outline of the selected area"));
349 
350     action = new KoColorPopupAction(this);
351     action->setIcon(koIcon("format-stroke-color"));
352     action->setToolTip(i18n("Select a new border color"));
353     action->setText(i18n("Border Color"));
354     static_cast<KoColorPopupAction*>(action)->setCurrentColor(Qt::black);
355     addAction("borderColor", action);
356     connect(action, SIGNAL(colorChanged(KoColor)), this, SLOT(borderColor(KoColor)));
357 
358     // -- text layout actions --
359 
360     action = new KToggleAction(koIcon("multirow"), i18n("Wrap Text"), this);
361     action->setIconText(i18n("Wrap"));
362     addAction("wrapText", action);
363     connect(action, SIGNAL(triggered(bool)), this, SLOT(wrapText(bool)));
364     action->setToolTip(i18n("Make the cell text wrap onto multiple lines"));
365 
366     action = new KToggleAction(koIcon("format-text-direction-vertical"), i18n("Vertical Text"), this);
367     action->setIconText(i18n("Vertical"));
368     addAction("verticalText", action);
369     connect(action, SIGNAL(triggered(bool)), this, SLOT(verticalText(bool)));
370     action->setToolTip(i18n("Print cell contents vertically"));
371 
372     action = new QAction(QIcon::fromTheme(QApplication::isRightToLeft() ? koIconName("format-indent-less") : koIconName("format-indent-more")), i18n("Increase Indent"), this);
373     addAction("increaseIndentation", action);
374     connect(action, SIGNAL(triggered(bool)), this, SLOT(increaseIndentation()));
375     action->setToolTip(i18n("Increase the indentation"));
376 
377     action = new QAction(QIcon::fromTheme(QApplication::isRightToLeft() ? koIconName("format-indent-more") : koIconName("format-indent-less")), i18n("Decrease Indent"), this);
378     addAction("decreaseIndentation", action);
379     connect(action, SIGNAL(triggered(bool)), this, SLOT(decreaseIndentation()));
380     action->setToolTip(i18n("Decrease the indentation"));
381 
382     action = new QAction(i18n("Change Angle..."), this);
383     action->setIconText(i18n("Angle"));
384     addAction("changeAngle", action);
385     connect(action, SIGNAL(triggered(bool)), this, SLOT(changeAngle()));
386     action->setToolTip(i18n("Change the angle that cell contents are printed"));
387 
388     // -- value format actions --
389 
390     action = new KToggleAction(koIcon("format-number-percent"), i18n("Percent Format"), this);
391     action->setIconText(i18n("Percent"));
392     addAction("percent", action);
393     connect(action, SIGNAL(triggered(bool)), this, SLOT(percent(bool)));
394     action->setToolTip(i18n("Set the cell formatting to look like a percentage"));
395 
396     action = new KToggleAction(koIcon("format-currency"), i18n("Money Format"), this);
397     action->setIconText(i18n("Money"));
398     addAction("currency", action);
399     connect(action, SIGNAL(triggered(bool)), this, SLOT(currency(bool)));
400     action->setToolTip(i18n("Set the cell formatting to look like your local currency"));
401 
402     action = new QAction(koIcon("format-precision-more"), i18n("Increase Precision"), this);
403     addAction("increasePrecision", action);
404     connect(action, SIGNAL(triggered(bool)), this, SLOT(increasePrecision()));
405     action->setToolTip(i18n("Increase the decimal precision shown onscreen"));
406 
407     action = new QAction(koIcon("format-precision-less"), i18n("Decrease Precision"), this);
408     addAction("decreasePrecision", action);
409     connect(action, SIGNAL(triggered(bool)), this, SLOT(decreasePrecision()));
410     action->setToolTip(i18n("Decrease the decimal precision shown onscreen"));
411 
412     // -- misc style attribute actions --
413 
414     action = new QAction(koIconWanted("no icon in Kate, but LO has one", "format-text-uppercase"), i18n("Upper Case"), this);
415     action->setIconText(i18n("Upper"));
416     addAction("toUpperCase", action);
417     connect(action, SIGNAL(triggered(bool)), this, SLOT(toUpperCase()));
418     action->setToolTip(i18n("Convert all letters to upper case"));
419 
420     action = new QAction(koIconWanted("no icon in Kate, but LO has one", "format-text-lowercase"), i18n("Lower Case"), this);
421     action->setIconText(i18n("Lower"));
422     addAction("toLowerCase", action);
423     connect(action, SIGNAL(triggered(bool)), this, SLOT(toLowerCase()));
424     action->setToolTip(i18n("Convert all letters to lower case"));
425 
426     action = new QAction(koIcon("format-text-capitalize"), i18n("Convert First Letter to Upper Case"), this);
427     action->setIconText(i18n("First Letter Upper"));
428     addAction("firstLetterToUpperCase", action);
429     connect(action, SIGNAL(triggered(bool)), this, SLOT(firstLetterToUpperCase()));
430     action->setToolTip(i18n("Capitalize the first letter"));
431 
432     action = new KoColorPopupAction(this);
433     action->setIcon(koIcon("format-fill-color"));
434     action->setToolTip(i18n("Set the background color"));
435     action->setText(i18n("Background Color"));
436     addAction("backgroundColor", action);
437     connect(action, SIGNAL(colorChanged(KoColor)), this, SLOT(changeBackgroundColor(KoColor)));
438 
439     // -- cell merging actions --
440 
441     action = new QAction(koIcon("mergecell"), i18n("Merge Cells"), this);
442     addAction("mergeCells", action);
443     connect(action, SIGNAL(triggered(bool)), this, SLOT(mergeCells()));
444     action->setToolTip(i18n("Merge the selected region"));
445 
446     action = new QAction(koIcon("mergecell-horizontal"), i18n("Merge Cells Horizontally"), this);
447     action->setToolTip(i18n("Merge the selected region horizontally"));
448     addAction("mergeCellsHorizontal", action);
449     connect(action, SIGNAL(triggered(bool)), this, SLOT(mergeCellsHorizontal()));
450 
451     action = new QAction(koIcon("mergecell-vertical"), i18n("Merge Cells Vertically"), this);
452     action->setToolTip(i18n("Merge the selected region vertically"));
453     addAction("mergeCellsVertical", action);
454     connect(action, SIGNAL(triggered(bool)), this, SLOT(mergeCellsVertical()));
455 
456     action = new QAction(koIcon("dissociatecell"), i18n("Dissociate Cells"), this);
457     action->setToolTip(i18n("Unmerge the selected region"));
458     addAction("dissociateCells", action);
459     connect(action, SIGNAL(triggered(bool)), this, SLOT(dissociateCells()));
460 
461     // -- column & row actions --
462 
463     action = new QAction(koIcon("resizecol"), i18n("Resize Column..."), this);
464     addAction("resizeCol", action);
465     connect(action, SIGNAL(triggered(bool)), this, SLOT(resizeColumn()));
466     action->setToolTip(i18n("Change the width of a column"));
467 
468     action = new QAction(koIcon("edit-table-insert-column-left"), i18n("Columns"), this);
469     action->setIconText(i18n("Insert Columns"));
470     action->setToolTip(i18n("Inserts a new column into the spreadsheet"));
471     addAction("insertColumn", action);
472     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertColumn()));
473 
474     action = new QAction(koIcon("edit-table-delete-column"), i18n("Columns"), this);
475     action->setIconText(i18n("Remove Columns"));
476     action->setToolTip(i18n("Removes the selected columns from the spreadsheet"));
477     addAction("deleteColumn", action);
478     connect(action, SIGNAL(triggered(bool)), this, SLOT(deleteColumn()));
479 
480     action = new QAction(koIcon("hide_table_column"), i18n("Hide Columns"), this);
481     addAction("hideColumn", action);
482     connect(action, SIGNAL(triggered(bool)), this, SLOT(hideColumn()));
483     action->setToolTip(i18n("Hide the column from this"));
484 
485     action = new QAction(koIcon("show_table_column"), i18n("Show Columns..."), this);
486     addAction("showColumn", action);
487     connect(action, SIGNAL(triggered(bool)), this, SLOT(slotShowColumnDialog()));
488     action->setToolTip(i18n("Show hidden columns"));
489 
490     action = new QAction(koIcon("adjustcol"), i18n("Equalize Column"), this);
491     addAction("equalizeCol", action);
492     connect(action, SIGNAL(triggered(bool)), this, SLOT(equalizeColumn()));
493     action->setToolTip(i18n("Resizes selected columns to be the same size"));
494 
495     action = new QAction(koIcon("show_table_column"), i18n("Show Columns"), this);
496     addAction("showSelColumns", action);
497     connect(action, SIGNAL(triggered(bool)), this, SLOT(showColumn()));
498     action->setToolTip(i18n("Show hidden columns in the selection"));
499     action->setEnabled(false);
500 
501     action = new QAction(koIcon("resizerow"), i18n("Resize Row..."), this);
502     addAction("resizeRow", action);
503     connect(action, SIGNAL(triggered(bool)), this, SLOT(resizeRow()));
504     action->setToolTip(i18n("Change the height of a row"));
505 
506     action = new QAction(koIcon("edit-table-insert-row-above"), i18n("Rows"), this);
507     action->setIconText(i18n("Insert Rows"));
508     action->setToolTip(i18n("Inserts a new row into the spreadsheet"));
509     addAction("insertRow", action);
510     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertRow()));
511 
512     action = new QAction(koIcon("edit-table-delete-row"), i18n("Rows"), this);
513     action->setIconText(i18n("Remove Rows"));
514     action->setToolTip(i18n("Removes a row from the spreadsheet"));
515     addAction("deleteRow", action);
516     connect(action, SIGNAL(triggered(bool)), this, SLOT(deleteRow()));
517 
518     action = new QAction(koIcon("hide_table_row"), i18n("Hide Rows"), this);
519     addAction("hideRow", action);
520     connect(action, SIGNAL(triggered(bool)), this, SLOT(hideRow()));
521     action->setToolTip(i18n("Hide a row from this"));
522 
523     action = new QAction(koIcon("show_table_row"), i18n("Show Rows..."), this);
524     addAction("showRow", action);
525     connect(action, SIGNAL(triggered(bool)), this, SLOT(slotShowRowDialog()));
526     action->setToolTip(i18n("Show hidden rows"));
527 
528     action = new QAction(koIcon("adjustrow"), i18n("Equalize Row"), this);
529     addAction("equalizeRow", action);
530     connect(action, SIGNAL(triggered(bool)), this, SLOT(equalizeRow()));
531     action->setToolTip(i18n("Resizes selected rows to be the same size"));
532 
533     action = new QAction(koIcon("show_table_row"), i18n("Show Rows"), this);
534     addAction("showSelRows", action);
535     connect(action, SIGNAL(triggered(bool)), this, SLOT(showRow()));
536     action->setEnabled(false);
537     action->setToolTip(i18n("Show hidden rows in the selection"));
538 
539     action = new QAction(i18n("Adjust Row && Column"), this);
540     addAction("adjust", action);
541     connect(action, SIGNAL(triggered(bool)), this, SLOT(adjust()));
542     action->setToolTip(i18n("Adjusts row/column size so that the contents will fit"));
543 
544     // -- cell insert/remove actions --
545 
546     action = new QAction(koIcon("insertcell"), i18n("Cells..."), this);
547     action->setIconText(i18n("Insert Cells..."));
548     action->setToolTip(i18n("Insert a blank cell into the spreadsheet"));
549     addAction("insertCell", action);
550     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertCells()));
551 
552     action = new QAction(koIcon("removecell"), i18n("Cells..."), this);
553     action->setIconText(i18n("Remove Cells..."));
554     action->setToolTip(i18n("Removes the cells from the spreadsheet"));
555     addAction("deleteCell", action);
556     connect(action, SIGNAL(triggered(bool)), this, SLOT(deleteCells()));
557 
558     // -- cell content actions --
559 
560     action = new QAction(koIcon("deletecell"), i18n("All"), this);
561     action->setIconText(i18n("Clear All"));
562     action->setToolTip(i18n("Clear all contents and formatting of the current cell"));
563     addAction("clearAll", action);
564     connect(action, SIGNAL(triggered(bool)), this, SLOT(clearAll()));
565 
566     action = new QAction(koIcon("edit-clear"), i18n("Contents"), this);
567     action->setIconText(i18n("Clear Contents"));
568     action->setToolTip(i18n("Remove the contents of the current cell"));
569     addAction("clearContents", action);
570     connect(action, SIGNAL(triggered(bool)), this, SLOT(clearContents()));
571 
572     action = new QAction(koIcon("edit-comment"), i18n("Comment..."), this);
573     action->setToolTip(i18n("Edit a comment for this cell"));
574     addAction("comment", action);
575     connect(action, SIGNAL(triggered(bool)), this, SLOT(comment()));
576 
577     action = new QAction(koIcon("delete-comment"), i18n("Comment"), this);
578     action->setIconText(i18n("Remove Comment"));
579     action->setToolTip(i18n("Remove this cell's comment"));
580     addAction("clearComment", action);
581     connect(action, SIGNAL(triggered(bool)), this, SLOT(clearComment()));
582 
583     action = new QAction(i18n("Conditional Styles..."), this);
584     action->setToolTip(i18n("Set cell style based on certain conditions"));
585     addAction("conditional", action);
586     connect(action, SIGNAL(triggered(bool)), this, SLOT(conditional()));
587 
588     action = new QAction(i18n("Conditional Styles"), this);
589     action->setIconText(i18n("Remove Conditional Styles"));
590     action->setToolTip(i18n("Remove the conditional cell styles"));
591     addAction("clearConditional", action);
592     connect(action, SIGNAL(triggered(bool)), this, SLOT(clearConditionalStyles()));
593 
594     action = new QAction(koIcon("insert-link"), i18n("&Link..."), this);
595     addAction("insertHyperlink", action);
596     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertHyperlink()));
597     action->setToolTip(i18n("Insert an Internet hyperlink"));
598 
599     action = new QAction(i18n("Link"), this);
600     action->setIconText(i18n("Remove Link"));
601     action->setToolTip(i18n("Remove a link"));
602     addAction("clearHyperlink", action);
603     connect(action, SIGNAL(triggered(bool)), this, SLOT(clearHyperlink()));
604 
605     action = new QAction(i18n("Validity..."), this);
606     action->setToolTip(i18n("Set tests to confirm cell data is valid"));
607     addAction("validity", action);
608     connect(action, SIGNAL(triggered(bool)), this, SLOT(validity()));
609 
610     action = new QAction(i18n("Validity"), this);
611     action->setIconText(i18n("Remove Validity"));
612     action->setToolTip(i18n("Remove the validity tests on this cell"));
613     addAction("clearValidity", action);
614     connect(action, SIGNAL(triggered(bool)), this, SLOT(clearValidity()));
615 
616     // -- sorting/filtering action --
617 
618     action = new QAction(i18n("&Sort..."), this);
619     addAction("sort", action);
620     connect(action, SIGNAL(triggered(bool)), this, SLOT(sort()));
621     action->setToolTip(i18n("Sort a group of cells"));
622 
623     action = new QAction(koIcon("view-sort-descending"), i18n("Sort &Decreasing"), this);
624     addAction("sortDec", action);
625     connect(action, SIGNAL(triggered(bool)), this, SLOT(sortDec()));
626     action->setToolTip(i18n("Sort a group of cells in decreasing(last to first) order"));
627 
628     action = new QAction(koIcon("view-sort-ascending"), i18n("Sort &Increasing"), this);
629     addAction("sortInc", action);
630     connect(action, SIGNAL(triggered(bool)), this, SLOT(sortInc()));
631     action->setToolTip(i18n("Sort a group of cells in ascending(first to last) order"));
632 
633     action = new QAction(koIcon("view-filter"), i18n("&Auto-Filter"), this);
634     addAction("autoFilter", action);
635     connect(action, SIGNAL(triggered(bool)), this, SLOT(autoFilter()));
636     action->setToolTip(i18n("Add an automatic filter to a cell range"));
637 
638     // -- fill actions --
639 
640     action = new QAction(/*koIcon("arrow-left"), */i18n("&Left"), this);
641     addAction("fillLeft", action);
642     connect(action, SIGNAL(triggered(bool)), this, SLOT(fillLeft()));
643 
644     action = new QAction(/*koIcon("arrow-right"), */i18n("&Right"), this);
645     addAction("fillRight", action);
646     connect(action, SIGNAL(triggered(bool)), this, SLOT(fillRight()));
647 
648     action = new QAction(/*koIcon("arrow-up"), */i18n("&Up"), this);
649     addAction("fillUp", action);
650     connect(action, SIGNAL(triggered(bool)), this, SLOT(fillUp()));
651 
652     action = new QAction(/*koIcon("arrow-down"), */i18n("&Down"), this);
653     addAction("fillDown", action);
654     connect(action, SIGNAL(triggered(bool)), this, SLOT(fillDown()));
655 
656     action = new QAction(koIcon("black_sum"), i18n("Autosum"), this);
657     addAction("autoSum", action);
658     connect(action, SIGNAL(triggered(bool)), this, SLOT(autoSum()));
659     action->setToolTip(i18n("Insert the 'sum' function"));
660 
661     // -- data insert actions --
662 
663     action = new QAction(koIcon("series"), i18n("&Series..."), this);
664     addAction("insertSeries", action);
665     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertSeries()));
666     action ->setToolTip(i18n("Insert a series"));
667 
668     action = new QAction(koIcon("insert-math-expression"), i18n("&Function..."), this);
669     addAction("insertFormula", action);
670     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertFormula()));
671     action->setToolTip(i18n("Insert math expression"));
672 
673     action = new QAction(koIcon("character-set"), i18n("S&pecial Character..."), this);
674     addAction("insertSpecialChar", action);
675     action->setToolTip(i18n("Insert one or more symbols or letters not found on the keyboard"));
676     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertSpecialChar()));
677 
678 #ifndef QT_NO_SQL
679     action = new QAction(koIcon("network-server-database"), i18n("From &Database..."), this);
680     action->setIconText(i18n("Database"));
681     addAction("insertFromDatabase", action);
682     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertFromDatabase()));
683     action->setToolTip(i18n("Insert data from a SQL database"));
684 #endif
685 
686     action = new QAction(koIcon("text-plain"), i18n("From &Text File..."), this);
687     action->setIconText(i18n("Text File"));
688     addAction("insertFromTextfile", action);
689     connect(action, SIGNAL(triggered(bool)), this,  SLOT(insertFromTextfile()));
690     action->setToolTip(i18n("Insert data from a text file to the current cursor position/selection"));
691 
692     action = new QAction(koIcon("edit-paste"), i18n("From &Clipboard..."), this);
693     action->setIconText(i18n("Clipboard"));
694     addAction("insertFromClipboard", action);
695     connect(action, SIGNAL(triggered(bool)), this, SLOT(insertFromClipboard()));
696     action->setToolTip(i18n("Insert CSV data from the clipboard to the current cursor position/selection"));
697 
698     action = new QAction(i18n("&Text to Columns..."), this);
699     addAction("textToColumns", action);
700     connect(action, SIGNAL(triggered(bool)), this, SLOT(textToColumns()));
701     action->setToolTip(i18n("Expand the content of cells to multiple columns"));
702 
703     action = new QAction(i18n("Custom Lists..."), this);
704     addAction("sortList", action);
705     connect(action, SIGNAL(triggered(bool)), this, SLOT(sortList()));
706     action->setToolTip(i18n("Create custom lists for sorting or autofill"));
707 
708     action = new QAction(i18n("&Consolidate..."), this);
709     addAction("consolidate", action);
710     connect(action, SIGNAL(triggered(bool)), this, SLOT(consolidate()));
711     action->setToolTip(i18n("Create a region of summary data from a group of similar regions"));
712 
713     action = new QAction(i18n("&Goal Seek..."), this);
714     addAction("goalSeek", action);
715     connect(action, SIGNAL(triggered(bool)), this, SLOT(goalSeek()));
716     action->setToolTip(i18n("Repeating calculation to find a specific value"));
717 
718     action = new QAction(i18n("&Subtotals..."), this);
719     addAction("subtotals", action);
720     connect(action, SIGNAL(triggered(bool)), this, SLOT(subtotals()));
721     action->setToolTip(i18n("Create different kind of subtotals to a list or database"));
722 
723     action = new QAction(i18n("&Pivot Tables..."), this);
724     addAction("Pivot", action);
725     connect(action, SIGNAL(triggered(bool)), this, SLOT(pivot()));
726     action->setToolTip(i18n("Create Pivot Tables"));
727 
728     action = new QAction(i18n("Area Name..."), this);
729     addAction("setAreaName", action);
730     connect(action, SIGNAL(triggered(bool)), this, SLOT(setAreaName()));
731     action->setToolTip(i18n("Set a name for a region of the spreadsheet"));
732 
733     action = new QAction(i18n("Named Areas..."), this);
734     action->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_G));
735     action->setIconText(i18n("Named Areas"));
736     action->setIcon(koIcon("bookmarks"));
737     action->setToolTip(i18n("Edit or select named areas"));
738     addAction("namedAreaDialog", action);
739     connect(action, SIGNAL(triggered(bool)), this, SLOT(namedAreaDialog()));
740 
741     action = new KSelectAction(i18n("Formula Selection"), this);
742     addAction("formulaSelection", action);
743     action->setToolTip(i18n("Insert a function"));
744     QStringList functionList;
745     functionList.append("SUM");
746     functionList.append("AVERAGE");
747     functionList.append("IF");
748     functionList.append("COUNT");
749     functionList.append("MIN");
750     functionList.append("MAX");
751     functionList.append(i18n("Others..."));
752     static_cast<KSelectAction*>(action)->setItems(functionList);
753     static_cast<KSelectAction*>(action)->setComboWidth(80);
754     static_cast<KSelectAction*>(action)->setCurrentItem(0);
755     connect(action, SIGNAL(triggered(QString)), this, SLOT(formulaSelection(QString)));
756 
757     // -- general editing actions --
758 
759     action = new QAction(koIcon("cell_edit"), i18n("Modify Cell"), this);
760     addAction("editCell", action);
761     action->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_M));
762     connect(action, SIGNAL(triggered(bool)), this, SLOT(edit()));
763     action->setToolTip(i18n("Edit the highlighted cell"));
764 
765     action = KStandardAction::cut(this, SLOT(cut()), this);
766     action->setToolTip(i18n("Move the cell object to the clipboard"));
767     addAction("cut", action);
768 
769     action = KStandardAction::copy(this, SLOT(copy()), this);
770     action->setToolTip(i18n("Copy the cell object to the clipboard"));
771     addAction("copy", action);
772 
773     action = KStandardAction::paste(this, SLOT(paste()), this);
774     action->setToolTip(i18n("Paste the contents of the clipboard at the cursor"));
775     addAction("paste", action);
776 
777     action = new QAction(koIcon("special_paste"), i18n("Special Paste..."), this);
778     addAction("specialPaste", action);
779     connect(action, SIGNAL(triggered(bool)), this, SLOT(specialPaste()));
780     action->setToolTip(i18n("Paste the contents of the clipboard with special options"));
781 
782     action = new QAction(koIcon("insertcellcopy"), i18n("Paste with Insertion"), this);
783     addAction("pasteWithInsertion", action);
784     connect(action, SIGNAL(triggered(bool)), this, SLOT(pasteWithInsertion()));
785     action->setToolTip(i18n("Inserts a cell from the clipboard into the spreadsheet"));
786 
787     action = KStandardAction::selectAll(this, SLOT(selectAll()), this);
788     action->setToolTip(i18n("Selects all cells in the current sheet"));
789     addAction("selectAll", action);
790 
791     action = KStandardAction::find(this, SLOT(find()), this);
792     addAction("edit_find", action);
793 
794     action = KStandardAction::findNext(this, SLOT(findNext()), this);
795     addAction("edit_find_next", action);
796 
797     action = KStandardAction::findPrev(this, SLOT(findPrevious()), this);
798     addAction("edit_find_last", action);
799 
800     action = KStandardAction::replace(this, SLOT(replace()), this);
801     addAction("edit_replace", action);
802 
803     // -- misc actions --
804 
805     action = new QAction(koIcon("go-jump"), i18n("Goto Cell..."), this);
806     action->setIconText(i18n("Goto"));
807     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G));
808     addAction("gotoCell", action);
809     connect(action, SIGNAL(triggered(bool)), this, SLOT(gotoCell()));
810     action->setToolTip(i18n("Move to a particular cell"));
811 
812     action = KStandardAction::spelling(this, SLOT(spellCheck()), this);
813     action->setToolTip(i18n("Check the spelling"));
814     addAction("tools_spelling", action);
815 
816     action = new QAction(koIconWanted("not used in UI, but devs might do, so nice to have", "inspector"), i18n("Run Inspector..."), this);
817     addAction("inspector", action);
818     action->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
819     connect(action, SIGNAL(triggered(bool)), this, SLOT(inspector()));
820 
821 #ifndef NDEBUG
822     action = new QAction(koIcon("table"), i18n("Show QTableView..."), this);
823     addAction("qTableView", action);
824     action->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_T));
825     connect(action, SIGNAL(triggered(bool)), this, SLOT(qTableView()));
826 #endif
827 
828     action = new QAction(i18n("Auto-Format..."), this);
829     addAction("sheetFormat", action);
830     connect(action, SIGNAL(triggered(bool)), this, SLOT(sheetFormat()));
831     action->setToolTip(i18n("Set the worksheet formatting"));
832 
833     action = new QAction(koIcon("application-vnd.oasis.opendocument.spreadsheet"), i18n("Document Settings..."), this);
834     addAction("documentSettingsDialog", action);
835     connect(action, SIGNAL(triggered(bool)), this, SLOT(documentSettingsDialog()));
836     action->setToolTip(i18n("Show document settings dialog"));
837 
838     action = new KToggleAction(i18n("Break Before Column"), this);
839     addAction("format_break_before_column", action);
840     connect(action, SIGNAL(triggered(bool)), this, SLOT(breakBeforeColumn(bool)));
841     action->setIconText(i18n("Column Break"));
842     action->setToolTip(i18n("Set a manual page break before the column"));
843 
844     action = new KToggleAction(i18n("Break Before Row"), this);
845     addAction("format_break_before_row", action);
846     connect(action, SIGNAL(triggered(bool)), this, SLOT(breakBeforeRow(bool)));
847     action->setIconText(i18n("Row Break"));
848     action->setToolTip(i18n("Set a manual page break before the row"));
849 
850     // Editor actions:
851     // Set up the permutation of the reference fixations action.
852     action = new QAction(i18n("Permute reference fixation"), this);
853     addAction("permuteFixation", action);
854     action->setShortcut(Qt::Key_F4);
855     // connect on creation of the embedded editor
856     action->setIconText(i18n("Permute fixation"));
857     action->setToolTip(i18n("Permute the fixation of the reference at the text cursor"));
858 
859     setTextMode(true);
860 
861 }
862 
~CellToolBase()863 CellToolBase::~CellToolBase()
864 {
865     delete d->formulaDialog;
866     delete d->popupListChoose;
867     delete d->cellEditor;
868     qDeleteAll(d->popupMenuActions);
869     qDeleteAll(actions());
870     delete d;
871 }
872 
paint(QPainter & painter,const KoViewConverter & viewConverter)873 void CellToolBase::paint(QPainter &painter, const KoViewConverter &viewConverter)
874 {
875     KoShape::applyConversion(painter, viewConverter);
876     painter.translate(offset()); // the table shape offset
877     const QRectF paintRect = QRectF(QPointF(), size());
878 
879     /* paint the selection */
880     d->paintReferenceSelection(painter, paintRect);
881     d->paintSelection(painter, paintRect);
882 }
883 
paintReferenceSelection(QPainter & painter,const QRectF & paintRect)884 void CellToolBase::paintReferenceSelection(QPainter &painter, const QRectF &paintRect)
885 {
886     d->paintReferenceSelection(painter, paintRect);
887 }
888 
paintSelection(QPainter & painter,const QRectF & paintRect)889 void CellToolBase::paintSelection(QPainter &painter, const QRectF &paintRect)
890 {
891     d->paintSelection(painter, paintRect);
892 }
893 
mousePressEvent(KoPointerEvent * event)894 void CellToolBase::mousePressEvent(KoPointerEvent* event)
895 {
896     KoInteractionTool::mousePressEvent(event);
897 }
898 
mouseMoveEvent(KoPointerEvent * event)899 void CellToolBase::mouseMoveEvent(KoPointerEvent* event)
900 {
901     // Special handling for drag'n'drop.
902     if (DragAndDropStrategy *const strategy = dynamic_cast<DragAndDropStrategy*>(currentStrategy())) {
903         // FIXME Stefan: QDrag*Event and QDropEvent are not handled by KoInteractionTool YET:
904         // Cancel the strategy after the drag has started.
905         if (strategy->dragStarted()) {
906             cancelCurrentStrategy();
907         }
908         KoInteractionTool::mouseMoveEvent(event);
909         return;
910     }
911     // Indicators are not necessary if there's a strategy.
912     if (currentStrategy()) {
913         return KoInteractionTool::mouseMoveEvent(event);
914     }
915 
916     Sheet *const sheet = selection()->activeSheet();
917 
918     // Get info about where the event occurred.
919     QPointF position = event->point - offset(); // the shape offset, not the scrolling one.
920 
921     // Diagonal cursor, if the selection handle was hit.
922     if (SelectionStrategy::hitTestReferenceSizeGrip(canvas(), selection(), position) ||
923         SelectionStrategy::hitTestSelectionSizeGrip(canvas(), selection(), position)) {
924         if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft) {
925             useCursor(Qt::SizeBDiagCursor);
926         } else {
927             useCursor(Qt::SizeFDiagCursor);
928         }
929         return KoInteractionTool::mouseMoveEvent(event);
930     }
931 
932     // Hand cursor, if the selected area was hit.
933     if (!selection()->referenceSelectionMode()) {
934         const Region::ConstIterator end(selection()->constEnd());
935         for (Region::ConstIterator it(selection()->constBegin()); it != end; ++it) {
936             const QRect range = (*it)->rect();
937             if (sheet->cellCoordinatesToDocument(range).contains(position)) {
938                 useCursor(Qt::PointingHandCursor);
939                 return KoInteractionTool::mouseMoveEvent(event);
940             }
941         }
942     }
943 
944     // In which cell did the user click?
945     qreal xpos;
946     qreal ypos;
947     const int col = this->selection()->activeSheet()->leftColumn(position.x(), xpos);
948     const int row = this->selection()->activeSheet()->topRow(position.y(), ypos);
949     // Check boundaries.
950     if (col < 1 || row < 1 || col > maxCol() || row > maxRow()) {
951         debugSheetsUI << "col or row is out of range:" << "col:" << col << " row:" << row;
952     } else {
953         const Cell cell = Cell(selection()->activeSheet(), col, row).masterCell();
954         SheetView* const sheetView = this->sheetView(selection()->activeSheet());
955 
956         QString url;
957         const CellView& cellView = sheetView->cellView(col, row);
958         if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft) {
959             url = cellView.testAnchor(sheetView, cell, cell.width() - position.x() + xpos, position.y() - ypos);
960         } else {
961             url = cellView.testAnchor(sheetView, cell, position.x() - xpos, position.y() - ypos);
962         }
963         if (!url.isEmpty()) {
964             useCursor(Qt::PointingHandCursor);
965             return KoInteractionTool::mouseMoveEvent(event);
966         }
967     }
968 
969     // Reset to normal cursor.
970     useCursor(Qt::ArrowCursor);
971     KoInteractionTool::mouseMoveEvent(event);
972 }
973 
mouseReleaseEvent(KoPointerEvent * event)974 void CellToolBase::mouseReleaseEvent(KoPointerEvent* event)
975 {
976     KoInteractionTool::mouseReleaseEvent(event);
977     scrollToCell(selection()->cursor());
978 }
979 
mouseDoubleClickEvent(KoPointerEvent * event)980 void CellToolBase::mouseDoubleClickEvent(KoPointerEvent* event)
981 {
982     Q_UNUSED(event)
983     cancelCurrentStrategy();
984     scrollToCell(selection()->cursor());
985     createEditor(false /* keep content */, true, true /*full editing*/);
986 }
987 
keyPressEvent(QKeyEvent * event)988 void CellToolBase::keyPressEvent(QKeyEvent* event)
989 {
990     register Sheet * const sheet = selection()->activeSheet();
991     if (!sheet) {
992         return;
993     }
994 
995     // Don't handle the remaining special keys.
996     if (event->modifiers() & (Qt::AltModifier | Qt::ControlModifier) &&
997             (event->key() != Qt::Key_Down) &&
998             (event->key() != Qt::Key_Up) &&
999             (event->key() != Qt::Key_Right) &&
1000             (event->key() != Qt::Key_Left) &&
1001             (event->key() != Qt::Key_Home) &&
1002             (event->key() != Qt::Key_Enter) &&
1003             (event->key() != Qt::Key_Return)) {
1004         event->ignore(); // QKeyEvent
1005         return;
1006     }
1007 
1008     // Check for formatting key combination CTRL + ...
1009     // Qt::Key_Exclam, Qt::Key_At, Qt::Key_Ampersand, Qt::Key_Dollar
1010     // Qt::Key_Percent, Qt::Key_AsciiCircum, Qt::Key_NumberSign
1011     if (d->formatKeyPress(event)) {
1012         return;
1013     }
1014 
1015 #if 0
1016     // TODO move this to the contextMenuEvent of the view.
1017     // keyPressEvent() is not called with the contextMenuKey,
1018     // it's handled separately by Qt.
1019     if (event->key() == KGlobalSettings::contextMenuKey()) {
1020         int row = d->canvas->selection()->marker().y();
1021         int col = d->canvas->selection()->marker().x();
1022         QPointF p(sheet->columnPosition(col), sheet->rowPosition(row));
1023         d->canvas->view()->openPopupMenu(d->canvas->mapToGlobal(p.toPoint()));
1024     }
1025 #endif
1026     switch (event->key()) {
1027     case Qt::Key_Return:
1028     case Qt::Key_Enter:
1029         d->processEnterKey(event);
1030         return;
1031         break;
1032     case Qt::Key_Down:
1033     case Qt::Key_Up:
1034     case Qt::Key_Left:
1035     case Qt::Key_Right:
1036     case Qt::Key_Tab: /* a tab behaves just like a right/left arrow */
1037     case Qt::Key_Backtab:  /* and so does Shift+Tab */
1038         if (event->modifiers() & Qt::ControlModifier) {
1039             if (!d->processControlArrowKey(event))
1040                 return;
1041         } else {
1042             d->processArrowKey(event);
1043             return;
1044         }
1045         break;
1046 
1047     case Qt::Key_Escape:
1048         d->processEscapeKey(event);
1049         return;
1050         break;
1051 
1052     case Qt::Key_Home:
1053         if (!d->processHomeKey(event))
1054             return;
1055         break;
1056 
1057     case Qt::Key_End:
1058         if (!d->processEndKey(event))
1059             return;
1060         break;
1061 
1062     case Qt::Key_PageUp:  /* Page Up */
1063         if (!d->processPriorKey(event))
1064             return;
1065         break;
1066 
1067     case Qt::Key_PageDown:   /* Page Down */
1068         if (!d->processNextKey(event))
1069             return;
1070         break;
1071 
1072     case Qt::Key_Backspace:
1073     case Qt::Key_Delete:
1074 	clearContents();
1075 	break;
1076 
1077     case Qt::Key_F2:
1078 	edit();
1079 	break;
1080 
1081     default:
1082         d->processOtherKey(event);
1083         return;
1084         break;
1085     }
1086 }
1087 
inputMethodEvent(QInputMethodEvent * event)1088 void CellToolBase::inputMethodEvent(QInputMethodEvent * event)
1089 {
1090     // Send it to the embedded editor.
1091     if (editor()) {
1092         QApplication::sendEvent(editor()->widget(), event);
1093     }
1094 }
1095 
activate(ToolActivation toolActivation,const QSet<KoShape * > & shapes)1096 void CellToolBase::activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes)
1097 {
1098     Q_UNUSED(toolActivation);
1099     Q_UNUSED(shapes);
1100 
1101     if (!d->initialized) {
1102         init();
1103         d->initialized = true;
1104     }
1105 
1106     useCursor(Qt::ArrowCursor);
1107 
1108 
1109     // paint the selection rectangle
1110     selection()->update();
1111     populateWordCollection();
1112     // Initialize cell style selection action.
1113     const StyleManager* styleManager = selection()->activeSheet()->map()->styleManager();
1114     static_cast<KSelectAction*>(this->action("setStyle"))->setItems(styleManager->styleNames());
1115 
1116     // Establish connections.
1117     connect(selection(), SIGNAL(changed(Region)),
1118             this, SLOT(selectionChanged(Region)));
1119     connect(selection(), SIGNAL(closeEditor(bool,bool)),
1120             this, SLOT(deleteEditor(bool,bool)));
1121     connect(selection(), SIGNAL(modified(Region)),
1122             this, SLOT(updateEditor()));
1123     connect(selection(), SIGNAL(activeSheetChanged(Sheet*)),
1124             this, SLOT(activeSheetChanged(Sheet*)));
1125     connect(selection(), SIGNAL(requestFocusEditor()),
1126             this, SLOT(focusEditorRequested()));
1127     connect(selection(), SIGNAL(documentReadWriteToggled(bool)),
1128             this, SLOT(documentReadWriteToggled(bool)));
1129     connect(selection(), SIGNAL(sheetProtectionToggled(bool)),
1130             this, SLOT(sheetProtectionToggled(bool)));
1131 }
1132 
deactivate()1133 void CellToolBase::deactivate()
1134 {
1135     Selection *sel = selection();
1136     // Disconnect.
1137     if (sel) disconnect(sel, 0, this, 0);
1138     // close the cell editor
1139     deleteEditor(true); // save changes
1140     // clear the selection rectangle
1141     if (sel) sel->update();
1142 }
1143 
init()1144 void CellToolBase::init()
1145 {
1146 }
1147 
createOptionWidgets()1148 QList<QPointer<QWidget> >  CellToolBase::createOptionWidgets()
1149 {
1150     QList<QPointer<QWidget> > widgets;
1151 
1152     QString xmlName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligrasheets/CellToolOptionWidgets.xml");
1153     debugSheets << xmlName;
1154     if (xmlName.isEmpty()) {
1155         warnSheets << "couldn't find CellToolOptionWidgets.xml file";
1156         return widgets;
1157     }
1158 
1159     QFile f(xmlName);
1160     if (!f.open(QIODevice::ReadOnly)) {
1161         warnSheets << "couldn't open CellToolOptionWidgets.xml file";
1162         return widgets;
1163     }
1164 
1165     QDomDocument doc(QString::fromLatin1("optionWidgets"));
1166     QString errorMsg;
1167     int errorLine, errorCol;
1168     if (!doc.setContent(&f, &errorMsg, &errorLine, &errorCol)) {
1169         f.close();
1170         warnSheets << "couldn't parse CellToolOptionWidgets.xml file:" << errorMsg << "on line" << errorLine << "column" << errorCol;
1171         return widgets;
1172     }
1173     f.close();
1174 
1175     QDomNodeList widgetNodes = doc.elementsByTagName("optionWidget");
1176     for (int i = 0; i < widgetNodes.size(); ++i) {
1177         QDomElement e = widgetNodes.at(i).toElement();
1178         widgets.append(new ActionOptionWidget(this, e));
1179     }
1180 
1181     return widgets;
1182 }
1183 
1184 // TODO: while this event sends the offset-adjusted position, the subsequent handleMouseMove calls do not. This means that they all contain the offset adjustment themselves, which is a needless duplication. Should be improved.
createStrategy(KoPointerEvent * event)1185 KoInteractionStrategy* CellToolBase::createStrategy(KoPointerEvent* event)
1186 {
1187     // Get info about where the event occurred.
1188     QPointF position = event->point - offset(); // the shape offset, not the scrolling one.
1189 
1190     // Autofilling or merging, if the selection handle was hit.
1191     if (SelectionStrategy::hitTestSelectionSizeGrip(canvas(), selection(), position)) {
1192         if (event->button() == Qt::LeftButton)
1193             return new AutoFillStrategy(this, position, event->modifiers());
1194         else if (event->button() == Qt::MidButton)
1195             return new MergeStrategy(this, position, event->modifiers());
1196     }
1197 
1198     // Pasting with the middle mouse button.
1199     if (event->button() == Qt::MidButton) {
1200         return new PasteStrategy(this, position, event->modifiers());
1201     }
1202 
1203     // Check, if the selected area was hit.
1204     bool hitSelection = false;
1205     Region::ConstIterator end = selection()->constEnd();
1206     for (Region::ConstIterator it = selection()->constBegin(); it != end; ++it) {
1207         const QRect range = (*it)->rect();
1208         if (selection()->activeSheet()->cellCoordinatesToDocument(range).contains(position)) {
1209             // Context menu with the right mouse button.
1210             if (event->button() == Qt::RightButton) {
1211                 // Setup the context menu.
1212                 setPopupActionList(d->popupActionList());
1213                 event->ignore();
1214                 return 0; // Act directly; no further strategy needed.
1215             }
1216             hitSelection = true;
1217             break;
1218         }
1219     }
1220 
1221     // In which cell did the user click?
1222     qreal xpos;
1223     qreal ypos;
1224     const int col = this->selection()->activeSheet()->leftColumn(position.x(), xpos);
1225     const int row = this->selection()->activeSheet()->topRow(position.y(), ypos);
1226     // Check boundaries.
1227     if (col > maxCol() || row > maxRow()) {
1228         debugSheetsUI << "col or row is out of range:" << "col:" << col << " row:" << row;
1229     } else {
1230         // Context menu with the right mouse button.
1231         if (event->button() == Qt::RightButton) {
1232             selection()->initialize(QPoint(col, row), selection()->activeSheet());
1233             // Setup the context menu.
1234             setPopupActionList(d->popupActionList());
1235             event->ignore();
1236             return 0; // Act directly; no further strategy needed.
1237         } else {
1238             const Cell cell = Cell(selection()->activeSheet(), col, row).masterCell();
1239             SheetView* const sheetView = this->sheetView(selection()->activeSheet());
1240 
1241             // Filter button hit.
1242             const double offsetX = canvas()->canvasController()->canvasOffsetX();
1243             const double offsetY = canvas()->canvasController()->canvasOffsetY();
1244             const QPointF p1 = QPointF(xpos, ypos) - offset(); // the shape offset, not the scrolling one.
1245             const QSizeF s1(cell.width(), cell.height());
1246             const QRectF cellRect = canvas()->viewConverter()->documentToView(QRectF(p1, s1));
1247             const QRect cellViewRect = cellRect.translated(offsetX, offsetY).toRect();
1248             if (sheetView->cellView(col, row).hitTestFilterButton(cell, cellViewRect, event->pos())) {
1249                 Database database = cell.database();
1250                 FilterPopup::showPopup(canvas()->canvasWidget(), cell, cellViewRect, &database);
1251                 return 0; // Act directly; no further strategy needed.
1252             }
1253 
1254             // Hyperlink hit.
1255             QString url;
1256             const CellView& cellView = sheetView->cellView(col, row);
1257             if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft) {
1258                 url = cellView.testAnchor(sheetView, cell, cell.width() - position.x() + xpos, position.y() - ypos);
1259             } else {
1260                 url = cellView.testAnchor(sheetView, cell, position.x() - xpos, position.y() - ypos);
1261             }
1262             if (!url.isEmpty()) {
1263                 return new HyperlinkStrategy(this, position,
1264                                              event->modifiers(), url, cellView.textRect());
1265             }
1266         }
1267     }
1268 
1269     // Do we want to drag and drop the selection?
1270     bool wantDragDrop = hitSelection;
1271     if (event->modifiers() & Qt::ControlModifier) wantDragDrop = false;   // no drag&drop if Ctrl is pressed
1272     QRect selRect = selection()->boundingRect();
1273     // no drag&drop if it's a single cell, assume they want a selection
1274     if ((selRect.width() <= 1) && (selRect.height() <= 1)) wantDragDrop = false;
1275     if (selection()->referenceSelectionMode()) wantDragDrop = false;
1276     if (wantDragDrop)
1277         return new DragAndDropStrategy(this, position, event->modifiers());
1278 
1279     return new SelectionStrategy(this, position, event->modifiers());
1280 }
1281 
selectionChanged(const Region & region)1282 void CellToolBase::selectionChanged(const Region& region)
1283 {
1284     Q_UNUSED(region);
1285     if (!d->externalEditor) {
1286         return;
1287     }
1288     // Update the editor, if the reference selection is enabled.
1289     if (editor() && selection()->referenceSelectionMode()) {
1290         // First, update the formula expression. This will send a signal with
1291         // the new expression to the external editor, which does not have focus
1292         // yet (the canvas has). If it would have, it would also send a signal
1293         // to inform the embedded editor about a changed text.
1294         editor()->selectionChanged();
1295         // Focus the embedded or external editor after updating the expression.
1296         focusEditorRequested();
1297         return;
1298     }
1299 
1300     // State of manual page breaks before columns/rows.
1301     bool columnBreakChecked = false;
1302     bool columnBreakEnabled = false;
1303     bool rowBreakChecked = false;
1304     bool rowBreakEnabled = false;
1305     const Region::ConstIterator end(selection()->constEnd());
1306     for (Region::ConstIterator it = selection()->constBegin(); it != end; ++it) {
1307         const Sheet *const sheet = (*it)->sheet();
1308         if (!sheet) {
1309             continue;
1310         }
1311         const QRect range = (*it)->rect();
1312         const int column = range.left();
1313         const int row = range.top();
1314         columnBreakChecked |= sheet->columnFormat(column)->hasPageBreak();
1315         columnBreakEnabled |= (column != 1);
1316         rowBreakChecked |= sheet->rowFormats()->hasPageBreak(row);
1317         rowBreakEnabled |= (row != 1);
1318     }
1319     action("format_break_before_column")->setChecked(columnBreakChecked);
1320     action("format_break_before_column")->setEnabled(columnBreakEnabled);
1321     action("format_break_before_row")->setChecked(rowBreakChecked);
1322     action("format_break_before_row")->setEnabled(rowBreakEnabled);
1323 
1324     const Cell cell = Cell(selection()->activeSheet(), selection()->cursor());
1325     if (!cell) {
1326         return;
1327     }
1328     d->updateEditor(cell);
1329     d->updateActions(cell);
1330 
1331     if (selection()->activeSheet()->isProtected()) {
1332         const Style style = cell.style();
1333         if (style.notProtected()) {
1334             if (selection()->isSingular()) {
1335                 if (!action("bold")->isEnabled()) {
1336                     d->setProtectedActionsEnabled(true);
1337                 }
1338             } else { // more than one cell
1339                 if (action("bold")->isEnabled()) {
1340                     d->setProtectedActionsEnabled(false);
1341                 }
1342             }
1343         } else {
1344             if (action("bold")->isEnabled()) {
1345                 d->setProtectedActionsEnabled(false);
1346             }
1347         }
1348     }
1349 }
1350 
scrollToCell(const QPoint & location)1351 void CellToolBase::scrollToCell(const QPoint &location)
1352 {
1353     Sheet *const sheet = selection()->activeSheet();
1354 
1355     // Adjust the maximum accessed column and row for the scrollbars.
1356     sheetView(sheet)->updateAccessedCellRange(location);
1357 
1358     // The cell geometry expanded by some pixels in each direction.
1359     const Cell cell = Cell(sheet, location).masterCell();
1360     const double xpos = sheet->columnPosition(cell.cellPosition().x());
1361     const double ypos = sheet->rowPosition(cell.cellPosition().y());
1362     const double pixelWidth = canvas()->viewConverter()->viewToDocumentX(1);
1363     const double pixelHeight = canvas()->viewConverter()->viewToDocumentY(1);
1364     QRectF rect(xpos, ypos, cell.width(), cell.height());
1365     rect.adjust(-2*pixelWidth, -2*pixelHeight, +2*pixelWidth, +2*pixelHeight);
1366     rect = rect & QRectF(QPointF(0.0, 0.0), sheet->documentSize());
1367 
1368     // Scroll to cell.
1369     canvas()->canvasController()->ensureVisible(canvas()->viewConverter()->documentToView(rect), true);
1370 }
1371 
editor() const1372 CellEditorBase* CellToolBase::editor() const
1373 {
1374     return d->cellEditor;
1375 }
1376 
setLastEditorWithFocus(Editor editor)1377 void CellToolBase::setLastEditorWithFocus(Editor editor)
1378 {
1379     d->lastEditorWithFocus = editor;
1380 }
1381 
createEditor(bool clear,bool focus,bool captureArrows)1382 bool CellToolBase::createEditor(bool clear, bool focus, bool captureArrows)
1383 {
1384     const Cell cell(selection()->activeSheet(), selection()->marker());
1385     if (selection()->activeSheet()->isProtected() && !cell.style().notProtected())
1386         return false;
1387 
1388     if (!editor()) {
1389         d->cellEditor = new CellEditor(this, d->wordCollection,canvas()->canvasWidget());
1390         d->cellEditor->setEditorFont(cell.style().font(), true, canvas()->viewConverter());
1391         connect(action("permuteFixation"), SIGNAL(triggered(bool)),
1392                 d->cellEditor, SLOT(permuteFixation()));
1393 
1394         if(d->externalEditor) {
1395             connect(d->cellEditor, SIGNAL(textChanged(QString)),
1396                     d->externalEditor, SLOT(setText(QString)));
1397             connect(d->externalEditor, SIGNAL(textChanged(QString)),
1398                     d->cellEditor, SLOT(setText(QString)));
1399             d->externalEditor->applyAction()->setEnabled(true);
1400             d->externalEditor->cancelAction()->setEnabled(true);
1401         }
1402 
1403         double w = cell.width();
1404         double h = cell.height();
1405         double min_w = cell.width();
1406         double min_h = cell.height();
1407 
1408         double xpos = selection()->activeSheet()->columnPosition(selection()->marker().x());
1409         xpos += canvas()->viewConverter()->viewToDocumentX(canvas()->canvasController()->canvasOffsetX());
1410 
1411         Qt::LayoutDirection sheetDir = selection()->activeSheet()->layoutDirection();
1412         bool rtlText = cell.displayText().isRightToLeft();
1413 
1414         // if sheet and cell direction don't match, then the editor's location
1415         // needs to be shifted backwards so that it's right above the cell's text
1416         if (w > 0 && ((sheetDir == Qt::RightToLeft && !rtlText) ||
1417                       (sheetDir == Qt::LeftToRight && rtlText)))
1418             xpos -= w - min_w;
1419 
1420         // paint editor above correct cell if sheet direction is RTL
1421         if (sheetDir == Qt::RightToLeft) {
1422             double dwidth = canvas()->viewConverter()->viewToDocumentX(canvas()->canvasWidget()->width());
1423             double w2 = qMax(w, min_w);
1424             xpos = dwidth - w2 - xpos;
1425         }
1426 
1427         double ypos = selection()->activeSheet()->rowPosition(selection()->marker().y());
1428         ypos += canvas()->viewConverter()->viewToDocumentY(canvas()->canvasController()->canvasOffsetY());
1429 
1430         // Setup the editor's palette.
1431         const Style style = cell.effectiveStyle();
1432         QPalette editorPalette(d->cellEditor->palette());
1433         QColor color = style.fontColor();
1434         if (!color.isValid())
1435             color = canvas()->canvasWidget()->palette().text().color();
1436         editorPalette.setColor(QPalette::Text, color);
1437         color = style.backgroundColor();
1438         if (!color.isValid())
1439             color = editorPalette.base().color();
1440         editorPalette.setColor(QPalette::Background, color);
1441         d->cellEditor->setPalette(editorPalette);
1442 
1443         // apply (table shape) offset
1444         xpos += offset().x();
1445         ypos += offset().y();
1446 
1447         const QRectF rect(xpos + 0.5, ypos + 0.5, w - 0.5, h - 0.5); //needed to circumvent rounding issue with height/width
1448         const QRectF zoomedRect = canvas()->viewConverter()->documentToView(rect);
1449         d->cellEditor->setGeometry(zoomedRect.toRect().adjusted(1, 1, -1, -1));
1450         d->cellEditor->setMinimumSize(QSize((int)canvas()->viewConverter()->documentToViewX(min_w) - 1,
1451                                        (int)canvas()->viewConverter()->documentToViewY(min_h) - 1));
1452         d->cellEditor->show();
1453 
1454         // Laurent 2001-12-05
1455         // Don't add focus when we create a new editor and
1456         // we select text in edit widget otherwise we don't delete
1457         // selected text.
1458         if (focus)
1459             d->cellEditor->setFocus();
1460 
1461         // clear the selection rectangle
1462         selection()->update();
1463     }
1464 
1465     d->cellEditor->setCaptureArrowKeys(captureArrows);
1466 
1467     if (!clear && !cell.isNull()) {
1468         d->cellEditor->setText(cell.userInput());
1469         // place cursor at the end
1470         int pos = d->cellEditor->toPlainText().length();
1471         d->cellEditor->setCursorPosition(pos);
1472         if (d->externalEditor) d->externalEditor->setCursorPosition(pos);
1473     }
1474     return true;
1475 }
1476 
populateWordCollection()1477 void CellToolBase::populateWordCollection()
1478 {
1479   const CellStorage* cellstore=selection()->activeSheet()->cellStorage();
1480   ValueConverter *conv=0,*conv2=0;
1481   int lastrow=cellstore->rows();
1482   int lastcolumn=cellstore->columns();
1483   if( lastrow < 2000 && lastcolumn < 20) {
1484   for (int j=1 ; j <= lastcolumn ; j++) {
1485     for (int i=1; i<=lastrow ; i++) {
1486       Value val=Cell( selection()->activeSheet(), j, i).value();
1487       if(val.isString()) {
1488 	QString value=conv->toString( conv2->asString(val) );
1489 
1490 	if(!d->wordCollection.values(j).contains(value)){
1491 	    d->wordCollection.insertMulti(j, value);
1492 	  }
1493       }
1494     }
1495   }
1496   }
1497 }
1498 
deleteEditor(bool saveChanges,bool expandMatrix)1499 void CellToolBase::deleteEditor(bool saveChanges, bool expandMatrix)
1500 {
1501     if (!d->cellEditor) {
1502         return;
1503     }
1504     const QString userInput = d->cellEditor->toPlainText();
1505     d->cellEditor->hide();
1506     // Delete the cell editor first and after that update the document.
1507     // That means we get a synchronous repaint after the cell editor
1508     // widget is gone. Otherwise we may get painting errors.
1509     delete d->cellEditor;
1510     d->cellEditor = 0;
1511 
1512     delete d->formulaDialog;
1513     d->formulaDialog = 0;
1514 
1515     if (saveChanges) {
1516         applyUserInput(userInput, expandMatrix);
1517     } else {
1518         selection()->update();
1519     }
1520     if (d->externalEditor) {
1521         d->externalEditor->applyAction()->setEnabled(false);
1522         d->externalEditor->cancelAction()->setEnabled(false);
1523     }
1524     canvas()->canvasWidget()->setFocus();
1525 }
1526 
activeSheetChanged(Sheet * sheet)1527 void CellToolBase::activeSheetChanged(Sheet* sheet)
1528 {
1529 #ifdef NDEBUG
1530     Q_UNUSED(sheet);
1531 #else
1532     Q_ASSERT(selection()->activeSheet() == sheet);
1533 #endif
1534     populateWordCollection();
1535     if (!selection()->referenceSelectionMode()) {
1536         return;
1537     }
1538     if (editor()) {
1539         if (selection()->originSheet() != selection()->activeSheet()) {
1540             editor()->widget()->hide();
1541         } else {
1542             editor()->widget()->show();
1543         }
1544     }
1545     focusEditorRequested();
1546 }
1547 
updateEditor()1548 void CellToolBase::updateEditor()
1549 {
1550     if (!d->externalEditor) {
1551         return;
1552     }
1553     const Cell cell = Cell(selection()->activeSheet(), selection()->cursor());
1554     if (!cell) {
1555         return;
1556     }
1557     d->updateEditor(cell);
1558 }
1559 
focusEditorRequested()1560 void CellToolBase::focusEditorRequested()
1561 {
1562     // Nothing to do, if not in editing mode.
1563     if (!editor()) {
1564         return;
1565     }
1566     // If we are in editing mode, we redirect the focus to the CellEditor or ExternalEditor.
1567     // This screws up <Tab> though (David)
1568     if (selection()->originSheet() != selection()->activeSheet()) {
1569         // Always focus the external editor, if not on the origin sheet.
1570         if (d->externalEditor) d->externalEditor->setFocus();
1571     } else {
1572         // Focus the last active editor, if on the origin sheet.
1573         if (d->lastEditorWithFocus == EmbeddedEditor) {
1574             editor()->widget()->setFocus();
1575         } else {
1576             if (d->externalEditor) d->externalEditor->setFocus();
1577         }
1578     }
1579 }
1580 
applyUserInput(const QString & userInput,bool expandMatrix)1581 void CellToolBase::applyUserInput(const QString &userInput, bool expandMatrix)
1582 {
1583     QString text = userInput;
1584     if (!text.isEmpty() && text.at(0) == '=') {
1585         //a formula
1586         int openParenthese = text.count('(');
1587         int closeParenthese = text.count(')');
1588         int diff = qAbs(openParenthese - closeParenthese);
1589         if (openParenthese > closeParenthese) {
1590             for (int i = 0; i < diff; ++i) {
1591                 text += ')';
1592             }
1593         }
1594     }
1595     DataManipulator* command = new DataManipulator();
1596     command->setSheet(selection()->activeSheet());
1597     command->setValue(Value(text));
1598     command->setParsing(true);
1599     command->setExpandMatrix(expandMatrix);
1600     command->add(expandMatrix ? *selection() : Region(selection()->cursor(), selection()->activeSheet()));
1601     command->execute(canvas());
1602 
1603     if (expandMatrix && selection()->isSingular())
1604         selection()->initialize(*command);
1605 
1606     Cell cell = Cell(selection()->activeSheet(), selection()->marker());
1607     if (cell.value().isString() && !text.isEmpty() && !text.at(0).isDigit() && !cell.isFormula()) {
1608         selection()->activeSheet()->map()->addStringCompletion(text);
1609     }
1610 }
1611 
documentReadWriteToggled(bool readWrite)1612 void CellToolBase::documentReadWriteToggled(bool readWrite)
1613 {
1614     d->setProtectedActionsEnabled(readWrite);
1615 }
1616 
sheetProtectionToggled(bool protect)1617 void CellToolBase::sheetProtectionToggled(bool protect)
1618 {
1619     d->setProtectedActionsEnabled(!protect);
1620 }
1621 
cellStyle()1622 void CellToolBase::cellStyle()
1623 {
1624     QPointer<CellFormatDialog> dialog = new CellFormatDialog(canvas()->canvasWidget(), selection());
1625     dialog->exec();
1626     delete dialog;
1627 }
1628 
setDefaultStyle()1629 void CellToolBase::setDefaultStyle()
1630 {
1631     StyleCommand* command = new StyleCommand();
1632     command->setSheet(selection()->activeSheet());
1633     command->setDefault();
1634     command->add(*selection());
1635     command->execute(canvas());
1636 }
1637 
styleDialog()1638 void CellToolBase::styleDialog()
1639 {
1640     Map* const map = selection()->activeSheet()->map();
1641     StyleManager* const styleManager = map->styleManager();
1642     QPointer<StyleManagerDialog> dialog = new StyleManagerDialog(canvas()->canvasWidget(), selection(), styleManager);
1643     dialog->exec();
1644     delete dialog;
1645 
1646     static_cast<KSelectAction*>(action("setStyle"))->setItems(styleManager->styleNames());
1647     if (selection()->activeSheet())
1648         map->addDamage(new CellDamage(selection()->activeSheet(), Region(1, 1, maxCol(), maxRow()), CellDamage::Appearance));
1649     canvas()->canvasWidget()->update();
1650 }
1651 
setStyle(const QString & stylename)1652 void CellToolBase::setStyle(const QString& stylename)
1653 {
1654     debugSheets << "CellToolBase::setStyle(" << stylename << ")";
1655     if (selection()->activeSheet()->map()->styleManager()->style(stylename)) {
1656         StyleCommand* command = new StyleCommand();
1657         command->setSheet(selection()->activeSheet());
1658         command->setParentName(stylename);
1659         command->add(*selection());
1660         command->execute(canvas());
1661     }
1662 }
1663 
createStyleFromCell()1664 void CellToolBase::createStyleFromCell()
1665 {
1666     QPoint p(selection()->marker());
1667     Cell cell = Cell(selection()->activeSheet(), p.x(), p.y());
1668 
1669     bool ok = false;
1670     QString styleName("");
1671 
1672     while (true) {
1673         styleName = QInputDialog::getText(canvas()->canvasWidget(),
1674                                           i18n("Create Style From Cell"),
1675                                           i18n("Enter name:"), QLineEdit::Normal, styleName, &ok);
1676 
1677         if (!ok) // User pushed an OK button.
1678             return;
1679 
1680         styleName = styleName.trimmed();
1681 
1682         if (styleName.length() < 1) {
1683             KMessageBox::sorry(canvas()->canvasWidget(), i18n("The style name cannot be empty."));
1684             continue;
1685         }
1686 
1687         if (selection()->activeSheet()->map()->styleManager()->style(styleName) != 0) {
1688             KMessageBox::sorry(canvas()->canvasWidget(), i18n("A style with this name already exists."));
1689             continue;
1690         }
1691         break;
1692     }
1693 
1694     const Style cellStyle = cell.style();
1695     CustomStyle*  style = new CustomStyle(styleName);
1696     style->merge(cellStyle);
1697 
1698     selection()->activeSheet()->map()->styleManager()->insertStyle(style);
1699     cell.setStyle(*style);
1700     QStringList functionList(static_cast<KSelectAction*>(action("setStyle"))->items());
1701     functionList.push_back(styleName);
1702     static_cast<KSelectAction*>(action("setStyle"))->setItems(functionList);
1703 }
1704 
bold(bool enable)1705 void CellToolBase::bold(bool enable)
1706 {
1707     StyleCommand* command = new StyleCommand();
1708     command->setSheet(selection()->activeSheet());
1709     command->setText(kundo2_i18n("Change Font"));
1710     command->setFontBold(enable);
1711     command->add(*selection());
1712     command->execute(canvas());
1713     if (editor()) {
1714         const Cell cell = Cell(selection()->activeSheet(), selection()->marker());
1715         editor()->setEditorFont(cell.style().font(), true, canvas()->viewConverter());
1716     }
1717 }
1718 
underline(bool enable)1719 void CellToolBase::underline(bool enable)
1720 {
1721     StyleCommand* command = new StyleCommand();
1722     command->setSheet(selection()->activeSheet());
1723     command->setText(kundo2_i18n("Change Font"));
1724     command->setFontUnderline(enable);
1725     command->add(*selection());
1726     command->execute(canvas());
1727     if (editor()) {
1728         const Cell cell = Cell(selection()->activeSheet(), selection()->marker());
1729         editor()->setEditorFont(cell.style().font(), true, canvas()->viewConverter());
1730     }
1731 }
1732 
strikeOut(bool enable)1733 void CellToolBase::strikeOut(bool enable)
1734 {
1735     StyleCommand* command = new StyleCommand();
1736     command->setSheet(selection()->activeSheet());
1737     command->setText(kundo2_i18n("Change Font"));
1738     command->setFontStrike(enable);
1739     command->add(*selection());
1740     command->execute(canvas());
1741     if (editor()) {
1742         const Cell cell = Cell(selection()->activeSheet(), selection()->marker());
1743         editor()->setEditorFont(cell.style().font(), true, canvas()->viewConverter());
1744     }
1745 }
1746 
1747 
italic(bool enable)1748 void CellToolBase::italic(bool enable)
1749 {
1750     StyleCommand* command = new StyleCommand();
1751     command->setSheet(selection()->activeSheet());
1752     command->setText(kundo2_i18n("Change Font"));
1753     command->setFontItalic(enable);
1754     command->add(*selection());
1755     command->execute(canvas());
1756     if (editor()) {
1757         const Cell cell = Cell(selection()->activeSheet(), selection()->marker());
1758         editor()->setEditorFont(cell.style().font(), true, canvas()->viewConverter());
1759     }
1760 }
1761 
font(const QString & font)1762 void CellToolBase::font(const QString& font)
1763 {
1764     StyleCommand* command = new StyleCommand();
1765     command->setSheet(selection()->activeSheet());
1766     command->setText(kundo2_i18n("Change Font"));
1767     command->setFontFamily(font.toLatin1());
1768     command->add(*selection());
1769     command->execute(canvas());
1770     // Don't leave the focus in the toolbars combo box ...
1771     if (editor()) {
1772         const Style style = Cell(selection()->activeSheet(), selection()->marker()).style();
1773         editor()->setEditorFont(style.font(), true, canvas()->viewConverter());
1774         focusEditorRequested();
1775     } else {
1776         canvas()->canvasWidget()->setFocus();
1777     }
1778 }
1779 
fontSize(int size)1780 void CellToolBase::fontSize(int size)
1781 {
1782     StyleCommand* command = new StyleCommand();
1783     command->setSheet(selection()->activeSheet());
1784     command->setText(kundo2_i18n("Change Font"));
1785     command->setFontSize(size);
1786     command->add(*selection());
1787     command->execute(canvas());
1788     // Don't leave the focus in the toolbars combo box ...
1789     if (editor()) {
1790         const Cell cell(selection()->activeSheet(), selection()->marker());
1791         editor()->setEditorFont(cell.style().font(), true, canvas()->viewConverter());
1792         focusEditorRequested();
1793     } else {
1794         canvas()->canvasWidget()->setFocus();
1795     }
1796 }
1797 
increaseFontSize()1798 void CellToolBase::increaseFontSize()
1799 {
1800     const Style style = Cell(selection()->activeSheet(), selection()->marker()).style();
1801     const int size = style.fontSize();
1802 
1803     StyleCommand* command = new StyleCommand();
1804     command->setSheet(selection()->activeSheet());
1805     command->setText(kundo2_i18n("Change Font"));
1806     command->setFontSize(size + 1);
1807     command->add(*selection());
1808     command->execute(canvas());
1809 }
1810 
decreaseFontSize()1811 void CellToolBase::decreaseFontSize()
1812 {
1813     const Style style = Cell(selection()->activeSheet(), selection()->marker()).style();
1814     const int size = style.fontSize();
1815 
1816     StyleCommand* command = new StyleCommand();
1817     command->setSheet(selection()->activeSheet());
1818     command->setText(kundo2_i18n("Change Font"));
1819     command->setFontSize(size - 1);
1820     command->add(*selection());
1821     command->execute(canvas());
1822 }
1823 
changeTextColor(const KoColor & color)1824 void CellToolBase::changeTextColor(const KoColor &color)
1825 {
1826     StyleCommand* command = new StyleCommand();
1827     command->setSheet(selection()->activeSheet());
1828     command->setText(kundo2_i18n("Change Text Color"));
1829     command->setFontColor(color.toQColor());
1830     command->add(*selection());
1831     command->execute(canvas());
1832 }
1833 
alignLeft(bool enable)1834 void CellToolBase::alignLeft(bool enable)
1835 {
1836     StyleCommand* command = new StyleCommand();
1837     command->setSheet(selection()->activeSheet());
1838     command->setText(kundo2_i18n("Change Horizontal Alignment"));
1839     command->setHorizontalAlignment(enable ? Style::Left : Style::HAlignUndefined);
1840     command->add(*selection());
1841     command->execute(canvas());
1842 }
1843 
alignRight(bool enable)1844 void CellToolBase::alignRight(bool enable)
1845 {
1846     StyleCommand* command = new StyleCommand();
1847     command->setSheet(selection()->activeSheet());
1848     command->setText(kundo2_i18n("Change Horizontal Alignment"));
1849     command->setHorizontalAlignment(enable ? Style::Right : Style::HAlignUndefined);
1850     command->add(*selection());
1851     command->execute(canvas());
1852 }
1853 
alignCenter(bool enable)1854 void CellToolBase::alignCenter(bool enable)
1855 {
1856     StyleCommand* command = new StyleCommand();
1857     command->setSheet(selection()->activeSheet());
1858     command->setText(kundo2_i18n("Change Horizontal Alignment"));
1859     command->setHorizontalAlignment(enable ? Style::Center : Style::HAlignUndefined);
1860     command->add(*selection());
1861     command->execute(canvas());
1862 }
1863 
alignTop(bool enable)1864 void CellToolBase::alignTop(bool enable)
1865 {
1866     StyleCommand* command = new StyleCommand();
1867     command->setSheet(selection()->activeSheet());
1868     command->setText(kundo2_i18n("Change Vertical Alignment"));
1869     command->setVerticalAlignment(enable ? Style::Top : Style::VAlignUndefined);
1870     command->add(*selection());
1871     command->execute(canvas());
1872 }
1873 
alignBottom(bool enable)1874 void CellToolBase::alignBottom(bool enable)
1875 {
1876     StyleCommand* command = new StyleCommand();
1877     command->setSheet(selection()->activeSheet());
1878     command->setText(kundo2_i18n("Change Vertical Alignment"));
1879     command->setVerticalAlignment(enable ? Style::Bottom : Style::VAlignUndefined);
1880     command->add(*selection());
1881     command->execute(canvas());
1882 }
1883 
alignMiddle(bool enable)1884 void CellToolBase::alignMiddle(bool enable)
1885 {
1886     StyleCommand* command = new StyleCommand();
1887     command->setSheet(selection()->activeSheet());
1888     command->setText(kundo2_i18n("Change Vertical Alignment"));
1889     command->setVerticalAlignment(enable ? Style::Middle : Style::VAlignUndefined);
1890     command->add(*selection());
1891     command->execute(canvas());
1892 }
1893 
borderLeft()1894 void CellToolBase::borderLeft()
1895 {
1896     QColor color = static_cast<KoColorPopupAction*>(action("borderColor"))->currentColor();
1897     StyleCommand* command = new StyleCommand();
1898     command->setSheet(selection()->activeSheet());
1899     command->setText(kundo2_i18n("Change Border"));
1900     if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft)
1901         command->setRightBorderPen(QPen(color, 1, Qt::SolidLine));
1902     else
1903         command->setLeftBorderPen(QPen(color, 1, Qt::SolidLine));
1904     command->add(*selection());
1905     command->execute(canvas());
1906 }
1907 
borderRight()1908 void CellToolBase::borderRight()
1909 {
1910     QColor color = static_cast<KoColorPopupAction*>(action("borderColor"))->currentColor();
1911     StyleCommand* command = new StyleCommand();
1912     command->setSheet(selection()->activeSheet());
1913     command->setText(kundo2_i18n("Change Border"));
1914     if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft)
1915         command->setLeftBorderPen(QPen(color, 1, Qt::SolidLine));
1916     else
1917         command->setRightBorderPen(QPen(color, 1, Qt::SolidLine));
1918     command->add(*selection());
1919     command->execute(canvas());
1920 }
1921 
borderTop()1922 void CellToolBase::borderTop()
1923 {
1924     QColor color = static_cast<KoColorPopupAction*>(action("borderColor"))->currentColor();
1925     StyleCommand* command = new StyleCommand();
1926     command->setSheet(selection()->activeSheet());
1927     command->setText(kundo2_i18n("Change Border"));
1928     command->setTopBorderPen(QPen(color, 1, Qt::SolidLine));
1929     command->add(*selection());
1930     command->execute(canvas());
1931 }
1932 
borderBottom()1933 void CellToolBase::borderBottom()
1934 {
1935     QColor color = static_cast<KoColorPopupAction*>(action("borderColor"))->currentColor();
1936     StyleCommand* command = new StyleCommand();
1937     command->setSheet(selection()->activeSheet());
1938     command->setText(kundo2_i18n("Change Border"));
1939     command->setBottomBorderPen(QPen(color, 1, Qt::SolidLine));
1940     command->add(*selection());
1941     command->execute(canvas());
1942 }
1943 
borderAll()1944 void CellToolBase::borderAll()
1945 {
1946     QColor color = static_cast<KoColorPopupAction*>(action("borderColor"))->currentColor();
1947     StyleCommand* command = new StyleCommand();
1948     command->setSheet(selection()->activeSheet());
1949     command->setText(kundo2_i18n("Change Border"));
1950     command->setTopBorderPen(QPen(color, 1, Qt::SolidLine));
1951     command->setBottomBorderPen(QPen(color, 1, Qt::SolidLine));
1952     command->setLeftBorderPen(QPen(color, 1, Qt::SolidLine));
1953     command->setRightBorderPen(QPen(color, 1, Qt::SolidLine));
1954     command->setHorizontalPen(QPen(color, 1, Qt::SolidLine));
1955     command->setVerticalPen(QPen(color, 1, Qt::SolidLine));
1956     command->add(*selection());
1957     command->execute(canvas());
1958 }
1959 
borderRemove()1960 void CellToolBase::borderRemove()
1961 {
1962     StyleCommand* command = new StyleCommand();
1963     command->setSheet(selection()->activeSheet());
1964     command->setText(kundo2_i18n("Change Border"));
1965     command->setTopBorderPen(QPen(Qt::NoPen));
1966     command->setBottomBorderPen(QPen(Qt::NoPen));
1967     command->setLeftBorderPen(QPen(Qt::NoPen));
1968     command->setRightBorderPen(QPen(Qt::NoPen));
1969     command->setHorizontalPen(QPen(Qt::NoPen));
1970     command->setVerticalPen(QPen(Qt::NoPen));
1971     command->add(*selection());
1972     command->execute(canvas());
1973 }
1974 
borderOutline()1975 void CellToolBase::borderOutline()
1976 {
1977     QColor color = static_cast<KoColorPopupAction*>(action("borderColor"))->currentColor();
1978     StyleCommand* command = new StyleCommand();
1979     command->setSheet(selection()->activeSheet());
1980     command->setText(kundo2_i18n("Change Border"));
1981     command->setTopBorderPen(QPen(color, 1, Qt::SolidLine));
1982     command->setBottomBorderPen(QPen(color, 1, Qt::SolidLine));
1983     command->setLeftBorderPen(QPen(color, 1, Qt::SolidLine));
1984     command->setRightBorderPen(QPen(color, 1, Qt::SolidLine));
1985     command->add(*selection());
1986     command->execute(canvas());
1987 }
1988 
borderColor(const KoColor & color)1989 void CellToolBase::borderColor(const KoColor &color)
1990 {
1991     BorderColorCommand* command = new BorderColorCommand();
1992     command->setSheet(selection()->activeSheet());
1993     command->setColor(color.toQColor());
1994     command->add(*selection());
1995     command->execute(canvas());
1996 }
1997 
wrapText(bool enable)1998 void CellToolBase::wrapText(bool enable)
1999 {
2000     StyleCommand* command = new StyleCommand();
2001     command->setSheet(selection()->activeSheet());
2002     command->setText(kundo2_i18n("Wrap Text"));
2003     command->setMultiRow(enable);
2004     command->setVerticalText(false);
2005     command->setAngle(0);
2006     command->add(*selection());
2007     command->execute(canvas());
2008 }
2009 
verticalText(bool enable)2010 void CellToolBase::verticalText(bool enable)
2011 {
2012     StyleCommand* command = new StyleCommand();
2013     command->setSheet(selection()->activeSheet());
2014     command->setText(kundo2_i18n("Vertical Text"));
2015     command->setVerticalText(enable);
2016     command->setMultiRow(false);
2017     command->setAngle(0);
2018     command->add(*selection());
2019     command->execute(canvas());
2020 }
2021 
increaseIndentation()2022 void CellToolBase::increaseIndentation()
2023 {
2024     IndentationCommand* command = new IndentationCommand();
2025     command->setSheet(selection()->activeSheet());
2026     command->add(*selection());
2027     if (!command->execute())
2028         delete command;
2029 }
2030 
decreaseIndentation()2031 void CellToolBase::decreaseIndentation()
2032 {
2033     IndentationCommand* command = new IndentationCommand();
2034     command->setSheet(selection()->activeSheet());
2035     command->setReverse(true);
2036     command->add(*selection());
2037     if (!command->execute())
2038         delete command;
2039 }
2040 
changeAngle()2041 void CellToolBase::changeAngle()
2042 {
2043     QPointer<AngleDialog> dialog = new AngleDialog(canvas()->canvasWidget(), selection());
2044     dialog->exec();
2045     delete dialog;
2046 }
2047 
percent(bool enable)2048 void CellToolBase::percent(bool enable)
2049 {
2050     StyleCommand* command = new StyleCommand();
2051     command->setSheet(selection()->activeSheet());
2052     command->setText(kundo2_i18n("Format Percent"));
2053     command->setFormatType(enable ? Format::Percentage : Format::Generic);
2054     command->add(*selection());
2055     command->execute(canvas());
2056 }
2057 
currency(bool enable)2058 void CellToolBase::currency(bool enable)
2059 {
2060     StyleCommand* command = new StyleCommand();
2061     command->setSheet(selection()->activeSheet());
2062     command->setText(kundo2_i18n("Format Money"));
2063     command->setFormatType(enable ? Format::Money : Format::Generic);
2064     command->setPrecision(enable ?  selection()->activeSheet()->map()->calculationSettings()->locale()->monetaryDecimalPlaces() : 0);
2065 
2066     command->add(*selection());
2067     command->execute(canvas());
2068 }
2069 
increasePrecision()2070 void CellToolBase::increasePrecision()
2071 {
2072     PrecisionCommand* command = new PrecisionCommand();
2073     command->setSheet(selection()->activeSheet());
2074     command->add(*selection());
2075     if (!command->execute())
2076         delete command;
2077 }
2078 
decreasePrecision()2079 void CellToolBase::decreasePrecision()
2080 {
2081     PrecisionCommand* command = new PrecisionCommand();
2082     command->setSheet(selection()->activeSheet());
2083     command->setReverse(true);
2084     command->add(*selection());
2085     if (!command->execute())
2086         delete command;
2087 }
2088 
toUpperCase()2089 void CellToolBase::toUpperCase()
2090 {
2091     CaseManipulator* command = new CaseManipulator;
2092     command->setSheet(selection()->activeSheet());
2093     command->setText(kundo2_i18n("Switch to uppercase"));
2094     command->changeMode(CaseManipulator::Upper);
2095     command->add(*selection());
2096     command->execute(canvas());
2097 }
2098 
toLowerCase()2099 void CellToolBase::toLowerCase()
2100 {
2101     CaseManipulator* command = new CaseManipulator;
2102     command->setSheet(selection()->activeSheet());
2103     command->setText(kundo2_i18n("Switch to lowercase"));
2104     command->changeMode(CaseManipulator::Lower);
2105     command->add(*selection());
2106     command->execute(canvas());
2107 }
2108 
firstLetterToUpperCase()2109 void CellToolBase::firstLetterToUpperCase()
2110 {
2111     CaseManipulator* command = new CaseManipulator;
2112     command->setSheet(selection()->activeSheet());
2113     command->setText(kundo2_i18n("First letter uppercase"));
2114     command->changeMode(CaseManipulator::FirstUpper);
2115     command->add(*selection());
2116     command->execute(canvas());
2117 }
2118 
changeBackgroundColor(const KoColor & color)2119 void CellToolBase::changeBackgroundColor(const KoColor &color)
2120 {
2121     StyleCommand* command = new StyleCommand();
2122     command->setSheet(selection()->activeSheet());
2123     command->setText(kundo2_i18n("Change Background Color"));
2124     command->setBackgroundColor(color.toQColor());
2125     command->add(*selection());
2126     command->execute(canvas());
2127 }
2128 
mergeCells()2129 void CellToolBase::mergeCells()
2130 {
2131     // sanity check
2132     if (selection()->activeSheet()->isProtected()) {
2133         return;
2134     }
2135     if (selection()->activeSheet()->map()->isProtected()) {
2136         return;
2137     }
2138     MergeCommand* const command = new MergeCommand();
2139     command->setSheet(selection()->activeSheet());
2140     command->setSelection(selection());
2141     command->setHorizontalMerge(false);
2142     command->setVerticalMerge(false);
2143     command->add(*selection());
2144     command->execute(canvas());
2145 }
2146 
mergeCellsHorizontal()2147 void CellToolBase::mergeCellsHorizontal()
2148 {
2149     // sanity check
2150     if (selection()->activeSheet()->isProtected()) {
2151         return;
2152     }
2153     if (selection()->activeSheet()->map()->isProtected()) {
2154         return;
2155     }
2156     MergeCommand* const command = new MergeCommand();
2157     command->setSheet(selection()->activeSheet());
2158     command->setHorizontalMerge(true);
2159     command->setVerticalMerge(false);
2160     command->setSelection(selection());
2161     command->add(*selection());
2162     command->execute(canvas());
2163 }
2164 
mergeCellsVertical()2165 void CellToolBase::mergeCellsVertical()
2166 {
2167     // sanity check
2168     if (selection()->activeSheet()->isProtected()) {
2169         return;
2170     }
2171     if (selection()->activeSheet()->map()->isProtected()) {
2172         return;
2173     }
2174     MergeCommand* const command = new MergeCommand();
2175     command->setSheet(selection()->activeSheet());
2176     command->setHorizontalMerge(false);
2177     command->setVerticalMerge(true);
2178     command->setSelection(selection());
2179     command->add(*selection());
2180     command->execute(canvas());
2181 }
2182 
dissociateCells()2183 void CellToolBase::dissociateCells()
2184 {
2185     // sanity check
2186     if (selection()->activeSheet()->isProtected()) {
2187         return;
2188     }
2189     if (selection()->activeSheet()->map()->isProtected()) {
2190         return;
2191     }
2192     MergeCommand* const command = new MergeCommand();
2193     command->setSheet(selection()->activeSheet());
2194     command->setReverse(true);
2195     command->setSelection(selection());
2196     command->add(*selection());
2197     command->execute(canvas());
2198 }
2199 
resizeColumn()2200 void CellToolBase::resizeColumn()
2201 {
2202     if (selection()->isRowSelected())
2203         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2204     else {
2205         QPointer<ResizeColumn> dialog = new ResizeColumn(canvas()->canvasWidget(), selection());
2206         dialog->exec();
2207         delete dialog;
2208     }
2209 }
2210 
insertColumn()2211 void CellToolBase::insertColumn()
2212 {
2213     InsertDeleteColumnManipulator* command = new InsertDeleteColumnManipulator();
2214     command->setSheet(selection()->activeSheet());
2215     command->add(*selection());
2216     command->execute(canvas());
2217 }
2218 
deleteColumn()2219 void CellToolBase::deleteColumn()
2220 {
2221     InsertDeleteColumnManipulator* command = new InsertDeleteColumnManipulator();
2222     command->setSheet(selection()->activeSheet());
2223     command->setReverse(true);
2224     command->add(*selection());
2225     command->execute(canvas());
2226 }
2227 
hideColumn()2228 void CellToolBase::hideColumn()
2229 {
2230     if (selection()->isRowSelected()) {
2231         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2232         return;
2233     }
2234 
2235     HideShowManipulator* command = new HideShowManipulator();
2236     command->setSheet(selection()->activeSheet());
2237     command->setManipulateColumns(true);
2238     command->add(*selection());
2239     command->execute(canvas());
2240 }
2241 
showColumn()2242 void CellToolBase::showColumn()
2243 {
2244     if (selection()->isRowSelected()) {
2245         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2246         return;
2247     }
2248 
2249     HideShowManipulator* command = new HideShowManipulator();
2250     command->setSheet(selection()->activeSheet());
2251     command->setManipulateColumns(true);
2252     command->setReverse(true);
2253     command->add(*selection());
2254     command->execute(canvas());
2255 }
2256 
slotShowColumnDialog()2257 void CellToolBase::slotShowColumnDialog()
2258 {
2259     QPointer<ShowColRow> dialog = new ShowColRow(canvas()->canvasWidget(), selection(), ShowColRow::Column);
2260     dialog->exec();
2261     delete dialog;
2262 }
2263 
equalizeColumn()2264 void CellToolBase::equalizeColumn()
2265 {
2266     if (selection()->isRowSelected())
2267         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2268     else {
2269         const QRect range = selection()->lastRange();
2270         const ColumnFormat* columnFormat = selection()->activeSheet()->columnFormat(range.left());
2271         double size = columnFormat->width();
2272         if (range.left() == range.right())
2273             return;
2274         for (int i = range.left() + 1; i <= range.right(); ++i)
2275             size = qMax(selection()->activeSheet()->columnFormat(i)->width(), size);
2276 
2277         if (size != 0.0) {
2278             ResizeColumnManipulator* command = new ResizeColumnManipulator();
2279             command->setSheet(selection()->activeSheet());
2280             command->setSize(qMax(2.0, size));
2281             command->add(*selection());
2282             if (!command->execute())
2283                 delete command;
2284         } else { // hide
2285             HideShowManipulator* command = new HideShowManipulator();
2286             command->setSheet(selection()->activeSheet());
2287             command->setManipulateColumns(true);
2288             command->add(*selection());
2289             if (!command->execute())
2290                 delete command;
2291         }
2292     }
2293 }
2294 
adjustColumn()2295 void CellToolBase::adjustColumn()
2296 {
2297     AdjustColumnRowManipulator* command = new AdjustColumnRowManipulator();
2298     command->setSheet(selection()->activeSheet());
2299     command->setAdjustColumn(true);
2300     command->add(*selection());
2301     command->execute(canvas());
2302 }
2303 
resizeRow()2304 void CellToolBase::resizeRow()
2305 {
2306     if (selection()->isColumnSelected())
2307         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2308     else {
2309         QPointer<ResizeRow> dialog = new ResizeRow(canvas()->canvasWidget(), selection());
2310         dialog->exec();
2311         delete dialog;
2312     }
2313 }
2314 
insertRow()2315 void CellToolBase::insertRow()
2316 {
2317     InsertDeleteRowManipulator* command = new InsertDeleteRowManipulator();
2318     command->setSheet(selection()->activeSheet());
2319     command->add(*selection());
2320     command->execute(canvas());
2321 }
2322 
deleteRow()2323 void CellToolBase::deleteRow()
2324 {
2325     InsertDeleteRowManipulator* command = new InsertDeleteRowManipulator();
2326     command->setSheet(selection()->activeSheet());
2327     command->setReverse(true);
2328     command->add(*selection());
2329     command->execute(canvas());
2330 }
2331 
hideRow()2332 void CellToolBase::hideRow()
2333 {
2334     if (selection()->isColumnSelected()) {
2335         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2336         return;
2337     }
2338 
2339     HideShowManipulator* command = new HideShowManipulator();
2340     command->setSheet(selection()->activeSheet());
2341     command->setManipulateRows(true);
2342     command->add(*selection());
2343     command->execute(canvas());
2344 }
2345 
showRow()2346 void CellToolBase::showRow()
2347 {
2348     if (selection()->isColumnSelected()) {
2349         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2350         return;
2351     }
2352 
2353     HideShowManipulator* command = new HideShowManipulator();
2354     command->setSheet(selection()->activeSheet());
2355     command->setManipulateRows(true);
2356     command->setReverse(true);
2357     command->add(*selection());
2358     command->execute(canvas());
2359 }
2360 
slotShowRowDialog()2361 void CellToolBase::slotShowRowDialog()
2362 {
2363     QPointer<ShowColRow> dialog = new ShowColRow(canvas()->canvasWidget(), selection(), ShowColRow::Row);
2364     dialog->exec();
2365     delete dialog;
2366 }
2367 
equalizeRow()2368 void CellToolBase::equalizeRow()
2369 {
2370     if (selection()->isColumnSelected())
2371         KMessageBox::error(canvas()->canvasWidget(), i18n("Area is too large."));
2372     else {
2373         const QRect range = selection()->lastRange();
2374         qreal size = selection()->activeSheet()->rowFormats()->rowHeight(range.top());
2375         if (range.top() == range.bottom())
2376             return;
2377         for (int i = range.top() + 1; i <= range.bottom(); ++i) {
2378             int lastRow;
2379             size = qMax(selection()->activeSheet()->rowFormats()->rowHeight(i, &lastRow), static_cast<qreal>(size));
2380             i = lastRow;
2381         }
2382 
2383         if (size != 0.0) {
2384             ResizeRowManipulator* command = new ResizeRowManipulator();
2385             command->setSheet(selection()->activeSheet());
2386             command->setSize(qMax(qreal(2.0), size));
2387             command->add(*selection());
2388             if (!command->execute())
2389                 delete command;
2390         } else { // hide
2391             HideShowManipulator* command = new HideShowManipulator();
2392             command->setSheet(selection()->activeSheet());
2393             command->setManipulateRows(true);
2394             command->add(*selection());
2395             if (!command->execute())
2396                 delete command;
2397         }
2398     }
2399 }
2400 
adjustRow()2401 void CellToolBase::adjustRow()
2402 {
2403     AdjustColumnRowManipulator* command = new AdjustColumnRowManipulator();
2404     command->setSheet(selection()->activeSheet());
2405     command->setAdjustRow(true);
2406     command->add(*selection());
2407     command->execute(canvas());
2408 }
2409 
adjust()2410 void CellToolBase::adjust()
2411 {
2412     AdjustColumnRowManipulator* command = new AdjustColumnRowManipulator();
2413     command->setSheet(selection()->activeSheet());
2414     command->setAdjustColumn(true);
2415     command->setAdjustRow(true);
2416     command->add(*selection());
2417     command->execute(canvas());
2418 }
2419 
insertCells()2420 void CellToolBase::insertCells()
2421 {
2422     QPointer<InsertDialog> dialog = new InsertDialog(canvas()->canvasWidget(), selection(), InsertDialog::Insert);
2423     dialog->exec();
2424     delete dialog;
2425 }
2426 
deleteCells()2427 void CellToolBase::deleteCells()
2428 {
2429     QPointer<InsertDialog> dialog = new InsertDialog(canvas()->canvasWidget(), selection(), InsertDialog::Remove);
2430     dialog->exec();
2431     delete dialog;
2432 }
2433 
clearAll()2434 void CellToolBase::clearAll()
2435 {
2436     DeleteCommand* command = new DeleteCommand();
2437     command->setSheet(selection()->activeSheet());
2438     command->add(*selection());
2439     command->execute(canvas());
2440 }
2441 
clearContents()2442 void CellToolBase::clearContents()
2443 {
2444     // TODO Stefan: Actually this check belongs into the command!
2445     if (selection()->activeSheet()->areaIsEmpty(*selection()))
2446         return;
2447 
2448     DataManipulator* command = new DataManipulator();
2449     command->setSheet(selection()->activeSheet());
2450     command->setText(kundo2_i18n("Clear Text"));
2451     // parsing gets set only so that parseUserInput is called as it should be,
2452     // no actual parsing shall be done
2453     command->setParsing(true);
2454     command->setValue(Value(""));
2455     command->add(*selection());
2456     command->execute(canvas());
2457 }
2458 
comment()2459 void CellToolBase::comment()
2460 {
2461     QPointer<CommentDialog> dialog = new CommentDialog(canvas()->canvasWidget(), selection());
2462     dialog->exec();
2463     delete dialog;
2464 }
2465 
clearComment()2466 void CellToolBase::clearComment()
2467 {
2468     // TODO Stefan: Actually this check belongs into the command!
2469     if (selection()->activeSheet()->areaIsEmpty(*selection(), Sheet::Comment))
2470         return;
2471 
2472     CommentCommand* command = new CommentCommand();
2473     command->setSheet(selection()->activeSheet());
2474     command->setText(kundo2_i18n("Remove Comment"));
2475     command->setComment(QString());
2476     command->add(*selection());
2477     command->execute(canvas());
2478 }
2479 
conditional()2480 void CellToolBase::conditional()
2481 {
2482     QPointer<ConditionalDialog> dialog = new ConditionalDialog(canvas()->canvasWidget(), selection());
2483     dialog->exec();
2484     delete dialog;
2485 }
2486 
clearConditionalStyles()2487 void CellToolBase::clearConditionalStyles()
2488 {
2489     // TODO Stefan: Actually this check belongs into the command!
2490     if (selection()->activeSheet()->areaIsEmpty(*selection(), Sheet::ConditionalCellAttribute))
2491         return;
2492 
2493     ConditionCommand* command = new ConditionCommand();
2494     command->setSheet(selection()->activeSheet());
2495     command->setConditionList(QLinkedList<Conditional>());
2496     command->add(*selection());
2497     command->execute(canvas());
2498 }
2499 
insertHyperlink()2500 void CellToolBase::insertHyperlink()
2501 {
2502     selection()->emitAboutToModify();
2503 
2504     QPoint marker(selection()->marker());
2505     Cell cell(selection()->activeSheet(), marker);
2506 
2507     QPointer<LinkDialog> dialog = new LinkDialog(canvas()->canvasWidget(), selection());
2508     dialog->setWindowTitle(i18n("Insert Link"));
2509     if (!cell.isNull()) {
2510         dialog->setText(cell.userInput());
2511         if (!cell.link().isEmpty()) {
2512             dialog->setWindowTitle(i18n("Edit Link"));
2513             dialog->setLink(cell.link());
2514         }
2515     }
2516 
2517     if (dialog->exec() == KoDialog::Accepted) {
2518         cell = Cell(selection()->activeSheet(), marker);
2519 
2520         LinkCommand* command = new LinkCommand(cell, dialog->text(), dialog->link());
2521         canvas()->addCommand(command);
2522 
2523         //refresh editWidget
2524         selection()->emitModified();
2525     }
2526     delete dialog;
2527 }
2528 
clearHyperlink()2529 void CellToolBase::clearHyperlink()
2530 {
2531     QPoint marker(selection()->marker());
2532     Cell cell(selection()->activeSheet(), marker);
2533     if (!cell)
2534         return;
2535     if (cell.link().isEmpty())
2536         return;
2537 
2538     LinkCommand* command = new LinkCommand(cell, QString(), QString());
2539     canvas()->addCommand(command);
2540 
2541     selection()->emitModified();
2542 }
2543 
validity()2544 void CellToolBase::validity()
2545 {
2546     QPointer<ValidityDialog> dialog = new ValidityDialog(canvas()->canvasWidget(), selection());
2547     dialog->exec();
2548     delete dialog;
2549 }
2550 
clearValidity()2551 void CellToolBase::clearValidity()
2552 {
2553     // TODO Stefan: Actually this check belongs into the command!
2554     if (selection()->activeSheet()->areaIsEmpty(*selection(), Sheet::Validity))
2555         return;
2556 
2557     ValidityCommand* command = new ValidityCommand();
2558     command->setSheet(selection()->activeSheet());
2559     command->setValidity(Validity()); // empty object removes validity
2560     command->add(*selection());
2561     command->execute(canvas());
2562 }
2563 
sort()2564 void CellToolBase::sort()
2565 {
2566     if (selection()->isSingular()) {
2567         KMessageBox::error(canvas()->canvasWidget(), i18n("You must select multiple cells."));
2568         return;
2569     }
2570 
2571     QPointer<SortDialog> dialog = new SortDialog(canvas()->canvasWidget(), selection());
2572     dialog->exec();
2573     delete dialog;
2574 }
2575 
sortInc()2576 void CellToolBase::sortInc()
2577 {
2578     if (selection()->isSingular()) {
2579         KMessageBox::error(canvas()->canvasWidget(), i18n("You must select multiple cells."));
2580         return;
2581     }
2582 
2583     SortManipulator* command = new SortManipulator();
2584     command->setSheet(selection()->activeSheet());
2585 
2586     // Entire row(s) selected ? Or just one row ? Sort by columns if yes.
2587     QRect range = selection()->lastRange();
2588     bool sortCols = selection()->isRowSelected();
2589     sortCols = sortCols || (range.top() == range.bottom());
2590     command->setSortRows(!sortCols);
2591     command->addCriterion(0, Qt::AscendingOrder, Qt::CaseInsensitive);
2592     command->add(*selection());
2593     command->execute(canvas());
2594 
2595     selection()->emitModified();
2596 }
2597 
sortDec()2598 void CellToolBase::sortDec()
2599 {
2600     if (selection()->isSingular()) {
2601         KMessageBox::error(canvas()->canvasWidget(), i18n("You must select multiple cells."));
2602         return;
2603     }
2604 
2605     SortManipulator* command = new SortManipulator();
2606     command->setSheet(selection()->activeSheet());
2607 
2608     // Entire row(s) selected ? Or just one row ? Sort by rows if yes.
2609     QRect range = selection()->lastRange();
2610     bool sortCols = selection()->isRowSelected();
2611     sortCols = sortCols || (range.top() == range.bottom());
2612     command->setSortRows(!sortCols);
2613     command->addCriterion(0, Qt::DescendingOrder, Qt::CaseInsensitive);
2614     command->add(*selection());
2615     command->execute(canvas());
2616 
2617     selection()->emitModified();
2618 }
2619 
autoFilter()2620 void CellToolBase::autoFilter()
2621 {
2622     AutoFilterCommand* command = new AutoFilterCommand();
2623     command->setSheet(selection()->activeSheet());
2624     command->add(*selection());
2625     command->execute(canvas());
2626 }
2627 
fillLeft()2628 void CellToolBase::fillLeft()
2629 {
2630     FillManipulator* command = new FillManipulator();
2631     command->setSheet(selection()->activeSheet());
2632     command->setDirection(FillManipulator::Left);
2633     command->add(*selection());
2634     command->execute(canvas());
2635 }
2636 
fillRight()2637 void CellToolBase::fillRight()
2638 {
2639     FillManipulator* command = new FillManipulator();
2640     command->setSheet(selection()->activeSheet());
2641     command->setDirection(FillManipulator::Right);
2642     command->add(*selection());
2643     command->execute(canvas());
2644 }
2645 
fillUp()2646 void CellToolBase::fillUp()
2647 {
2648     FillManipulator* command = new FillManipulator();
2649     command->setSheet(selection()->activeSheet());
2650     command->setDirection(FillManipulator::Up);
2651     command->add(*selection());
2652     command->execute(canvas());
2653 }
2654 
fillDown()2655 void CellToolBase::fillDown()
2656 {
2657     FillManipulator* command = new FillManipulator();
2658     command->setSheet(selection()->activeSheet());
2659     command->setDirection(FillManipulator::Down);
2660     command->add(*selection());
2661     command->execute(canvas());
2662 }
2663 
autoSum()2664 void CellToolBase::autoSum()
2665 {
2666     selection()->emitAboutToModify();
2667 
2668     //Get the selected range and remove the current cell from it(as that is
2669     //where the result of the autosum will be stored - perhaps change
2670     //this behaviour??)
2671     QRect sel = selection()->lastRange();
2672 
2673     if (sel.height() > 1) {
2674         if (selection()->marker().y() == sel.top())
2675             sel.setTop(sel.top() + 1);
2676         if (selection()->marker().y() == sel.bottom())
2677             sel.setBottom(sel.bottom() - 1);
2678     } else {
2679         if (sel.width() > 1) {
2680             if (selection()->marker().x() == sel.left())
2681                 sel.setLeft(sel.left() + 1);
2682 
2683             if (selection()->marker().x() == sel.right())
2684                 sel.setRight(sel.right() - 1);
2685         } else {
2686             sel = QRect();
2687 
2688             // only 1 cell selected
2689             // try to automagically find cells the user wants to sum up
2690 
2691             int start = -1, end = -1;
2692 
2693             if ((selection()->marker().y() > 1) && Cell(selection()->activeSheet(), selection()->marker().x(), selection()->marker().y() - 1).value().isNumber()) {
2694                 // check cells above the current one
2695                 start = end = selection()->marker().y() - 1;
2696                 for (--start; (start > 0) && Cell(selection()->activeSheet(), selection()->marker().x(), start).value().isNumber(); --start) ;
2697 
2698                 const Region region(QRect(QPoint(selection()->marker().x(), start + 1),
2699                                           QPoint(selection()->marker().x(), end)), selection()->activeSheet());
2700                 const QString str = region.name(selection()->activeSheet());
2701 
2702                 createEditor(true, true, true);
2703                 editor()->setText("=SUM(" + str + ')');
2704                 editor()->setCursorPosition(5 + str.length());
2705                 return;
2706             } else if ((selection()->marker().x() > 1) && Cell(selection()->activeSheet(), selection()->marker().x() - 1, selection()->marker().y()).value().isNumber()) {
2707                 // check cells to the left of the current one
2708                 start = end = selection()->marker().x() - 1;
2709                 for (--start; (start > 0) && Cell(selection()->activeSheet(), start, selection()->marker().y()).value().isNumber(); --start) ;
2710 
2711                 const Region region(QRect(QPoint(start + 1, selection()->marker().y()),
2712                                           QPoint(end, selection()->marker().y())), selection()->activeSheet());
2713                 const QString str = region.name(selection()->activeSheet());
2714 
2715                 createEditor(true, true, true);
2716                 editor()->setText("=SUM(" + str + ')');
2717                 editor()->setCursorPosition(5 + str.length());
2718                 return;
2719             }
2720         }
2721     }
2722 
2723     if ((sel.width() > 1) && (sel.height() > 1))
2724         sel = QRect();
2725 
2726     createEditor(true, true, true);
2727 
2728     const Region region(sel, selection()->activeSheet());
2729     if (region.isValid()) {
2730         editor()->setText("=SUM(" + region.name(selection()->activeSheet()) + ')');
2731         deleteEditor(true);
2732     } else {
2733         selection()->startReferenceSelection();
2734         editor()->setText("=SUM()");
2735         editor()->setCursorPosition(5);
2736     }
2737 }
2738 
insertSeries()2739 void CellToolBase::insertSeries()
2740 {
2741     selection()->emitAboutToModify();
2742     QPointer<SeriesDialog> dialog = new SeriesDialog(canvas()->canvasWidget(), selection());
2743     dialog->exec();
2744     delete dialog;
2745 }
2746 
insertSpecialChar()2747 void CellToolBase::insertSpecialChar()
2748 {
2749     QString fontFamily = Cell(selection()->activeSheet(), selection()->marker()).style().fontFamily();
2750     QChar c = ' ';
2751 
2752     if (d->specialCharDialog == 0) {
2753         d->specialCharDialog = new CharacterSelectDialog(canvas()->canvasWidget(), "SpecialCharDialog", fontFamily, c, false);
2754         connect(d->specialCharDialog, SIGNAL(insertChar(QChar,QString)),
2755                 this, SLOT(specialChar(QChar,QString)));
2756         connect(d->specialCharDialog, SIGNAL(finished()),
2757                 this, SLOT(specialCharDialogClosed()));
2758     }
2759     d->specialCharDialog->show();
2760 }
2761 
specialCharDialogClosed()2762 void CellToolBase::specialCharDialogClosed()
2763 {
2764     if (d->specialCharDialog) {
2765         disconnect(d->specialCharDialog, SIGNAL(insertChar(QChar,QString)),
2766                    this, SLOT(specialChar(QChar,QString)));
2767         disconnect(d->specialCharDialog, SIGNAL(finished()),
2768                    this, SLOT(specialCharDialogClosed()));
2769         d->specialCharDialog->deleteLater();
2770         d->specialCharDialog = 0;
2771     }
2772 }
2773 
specialChar(QChar character,const QString & fontName)2774 void CellToolBase::specialChar(QChar character, const QString& fontName)
2775 {
2776     const Style style = Cell(selection()->activeSheet(), selection()->marker()).style();
2777     if (style.fontFamily() != fontName) {
2778         Style newStyle;
2779         newStyle.setFontFamily(fontName);
2780         selection()->activeSheet()->cellStorage()->setStyle(Region(selection()->marker()), newStyle);
2781     }
2782     QKeyEvent keyEvent(QEvent::KeyPress, 0, Qt::NoModifier, QString(character));
2783     if (!editor()) {
2784         createEditor();
2785     }
2786     QApplication::sendEvent(editor()->widget(), &keyEvent);
2787 }
2788 
insertFormula()2789 void CellToolBase::insertFormula()
2790 {
2791     if (! d->formulaDialog) {
2792         if (! createEditor())
2793             return;
2794         d->formulaDialog = new FormulaDialog(canvas()->canvasWidget(), selection(), editor());
2795     }
2796     d->formulaDialog->show(); // dialog deletes itself later
2797 }
2798 
insertFromDatabase()2799 void CellToolBase::insertFromDatabase()
2800 {
2801 #ifndef QT_NO_SQL
2802     selection()->emitAboutToModify();
2803 
2804     QStringList str = QSqlDatabase::drivers();
2805     if (str.isEmpty()) {
2806         KMessageBox::error(canvas()->canvasWidget(), i18n("No database drivers available. To use this feature you need "
2807                            "to install the necessary Qt database drivers."));
2808         return;
2809     }
2810 
2811     QPointer<DatabaseDialog> dialog = new DatabaseDialog(canvas()->canvasWidget(), selection());
2812     dialog->exec();
2813     delete dialog;
2814 #endif
2815 }
2816 
insertFromTextfile()2817 void CellToolBase::insertFromTextfile()
2818 {
2819     selection()->emitAboutToModify();
2820 
2821     QPointer<CSVDialog> dialog = new CSVDialog(canvas()->canvasWidget(), selection(), CSVDialog::File);
2822     dialog->setDecimalSymbol(selection()->activeSheet()->map()->calculationSettings()->locale()->decimalSymbol());
2823     dialog->setThousandsSeparator(selection()->activeSheet()->map()->calculationSettings()->locale()->thousandsSeparator());
2824     if (!dialog->canceled())
2825         dialog->exec();
2826     delete dialog;
2827 }
2828 
insertFromClipboard()2829 void CellToolBase::insertFromClipboard()
2830 {
2831     selection()->emitAboutToModify();
2832 
2833     QPointer<CSVDialog> dialog = new CSVDialog(canvas()->canvasWidget(), selection(), CSVDialog::Clipboard);
2834     dialog->setDecimalSymbol(selection()->activeSheet()->map()->calculationSettings()->locale()->decimalSymbol());
2835     dialog->setThousandsSeparator(selection()->activeSheet()->map()->calculationSettings()->locale()->thousandsSeparator());
2836     QString oldDelimiter = dialog->delimiter();
2837     dialog->setDelimiter(QString());
2838     if (!dialog->canceled())
2839         dialog->exec();
2840     dialog->setDelimiter(oldDelimiter);
2841     delete dialog;
2842 }
2843 
textToColumns()2844 void CellToolBase::textToColumns()
2845 {
2846     selection()->emitAboutToModify();
2847 
2848     QRect area = selection()->lastRange();
2849     area.setRight(area.left()); // only use the first column
2850     Region oldSelection = *selection(); // store
2851     selection()->initialize(area);
2852 
2853     QPointer<CSVDialog> dialog = new CSVDialog(canvas()->canvasWidget(), selection(), CSVDialog::Column);
2854     dialog->setDecimalSymbol(selection()->activeSheet()->map()->calculationSettings()->locale()->decimalSymbol());
2855     dialog->setThousandsSeparator(selection()->activeSheet()->map()->calculationSettings()->locale()->thousandsSeparator());
2856     if (!dialog->canceled())
2857         dialog->exec();
2858     else
2859         selection()->initialize(oldSelection);
2860     delete dialog;
2861 }
2862 
sortList()2863 void CellToolBase::sortList()
2864 {
2865     QPointer<ListDialog> dialog = new ListDialog(canvas()->canvasWidget());
2866     dialog->exec();
2867     delete dialog;
2868 }
2869 
consolidate()2870 void CellToolBase::consolidate()
2871 {
2872     selection()->emitAboutToModify();
2873     ConsolidateDialog * dialog = new ConsolidateDialog(canvas()->canvasWidget(), selection());
2874     dialog->show(); // dialog deletes itself later
2875 }
2876 
goalSeek()2877 void CellToolBase::goalSeek()
2878 {
2879     selection()->emitAboutToModify();
2880 
2881     GoalSeekDialog* dialog = new GoalSeekDialog(canvas()->canvasWidget(), selection());
2882     dialog->show(); // dialog deletes itself later
2883 }
2884 
subtotals()2885 void CellToolBase::subtotals()
2886 {
2887     if ((selection()->lastRange().width() < 2) || (selection()->lastRange().height() < 2)) {
2888         KMessageBox::error(canvas()->canvasWidget(), i18n("You must select multiple cells."));
2889         return;
2890     }
2891 
2892     QPointer<SubtotalDialog> dialog = new SubtotalDialog(canvas()->canvasWidget(), selection());
2893     dialog->exec();
2894     delete dialog;
2895 }
2896 
pivot()2897 void CellToolBase::pivot()
2898 {
2899     if ((selection()->lastRange().width() < 2) || (selection()->lastRange().height() < 2)) {
2900         KMessageBox::error(canvas()->canvasWidget(), i18n("You must select multiple cells."));
2901         return;
2902     }
2903 
2904     QPointer<Pivot> dialog = new Pivot(canvas()->canvasWidget(), selection());
2905     dialog->exec();
2906     delete dialog;
2907 }
2908 
setAreaName()2909 void CellToolBase::setAreaName()
2910 {
2911     QPointer<AddNamedAreaDialog> dialog = new AddNamedAreaDialog(canvas()->canvasWidget(), selection());
2912     dialog->exec();
2913     delete dialog;
2914 }
2915 
namedAreaDialog()2916 void CellToolBase::namedAreaDialog()
2917 {
2918     QPointer<NamedAreaDialog> dialog = new NamedAreaDialog(canvas()->canvasWidget(), selection());
2919     dialog->exec();
2920     delete dialog;
2921 }
2922 
formulaSelection(const QString & expression)2923 void CellToolBase::formulaSelection(const QString& expression)
2924 {
2925     if (expression == i18n("Others...")) {
2926         insertFormula();
2927         return;
2928     }
2929 
2930     createEditor();
2931     FormulaDialog* dialog = new FormulaDialog(canvas()->canvasWidget(), selection(), editor(), expression);
2932     dialog->show(); // dialog deletes itself later
2933 }
2934 
edit()2935 void CellToolBase::edit()
2936 {
2937     // Not yet in edit mode?
2938     if (!editor()) {
2939         createEditor(false /* keep content */, true, true /*capture arrow keys*/);
2940         return;
2941     }
2942 
2943     // If the editor doesn't allow cursor movement, enable it now (enters real editing mode)
2944     if (!editor()->captureArrowKeys()) {
2945         editor()->setCaptureArrowKeys(true);
2946         return;
2947     }
2948 
2949     // Switch focus.
2950     if (editor()->widget()->hasFocus()) {
2951         if (d->externalEditor) d->externalEditor->setFocus();
2952     } else {
2953         editor()->widget()->setFocus();
2954     }
2955 }
2956 
cut()2957 void CellToolBase::cut()
2958 {
2959     if (editor()) {
2960         editor()->cut();
2961         selection()->emitModified();
2962         return;
2963     }
2964 
2965     QDomDocument doc = CopyCommand::saveAsXml(*selection(), true);
2966     doc.documentElement().setAttribute("cut", selection()->Region::name());
2967 
2968     // Save to buffer
2969     QBuffer buffer;
2970     buffer.open(QIODevice::WriteOnly);
2971     QTextStream str(&buffer);
2972     str.setCodec("UTF-8");
2973     str << doc;
2974     buffer.close();
2975 
2976     QMimeData* mimeData = new QMimeData();
2977     mimeData->setText(CopyCommand::saveAsPlainText(*selection()));
2978     mimeData->setData("application/x-kspread-snippet", buffer.buffer());
2979 
2980     QApplication::clipboard()->setMimeData(mimeData);
2981 
2982     DeleteCommand* command = new DeleteCommand();
2983     command->setText(kundo2_i18n("Cut"));
2984     command->setSheet(selection()->activeSheet());
2985     command->add(*selection());
2986     command->execute();
2987 
2988     selection()->emitModified();
2989 }
2990 
copy() const2991 void CellToolBase::copy() const
2992 {
2993     Selection* selection = const_cast<CellToolBase*>(this)->selection();
2994     if (editor()) {
2995         editor()->copy();
2996         return;
2997     }
2998 
2999     QDomDocument doc = CopyCommand::saveAsXml(*selection);
3000 
3001     // Save to buffer
3002     QBuffer buffer;
3003     buffer.open(QIODevice::WriteOnly);
3004     QTextStream str(&buffer);
3005     str.setCodec("UTF-8");
3006     str << doc;
3007     buffer.close();
3008 
3009     QMimeData* mimeData = new QMimeData();
3010     mimeData->setText(CopyCommand::saveAsPlainText(*selection));
3011     mimeData->setData("application/x-kspread-snippet", buffer.buffer());
3012 
3013     QApplication::clipboard()->setMimeData(mimeData);
3014 }
3015 
paste()3016 bool CellToolBase::paste()
3017 {
3018     if (!selection()->activeSheet()->map()->isReadWrite()) // don't paste into a read only document
3019         return false;
3020 
3021     const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
3022 
3023     if (mimeData->hasFormat("application/vnd.oasis.opendocument.spreadsheet")) {
3024         QByteArray returnedTypeMime = "application/vnd.oasis.opendocument.spreadsheet";
3025         QByteArray arr = mimeData->data(returnedTypeMime);
3026         if (arr.isEmpty())
3027             return false;
3028         QBuffer buffer(&arr);
3029         Map *map = selection()->activeSheet()->map();
3030         if (!Odf::paste(buffer, map)) return false;
3031     }
3032 
3033     if (!editor()) {
3034         const QMimeData* mimedata = QApplication::clipboard()->mimeData();
3035         if (!mimedata->hasFormat("application/x-kspread-snippet") &&
3036             !mimedata->hasHtml() && mimedata->hasText() &&
3037             mimeData->text().split('\n').count() >= 2 )
3038         {
3039             insertFromClipboard();
3040         } else {
3041             //debugSheetsUI <<"Pasting. Rect=" << selection()->lastRange() <<" bytes";
3042             PasteCommand *const command = new PasteCommand();
3043             command->setSheet(selection()->activeSheet());
3044             command->add(*selection());
3045             command->setMimeData(mimedata);
3046             command->setPasteFC(true);
3047             command->execute(canvas());
3048         }
3049         d->updateEditor(Cell(selection()->activeSheet(), selection()->cursor()));
3050     } else {
3051         editor()->paste();
3052     }
3053     selection()->emitModified();
3054     return true;
3055 }
3056 
specialPaste()3057 void CellToolBase::specialPaste()
3058 {
3059     QPointer<SpecialPasteDialog> dialog = new SpecialPasteDialog(canvas()->canvasWidget(), selection());
3060     if (dialog->exec()) {
3061         selection()->emitModified();
3062     }
3063     delete dialog;
3064 }
3065 
pasteWithInsertion()3066 void CellToolBase::pasteWithInsertion()
3067 {
3068     const QMimeData *const mimeData = QApplication::clipboard()->mimeData();
3069     if (!PasteCommand::unknownShiftDirection(mimeData)) {
3070         PasteCommand *const command = new PasteCommand();
3071         command->setSheet(selection()->activeSheet());
3072         command->add(*selection());
3073         command->setMimeData(mimeData);
3074         command->setInsertionMode(PasteCommand::ShiftCells);
3075         command->execute(canvas());
3076     } else {
3077         QPointer<PasteInsertDialog> dialog= new PasteInsertDialog(canvas()->canvasWidget(), selection());
3078         dialog->exec();
3079         delete dialog;
3080     }
3081     d->updateEditor(Cell(selection()->activeSheet(), selection()->cursor()));
3082 }
3083 
deleteSelection()3084 void CellToolBase::deleteSelection()
3085 {
3086     clearContents();
3087 }
3088 
selectAll()3089 void CellToolBase::selectAll()
3090 {
3091     selection()->selectAll();
3092 }
3093 
find()3094 void CellToolBase::find()
3095 {
3096     QPointer<FindDlg> dialog = new FindDlg(canvas()->canvasWidget(), "Find", d->findOptions, d->findStrings);
3097     dialog->setHasSelection(!selection()->isSingular());
3098     dialog->setHasCursor(true);
3099     if (KFindDialog::Accepted != dialog->exec())
3100         return;
3101 
3102     // Save for next time
3103     d->findOptions = dialog->options();
3104     d->findStrings = dialog->findHistory();
3105     d->typeValue = dialog->searchType();
3106     d->directionValue = dialog->searchDirection();
3107 
3108     // Create the KFind object
3109     delete d->find;
3110     delete d->replace;
3111     d->find = new KFind(dialog->pattern(), dialog->options(), canvas()->canvasWidget());
3112     d->replace = 0;
3113     d->replaceCommand = 0;
3114 
3115     d->searchInSheets.currentSheet = selection()->activeSheet();
3116     d->searchInSheets.firstSheet = d->searchInSheets.currentSheet;
3117 
3118     initFindReplace();
3119     findNext();
3120     delete dialog;
3121 }
3122 
3123 // Initialize a find or replace operation, using d->find or d->replace,
3124 // and d->findOptions.
initFindReplace()3125 void CellToolBase::initFindReplace()
3126 {
3127     KFind* findObj = d->find ? d->find : d->replace;
3128     Q_ASSERT(findObj);
3129     connect(findObj, SIGNAL(highlight(QString,int,int)),
3130             this, SLOT(slotHighlight(QString,int,int)));
3131     connect(findObj, SIGNAL(findNext()),
3132             this, SLOT(findNext()));
3133 
3134     bool bck = d->findOptions & KFind::FindBackwards;
3135     Sheet* currentSheet = d->searchInSheets.currentSheet;
3136 
3137     QRect region = (d->findOptions & KFind::SelectedText)
3138                    ? selection()->lastRange()
3139                    : QRect(1, 1, currentSheet->cellStorage()->columns(), currentSheet->cellStorage()->rows()); // All cells
3140 
3141     int colStart = !bck ? region.left() : region.right();
3142     int colEnd = !bck ? region.right() : region.left();
3143     int rowStart = !bck ? region.top() : region.bottom();
3144     int rowEnd = !bck ? region.bottom() : region.top();
3145 
3146     d->findLeftColumn = region.left();
3147     d->findRightColumn = region.right();
3148     d->findTopRow = region.top();
3149     d->findBottomRow = region.bottom();
3150 
3151     d->findStart = QPoint(colStart, rowStart);
3152     d->findPos = (d->findOptions & KFind::FromCursor) ? selection()->marker() : d->findStart;
3153     d->findEnd = QPoint(colEnd, rowEnd);
3154     //debugSheets << d->findPos <<" to" << d->findEnd;
3155     //debugSheets <<"leftcol=" << d->findLeftColumn <<" rightcol=" << d->findRightColumn;
3156 }
3157 
findNext()3158 void CellToolBase::findNext()
3159 {
3160     KFind* findObj = d->find ? d->find : d->replace;
3161     if (!findObj)  {
3162         find();
3163         return;
3164     }
3165     KFind::Result res = KFind::NoMatch;
3166     Cell cell = findNextCell();
3167     bool forw = !(d->findOptions & KFind::FindBackwards);
3168     while (res == KFind::NoMatch && !cell.isNull()) {
3169         if (findObj->needData()) {
3170             if (d->typeValue == FindOption::Note)
3171                 findObj->setData(cell.comment());
3172             else
3173                 findObj->setData(cell.userInput());
3174             d->findPos = QPoint(cell.column(), cell.row());
3175             //debugSheets <<"setData(cell" << d->findPos << ')';
3176         }
3177 
3178         // Let KFind inspect the text fragment, and display a dialog if a match is found
3179         if (d->find)
3180             res = d->find->find();
3181         else
3182             res = d->replace->replace();
3183 
3184         if (res == KFind::NoMatch)  {
3185             // Go to next cell, skipping unwanted cells
3186             if (d->directionValue == FindOption::Row) {
3187                 if (forw)
3188                     ++d->findPos.rx();
3189                 else
3190                     --d->findPos.rx();
3191             } else {
3192                 if (forw)
3193                     ++d->findPos.ry();
3194                 else
3195                     --d->findPos.ry();
3196             }
3197             cell = findNextCell();
3198         }
3199     }
3200 
3201     if (res == KFind::NoMatch) {
3202         //emitUndoRedo();
3203         //removeHighlight();
3204         if (findObj->shouldRestart()) {
3205             d->findOptions &= ~KFind::FromCursor;
3206             d->findPos = d->findStart;
3207             findObj->resetCounts();
3208             findNext();
3209         } else { // done, close the 'find next' dialog
3210             if (d->find)
3211                 d->find->closeFindNextDialog();
3212             else {
3213                 canvas()->addCommand(d->replaceCommand);
3214                 d->replaceCommand = 0;
3215                 d->replace->closeReplaceNextDialog();
3216             }
3217         }
3218     }
3219     else if (!cell.isNull()) {
3220         // move to the cell
3221         if (cell.sheet() != selection()->activeSheet())
3222             selection()->emitVisibleSheetRequested(cell.sheet());
3223         selection()->initialize (Region (cell.column(), cell.row(), cell.sheet()), cell.sheet());
3224         scrollToCell (selection()->cursor());
3225     }
3226 }
3227 
nextFindValidCell(int col,int row)3228 Cell CellToolBase::nextFindValidCell(int col, int row)
3229 {
3230     Cell cell = Cell(d->searchInSheets.currentSheet, col, row);
3231     if (cell.isDefault() || cell.isPartOfMerged() || cell.isFormula())
3232         cell = Cell();
3233     if (d->typeValue == FindOption::Note && !cell.isNull() && cell.comment().isEmpty())
3234         cell = Cell();
3235     return cell;
3236 }
3237 
findNextCell()3238 Cell CellToolBase::findNextCell()
3239 {
3240     // cellStorage()->firstInRow / cellStorage()->nextInRow would be faster at doing that,
3241     // but it doesn't seem to be easy to combine it with 'start a column d->find.x()'...
3242 
3243     Sheet* sheet = d->searchInSheets.currentSheet;
3244     Cell cell;
3245     bool forw = !(d->findOptions & KFind::FindBackwards);
3246     int col = d->findPos.x();
3247     int row = d->findPos.y();
3248     int maxRow = sheet->cellStorage()->rows();
3249 //     warnSheets <<"findNextCell starting at" << col << ',' << row <<"   forw=" << forw;
3250 
3251     if (d->directionValue == FindOption::Row) {
3252         while (!cell && (row >= d->findTopRow) && (row <= d->findBottomRow) && (forw ? row <= maxRow : row >= 0)) {
3253             while (!cell && (forw ? col <= d->findRightColumn : col >= d->findLeftColumn)) {
3254                 cell = nextFindValidCell(col, row);
3255                 if (forw) ++col;
3256                 else --col;
3257             }
3258             if (!cell.isNull())
3259                 break;
3260             // Prepare looking in the next row
3261             if (forw)  {
3262                 col = d->findLeftColumn;
3263                 ++row;
3264             } else {
3265                 col = d->findRightColumn;
3266                 --row;
3267             }
3268             //warnSheets <<"next row:" << col << ',' << row;
3269         }
3270     } else {
3271         while (!cell && (forw ? col <= d->findRightColumn : col >= d->findLeftColumn)) {
3272             while (!cell && (row >= d->findTopRow) && (row <= d->findBottomRow) && (forw ? row <= maxRow : row >= 0)) {
3273                 cell = nextFindValidCell(col, row);
3274                 if (forw) ++row;
3275                 else --row;
3276             }
3277             if (!cell.isNull())
3278                 break;
3279             // Prepare looking in the next col
3280             if (forw)  {
3281                 row = d->findTopRow;
3282                 ++col;
3283             } else {
3284                 row = d->findBottomRow;
3285                 --col;
3286             }
3287             //debugSheets <<"next row:" << col << ',' << row;
3288         }
3289     }
3290     // if (!cell)
3291     // No more next cell - TODO go to next sheet (if not looking in a selection)
3292     // (and make d->findEnd(max, max) in that case...)
3293 //    if (cell.isNull()) warnSheets<<"returning null"<<endl;
3294 //    else warnSheets <<" returning" << cell;
3295 
3296     return cell;
3297 }
3298 
findPrevious()3299 void CellToolBase::findPrevious()
3300 {
3301     KFind* findObj = d->find ? d->find : d->replace;
3302     if (!findObj)  {
3303         find();
3304         return;
3305     }
3306     //debugSheets <<"findPrevious";
3307     int opt = d->findOptions;
3308     bool forw = !(opt & KFind::FindBackwards);
3309     if (forw)
3310         d->findOptions = (opt | KFind::FindBackwards);
3311     else
3312         d->findOptions = (opt & ~KFind::FindBackwards);
3313 
3314     findNext();
3315 
3316     d->findOptions = opt; // restore initial options
3317 }
3318 
replace()3319 void CellToolBase::replace()
3320 {
3321     QPointer<SearchDlg> dialog = new SearchDlg(canvas()->canvasWidget(), "Replace", d->findOptions, d->findStrings, d->replaceStrings);
3322     dialog->setHasSelection(!selection()->isSingular());
3323     dialog->setHasCursor(true);
3324     if (KReplaceDialog::Accepted != dialog->exec())
3325         return;
3326 
3327     d->findOptions = dialog->options();
3328     d->findStrings = dialog->findHistory();
3329     d->replaceStrings = dialog->replacementHistory();
3330     d->typeValue = dialog->searchType();
3331 
3332     delete d->find;
3333     delete d->replace;
3334     d->find = 0;
3335     // NOTE Stefan: Avoid beginning of line replacements with nothing which
3336     //              will lead to an infinite loop (Bug #125535). The reason
3337     //              for this is unclear to me, but who cares and who would
3338     //              want to do something like this, häh?!
3339     if (dialog->pattern() == "^" && dialog->replacement().isEmpty())
3340         return;
3341     d->replace = new KReplace(dialog->pattern(), dialog->replacement(), dialog->options());
3342 
3343     d->searchInSheets.currentSheet = selection()->activeSheet();
3344     d->searchInSheets.firstSheet = d->searchInSheets.currentSheet;
3345     initFindReplace();
3346     connect(d->replace, SIGNAL(replace(QString,int,int,int)),
3347             this, SLOT(slotReplace(QString,int,int,int)));
3348 
3349     d->replaceCommand = new KUndo2Command(kundo2_i18n("Replace"));
3350 
3351     findNext();
3352     delete dialog;
3353 
3354 #if 0
3355     // Refresh the editWidget
3356     // TODO - after a replacement only?
3357     Cell cell = Cell(activeSheet(), selection()->marker());
3358     if (cell.userInput() != 0)
3359         d->editWidget->setText(cell.userInput());
3360     else
3361         d->editWidget->setText("");
3362 #endif
3363 }
3364 
slotHighlight(const QString &,int,int)3365 void CellToolBase::slotHighlight(const QString &/*text*/, int /*matchingIndex*/, int /*matchedLength*/)
3366 {
3367     selection()->initialize(d->findPos);
3368     QDialog *dialog = 0;
3369     if (d->find)
3370         dialog = d->find->findNextDialog();
3371     else
3372         dialog = d->replace->replaceNextDialog();
3373     debugSheets << " baseDialog :" << dialog;
3374     QRect globalRect(d->findPos, d->findEnd);
3375     globalRect.moveTopLeft(canvas()->canvasWidget()->mapToGlobal(globalRect.topLeft()));
3376     KoDialog::avoidArea(dialog, QRect(d->findPos, d->findEnd));
3377 }
3378 
slotReplace(const QString & newText,int,int,int)3379 void CellToolBase::slotReplace(const QString &newText, int, int, int)
3380 {
3381     if (d->typeValue == FindOption::Value) {
3382         DataManipulator* command = new DataManipulator(d->replaceCommand);
3383         command->setParsing(true);
3384         command->setSheet(d->searchInSheets.currentSheet);
3385         command->setValue(Value(newText));
3386         command->add(Region(d->findPos, d->searchInSheets.currentSheet));
3387     } else if (d->typeValue == FindOption::Note) {
3388         CommentCommand* command = new CommentCommand(d->replaceCommand);
3389         command->setComment(newText);
3390         command->setSheet(d->searchInSheets.currentSheet);
3391         command->add(Region(d->findPos, d->searchInSheets.currentSheet));
3392     }
3393 }
3394 
gotoCell()3395 void CellToolBase::gotoCell()
3396 {
3397     QPointer<GotoDialog> dialog = new GotoDialog(canvas()->canvasWidget(), selection());
3398     dialog->exec();
3399     delete dialog;
3400     scrollToCell(selection()->cursor());
3401 }
3402 
spellCheck()3403 void CellToolBase::spellCheck()
3404 {
3405     SpellCheckCommand* command = new SpellCheckCommand(*selection(), canvas());
3406     command->start();
3407 }
3408 
inspector()3409 void CellToolBase::inspector()
3410 {
3411     // useful to inspect objects
3412     Cell cell(selection()->activeSheet(), selection()->marker());
3413     QPointer<Calligra::Sheets::Inspector> ins = new Calligra::Sheets::Inspector(cell);
3414     ins->exec();
3415     delete ins;
3416 }
3417 
qTableView()3418 void CellToolBase::qTableView()
3419 {
3420 #ifndef NDEBUG
3421     QPointer<KoDialog> dialog = new KoDialog(canvas()->canvasWidget());
3422     QTableView* const view = new QTableView(dialog);
3423     SheetModel* const model = new SheetModel(selection()->activeSheet());
3424     view->setModel(model);
3425     dialog->setCaption("Read{Only,Write}TableModel Test");
3426     dialog->setMainWidget(view);
3427     dialog->exec();
3428     delete dialog;
3429     delete model;
3430 #endif
3431 }
3432 
sheetFormat()3433 void CellToolBase::sheetFormat()
3434 {
3435     QPointer<AutoFormatDialog> dialog = new AutoFormatDialog(canvas()->canvasWidget(), selection());
3436     dialog->exec();
3437     delete dialog;
3438 }
3439 
listChoosePopupMenu()3440 void CellToolBase::listChoosePopupMenu()
3441 {
3442     if (!selection()->activeSheet()->map()->isReadWrite()) {
3443         return;
3444     }
3445 
3446     delete d->popupListChoose;
3447     d->popupListChoose = new QMenu();
3448 
3449     const Sheet *const sheet = selection()->activeSheet();
3450     const Cell cursorCell(sheet, selection()->cursor());
3451     const QString text = cursorCell.userInput();
3452     const CellStorage *const storage = sheet->cellStorage();
3453 
3454     QStringList itemList;
3455     const Region::ConstIterator end(selection()->constEnd());
3456     for (Region::ConstIterator it(selection()->constBegin()); it != end; ++it) {
3457         const QRect range = (*it)->rect();
3458         if (cursorCell.column() < range.left() || cursorCell.column() > range.right()) {
3459             continue; // next range
3460         }
3461         Cell cell;
3462         if (range.top() == 1) {
3463             cell = storage->firstInColumn(cursorCell.column(), CellStorage::Values);
3464         } else {
3465             cell = storage->nextInColumn(cursorCell.column(), range.top() - 1, CellStorage::Values);
3466         }
3467         while (!cell.isNull() && cell.row() <= range.bottom()) {
3468             if (!cell.isPartOfMerged() && !(cell == cursorCell)) {
3469                 const QString userInput = cell.userInput();
3470                 if (cell.value().isString() && userInput != text && !userInput.isEmpty()) {
3471                     if (itemList.indexOf(userInput) == -1) {
3472                         itemList.append(userInput);
3473                     }
3474                 }
3475             }
3476             cell = storage->nextInColumn(cell.column(), cell.row(), CellStorage::Values);
3477         }
3478     }
3479 
3480     for (QStringList::ConstIterator it = itemList.constBegin(); it != itemList.constEnd(); ++it) {
3481         d->popupListChoose->addAction((*it));
3482     }
3483 
3484     if (itemList.isEmpty()) {
3485         return;
3486     }
3487     double tx = sheet->columnPosition(selection()->marker().x());
3488     double ty = sheet->rowPosition(selection()->marker().y());
3489     double h = cursorCell.height();
3490     if (sheetView(sheet)->obscuresCells(selection()->marker())) {
3491         const CellView& cellView = sheetView(sheet)->cellView(selection()->marker().x(), selection()->marker().y());
3492         h = cellView.cellHeight();
3493     }
3494     ty += h;
3495 
3496     if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft) {
3497         tx = canvas()->canvasWidget()->width() - tx;
3498     }
3499 
3500     QPoint p((int)tx, (int)ty);
3501     QPoint p2 = canvas()->canvasWidget()->mapToGlobal(p);
3502 
3503     if (selection()->activeSheet()->layoutDirection() == Qt::RightToLeft) {
3504         p2.setX(p2.x() - d->popupListChoose->sizeHint().width() + 1);
3505     }
3506 
3507     d->popupListChoose->popup(p2);
3508     connect(d->popupListChoose, SIGNAL(triggered(QAction*)),
3509             this, SLOT(listChooseItemSelected(QAction*)));
3510 }
3511 
3512 
listChooseItemSelected(QAction * action)3513 void CellToolBase::listChooseItemSelected(QAction* action)
3514 {
3515     const Cell cell(selection()->activeSheet(), selection()->marker());
3516     if (action->text() == cell.userInput())
3517         return;
3518 
3519     DataManipulator *command = new DataManipulator;
3520     command->setSheet(selection()->activeSheet());
3521     command->setValue(Value(action->text()));
3522     command->setParsing(true);
3523     command->add(selection()->marker());
3524     command->execute(canvas());
3525 }
3526 
documentSettingsDialog()3527 void CellToolBase::documentSettingsDialog()
3528 {
3529     QPointer<DocumentSettingsDialog> dialog = new DocumentSettingsDialog(selection(), canvas()->canvasWidget());
3530     dialog->exec();
3531     delete dialog;
3532 }
3533 
breakBeforeColumn(bool enable)3534 void CellToolBase::breakBeforeColumn(bool enable)
3535 {
3536     PageBreakCommand *command = new PageBreakCommand();
3537     command->setSheet(selection()->activeSheet());
3538     command->setMode(PageBreakCommand::BreakBeforeColumn);
3539     command->setReverse(!enable);
3540     command->add(*selection());
3541     command->execute(canvas());
3542 }
3543 
breakBeforeRow(bool enable)3544 void CellToolBase::breakBeforeRow(bool enable)
3545 {
3546     PageBreakCommand *command = new PageBreakCommand();
3547     command->setSheet(selection()->activeSheet());
3548     command->setMode(PageBreakCommand::BreakBeforeRow);
3549     command->setReverse(!enable);
3550     command->add(*selection());
3551     command->execute(canvas());
3552 }
3553 
setExternalEditor(Calligra::Sheets::ExternalEditor * editor)3554 void CellToolBase::setExternalEditor(Calligra::Sheets::ExternalEditor *editor)
3555 {
3556     d->externalEditor = editor;
3557 }
3558