1 /*
2 * Copyright (c) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
3 * Copyright (c) 2009,2010 Cyrille Berger <cberger@cberger.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * either version 2, or (at your option) any later version of the License.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; see the file COPYING. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "Canvas.h"
22
23 #include <QMenu>
24 #include <QMouseEvent>
25 #include <QPainter>
26
27 #include <kxmlguifactory.h>
28 #include <kundo2command.h>
29
30 #include <KoCanvasController.h>
31 #include <KoSelection.h>
32 #include <KoShapeManager.h>
33 #include <KoShapeLayer.h>
34 #include <KoToolProxy.h>
35 #include <KoUnit.h>
36
37 #include "RootSection.h"
38 #include "View.h"
39 #include "ViewManager.h"
40 #include "Section.h"
41 #include "Layout.h"
42 #include "SectionContainer.h"
43
Canvas(View * view,RootSection * doc,Section * currentSection)44 Canvas::Canvas(View* view, RootSection* doc, Section* currentSection)
45 : QWidget(view)
46 , KoCanvasBase(currentSection ? currentSection->sectionContainer() : 0)
47 , m_origin(0, 0)
48 , m_view(view)
49 , m_doc(doc)
50 {
51 m_shapeManager = new KoShapeManager(this);
52 connect(m_shapeManager, SIGNAL(selectionChanged()), SLOT(updateOriginAndSize()));
53 m_toolProxy = new KoToolProxy(this);
54 setFocusPolicy(Qt::StrongFocus);
55 // this is much faster than painting it in the paintevent
56 QPalette pal = palette();
57 pal.setColor(QPalette::Base, Qt::white);
58 pal.setColor(QPalette::Text, Qt::black);
59 setPalette(pal);
60 setBackgroundRole(QPalette::Base);
61 setAutoFillBackground(true);
62 setAttribute(Qt::WA_InputMethodEnabled, true);
63
64 if(currentSection) {
65
66 QList<KoShape*> shapes;
67 shapes.push_back(currentSection->sectionContainer()->layer());
68 shapeManager()->setShapes(shapes, KoShapeManager::AddWithoutRepaint);
69
70 KoShapeLayer* layer = currentSection->sectionContainer()->layer();
71 shapeManager()->selection()->setActiveLayer(layer);
72
73 // Make sure the canvas is enabled
74 setEnabled(true);
75
76 update();
77 } else {
78 setEnabled(false);
79 }
80 }
81
~Canvas()82 Canvas::~Canvas()
83 {
84 delete m_toolProxy;
85 delete m_shapeManager;
86 }
87
setDocumentOffset(const QPoint & offset)88 void Canvas::setDocumentOffset(const QPoint &offset)
89 {
90 m_originalOffset = offset;
91 updateOffset();
92 }
93
addCommand(KUndo2Command * command)94 void Canvas::addCommand(KUndo2Command *command)
95 {
96 m_doc->addCommand(m_view->activeSection(), command);
97 updateOriginAndSize();
98 }
99
shapeManager() const100 KoShapeManager * Canvas::shapeManager() const
101 {
102 return m_shapeManager;
103 }
104
updateCanvas(const QRectF & rc)105 void Canvas::updateCanvas(const QRectF& rc)
106 {
107 QRect clipRect(viewToWidget(viewConverter()->documentToView(rc).toRect()));
108 clipRect.adjust(-2, -2, 2, 2); // Resize to fit anti-aliasing
109 clipRect.moveTopLeft(clipRect.topLeft() - m_documentOffset);
110 update(clipRect);
111
112 emit canvasUpdated();
113 }
114
viewConverter() const115 KoViewConverter * Canvas::viewConverter() const
116 {
117 return m_view->zoomHandler();
118 }
119
unit() const120 KoUnit Canvas::unit() const
121 {
122 return KoUnit(KoUnit::Centimeter);
123 }
124
documentOffset() const125 const QPoint & Canvas::documentOffset() const
126 {
127 return m_documentOffset;
128 }
129
documentOrigin() const130 QPoint Canvas::documentOrigin() const
131 {
132 return m_origin;
133 }
134
paintEvent(QPaintEvent * event)135 void Canvas::paintEvent(QPaintEvent *event)
136 {
137 QPainter painter(this);
138
139 painter.translate(-documentOffset());
140 painter.setRenderHint(QPainter::Antialiasing);
141 QRectF clipRect = event->rect().translated(documentOffset());
142 painter.setClipRect(clipRect);
143
144 painter.translate(m_origin.x(), m_origin.y());
145
146 const KoViewConverter* converter = viewConverter();
147 shapeManager()->paint(painter, *converter, false);
148 painter.setRenderHint(QPainter::Antialiasing, false);
149
150 painter.setRenderHint(QPainter::Antialiasing);
151 m_toolProxy->paint(painter, *converter);
152 }
153
tabletEvent(QTabletEvent * event)154 void Canvas::tabletEvent(QTabletEvent *event)
155 {
156 m_toolProxy->tabletEvent(event, viewConverter()->viewToDocument(widgetToView(event->pos() + m_documentOffset)));
157 }
158
mousePressEvent(QMouseEvent * event)159 void Canvas::mousePressEvent(QMouseEvent *event)
160 {
161 m_toolProxy->mousePressEvent(event, viewConverter()->viewToDocument(widgetToView(event->pos() + m_documentOffset)));
162
163 if(!event->isAccepted() && event->button() == Qt::RightButton) {
164 showContextMenu(event->globalPos(), toolProxy()->popupActionList());
165 }
166
167 event->setAccepted(true);
168 }
169
mouseDoubleClickEvent(QMouseEvent * event)170 void Canvas::mouseDoubleClickEvent(QMouseEvent *event)
171 {
172 m_toolProxy->mouseDoubleClickEvent(event, viewConverter()->viewToDocument(widgetToView(event->pos() + m_documentOffset)));
173 }
174
mouseMoveEvent(QMouseEvent * event)175 void Canvas::mouseMoveEvent(QMouseEvent *event)
176 {
177 m_toolProxy->mouseMoveEvent(event, viewConverter()->viewToDocument(widgetToView(event->pos() + m_documentOffset)));
178 }
179
mouseReleaseEvent(QMouseEvent * event)180 void Canvas::mouseReleaseEvent(QMouseEvent *event)
181 {
182 m_toolProxy->mouseReleaseEvent(event, viewConverter()->viewToDocument(widgetToView(event->pos() + m_documentOffset)));
183 }
184
keyPressEvent(QKeyEvent * event)185 void Canvas::keyPressEvent(QKeyEvent *event)
186 {
187 m_toolProxy->keyPressEvent(event);
188 #if 0
189
190 if(! event->isAccepted()) {
191 event->accept();
192 switch(event->key()) {
193 case Qt::Key_Home:
194 m_view->navigatePage(KoPageApp::PageFirst);
195 break;
196 case Qt::Key_PageUp:
197 m_view->navigatePage(KoPageApp::PagePrevious);
198 break;
199 case Qt::Key_PageDown:
200 m_view->navigatePage(KoPageApp::PageNext);
201 break;
202 case Qt::Key_End:
203 m_view->navigatePage(KoPageApp::PageLast);
204 break;
205 default:
206 event->ignore();
207 break;
208 }
209 }
210 if(! event->isAccepted()) {
211 if(event->key() == Qt::Key_Backtab
212 or(event->key() == Qt::Key_Tab && (event->modifiers() & Qt::ShiftModifier))) {
213 focusNextPrevChild(false);
214 } else if(event->key() == Qt::Key_Tab) {
215 focusNextPrevChild(true);
216 }
217 }
218 #endif
219 }
220
keyReleaseEvent(QKeyEvent * event)221 void Canvas::keyReleaseEvent(QKeyEvent *event)
222 {
223 m_toolProxy->keyReleaseEvent(event);
224 }
225
wheelEvent(QWheelEvent * event)226 void Canvas::wheelEvent(QWheelEvent * event)
227 {
228 m_toolProxy->wheelEvent(event, viewConverter()->viewToDocument(widgetToView(event->pos() + m_documentOffset)));
229 }
230
closeEvent(QCloseEvent * event)231 void Canvas::closeEvent(QCloseEvent * event)
232 {
233 event->ignore();
234 }
235
updateInputMethodInfo()236 void Canvas::updateInputMethodInfo()
237 {
238 updateMicroFocus();
239 }
240
inputMethodQuery(Qt::InputMethodQuery query) const241 QVariant Canvas::inputMethodQuery(Qt::InputMethodQuery query) const
242 {
243 if (query == Qt::ImMicroFocus) {
244 QRectF rect = (m_toolProxy->inputMethodQuery(query, *(viewConverter())).toRectF()).toRect();
245 QPointF scroll(canvasController()->scrollBarValue());
246 rect.translate(documentOrigin() - scroll);
247 return rect.toRect();
248 }
249 return m_toolProxy->inputMethodQuery(query, *(viewConverter()));
250 }
251
inputMethodEvent(QInputMethodEvent * event)252 void Canvas::inputMethodEvent(QInputMethodEvent *event)
253 {
254 m_toolProxy->inputMethodEvent(event);
255 }
256
resizeEvent(QResizeEvent * event)257 void Canvas::resizeEvent(QResizeEvent * event)
258 {
259 emit sizeChanged(event->size());
260 updateOriginAndSize();
261 }
262
showContextMenu(const QPoint & globalPos,const QList<QAction * > & actionList)263 void Canvas::showContextMenu(const QPoint& globalPos, const QList<QAction*>& actionList)
264 {
265 m_view->unplugActionList("toolproxy_action_list");
266 m_view->plugActionList("toolproxy_action_list", actionList);
267 QMenu *menu = dynamic_cast<QMenu*>(m_view->factory()->container("default_canvas_popup", m_view));
268
269 if(menu)
270 menu->exec(globalPos);
271 }
272
setBackgroundColor(const QColor & color)273 void Canvas::setBackgroundColor(const QColor &color)
274 {
275 QPalette pal = palette();
276 pal.setColor(QPalette::Normal, backgroundRole(), color);
277 pal.setColor(QPalette::Inactive, backgroundRole(), color);
278 setPalette(pal);
279 }
280
updateOriginAndSize()281 void Canvas::updateOriginAndSize()
282 {
283 if(m_view->activeSection()) {
284 QRectF rect = m_view->activeSection()->layout()->boundingBox();
285 if(rect != m_oldDocumentRect) {
286 m_oldDocumentRect = rect;
287 emit(documentRect(rect));
288 update();
289 }
290 QRect viewRect = viewConverter()->documentToView(rect).toRect();
291 if(m_oldViewDocumentRect != viewRect) {
292 m_oldViewDocumentRect = viewRect;
293 m_origin = -viewRect.topLeft();
294 KoCanvasController* controller = canvasController();
295 if(controller) {
296 // tell canvas controller the new document size in pixel
297 controller->updateDocumentSize(viewRect.size(), true);
298 // make sure the actual selection is visible
299 KoSelection * selection = m_shapeManager->selection();
300 if(selection->count())
301 controller->ensureVisible(viewConverter()->documentToView(selection->boundingRect()));
302 updateOffset();
303 }
304 }
305 }
306 }
307
updateOffset()308 void Canvas::updateOffset()
309 {
310 qreal dx = qMax(0, (size().width() - m_oldViewDocumentRect.size().width()) / 2);
311 qreal dy = qMax(0, (size().height() - m_oldViewDocumentRect.size().height()) / 2);
312 m_documentOffset = m_originalOffset - QPoint(dx, dy);
313 }
314
gridSize(qreal * horizontal,qreal * vertical) const315 void Canvas::gridSize(qreal *horizontal, qreal *vertical) const
316 {
317 *horizontal = 1;
318 *vertical = 1;
319 }
320
snapToGrid() const321 bool Canvas::snapToGrid() const
322 {
323 return false;
324 }
325
setCursor(const QCursor & cursor)326 void Canvas::setCursor(const QCursor &cursor)
327 {
328 QWidget::setCursor(cursor);
329 }
330
focusInEvent(QFocusEvent * event)331 void Canvas::focusInEvent(QFocusEvent * event)
332 {
333 QWidget::focusInEvent(event);
334 emit(canvasReceivedFocus());
335 }
336
widgetToView(const QPoint & p) const337 QPoint Canvas::widgetToView(const QPoint& p) const
338 {
339 return p - m_origin;
340 }
341
widgetToView(const QRect & r) const342 QRect Canvas::widgetToView(const QRect& r) const
343 {
344 return r.translated(- m_origin);
345 }
346
viewToWidget(const QPoint & p) const347 QPoint Canvas::viewToWidget(const QPoint& p) const
348 {
349 return p + m_origin;
350 }
351
viewToWidget(const QRect & r) const352 QRect Canvas::viewToWidget(const QRect& r) const
353 {
354 return r.translated(m_origin);
355 }
356