compile
[kdegraphics.git] / kolourpaint / tools / selection / kpAbstractSelectionTool.cpp
blob86d5fd723f0e1dd8127efe3fba8d8b0960528773
2 /*
3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #define DEBUG_KP_TOOL_SELECTION 0
32 #include <kpAbstractSelectionTool.h>
33 #include <kpAbstractSelectionToolPrivate.h>
35 #include <qcursor.h>
36 #include <qmenu.h>
37 #include <qtimer.h>
39 #include <kdebug.h>
40 #include <klocale.h>
42 #include <kpAbstractSelection.h>
43 #include <kpAbstractSelectionContentCommand.h>
44 #include <kpBug.h>
45 #include <kpCommandHistory.h>
46 #include <kpDefs.h>
47 #include <kpDocument.h>
48 #include <kpMacroCommand.h>
49 #include <kpToolSelectionCreateCommand.h>
50 #include <kpToolSelectionEnvironment.h>
51 #include <kpToolToolBar.h>
52 #include <kpToolWidgetOpaqueOrTransparent.h>
53 #include <kpView.h>
54 #include <kpViewManager.h>
57 // For either of these timers, they are only active during the "drawing" phase
58 // of kpTool.
59 static void AssertAllTimersInactive (struct kpAbstractSelectionToolPrivate *d)
61 Q_ASSERT (!d->createNOPTimer->isActive ());
62 Q_ASSERT (!d->RMBMoveUpdateGUITimer->isActive ());
66 kpAbstractSelectionTool::kpAbstractSelectionTool (
67 const QString &text,
68 const QString &description,
69 int key,
70 kpToolSelectionEnvironment *environ, QObject *parent,
71 const QString &name)
73 : kpTool (text, description, key, environ, parent, name),
74 d (new kpAbstractSelectionToolPrivate ())
76 d->drawType = None;
77 d->currentSelContentCommand = 0;
79 // d->dragAccepted
80 // d->hadSelectionBeforeDrag
82 // d->cancelledShapeButStillHoldingButtons
84 d->toolWidgetOpaqueOrTransparent = 0;
87 initCreate ();
88 initMove ();
89 initResizeScale ();
91 // It would be bad practice to have timers ticking even when this tool
92 // is not in use.
93 ::AssertAllTimersInactive (d);
96 kpAbstractSelectionTool::~kpAbstractSelectionTool ()
98 uninitCreate ();
99 uninitMove ();
100 uninitResizeScale ();
103 // (state must be after construction, or after some time after end())
104 Q_ASSERT (d->drawType == None);
105 Q_ASSERT (!d->currentSelContentCommand);
107 // d->dragAccepted
108 // d->hadSelectionBeforeDraw
110 // d->cancelledShapeButStillHoldingButtons
112 // d->toolWidgetOpaqueOrTransparent
115 delete d;
119 // protected
120 kpAbstractSelectionTool::DrawType kpAbstractSelectionTool::drawType () const
122 return d->drawType;
125 // protected
126 bool kpAbstractSelectionTool::hadSelectionBeforeDraw () const
128 return d->hadSelectionBeforeDraw;
132 // protected overrides [base kpTool]
133 kpToolSelectionEnvironment *kpAbstractSelectionTool::environ () const
135 kpToolEnvironment *e = kpTool::environ ();
136 Q_ASSERT (dynamic_cast <kpToolSelectionEnvironment *> (e));
137 return static_cast <kpToolSelectionEnvironment *> (e);
141 // protected
142 bool kpAbstractSelectionTool::controlOrShiftPressed () const
144 return (controlPressed () || shiftPressed ());
148 // protected
149 void kpAbstractSelectionTool::pushOntoDocument ()
151 #if DEBUG_KP_TOOL_SELECTION && 1
152 kDebug () << "kpAbstractSelectionTool::pushOntoDocument() selection="
153 << document ()->selection () << endl;
154 #endif
155 Q_ASSERT (document ()->selection ());
156 environ ()->deselectSelection ();
160 // protected
161 void kpAbstractSelectionTool::giveContentIfNeeded ()
163 kpAbstractSelection *sel = document ()->selection ();
164 Q_ASSERT (sel);
166 if (sel->hasContent ())
167 return;
169 if (d->currentSelContentCommand)
170 return;
172 d->currentSelContentCommand = /*virtual*/newGiveContentCommand ();
173 d->currentSelContentCommand->execute ();
176 // protected
177 // REFACTOR: sync: Code dup with kpMainWindow::addImageOrSelectionCommand ().
178 void kpAbstractSelectionTool::addNeedingContentCommand (kpCommand *cmd)
180 Q_ASSERT (cmd);
182 // Did we fill the selection with content?
183 if (d->currentSelContentCommand)
185 // Make the border creation a command.
186 #if DEBUG_KP_TOOL_SELECTION
187 kDebug () << "\thave currentSelContentCommand";
188 #endif
189 commandHistory ()->addCreateSelectionCommand (
190 new kpToolSelectionCreateCommand (
191 /*virtual*/nameOfCreateCommand (),
192 *d->currentSelContentCommand->originalSelection (),
193 environ ()->commandEnvironment ()),
194 false/*no exec - user already dragged out sel*/);
197 // Do we have a content setting command we need to commit?
198 // (yes, this is the same check as the previous "if")
199 if (d->currentSelContentCommand)
201 // Put the content command + given command (e.g. movement) together
202 // as a macro command, in the command history.
203 kpMacroCommand *macroCmd = new kpMacroCommand (
204 cmd->name (), environ ()->commandEnvironment ());
206 macroCmd->addCommand (d->currentSelContentCommand);
207 d->currentSelContentCommand = 0;
209 macroCmd->addCommand (cmd);
211 commandHistory ()->addCommand (macroCmd, false/*no exec*/);
213 else
215 // Put the given command into the command history.
216 commandHistory ()->addCommand (cmd, false/*no exec*/);
221 // protected virtual
222 void kpAbstractSelectionTool::setSelectionBorderForHaventBegunDraw ()
224 viewManager ()->setQueueUpdates ();
226 viewManager ()->setSelectionBorderVisible (true);
227 viewManager ()->setSelectionBorderFinished (true);
229 viewManager ()->restoreQueueUpdates ();
232 // private
233 QString kpAbstractSelectionTool::haventBegunDrawUserMessage ()
235 #if DEBUG_KP_TOOL_SELECTION && 0
236 kDebug () << "kpAbstractSelectionTool::haventBegunDrawUserMessage()"
237 " cancelledShapeButStillHoldingButtons="
238 << d->cancelledShapeButStillHoldingButtons
239 << endl;
240 #endif
242 if (d->cancelledShapeButStillHoldingButtons)
243 return i18n ("Let go of all the mouse buttons.");
245 return operation (calculateDrawType (), HaventBegunDrawUserMessage).toString ();
249 // public virtual [base kpTool]
250 void kpAbstractSelectionTool::begin ()
252 #if DEBUG_KP_TOOL_SELECTION
253 kDebug () << "kpAbstractSelectionTool<" << objectName () << ">::begin()";
254 #endif
256 ::AssertAllTimersInactive (d);
259 // (state must be after construction, or after some time after end())
260 Q_ASSERT (d->drawType == None);
261 Q_ASSERT (!d->currentSelContentCommand);
263 d->dragAccepted = false;
264 // d->hadSelectionBeforeDraw
266 d->cancelledShapeButStillHoldingButtons = false;
269 kpToolToolBar *tb = toolToolBar ();
270 Q_ASSERT (tb);
272 d->toolWidgetOpaqueOrTransparent = tb->toolWidgetOpaqueOrTransparent ();
273 Q_ASSERT (d->toolWidgetOpaqueOrTransparent);
274 connect (d->toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)),
275 this, SLOT (slotIsOpaqueChanged (bool)));
276 d->toolWidgetOpaqueOrTransparent->show ();
278 /*virtual*/setSelectionBorderForHaventBegunDraw ();
281 beginCreate ();
282 beginMove ();
283 beginResizeScale ();
286 setUserMessage (haventBegunDrawUserMessage ());
289 // public virtual [base kpTool]
290 void kpAbstractSelectionTool::end ()
292 #if DEBUG_KP_TOOL_SELECTION
293 kDebug () << "kpAbstractSelectionTool<" << objectName () << ">::end()";
294 #endif
296 if (document ()->selection ())
297 pushOntoDocument ();
300 endCreate ();
301 endMove ();
302 endResizeScale ();
305 // (should have been killed by cancelShape() or endDraw())
306 Q_ASSERT (d->drawType == None);
307 Q_ASSERT (!d->currentSelContentCommand);
309 // d->dragAccepted
310 // d->hadSelectionBeforeDraw
312 // d->cancelledShapeButStillHoldingButtons
315 Q_ASSERT (d->toolWidgetOpaqueOrTransparent);
316 disconnect (d->toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)),
317 this, SLOT (slotIsOpaqueChanged (bool)));
318 d->toolWidgetOpaqueOrTransparent = 0;
321 viewManager ()->unsetCursor ();
323 ::AssertAllTimersInactive (d);
327 // public virtual [base kpTool]
328 void kpAbstractSelectionTool::reselect ()
330 #if DEBUG_KP_TOOL_SELECTION
331 kDebug () << "kpAbstractSelectionTool::reselect()";
332 #endif
334 if (document ()->selection ())
335 pushOntoDocument ();
339 // protected virtual
340 kpAbstractSelectionTool::DrawType kpAbstractSelectionTool::calculateDrawTypeInsideSelection () const
342 #if DEBUG_KP_TOOL_SELECTION
343 kDebug () << "\t\tis move";
344 #endif
345 return kpAbstractSelectionTool::Move;
348 // protected virtual
349 kpAbstractSelectionTool::DrawType kpAbstractSelectionTool::calculateDrawType () const
351 kpAbstractSelection *sel = document ()->selection ();
352 if (!sel)
353 return Create;
354 #if DEBUG_KP_TOOL_SELECTION
355 kDebug () << "\thas sel region rect=" << sel->boundingRect ();
356 #endif
358 if (onSelectionResizeHandle () && !controlOrShiftPressed ())
359 return ResizeScale;
360 else if (sel->contains (currentPoint ()))
361 return /*virtual*/calculateDrawTypeInsideSelection ();
362 else
363 return Create;
366 // public virtual [base kpTool]
367 void kpAbstractSelectionTool::beginDraw ()
369 #if DEBUG_KP_TOOL_SELECTION
370 kDebug () << "kpAbstractSelectionTool::beginDraw() startPoint ()="
371 << startPoint ()
372 << " QCursor::pos() view startPoint="
373 << viewUnderStartPoint ()->mapFromGlobal (QCursor::pos ())
374 << endl;
375 #endif
377 // endDraw() and cancelShape() should have taken care of these.
378 ::AssertAllTimersInactive (d);
381 // In case the cursor was wrong to start with
382 // (forgot to call kpTool::somethingBelowTheCursorChanged()),
383 // make sure it is correct during this operation.
384 hover (currentPoint ());
386 // Currently used only to end the current text
387 if (hasBegunShape ())
389 endShape (currentPoint (),
390 kpBug::QRect_Normalized (
391 QRect (startPoint ()/* TODO: wrong */, currentPoint ())));
394 d->drawType = calculateDrawType ();
395 d->dragAccepted = false;
397 kpAbstractSelection *sel = document ()->selection ();
398 d->hadSelectionBeforeDraw = bool (sel);
400 operation (d->drawType, BeginDraw);
404 // public virtual [base kpTool]
405 void kpAbstractSelectionTool::hover (const QPoint &point)
407 #if DEBUG_KP_TOOL_SELECTION && 1
408 kDebug () << "kpAbstractSelectionTool::hover" << point;
409 #endif
411 operation (calculateDrawType (), SetCursor);
413 setUserShapePoints (point, KP_INVALID_POINT, false/*don't set size*/);
414 if (document () && document ()->selection ())
416 setUserShapeSize (document ()->selection ()->width (),
417 document ()->selection ()->height ());
419 else
421 setUserShapeSize (KP_INVALID_SIZE);
424 QString mess = haventBegunDrawUserMessage ();
425 if (mess != userMessage ())
426 setUserMessage (mess);
430 // public virtual [base kpTool]
431 void kpAbstractSelectionTool::draw (const QPoint &thisPoint, const QPoint & /*lastPoint*/,
432 const QRect &normalizedRect)
434 #if DEBUG_KP_TOOL_SELECTION && 1
435 kDebug () << "kpAbstractSelectionTool::draw (" << thisPoint
436 << ",startPoint=" << startPoint ()
437 << ",normalizedRect=" << normalizedRect << ")" << endl;
438 #else
439 Q_UNUSED (thisPoint);
440 Q_UNUSED (normalizedRect);
441 #endif
444 // OPT: return when thisPoint == lastPoint () so that e.g. when creating
445 // Points sel, press modifiers doesn't add multiple points in same
446 // place
449 operation (d->drawType, Draw);
453 // public virtual [base kpTool]
454 void kpAbstractSelectionTool::cancelShape ()
456 #if DEBUG_KP_TOOL_SELECTION
457 kDebug () << "kpAbstractSelectionTool::cancelShape() mouseButton="
458 << mouseButton () << endl;
459 #endif
461 const DrawType oldDrawType = d->drawType;
462 // kpTool::hasBegunDraw() returns false in this method so be consistent
463 // and clear "drawType" before dispatching the operation() below.
464 d->drawType = None;
467 viewManager ()->setQueueUpdates ();
469 operation (oldDrawType, Cancel);
472 if (d->currentSelContentCommand)
474 #if DEBUG_KP_TOOL_SELECTION
475 kDebug () << "\t\tundo sel content";
476 #endif
477 d->currentSelContentCommand->unexecute ();
478 delete d->currentSelContentCommand;
479 d->currentSelContentCommand = 0;
483 /*virtual*/setSelectionBorderForHaventBegunDraw ();
485 viewManager ()->restoreQueueUpdates ();
488 d->cancelledShapeButStillHoldingButtons = true;
489 setUserMessage (i18n ("Let go of all the mouse buttons."));
492 ::AssertAllTimersInactive (d);
495 // public virtual [base kpTool]
496 void kpAbstractSelectionTool::releasedAllButtons ()
498 d->cancelledShapeButStillHoldingButtons = false;
499 setUserMessage (haventBegunDrawUserMessage ());
503 // protected
504 void kpAbstractSelectionTool::popupRMBMenu ()
506 #if DEBUG_KP_TOOL_SELECTION
507 kDebug () << "CALL - exec'ing menu";
508 #endif
510 QMenu *pop = environ ()->selectionToolRMBMenu ();
511 Q_ASSERT (pop);
513 // Blocks until the menu closes.
514 // WARNING: Enters event loop - may re-enter view/tool event handlers.
515 pop->exec (QCursor::pos ());
516 #if DEBUG_KP_TOOL_SELECTION
517 kDebug () << "calling somethingBelowTheCursorChanged()";
518 #endif
520 // Cursor may have moved while the menu was up, triggering QMouseMoveEvents
521 // for the menu -- but not the view -- so we may have missed cursor moves.
522 // Update cursor position now.
523 somethingBelowTheCursorChanged ();
524 #if DEBUG_KP_TOOL_SELECTION
525 kDebug () << "DONE";
526 #endif
529 // public virtual [base kpTool]
530 void kpAbstractSelectionTool::endDraw (const QPoint & /*thisPoint*/,
531 const QRect & /*normalizedRect*/)
533 #if DEBUG_KP_TOOL_SELECTION
534 kDebug () << "kpAbstractSelectionTool::endDraw()";
535 #endif
537 const DrawType oldDrawType = d->drawType;
538 // kpTool::hasBegunDraw() returns false in this method so be consistent
539 // and clear "drawType" before dispatching the operation() below.
540 d->drawType = None;
543 viewManager ()->setQueueUpdates ();
545 operation (oldDrawType, EndDraw);
547 /*virtual*/setSelectionBorderForHaventBegunDraw ();
549 viewManager ()->restoreQueueUpdates ();
552 setUserMessage (haventBegunDrawUserMessage ());
555 ::AssertAllTimersInactive (d);
558 if (mouseButton () == 1/*right*/)
559 popupRMBMenu ();
562 // WARNING: Do not place any code after the popupRMBMenu() call
563 // (see the popupRMBMenu() API).
567 // protected virtual
568 QVariant kpAbstractSelectionTool::operation (DrawType drawType, Operation op,
569 const QVariant &data1, const QVariant &data2)
571 switch (drawType)
573 case None:
574 // NOP.
575 return QVariant ();
577 case Create:
578 return operationCreate (op, data1, data2);
580 case Move:
581 return operationMove (op, data1, data2);
583 case ResizeScale:
584 return operationResizeScale (op, data1, data2);
586 default:
587 Q_ASSERT (!"Unhandled drag type");
588 return QVariant ();
593 #include <kpAbstractSelectionTool.moc>