1 /* This file is part of the KDE project
2  * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com)
3  * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
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; either
8  * version 2.1 of the License, or (at your option) any later version.
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
16  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "KReportDesignerItemRectBase.h"
20 #include "KReportDesignerSectionView.h"
21 #include "KReportDesigner.h"
22 #include "KReportDesignerSectionScene.h"
23 #include "KReportUtils_p.h"
24 
25 #include <KPropertySet>
26 #include <QGraphicsSceneMouseEvent>
27 #include <QApplication>
28 
29 class Q_DECL_HIDDEN KReportDesignerItemRectBase::Private
30 {
31 public:
32     Private();
33     ~Private();
34 
35     int grabAction = 0;
36     int dpiX = KReportPrivate::dpiX();
37     int dpiY = KReportPrivate::dpiY();
38     bool insideSetSceneRect = false;
39 };
40 
Private()41 KReportDesignerItemRectBase::Private::Private()
42 {
43 }
44 
~Private()45 KReportDesignerItemRectBase::Private::~Private()
46 {
47 }
48 
KReportDesignerItemRectBase(KReportDesigner * r,KReportItemBase * b)49 KReportDesignerItemRectBase::KReportDesignerItemRectBase(KReportDesigner *r, KReportItemBase *b)
50         : QGraphicsRectItem(), KReportDesignerItemBase(r, b), d(new KReportDesignerItemRectBase::Private)
51 {
52     setAcceptHoverEvents(true);
53     setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges);
54 }
55 
~KReportDesignerItemRectBase()56 KReportDesignerItemRectBase::~KReportDesignerItemRectBase()
57 {
58     delete d;
59 }
60 
sceneRect()61 QRectF KReportDesignerItemRectBase::sceneRect()
62 {
63     return QRectF(KReportItemBase::scenePosition(item()->position()), KReportItemBase::sceneSize(item()->size()));
64 }
65 
pointRect() const66 QRectF KReportDesignerItemRectBase::pointRect() const
67 {
68     return QRectF(item()->position(), item()->size());
69 }
70 
setSceneRect(const QPointF & topLeft,const QSizeF & size,SceneRectFlag update)71 void KReportDesignerItemRectBase::setSceneRect(const QPointF& topLeft, const QSizeF& size, SceneRectFlag update)
72 {
73     setSceneRect(QRectF(topLeft, size), update);
74 }
75 
setSceneRect(const QRectF & rect,SceneRectFlag update)76 void KReportDesignerItemRectBase::setSceneRect(const QRectF& rect, SceneRectFlag update)
77 {
78     if (d->insideSetSceneRect) {
79         return;
80     }
81     d->insideSetSceneRect = true;
82     QGraphicsRectItem::setPos(rect.x(), rect.y());
83     setRect(0, 0, rect.width(), rect.height());
84     if (update == SceneRectFlag::UpdateProperty) {
85         item()->setPosition(KReportItemBase::positionFromScene(QPointF(rect.x(), rect.y())));
86         item()->setSize(KReportItemBase::sizeFromScene(QSizeF(rect.width(), rect.height())));
87     }
88     this->update();
89     d->insideSetSceneRect = false;
90 }
91 
mousePressEvent(QGraphicsSceneMouseEvent * event)92 void KReportDesignerItemRectBase::mousePressEvent(QGraphicsSceneMouseEvent * event)
93 {
94     //Update and show properties
95     if (item()->dataSourceProperty()) {
96         item()->dataSourceProperty()->setListData(designer()->fieldKeys(), designer()->fieldNames());
97     }
98     item()->setPosition(KReportItemBase::positionFromScene(QPointF(sceneRect().x(), sceneRect().y())));
99     designer()->changeSet(item()->propertySet());
100     setSelected(true);
101     scene()->update();
102 
103     QGraphicsItem::mousePressEvent(event);
104 }
105 
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)106 void KReportDesignerItemRectBase::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
107 {
108     //Keep the size and position in sync
109     item()->setPosition(KReportItemBase::positionFromScene(pos()));
110     item()->setSize(KReportItemBase::sizeFromScene(QSizeF(rect().width(), rect().height())));
111 
112     QGraphicsItem::mouseReleaseEvent(event);
113 }
114 
mouseMoveEvent(QGraphicsSceneMouseEvent * event)115 void KReportDesignerItemRectBase::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
116 {
117     //kreportDebug() << m_grabAction;
118 
119     qreal w, h;
120 
121     KReportDesignerSectionScene *section = qobject_cast<KReportDesignerSectionScene*>(scene());
122     if (!section) {
123         return;
124     }
125 
126     QPointF p  = section->gridPoint(event->scenePos());
127     w = p.x() - scenePos().x();
128     h = p.y() - scenePos().y();
129 
130     //! @todo use an enum for the directions
131 
132     switch (d->grabAction) {
133     case 1:
134         if (sceneRect().y() - p.y() + rect().height() > 0 && sceneRect().x() - p.x() + rect().width() >= 0)
135             setSceneRect(QPointF(p.x(), p.y()), QSizeF(sceneRect().x() - p.x() + rect().width(), sceneRect().y() - p.y() + rect().height()));
136         break;
137     case 2:
138         if (sceneRect().y() - p.y() + rect().height() >= 0)
139             setSceneRect(QPointF(sceneRect().x(), p.y()), QSizeF(rect().width(), sceneRect().y() - p.y() + rect().height()));
140         break;
141     case 3:
142         if (sceneRect().y() - p.y() + rect().height() >= 0 && w >= 0)
143             setSceneRect(QPointF(sceneRect().x(), p.y()), QSizeF(w, sceneRect().y() - p.y() + rect().height()));
144         break;
145     case 4:
146         if (w >= 0)
147             setSceneRect(QPointF(sceneRect().x(), sceneRect().y()), QSizeF(w, (rect().height())));
148         break;
149     case 5:
150         if (h >= 0 && w >= 0)
151             setSceneRect(QPointF(sceneRect().x(), sceneRect().y()), QSizeF(w, h));
152         break;
153     case 6:
154         if (h >= 0)
155             setSceneRect(QPointF(sceneRect().x(), sceneRect().y()), QSizeF((rect().width()), h));
156         break;
157     case 7:
158         if (sceneRect().x() - p.x() + rect().width() >= 0 && h >= 0)
159             setSceneRect(QPointF(p.x(), sceneRect().y()), QSizeF(sceneRect().x() - p.x() + rect().width(), h));
160         break;
161     case 8:
162         if (sceneRect().x() - p.x() + rect().width() >= 0)
163             setSceneRect(QPointF(p.x(), sceneRect().y()), QSizeF(sceneRect().x() - p.x() + rect().width(), rect().height()));
164         break;
165     default:
166         QGraphicsItem::mouseMoveEvent(event);
167     }
168 }
169 
hoverMoveEvent(QGraphicsSceneHoverEvent * event)170 void KReportDesignerItemRectBase::hoverMoveEvent(QGraphicsSceneHoverEvent * event)
171 {
172     //m_grabAction = 0;
173 
174     if (isSelected()) {
175         d->grabAction = grabHandle(event->pos());
176         switch (d->grabAction) {
177         case 1:
178             setCursor(Qt::SizeFDiagCursor);
179             break;
180         case 2:
181             setCursor(Qt::SizeVerCursor);
182             break;
183         case 3:
184             setCursor(Qt::SizeBDiagCursor);
185             break;
186         case 4:
187             setCursor(Qt::SizeHorCursor);
188             break;
189         case 5:
190             setCursor(Qt::SizeFDiagCursor);
191             break;
192         case 6:
193             setCursor(Qt::SizeVerCursor);
194             break;
195         case 7:
196             setCursor(Qt::SizeBDiagCursor);
197             break;
198         case 8:
199             setCursor(Qt::SizeHorCursor);
200             break;
201         default:
202             unsetCursor();
203         }
204     }
205     //kreportDebug() << m_grabAction;
206 }
207 
drawHandles(QPainter * painter)208 void KReportDesignerItemRectBase::drawHandles(QPainter *painter)
209 {
210     if (isSelected()) {
211         // draw a selected border for visual purposes
212         painter->setPen(QPen(QColor(128, 128, 255), 0, Qt::DotLine));
213 
214         painter->drawRect(rect());
215 
216         const QRectF r = rect();
217         double halfW = (r.width() / 2);
218         double halfH = (r.height() / 2);
219         QPointF center = r.center();
220 
221         center += QPointF(0.75,0.75);
222 
223         painter->fillRect(center.x() - halfW, center.y() - halfH , 5, 5, QColor(128, 128, 255));
224         painter->fillRect(center.x() - 2, center.y() - halfH , 5, 5, QColor(128, 128, 255));
225         painter->fillRect(center.x() + halfW - 4, center.y() - halfH, 5, 5, QColor(128, 128, 255));
226 
227         painter->fillRect(center.x() + (halfW - 4), center.y() - 2, 5, 5, QColor(128, 128, 255));
228 
229         painter->fillRect(center.x() +  halfW - 4 , center.y() + halfH - 4 , 5, 5, QColor(128, 128, 255));
230         painter->fillRect(center.x() - 2, center.y() + halfH - 4, 5, 5, QColor(128, 128, 255));
231         painter->fillRect(center.x() - halfW, center.y() + halfH - 4 , 5, 5, QColor(128, 128, 255));
232 
233         painter->fillRect(center.x() - halfW, center.y() - 2, 5, 5, QColor(128, 128, 255));
234 
235     }
236 }
237 
238 /**
239  @return 1 2 3
240   8 0 4
241   7 6 5
242 */
grabHandle(const QPointF & pos)243 int KReportDesignerItemRectBase::grabHandle(const QPointF &pos)
244 {
245     QRectF r = boundingRect();
246     int halfW = (int)(r.width() / 2);
247     int halfH = (int)(r.height() / 2);
248     QPointF center = r.center();
249 
250     if (QRectF(center.x() - (halfW), center.y() - (halfH), 5, 5).contains(pos)) {
251         // we are over the top-left handle
252         return 1;
253     } else if (QRectF(center.x() - 2, center.y() - (halfH), 5, 5).contains(pos)) {
254         // top-middle handle
255         return 2;
256     } else if (QRectF(center.x() + (halfW - 4), center.y() - (halfH), 5, 5).contains(pos)) {
257         // top-right
258         return 3;
259     } else if (QRectF(center.x() + (halfW - 4), center.y() - 2, 5, 5).contains(pos)) {
260         // middle-right
261         return 4;
262     } else if (QRectF(center.x() + (halfW - 4), center.y() + (halfH - 4), 5, 5).contains(pos)) {
263         // bottom-left
264         return 5;
265     } else if (QRectF(center.x() - 2, center.y() + (halfH - 4), 5, 5).contains(pos)) {
266         // bottom-middle
267         return 6;
268     } else if (QRectF(center.x() - (halfW), center.y() + (halfH - 4), 5, 5).contains(pos)) {
269         // bottom-right
270         return 7;
271     } else if (QRectF(center.x() - (halfW), center.y() - 2, 5, 5).contains(pos)) {
272         // middle-right
273         return 8;
274     }
275     return 0;
276 }
277 
itemChange(GraphicsItemChange change,const QVariant & value)278 QVariant KReportDesignerItemRectBase::itemChange(GraphicsItemChange change, const QVariant &value)
279 {
280     KReportDesignerSectionScene *section = qobject_cast<KReportDesignerSectionScene*>(scene());
281     if (section) {
282 
283         if (change == ItemPositionChange) {
284             QPointF newPos = value.toPointF();
285 
286             newPos = section->gridPoint(newPos);
287             if (newPos.x() < 0)
288                 newPos.setX(0);
289             else if (newPos.x() > (scene()->width() - rect().width()))
290                 newPos.setX(scene()->width() - rect().width());
291 
292             if (newPos.y() < 0)
293                 newPos.setY(0);
294             else if (newPos.y() > (scene()->height() - rect().height()))
295                 newPos.setY(scene()->height() - rect().height());
296 
297             return newPos;
298         } else if (change == ItemPositionHasChanged) {
299             setSceneRect(value.toPointF(),
300                  KReportItemBase::sceneSize(item()->size()), SceneRectFlag::UpdateProperty);
301         } else if (change == ItemSceneHasChanged && item()) {
302             QPointF newPos = pos();
303 
304             newPos = section->gridPoint(newPos);
305             if (newPos.x() < 0)
306                 newPos.setX(0);
307             else if (newPos.x() > (scene()->width() - rect().width()))
308                 newPos.setX(scene()->width() - rect().width());
309 
310             if (newPos.y() < 0)
311                 newPos.setY(0);
312             else if (newPos.y() > (scene()->height() - rect().height()))
313                 newPos.setY(scene()->height() - rect().height());
314 
315             setSceneRect(newPos, KReportItemBase::sceneSize(item()->size()),
316                          KReportDesignerItemRectBase::SceneRectFlag::DontUpdateProperty);
317         }
318     }
319     return QGraphicsItem::itemChange(change, value);
320 }
321 
propertyChanged(const KPropertySet & s,const KProperty & p)322 void KReportDesignerItemRectBase::propertyChanged(const KPropertySet &s, const KProperty &p)
323 {
324     Q_UNUSED(s)
325     Q_UNUSED(p)
326 #if 0
327     if (p.name() == "position") {
328         item()->setPosition(item()->unit().convertToPoint(p.value().toPointF())); //TODO dont update property
329     } else if (p.name() == "size") {
330         item()->setSize(item()->unit().convertToPoint(p.value().toSizeF())); //TODO dont update property
331     }
332 #endif
333     setSceneRect(KReportItemBase::scenePosition(item()->position()),
334                  KReportItemBase::sceneSize(item()->size()), SceneRectFlag::DontUpdateProperty);
335 }
336 
move(const QPointF &)337 void KReportDesignerItemRectBase::move(const QPointF& /*m*/)
338 {
339 //! @todo
340 }
341 
properPressPoint(const KReportDesigner & d) const342 QPointF KReportDesignerItemRectBase::properPressPoint(const KReportDesigner &d) const
343 {
344     const QPointF pressPoint = d.getPressPoint();
345     const QPointF releasePoint = d.getReleasePoint();
346     if (releasePoint.x() < pressPoint.x() && releasePoint.y() < pressPoint.y()) {
347         return releasePoint;
348     }
349     if (releasePoint.x() < pressPoint.x() && releasePoint.y() > pressPoint.y()) {
350         return QPointF(releasePoint.x(), pressPoint.y());
351     }
352     if (releasePoint.x() > pressPoint.x() && releasePoint.y() < pressPoint.y()) {
353         return QPointF(pressPoint.x(), releasePoint.y());
354     }
355     return QPointF(pressPoint);
356 }
357 
properRect(const KReportDesigner & d,qreal minWidth,qreal minHeight) const358 QRectF KReportDesignerItemRectBase::properRect(const KReportDesigner &d, qreal minWidth, qreal minHeight) const
359 {
360     QPointF tempPressPoint = properPressPoint(d);
361     qreal currentPressX = tempPressPoint.x();
362     qreal currentPressY = tempPressPoint.y();
363     const qreal width = qMax(d.countSelectionWidth(), minWidth);
364     const qreal height = qMax(d.countSelectionHeight(), minHeight);
365 
366     qreal tempReleasePointX = tempPressPoint.x() + width;
367     qreal tempReleasePointY = tempPressPoint.y() + height;
368 
369     if (tempReleasePointX > scene()->width()) {
370         int offsetWidth = tempReleasePointX - scene()->width();
371         currentPressX = tempPressPoint.x() - offsetWidth;
372     }
373     if (tempReleasePointY > scene()->height()) {
374         int offsetHeight = tempReleasePointY - scene()->height();
375         currentPressY = tempPressPoint.y() - offsetHeight;
376     }
377     return (QRectF(QPointF(currentPressX, currentPressY), QSizeF(width, height)));
378 }
379 
enterInlineEditingMode()380 void KReportDesignerItemRectBase::enterInlineEditingMode()
381 {
382 }
383 
exitInlineEditingMode()384 void KReportDesignerItemRectBase::exitInlineEditingMode()
385 {
386 }
387 
updateRenderText(const QString & itemDataSource,const QString & itemStaticValue,const QString & itemType)388 void KReportDesignerItemBase::updateRenderText(const QString &itemDataSource, const QString &itemStaticValue, const QString &itemType)
389 {
390     if (itemDataSource.isEmpty()) {
391         if (itemType.isEmpty()) {
392             setRenderText(itemStaticValue);
393         } else {
394             setRenderText(dataSourceAndObjectTypeName(itemStaticValue, itemType));
395         }
396     } else {
397         if (itemType.isEmpty()) {
398             setRenderText(itemDataSource);
399         } else {
400             setRenderText(dataSourceAndObjectTypeName(itemDataSource, itemType));
401         }
402     }
403 }
404 
dpiX() const405 int KReportDesignerItemRectBase::dpiX() const
406 {
407     return d->dpiX;
408 }
409 
dpiY() const410 int KReportDesignerItemRectBase::dpiY() const
411 {
412     return d->dpiY;
413 }
414