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