1 /*
2  For general Scribus (>=1.3.2) copyright and licensing information please refer
3  to the COPYING file provided with the program. Following this notice may exist
4  a copyright and/or license notice that predates the release of Scribus 1.3.2
5  for which a new license (GPL+exception) is in place.
6  */
7 /***************************************************************************
8 *                                                                         *
9 *   This program is free software; you can redistribute it and/or modify  *
10 *   it under the terms of the GNU General Public License as published by  *
11 *   the Free Software Foundation; either version 2 of the License, or     *
12 *   (at your option) any later version.                                   *
13 *                                                                         *
14 ***************************************************************************/
15 
16 
17 #include "canvasmode_edit.h"
18 
19 #include <QApplication>
20 #include <QButtonGroup>
21 #include <QCheckBox>
22 #include <QCursor>
23 #include <QDebug>
24 #include <QEvent>
25 #include <QMessageBox>
26 #include <QMouseEvent>
27 #include <QPainterPath>
28 #include <QPoint>
29 #include <QPointF>
30 #include <QRect>
31 #include <QTimer>
32 #include <QWidgetAction>
33 
34 #include "appmodes.h"
35 #include "canvas.h"
36 #include "fpoint.h"
37 #include "fpointarray.h"
38 #include "hyphenator.h"
39 #include "iconmanager.h"
40 #include "pageitem_noteframe.h"
41 #include "pageitem_textframe.h"
42 #include "prefscontext.h"
43 #include "prefsfile.h"
44 #include "prefsmanager.h"
45 #include "sccolorengine.h"
46 #include "scmimedata.h"
47 #include "scribus.h"
48 #include "scribusXml.h"
49 #include "scribusdoc.h"
50 #include "scribusview.h"
51 #include "selection.h"
52 #include "ui/aligndistribute.h"
53 #include "ui/contextmenu.h"
54 #include "ui/hruler.h"
55 #include "ui/insertTable.h"
56 #include "ui/pageselector.h"
57 #include "ui/propertiespalette.h"
58 #include "undomanager.h"
59 #include "units.h"
60 #include "util.h"
61 #include "util_math.h"
62 
63 
CanvasMode_Edit(ScribusView * view)64 CanvasMode_Edit::CanvasMode_Edit(ScribusView* view) : CanvasMode(view), m_ScMW(view->m_ScMW)
65 {
66 	m_blinker = new QTimer(view);
67 	connect(m_blinker, SIGNAL(timeout()), this, SLOT(blinkTextCursor()));
68 	connect(view->horizRuler, SIGNAL(MarkerMoved(double,double)), this, SLOT(rulerPreview(double,double)));
69 }
70 
GetItem(PageItem ** pi)71 inline bool CanvasMode_Edit::GetItem(PageItem** pi)
72 {
73 	*pi = m_doc->m_Selection->itemAt(0);
74 	return (*pi) != nullptr;
75 }
76 
77 
blinkTextCursor()78 void CanvasMode_Edit::blinkTextCursor()
79 {
80 	PageItem* currItem;
81 	if (m_doc->appMode == modeEdit && GetItem(&currItem))
82 	{
83 		QRectF brect = QRectF(0, 0, currItem->width(), currItem->height());
84 		QTransform m = currItem->getTransform();
85 		brect = m.mapRect(brect);
86 		m_canvas->update(QRectF(m_canvas->canvasToLocal(brect.topLeft()), QSizeF(brect.width(),brect.height())*m_canvas->scale()).toRect());
87 	}
88 }
89 
keyPressEvent(QKeyEvent * e)90 void CanvasMode_Edit::keyPressEvent(QKeyEvent *e)
91 {
92 	if (m_keyRepeat)
93 		return;
94 	m_keyRepeat = true;
95 	e->accept();
96 
97 	if (e->key() == Qt::Key_Escape)
98 	{
99 		// Go back to normal mode.
100 		m_view->requestMode(modeNormal);
101 		m_keyRepeat = false;
102 		return;
103 	}
104 
105 	PageItem* currItem;
106 	if (!GetItem(&currItem))
107 	{
108 		m_keyRepeat = false;
109 		return;
110 	}
111 
112 	if (currItem->isImageFrame() && !currItem->locked())
113 	{
114 		currItem->handleModeEditKey(e, m_keyRepeat);
115 	}
116 	if (currItem->isTextFrame())
117 	{
118 		bool oldKeyRepeat = m_keyRepeat;
119 
120 		m_cursorVisible = true;
121 		switch (e->key())
122 		{
123 			case Qt::Key_PageUp:
124 			case Qt::Key_PageDown:
125 			case Qt::Key_Up:
126 			case Qt::Key_Down:
127 			case Qt::Key_Home:
128 			case Qt::Key_End:
129 				m_longCursorTime=true;
130 				break;
131 			default:
132 				m_longCursorTime=false;
133 				break;
134 		}
135 		blinkTextCursor();
136 		if (!currItem->isTextFrame() || (currItem->isAutoNoteFrame() && currItem->asNoteFrame()->notesList().isEmpty()))
137 			m_ScMW->slotDocCh(false);
138 		currItem->handleModeEditKey(e, m_keyRepeat);
139 		if (currItem->isAutoNoteFrame() && currItem->asNoteFrame()->notesList().isEmpty())
140 		{
141 			PageItem_NoteFrame* noteFrame = currItem->asNoteFrame();
142 			if (!noteFrame->isEndNotesFrame() && noteFrame->masterFrame())
143 			{
144 				PageItem_TextFrame* masterFrame = noteFrame->masterFrame();
145 				masterFrame->invalidateLayout(false);
146 				masterFrame->updateLayout();
147 			}
148 			else if (!noteFrame->isEndNotesFrame() && !noteFrame->masterFrame())
149 				qDebug() << "Broken note frame without master frame detected";
150 		}
151 		m_keyRepeat = oldKeyRepeat;
152 		m_doc->regionsChanged()->update(QRectF());
153 	}
154 	m_keyRepeat = false;
155 }
156 
157 
158 
rulerPreview(double base,double xp)159 void CanvasMode_Edit::rulerPreview(double base, double xp)
160 {
161 	PageItem* currItem;
162 	if (m_doc->appMode == modeEdit && GetItem(&currItem))
163 	{
164 		QTransform mm = currItem->getTransform();
165 		QPointF itPos = mm.map(QPointF(0, currItem->yPos()));
166 		QPoint oldP = m_canvas->canvasToLocal(QPointF(mRulerGuide, itPos.y()));
167 		mRulerGuide = base + xp;
168 		QPoint p = m_canvas->canvasToLocal(QPointF(mRulerGuide, itPos.y() + currItem->height() * mm.m22()));
169 		m_canvas->update(QRect(oldP.x()-2, oldP.y(), p.x()+2, p.y()));
170 	}
171 }
172 
173 
drawControls(QPainter * p)174 void CanvasMode_Edit::drawControls(QPainter* p)
175 {
176 	commonDrawControls(p, false);
177 	PageItem* currItem;
178 	if (GetItem(&currItem))
179 	{
180 		QPen pp = QPen(Qt::blue, 1.0 / m_canvas->scale(), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
181 		pp.setCosmetic(true);
182 		PageItem_TextFrame* textframe = currItem->asTextFrame();
183 		if (textframe)
184 		{
185 			if (mRulerGuide >= 0)
186 			{
187 				QTransform mm = currItem->getTransform();
188 				QPointF itPos = mm.map(QPointF(0, currItem->yPos()));
189 				p->save();
190 				p->setTransform(mm, true);
191 				p->setPen(QPen(Qt::blue, 1.0 / m_canvas->scale(), Qt::DashLine, Qt::FlatCap, Qt::MiterJoin));
192 				p->setClipRect(QRectF(0.0, 0.0, currItem->width(), currItem->height()));
193 				p->setBrush(Qt::NoBrush);
194 				p->setRenderHint(QPainter::Antialiasing);
195 				p->drawLine(mRulerGuide - itPos.x(), 0, mRulerGuide - itPos.x(), currItem->height() * mm.m22());
196 				p->restore();
197 			}
198 			drawTextCursor(p, textframe);
199 		}
200 		else if (currItem->isImageFrame())
201 		{
202 			QTransform mm = currItem->getTransform();
203 			p->save();
204 			p->setTransform(mm, true);
205 			p->setClipRect(QRectF(0.0, 0.0, currItem->width(), currItem->height()));
206 			p->setPen(pp);
207 			p->setBrush(QColor(0,0,255,10));
208 			p->setRenderHint(QPainter::Antialiasing);
209 			if (currItem->imageFlippedH())
210 			{
211 				p->translate(currItem->width(), 0);
212 				p->scale(-1.0, 1.0);
213 			}
214 			if (currItem->imageFlippedV())
215 			{
216 				p->translate(0, currItem->height());
217 				p->scale(1.0, -1.0);
218 			}
219 			p->translate(currItem->imageXOffset()*currItem->imageXScale(), currItem->imageYOffset()*currItem->imageYScale());
220 			p->rotate(currItem->imageRotation());
221 			p->drawRect(0, 0, currItem->OrigW*currItem->imageXScale(), currItem->OrigH*currItem->imageYScale());
222 			p->translate(currItem->OrigW*currItem->imageXScale() / 2, currItem->OrigH*currItem->imageYScale() / 2);
223 			p->scale(1.0 / m_canvas->scale(), 1.0 / m_canvas->scale());
224 			QPen pps = QPen(Qt::blue, 1.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
225 			pps.setCosmetic(true);
226 			p->setPen(pps);
227 			p->drawLine(-10, 0, 10, 0);
228 			p->drawLine(0, -10, 0, 10);
229 			p->setBrush(QColor(0,0,255,70));
230 			p->drawEllipse(QPointF(0.0, 0.0), 10.0, 10.0);
231 			p->restore();
232 		}
233 	}
234 }
235 
236 
drawTextCursor(QPainter * p,PageItem_TextFrame * textframe)237 void CanvasMode_Edit::drawTextCursor ( QPainter *p, PageItem_TextFrame* textframe )
238 {
239 	if ((!m_longCursorTime && m_blinkTime.elapsed() > qApp->cursorFlashTime() / 2 ) ||
240 		(m_longCursorTime && m_blinkTime.elapsed() > qApp->cursorFlashTime() )
241 		)
242 	{
243 		m_cursorVisible = !m_cursorVisible;
244 		m_blinkTime.restart();
245 		m_longCursorTime=false;
246 	}
247 	if ( m_cursorVisible )
248 	{
249 		commonDrawTextCursor(p, textframe, QPointF());
250 	}
251 }
252 
enterEvent(QEvent * e)253 void CanvasMode_Edit::enterEvent(QEvent *e)
254 {
255 	if (!m_canvas->m_viewMode.m_MouseButtonPressed)
256 	{
257 		setModeCursor();
258 	}
259 }
260 
leaveEvent(QEvent * e)261 void CanvasMode_Edit::leaveEvent(QEvent *e)
262 {
263 }
264 
activate(bool fromGesture)265 void CanvasMode_Edit::activate(bool fromGesture)
266 {
267 	CanvasMode::activate(fromGesture);
268 
269 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
270 	m_canvas->resetRenderMode();
271 	m_doc->DragP = false;
272 	m_doc->leaveDrag = false;
273 	m_canvas->m_viewMode.operItemMoving = false;
274 	m_canvas->m_viewMode.operItemResizing = false;
275 	m_view->MidButt = false;
276 	Mxp = Myp = -1;
277 	Dxp = Dyp = -1;
278 	SeRx = SeRy = -1;
279 	oldCp = Cp = -1;
280 	frameResizeHandle = -1;
281 	setModeCursor();
282 	if (fromGesture)
283 	{
284 		m_view->update();
285 	}
286 	mRulerGuide = -1;
287 	PageItem * it(nullptr);
288 	if (GetItem(&it))
289 	{
290 		if (it->isTextFrame())
291 		{
292 			m_canvas->setupEditHRuler(it, true);
293 			if (m_doc->appMode == modeEdit)
294 			{
295 				m_blinker->start(200);
296 				m_blinkTime.start();
297 				m_cursorVisible = true;
298 				blinkTextCursor();
299 			}
300 		}
301 	}
302 }
303 
deactivate(bool forGesture)304 void CanvasMode_Edit::deactivate(bool forGesture)
305 {
306 	m_view->setRedrawMarkerShown(false);
307 	if (!forGesture)
308 	{
309 		mRulerGuide = -1;
310 		m_blinker->stop();
311 	}
312 	CanvasMode::deactivate(forGesture);
313 }
314 
mouseDoubleClickEvent(QMouseEvent * m)315 void CanvasMode_Edit::mouseDoubleClickEvent(QMouseEvent *m)
316 {
317 	m->accept();
318 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
319 	m_canvas->resetRenderMode();
320 	PageItem *currItem = nullptr;
321 	if (GetItem(&currItem) && (m_doc->appMode == modeEdit) && currItem->isTextFrame())
322 	{
323 		//CB if annotation, open the annotation dialog
324 		if (currItem->isAnnotation())
325 		{
326 		//	qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
327 			m_view->requestMode(submodeAnnotProps);
328 		}
329 		//otherwise, select between the whitespace
330 		else
331 		{
332 			if (m->modifiers() & Qt::ControlModifier)
333 			{
334 				int start=0, stop=0;
335 
336 				if (m->modifiers() & Qt::ShiftModifier)
337 				{//Double click with Ctrl+Shift in a frame to select few paragraphs
338 					uint oldPar = currItem->itemText.nrOfParagraph(oldCp);
339 					uint newPar = currItem->itemText.nrOfParagraph();
340 					if (oldPar < newPar)
341 					{
342 						start = currItem->itemText.startOfParagraph(oldPar);
343 						stop = currItem->itemText.endOfParagraph(newPar);
344 					}
345 					else
346 					{
347 						start = currItem->itemText.startOfParagraph(newPar);
348 						stop = currItem->itemText.endOfParagraph(oldPar);
349 					}
350 				}
351 				else
352 				{//Double click with Ctrl in a frame to select a paragraph
353 					oldCp = currItem->itemText.cursorPosition();
354 					uint nrPar = currItem->itemText.nrOfParagraph(oldCp);
355 					start = currItem->itemText.startOfParagraph(nrPar);
356 					stop = currItem->itemText.endOfParagraph(nrPar);
357 				}
358 				currItem->itemText.deselectAll();
359 				currItem->itemText.extendSelection(start, stop);
360 				currItem->itemText.setCursorPosition(stop);
361 			}
362 			else if ((currItem->itemText.cursorPosition() < currItem->itemText.length()) && (currItem->itemText.hasMark(currItem->itemText.cursorPosition())))
363 			{	//invoke edit marker dialog
364 				m_ScMW->slotEditMark();
365 				return;
366 			}
367 			else
368 			{	//Double click in a frame to select a word
369 				oldCp = currItem->itemText.cursorPosition();
370 				bool validPos = (oldCp >= 0 && oldCp < currItem->itemText.length());
371 				if (validPos && currItem->itemText.hasObject(oldCp))
372 				{
373 					currItem->itemText.select(oldCp, 1, true);
374 					InlineFrame iItem = currItem->itemText.object(oldCp);
375 					m_ScMW->editInlineStart(iItem.getInlineCharID());
376 				}
377 				else
378 				{
379 					currItem->itemText.selectWord(oldCp);
380 				}
381 			}
382 			currItem->HasSel = currItem->itemText.hasSelection();
383 		}
384 	}
385 	else
386 	{
387 		mousePressEvent(m);
388 		return;
389 	}
390 }
391 
392 
mouseMoveEvent(QMouseEvent * m)393 void CanvasMode_Edit::mouseMoveEvent(QMouseEvent *m)
394 {
395 // 	const double mouseX = m->globalX();
396 // 	const double mouseY = m->globalY();
397 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
398 
399 	double newX, newY;
400 	PageItem *currItem;
401 	//bool erf = false;
402 	m->accept();
403 	if (commonMouseMove(m))
404 		return;
405 	if (GetItem(&currItem))
406 	{
407 		newX = qRound(mousePointDoc.x()); //m_view->translateToDoc(m->x(), m->y()).x());
408 		newY = qRound(mousePointDoc.y()); //m_view->translateToDoc(m->x(), m->y()).y());
409 		if (m_doc->DragP)
410 			return;
411 		if (m_canvas->m_viewMode.m_MouseButtonPressed && (m_doc->appMode == modeEdit))
412 		{
413 			if (currItem->isImageFrame())
414 			{
415 				if (m->modifiers() & Qt::ShiftModifier)
416 				{
417 					m_view->setCursor(IconManager::instance().loadCursor("Rotieren2.png"));
418 					QTransform p = currItem->getTransform();
419 					p.translate(currItem->imageXOffset()*currItem->imageXScale(), currItem->imageYOffset()*currItem->imageYScale());
420 					QPointF rotP = p.map(QPointF(0.0, 0.0));
421 					double itemRotation = xy2Deg(mousePointDoc.x() - rotP.x(), mousePointDoc.y() - rotP.y());
422 					currItem->setImageRotation(itemRotation);
423 					m_canvas->displayRotHUD(m->globalPos(), itemRotation);
424 				}
425 				else
426 				{
427 					m_view->setCursor(IconManager::instance().loadCursor("handc.png"));
428 					QTransform mm1 = currItem->getTransform();
429 					QTransform mm2 = mm1.inverted();
430 					QPointF rota = mm2.map(QPointF(newX, newY)) - mm2.map(QPointF(Mxp, Myp));
431 					currItem->moveImageInFrame(rota.x() / currItem->imageXScale(), rota.y() / currItem->imageYScale());
432 					m_canvas->displayXYHUD(m->globalPos(), currItem->imageXOffset() * currItem->imageXScale(), currItem->imageYOffset() * currItem->imageYScale());
433 				}
434 				currItem->update();
435 				Mxp = newX;
436 				Myp = newY;
437 			}
438 			if (currItem->isTextFrame())
439 			{
440 				int refStartSel(currItem->asTextFrame()->itemText.startOfSelection());
441 				int refEndSel(currItem->asTextFrame()->itemText.endOfSelection());
442 				currItem->itemText.deselectAll();
443 				currItem->HasSel = false;
444 				m_view->slotSetCurs(m->globalPos().x(), m->globalPos().y());
445 				//Make sure we don't go here if the old cursor position was not set
446 				if (oldCp!=-1 && currItem->itemText.length() > 0)
447 				{
448 					if (currItem->itemText.cursorPosition() < oldCp)
449 					{
450 						currItem->itemText.select(currItem->itemText.cursorPosition(), oldCp - currItem->itemText.cursorPosition());
451 						currItem->HasSel = true;
452 					}
453 					if (currItem->itemText.cursorPosition() > oldCp)
454 					{
455 						currItem->itemText.select(oldCp, currItem->itemText.cursorPosition() - oldCp);
456 						currItem->HasSel = true;
457 					}
458 				}
459 				m_ScMW->setCopyCutEnabled(currItem->HasSel);
460 				if (currItem->HasSel)
461 				{
462 					m_canvas->m_viewMode.operTextSelecting = true;
463 					if ((refStartSel != currItem->asTextFrame()->itemText.startOfSelection()) ||
464 						(refEndSel   != currItem->asTextFrame()->itemText.endOfSelection()))
465 					{
466 						QRectF br(currItem->getBoundingRect());
467 						m_canvas->update(QRectF(m_canvas->canvasToLocal(br.topLeft()), br.size() * m_canvas->scale()).toRect());
468 					}
469 					// We have to call this unconditionally because slotSetCurs() doesn't know selection
470 					// when it is called
471 					m_doc->scMW()->setTBvals(currItem);
472 				}
473 			}
474 		}
475 		if (!m_canvas->m_viewMode.m_MouseButtonPressed)
476 		{
477 			if (m_doc->m_Selection->isMultipleSelection())
478 			{
479 				setModeCursor();
480 				return;
481 			}
482 			for (int a = 0; a < m_doc->m_Selection->count(); ++a)
483 			{
484 				currItem = m_doc->m_Selection->itemAt(a);
485 				if (currItem->locked())
486 					break;
487 				int hitTest = m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem);
488 				if (hitTest >= 0)
489 				{
490 					if (hitTest == Canvas::INSIDE)
491 					{
492 						if (currItem->isTextFrame())
493 							m_view->setCursor(QCursor(Qt::IBeamCursor));
494 						if (currItem->isImageFrame())
495 						{
496 							if (m->modifiers() & Qt::ShiftModifier)
497 								m_view->setCursor(IconManager::instance().loadCursor("Rotieren2.png"));
498 							else
499 								m_view->setCursor(IconManager::instance().loadCursor("handc.png"));
500 						}
501 					}
502 				}
503 				else
504 				{
505 // 					setModeCursor();
506 					m_view->setCursor(QCursor(Qt::ArrowCursor));
507 				}
508 			}
509 		}
510 	}
511 	else
512 	{
513 		if ((m_canvas->m_viewMode.m_MouseButtonPressed) && (m->buttons() & Qt::LeftButton))
514 		{
515 			newX = qRound(mousePointDoc.x()); //m_view->translateToDoc(m->x(), m->y()).x());
516 			newY = qRound(mousePointDoc.y()); //m_view->translateToDoc(m->x(), m->y()).y());
517 			SeRx = newX;
518 			SeRy = newY;
519 			QPoint startP = m_canvas->canvasToGlobal(QPointF(Mxp, Myp));
520 			m_view->redrawMarker->setGeometry(QRect(m_view->mapFromGlobal(startP), m_view->mapFromGlobal(m->globalPos())).normalized());
521 			m_view->setRedrawMarkerShown(true);
522 			m_view->HaveSelRect = true;
523 			return;
524 		}
525 	}
526 }
527 
mousePressEvent(QMouseEvent * m)528 void CanvasMode_Edit::mousePressEvent(QMouseEvent *m)
529 {
530 	if (UndoManager::undoEnabled())
531 	{
532 		SimpleState *ss = dynamic_cast<SimpleState*>(undoManager->getLastUndo());
533 		if (ss)
534 			ss->set("ETEA", QString(""));
535 		else
536 		{
537 			TransactionState *ts = dynamic_cast<TransactionState*>(undoManager->getLastUndo());
538 			if (ts)
539 				ss = dynamic_cast<SimpleState*>(ts->last());
540 			if (ss)
541 				ss->set("ETEA", QString(""));
542 		}
543 	}
544 // 	const double mouseX = m->globalX();
545 // 	const double mouseY = m->globalY();
546 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
547 
548 	bool inText;
549 	PageItem *currItem;
550 	m_canvas->PaintSizeRect(QRect());
551 	FPoint npf, npf2;
552 	QTransform pm;
553 	m_canvas->m_viewMode.m_MouseButtonPressed = true;
554 	m_canvas->m_viewMode.operItemMoving = false;
555 	m_view->HaveSelRect = false;
556 	m_doc->DragP = false;
557 	m_doc->leaveDrag = false;
558 //	oldClip = 0;
559 	m->accept();
560 	m_view->registerMousePress(m->globalPos());
561 	Mxp = mousePointDoc.x(); //qRound(m->x()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.x());
562 	Myp = mousePointDoc.y(); //qRound(m->y()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.y());
563 // 	QRect mpo(m->x()-m_doc->guidesPrefs().grabRad, m->y()-m_doc->guidesPrefs().grabRad, m_doc->guidesPrefs().grabRad*2, m_doc->guidesPrefs().grabRad*2);
564 //	mpo.moveBy(qRound(m_doc->minCanvasCoordinate.x() * m_canvas->scale()), qRound(m_doc->minCanvasCoordinate.y() * m_canvas->scale()));
565 	SeRx = Mxp;
566 	SeRy = Myp;
567 	if (m->button() == Qt::MidButton)
568 	{
569 		m_view->MidButt = true;
570 		if (m->modifiers() & Qt::ControlModifier)
571 			m_view->DrawNew();
572 		return;
573 	}
574 
575 	frameResizeHandle = 0;
576 	int oldP=0;
577 	if (GetItem(&currItem))
578 	{
579 //		m_view->slotDoCurs(false);
580 		if ((!currItem->locked() || currItem->isTextFrame()) && !currItem->isLine())
581 		{
582 			FPoint canvasPoint = m_canvas->globalToCanvas(m->globalPos());
583 			if (m_canvas->frameHitTest(QPointF(canvasPoint.x(), canvasPoint.y()), currItem) < 0)
584 			{
585 				m_doc->m_Selection->delaySignalsOn();
586 				m_view->deselectItems(true);
587 				bool wantNormal = true;
588 				if (SeleItem(m))
589 				{
590 					currItem = m_doc->m_Selection->itemAt(0);
591 					if ((currItem->isTextFrame()) || (currItem->isImageFrame()))
592 					{
593 						m_view->requestMode(modeEdit);
594 						wantNormal = false;
595 					}
596 					else
597 					{
598 						m_view->requestMode(submodePaintingDone);
599 						m_view->setCursor(QCursor(Qt::ArrowCursor));
600 					}
601 					if (currItem->isTextFrame())
602 					{
603 						m_view->slotSetCurs(m->globalPos().x(), m->globalPos().y());
604 						oldCp = currItem->itemText.cursorPosition();
605 					}
606 				}
607 				else
608 				{
609 					m_view->requestMode(submodePaintingDone);
610 					m_view->setCursor(QCursor(Qt::ArrowCursor));
611 				}
612 				m_doc->m_Selection->delaySignalsOff();
613 				if (wantNormal)
614 				{
615 					m_view->requestMode(modeNormal);
616 					m_view->canvasMode()->mousePressEvent(m);
617 				}
618 				return;
619 			}
620 		}
621 		oldP = currItem->itemText.cursorPosition();
622 		//CB Where we set the cursor for a click in text frame
623 		if (currItem->isTextFrame())
624 		{
625 			inText = m_view->slotSetCurs(m->globalPos().x(), m->globalPos().y());
626 			//CB If we clicked outside a text frame to go out of edit mode and deselect the frame
627 			if (!inText)
628 			{
629 				currItem->invalidateLayout();
630 				m_view->deselectItems(true);
631 				//m_view->slotDoCurs(true);
632 				m_view->requestMode(modeNormal);
633 				m_view->canvasMode()->mousePressEvent(m);
634 				return;
635 			}
636 
637 			if (m->button() != Qt::RightButton)
638 			{
639 				//currItem->asTextFrame()->deselectAll();
640 				//<<CB Add in shift select to text frames
641 				if (m->modifiers() & Qt::ShiftModifier)
642 				{
643 					if (currItem->itemText.hasSelection())
644 					{
645 						if (currItem->itemText.cursorPosition() < (currItem->itemText.startOfSelection() + currItem->itemText.endOfSelection()) / 2)
646 						{
647 							if (m->modifiers() & Qt::ControlModifier)
648 								currItem->itemText.setCursorPosition(currItem->itemText.startOfParagraph());
649 							oldP = currItem->itemText.startOfSelection();
650 						}
651 						else
652 						{
653 							if (m->modifiers() & Qt::ControlModifier)
654 								currItem->itemText.setCursorPosition(currItem->itemText.endOfParagraph());
655 							oldP = currItem->itemText.endOfSelection();
656 						}
657 						currItem->asTextFrame()->itemText.extendSelection(oldP, currItem->itemText.cursorPosition());
658 						oldCp = currItem->itemText.cursorPosition();
659 					}
660 					else
661 					{
662 						int dir=1;
663 						if (oldCp > currItem->itemText.cursorPosition())
664 							dir=-1;
665 						if (m->modifiers() & Qt::ControlModifier) //no selection but Ctrl+Shift+click still select paragraphs
666 						{
667 							if (dir == 1)
668 								currItem->itemText.setCursorPosition(currItem->itemText.endOfParagraph());
669 							else
670 								currItem->itemText.setCursorPosition(currItem->itemText.startOfParagraph());
671 						}
672 						currItem->asTextFrame()->ExpandSel(oldP);
673 						oldCp = oldP;
674 					}
675 				}
676 				else //>>CB
677 				{
678 					oldCp = currItem->itemText.cursorPosition();
679 					currItem->itemText.deselectAll();
680 					currItem->HasSel = false;
681 				}
682 				currItem->emitAllToGUI();
683 				if (m->button() == Qt::MidButton)
684 				{
685 					m_canvas->m_viewMode.m_MouseButtonPressed = false;
686 					m_view->MidButt = false;
687 					QString cc;
688 					cc = QApplication::clipboard()->text(QClipboard::Selection);
689 					if (cc.isNull())
690 						cc = QApplication::clipboard()->text(QClipboard::Clipboard);
691 					if (!cc.isNull())
692 					{
693 						// K.I.S.S.:
694 						currItem->itemText.insertChars(0, cc, true);
695 						if (m_doc->docHyphenator->AutoCheck)
696 							m_doc->docHyphenator->slotHyphenate(currItem);
697 						m_ScMW->BookMarkTxT(currItem);
698 						//							m_ScMW->outlinePalette->BuildTree();
699 					}
700 					else
701 					{
702 						if (ScMimeData::clipboardHasScribusText())
703 							m_ScMW->slotEditPaste();
704 					}
705 					currItem->update();
706 				}
707 			}
708 		}
709 		else if (!currItem->isImageFrame() || m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem) < 0)
710 		{
711 			m_view->deselectItems(true);
712 			if (SeleItem(m))
713 			{
714 				currItem = m_doc->m_Selection->itemAt(0);
715 				if ((currItem->isTextFrame()) || (currItem->isImageFrame()))
716 				{
717 					m_view->requestMode(modeEdit);
718 				}
719 				else
720 				{
721 					m_view->requestMode(submodePaintingDone);
722 					m_view->setCursor(QCursor(Qt::ArrowCursor));
723 				}
724 			}
725 			else
726 			{
727 				m_view->requestMode(submodePaintingDone);
728 				m_view->setCursor(QCursor(Qt::ArrowCursor));
729 			}
730 		}
731 	}
732 }
733 
734 
735 
mouseReleaseEvent(QMouseEvent * m)736 void CanvasMode_Edit::mouseReleaseEvent(QMouseEvent *m)
737 {
738 #ifdef GESTURE_FRAME_PREVIEW
739 	clearPixmapCache();
740 #endif // GESTURE_FRAME_PREVIEW
741 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
742 	PageItem *currItem;
743 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
744 	m_canvas->resetRenderMode();
745 	m->accept();
746 //	m_view->stopDragTimer();
747 	if ((GetItem(&currItem)) && (m->button() == Qt::RightButton) && (!m_doc->DragP))
748 	{
749 		createContextMenu(currItem, mousePointDoc.x(), mousePointDoc.y());
750 		return;
751 	}
752 	if (m_view->moveTimerElapsed() && (GetItem(&currItem)))
753 	{
754 //		m_view->stopDragTimer();
755 		m_canvas->setRenderModeUseBuffer(false);
756 		if (!m_doc->m_Selection->isMultipleSelection())
757 		{
758 			m_doc->setRedrawBounding(currItem);
759 			currItem->OwnPage = m_doc->OnPage(currItem);
760 			m_canvas->m_viewMode.operItemResizing = false;
761 			if (currItem->isLine())
762 				m_view->updateContents();
763 		}
764 		if (m_canvas->m_viewMode.operItemMoving)
765 		{
766 			m_view->updatesOn(false);
767 			if (m_doc->m_Selection->isMultipleSelection())
768 			{
769 				if (!m_view->groupTransactionStarted())
770 				{
771 					m_view->startGroupTransaction(Um::Move, "", Um::IMove);
772 				}
773 				double gx, gy, gh, gw;
774 				m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
775 				double nx = gx;
776 				double ny = gy;
777 				if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true))
778 				{
779 					FPoint npx = m_doc->ApplyGridF(FPoint(gx, gy));
780 					FPoint npw = m_doc->ApplyGridF(FPoint(gx + gw, gy + gh));
781 					if ((fabs(gx - npx.x())) > (fabs((gx + gw) - npw.x())))
782 						nx = npw.x() - gw;
783 					else
784 						nx = npx.x();
785 					if ((fabs(gy - npx.y())) > (fabs((gy + gh) - npw.y())))
786 						ny = npw.y() - gh;
787 					else
788 						ny = npx.y();
789 				}
790 				m_doc->moveGroup(nx - gx, ny - gy);
791 				m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
792 				nx = gx + gw;
793 				ny = gy + gh;
794 				if (m_doc->ApplyGuides(&nx, &ny) || m_doc->ApplyGuides(&nx,&ny,true))
795 					m_doc->moveGroup(nx - (gx + gw), ny - (gy + gh));
796 				m_doc->m_Selection->setGroupRect();
797 			}
798 			else
799 			{
800 				currItem = m_doc->m_Selection->itemAt(0);
801 				if (m_doc->SnapGrid)
802 				{
803 					double nx = currItem->xPos();
804 					double ny = currItem->yPos();
805 					if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true))
806 					{
807 						double gx, gy, gh, gw;
808 						m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
809 						FPoint npx = m_doc->ApplyGridF(FPoint(gx, gy));
810 						FPoint npw = m_doc->ApplyGridF(FPoint(gx + gw, gy + gh));
811 						if ((fabs(gx - npx.x())) > (fabs((gx + gw) - npw.x())))
812 							nx = npw.x() - gw;
813 						else
814 							nx = npx.x();
815 						if ((fabs(gy - npx.y())) > (fabs((gy + gh) - npw.y())))
816 							ny = npw.y() - gh;
817 						else
818 							ny = npx.y();
819 					}
820 					m_doc->moveItem(nx-currItem->xPos(), ny-currItem->yPos(), currItem);
821 				}
822 				else
823 					m_doc->moveItem(0, 0, currItem);
824 			}
825 			m_canvas->m_viewMode.operItemMoving = false;
826 			if (m_doc->m_Selection->isMultipleSelection())
827 			{
828 				double gx, gy, gh, gw;
829 				m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
830 				FPoint maxSize(gx + gw + m_doc->scratch()->right(), gy + gh + m_doc->scratch()->bottom());
831 				FPoint minSize(gx - m_doc->scratch()->left(), gy - m_doc->scratch()->top());
832 				m_doc->adjustCanvas(minSize, maxSize);
833 			}
834 			m_doc->setRedrawBounding(currItem);
835 			currItem->OwnPage = m_doc->OnPage(currItem);
836 			if (currItem->OwnPage != -1)
837 			{
838 				m_doc->setCurrentPage(m_doc->Pages->at(currItem->OwnPage));
839 				m_view->m_ScMW->slotSetCurrentPage(currItem->OwnPage);
840 			}
841 			//CB done with emitAllToGUI
842 			//emit HaveSel();
843 			//EmitValues(currItem);
844 			//CB need this for? a moved item will send its new data with the new xpos/ypos emits
845 			//CB TODO And what if we have dragged to a new page. Items X&Y are not updated anyway now
846 			//currItem->emitAllToGUI();
847 			m_view->updatesOn(true);
848 			m_view->updateContents();
849 		}
850 	}
851 	//CB Drag selection performed here
852 	if ((m_doc->m_Selection->isEmpty()) && (m_view->HaveSelRect) && (!m_view->MidButt))
853 	{
854 		QRectF Sele = QRectF(Dxp, Dyp, SeRx-Dxp, SeRy-Dyp).normalized();
855 		if (!m_doc->masterPageMode())
856 		{
857 			uint docPagesCount=m_doc->Pages->count();
858 			uint docCurrPageNo=m_doc->currentPageNumber();
859 			for (uint i = 0; i < docPagesCount; ++i)
860 			{
861 				if (QRectF(m_doc->Pages->at(i)->xOffset(), m_doc->Pages->at(i)->yOffset(), m_doc->Pages->at(i)->width(), m_doc->Pages->at(i)->height()).intersects(Sele))
862 				{
863 					if (docCurrPageNo != i)
864 					{
865 						m_doc->setCurrentPage(m_doc->Pages->at(i));
866 						m_view->m_ScMW->slotSetCurrentPage(i);
867 					}
868 					break;
869 				}
870 			}
871 			m_view->setRulerPos(m_view->contentsX(), m_view->contentsY());
872 		}
873 		int docItemCount=m_doc->Items->count();
874 		if (docItemCount != 0)
875 		{
876 			m_doc->m_Selection->delaySignalsOn();
877 			for (int a = 0; a < docItemCount; ++a)
878 			{
879 				PageItem* docItem = m_doc->Items->at(a);
880 				QTransform p;
881 				m_canvas->Transform(docItem, p);
882 				QRegion apr = QRegion(docItem->Clip * p);
883 				QRect apr2(docItem->getRedrawBounding(1.0));
884 				if ((m_doc->masterPageMode()) && (docItem->OnMasterPage != m_doc->currentPage()->pageName()))
885 					continue;
886 				if (((Sele.contains(apr.boundingRect())) || (Sele.contains(apr2))) && m_doc->canSelectItemOnLayer(docItem->m_layerID))
887 				{
888 					bool redrawSelection=false;
889 					m_view->selectItemByNumber(a, redrawSelection);
890 				}
891 			}
892 			m_doc->m_Selection->delaySignalsOff();
893 			if (m_doc->m_Selection->count() > 1)
894 			{
895 				double x, y, w, h;
896 				m_doc->m_Selection->getGroupRect(&x, &y, &w, &h);
897 				m_view->getGroupRectScreen(&x, &y, &w, &h);
898 			}
899 		}
900 		m_view->HaveSelRect = false;
901 		m_view->setRedrawMarkerShown(false);
902 		m_view->updateContents();
903 	}
904 	if (GetItem(&currItem))
905 	{
906 		if (m_doc->m_Selection->count() > 1)
907 		{
908 			double x, y, w, h;
909 			m_doc->m_Selection->getGroupRect(&x, &y, &w, &h);
910 			m_canvas->m_viewMode.operItemMoving = false;
911 			m_canvas->m_viewMode.operItemResizing = false;
912 			m_view->updateContents(QRect(static_cast<int>(x-5), static_cast<int>(y-5), static_cast<int>(w+10), static_cast<int>(h+10)));
913 		}
914 		/*else
915 			currItem->emitAllToGUI();*/
916 	}
917 	m_canvas->setRenderModeUseBuffer(false);
918 	m_doc->DragP = false;
919 	m_doc->leaveDrag = false;
920 	m_canvas->m_viewMode.operItemMoving = false;
921 	m_canvas->m_viewMode.operItemResizing = false;
922 	m_view->MidButt = false;
923 	if (m_view->groupTransactionStarted())
924 	{
925 		for (int i = 0; i < m_doc->m_Selection->count(); ++i)
926 			m_doc->m_Selection->itemAt(i)->checkChanges(true);
927 		m_view->endGroupTransaction();
928 	}
929 	for (int i = 0; i < m_doc->m_Selection->count(); ++i)
930 		m_doc->m_Selection->itemAt(i)->checkChanges(true);
931 	//Commit drag created items to undo manager.
932 	if (m_doc->m_Selection->itemAt(0)!=nullptr)
933 	{
934 		m_doc->itemAddCommit(m_doc->m_Selection->itemAt(0));
935 	}
936 	//Make sure the Zoom spinbox and page selector don't have focus if we click on the canvas
937 	m_view->m_ScMW->zoomSpinBox->clearFocus();
938 	m_view->m_ScMW->pageSelector->clearFocus();
939 	if (m_doc->m_Selection->itemAt(0) != nullptr) // is there the old clip stored for the undo action
940 	{
941 		currItem = m_doc->m_Selection->itemAt(0);
942 		m_doc->nodeEdit.finishTransaction(currItem);
943 	}
944 	if (GetItem(&currItem) && currItem->isTextFrame())
945 		m_ScMW->setCopyCutEnabled(currItem->itemText.hasSelection());
946 }
947 
948 //CB-->Doc/Fix
SeleItem(QMouseEvent * m)949 bool CanvasMode_Edit::SeleItem(QMouseEvent *m)
950 {
951 	const unsigned SELECT_IN_GROUP = Qt::AltModifier;
952 	const unsigned SELECT_MULTIPLE = Qt::ShiftModifier;
953 	const unsigned SELECT_BENEATH = Qt::ControlModifier;
954 	QTransform p;
955 	QRectF mpo;
956 	PageItem *currItem;
957 	m_canvas->m_viewMode.m_MouseButtonPressed = true;
958 	FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
959 	Mxp = mousePointDoc.x(); //m->x()/m_canvas->scale());
960 	Myp = mousePointDoc.y(); //m->y()/m_canvas->scale());
961 	double grabRadius = m_doc->guidesPrefs().grabRadius / m_canvas->scale();
962 	int MxpS = static_cast<int>(mousePointDoc.x()); //m->x()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.x());
963 	int MypS = static_cast<int>(mousePointDoc.y()); //m->y()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.y());
964 	mpo = QRectF(Mxp-grabRadius, Myp-grabRadius, grabRadius*2, grabRadius*2);
965 //	mpo.translate(m_doc->minCanvasCoordinate.x() * m_canvas->scale(), m_doc->minCanvasCoordinate.y() * m_canvas->scale());
966 	m_doc->nodeEdit.deselect();
967 // 	int a;
968 	if (!m_doc->masterPageMode())
969 	{
970 		int pgNum = -1;
971 		int docPageCount = static_cast<int>(m_doc->Pages->count() - 1);
972 		MarginStruct pageBleeds;
973 		bool drawBleed = false;
974 		if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
975 			drawBleed = true;
976 		for (int a = docPageCount; a > -1; a--)
977 		{
978 			if (drawBleed)
979 				m_doc->getBleeds(a, pageBleeds);
980 			int x = static_cast<int>(m_doc->Pages->at(a)->xOffset() - pageBleeds.left());
981 			int y = static_cast<int>(m_doc->Pages->at(a)->yOffset() - pageBleeds.top());
982 			int w = static_cast<int>(m_doc->Pages->at(a)->width() + pageBleeds.left() + pageBleeds.right());
983 			int h = static_cast<int>(m_doc->Pages->at(a)->height() + pageBleeds.bottom() + pageBleeds.top());
984 			if (QRect(x, y, w, h).contains(MxpS, MypS))
985 			{
986 				pgNum = static_cast<int>(a);
987 				if (drawBleed)  // check again if its really on the correct page
988 				{
989 					for (int a2 = docPageCount; a2 > -1; a2--)
990 					{
991 						int xn = static_cast<int>(m_doc->Pages->at(a2)->xOffset());
992 						int yn = static_cast<int>(m_doc->Pages->at(a2)->yOffset());
993 						int wn = static_cast<int>(m_doc->Pages->at(a2)->width());
994 						int hn = static_cast<int>(m_doc->Pages->at(a2)->height());
995 						if (QRect(xn, yn, wn, hn).contains(MxpS, MypS))
996 						{
997 							pgNum = static_cast<int>(a2);
998 							break;
999 						}
1000 					}
1001 				}
1002 				break;
1003 			}
1004 		}
1005 		if (pgNum >= 0)
1006 		{
1007 			if (m_doc->currentPageNumber() != pgNum)
1008 			{
1009 				m_doc->setCurrentPage(m_doc->Pages->at(pgNum));
1010 				m_view->m_ScMW->slotSetCurrentPage(pgNum);
1011 				m_view->DrawNew();
1012 			}
1013 		}
1014 		m_view->setRulerPos(m_view->contentsX(), m_view->contentsY());
1015 	}
1016 
1017 	currItem = nullptr;
1018 	if ((m->modifiers() & SELECT_BENEATH) != 0)
1019 	{
1020 		for (int i = 0; i < m_doc->m_Selection->count(); ++i)
1021 		{
1022 			if (m_canvas->frameHitTest(QPointF(mousePointDoc.x(), mousePointDoc.y()), m_doc->m_Selection->itemAt(i)) >= 0)
1023 			{
1024 				currItem = m_doc->m_Selection->itemAt(i);
1025 				m_doc->m_Selection->removeItem(currItem);
1026 				break;
1027 			}
1028 		}
1029 	}
1030 	else if ( (m->modifiers() & SELECT_MULTIPLE) == Qt::NoModifier)
1031 	{
1032 		m_view->deselectItems(false);
1033 	}
1034 	currItem = m_canvas->itemUnderCursor(m->globalPos(), currItem, (m->modifiers() & SELECT_IN_GROUP));
1035 	if (currItem)
1036 	{
1037 		m_doc->m_Selection->delaySignalsOn();
1038 		if (m_doc->m_Selection->containsItem(currItem))
1039 		{
1040 			m_doc->m_Selection->removeItem(currItem);
1041 		}
1042 		else
1043 		{
1044 			//CB: If we have a selection but the user clicks with control on another item that is not below the current
1045 			//then clear and select the new item
1046 			if ((m->modifiers() == SELECT_BENEATH) && m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem) >= 0)
1047 				m_doc->m_Selection->clear();
1048 			//CB: #7186: This was prependItem, does not seem to need to be anymore with current select code
1049 			m_doc->m_Selection->addItem(currItem);
1050 			if ( (m->modifiers() & SELECT_IN_GROUP) && (!currItem->isGroup()))
1051 			{
1052 				currItem->isSingleSel = true;
1053 			}
1054 		}
1055 		m_canvas->update();
1056 		m_doc->m_Selection->delaySignalsOff();
1057 		if (m_doc->m_Selection->count() > 1)
1058 		{
1059 			double x, y, w, h;
1060 			m_doc->m_Selection->getGroupRect(&x, &y, &w, &h);
1061 			m_view->getGroupRectScreen(&x, &y, &w, &h);
1062 		}
1063 		if (m_doc->m_Selection->count() == 1)
1064 		{
1065 			frameResizeHandle = m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem);
1066 			if ((frameResizeHandle == Canvas::INSIDE) && (!currItem->locked()))
1067 				m_view->setCursor(QCursor(Qt::SizeAllCursor));
1068 		}
1069 		else
1070 		{
1071 			m_view->setCursor(QCursor(Qt::SizeAllCursor));
1072 			m_canvas->m_viewMode.operItemResizing = false;
1073 		}
1074 		return true;
1075 	}
1076 	m_doc->m_Selection->connectItemToGUI();
1077 	if ( !(m->modifiers() & SELECT_MULTIPLE))
1078 		m_view->deselectItems(true);
1079 	return false;
1080 }
1081 
createContextMenu(PageItem * currItem,double mx,double my)1082 void CanvasMode_Edit::createContextMenu(PageItem* currItem, double mx, double my)
1083 {
1084 	ContextMenu* cmen=nullptr;
1085 	m_view->setCursor(QCursor(Qt::ArrowCursor));
1086 	m_view->setObjectUndoMode();
1087 	Mxp = mx;
1088 	Myp = my;
1089 	if (currItem!=nullptr)
1090 		cmen = new ContextMenu(*(m_doc->m_Selection), m_ScMW, m_doc);
1091 	else
1092 		cmen = new ContextMenu(m_ScMW, m_doc, mx, my);
1093 	if (cmen)
1094 		cmen->exec(QCursor::pos());
1095 	m_view->setGlobalUndoMode();
1096 	delete cmen;
1097 }
1098