File indexing completed on 2024-05-12 15:27:35
0001 /*************************************************************************** 0002 File : WorksheetElement.cpp 0003 Project : LabPlot 0004 Description : Base class for all Worksheet children. 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2009 Tilman Benkert (thzs@gmx.net) 0007 Copyright : (C) 2012-2017 by Alexander Semke (alexander.semke@web.de) 0008 0009 ***************************************************************************/ 0010 0011 /*************************************************************************** 0012 * * 0013 * This program is free software; you can redistribute it and/or modify * 0014 * it under the terms of the GNU General Public License as published by * 0015 * the Free Software Foundation; either version 2 of the License, or * 0016 * (at your option) any later version. * 0017 * * 0018 * This program is distributed in the hope that it will be useful, * 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0021 * GNU General Public License for more details. * 0022 * * 0023 * You should have received a copy of the GNU General Public License * 0024 * along with this program; if not, write to the Free Software * 0025 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0026 * Boston, MA 02110-1301 USA * 0027 * * 0028 ***************************************************************************/ 0029 0030 #include "backend/worksheet/Worksheet.h" 0031 #include "backend/worksheet/WorksheetElement.h" 0032 #include "backend/worksheet/plots/AbstractPlot.h" 0033 0034 #include <QGraphicsItem> 0035 #include <QMenu> 0036 #include <QPen> 0037 #include <KLocalizedString> 0038 0039 /** 0040 * \class WorksheetElement 0041 * \brief Base class for all Worksheet children. 0042 * 0043 */ 0044 WorksheetElement::WorksheetElement(const QString &name, AspectType type) 0045 : AbstractAspect(name, type) { 0046 0047 m_drawingOrderMenu = new QMenu(i18n("Drawing &order")); 0048 m_drawingOrderMenu->setIcon(QIcon::fromTheme("layer-bottom")); 0049 m_moveBehindMenu = new QMenu(i18n("Move &behind")); 0050 m_moveBehindMenu->setIcon(QIcon::fromTheme("draw-arrow-down")); 0051 m_moveInFrontOfMenu = new QMenu(i18n("Move in &front of")); 0052 m_moveInFrontOfMenu->setIcon(QIcon::fromTheme("draw-arrow-up")); 0053 m_drawingOrderMenu->addMenu(m_moveBehindMenu); 0054 m_drawingOrderMenu->addMenu(m_moveInFrontOfMenu); 0055 0056 connect(m_moveBehindMenu, &QMenu::aboutToShow, this, &WorksheetElement::prepareMoveBehindMenu); 0057 connect(m_moveInFrontOfMenu, &QMenu::aboutToShow, this, &WorksheetElement::prepareMoveInFrontOfMenu); 0058 connect(m_moveBehindMenu, &QMenu::triggered, this, &WorksheetElement::execMoveBehind); 0059 connect(m_moveInFrontOfMenu, &QMenu::triggered, this, &WorksheetElement::execMoveInFrontOf); 0060 } 0061 0062 WorksheetElement::~WorksheetElement() { 0063 delete m_moveBehindMenu; 0064 delete m_moveInFrontOfMenu; 0065 delete m_drawingOrderMenu; 0066 } 0067 0068 /** 0069 * \fn QGraphicsItem *WorksheetElement::graphicsItem() const 0070 * \brief Return the graphics item representing this element. 0071 * 0072 */ 0073 0074 /** 0075 * \fn void WorksheetElement::setVisible(bool on) 0076 * \brief Show/hide the element. 0077 * 0078 */ 0079 0080 /** 0081 * \fn bool WorksheetElement::isVisible() const 0082 * \brief Return whether the element is (at least) partially visible. 0083 * 0084 */ 0085 0086 /** 0087 * \brief Return whether the element is fully visible (i.e., including all child elements). 0088 * 0089 * The standard implementation returns isVisible(). 0090 */ 0091 bool WorksheetElement::isFullyVisible() const { 0092 return isVisible(); 0093 } 0094 0095 /** 0096 * \fn void WorksheetElement::setPrinting(bool on) 0097 * \brief Switches the printing mode on/off 0098 * 0099 */ 0100 0101 /** 0102 * \fn void WorksheetElement::retransform() 0103 * \brief Tell the element to newly transform its graphics item into its coordinate system. 0104 * 0105 * This method must not change the undo-aware data of the element, only 0106 * the graphics item which represents the item is to be updated. 0107 */ 0108 0109 void WorksheetElement::setZValue(qreal value) { 0110 graphicsItem()->setZValue(value); 0111 } 0112 0113 /** 0114 This does exactly what Qt internally does to creates a shape from a painter path. 0115 */ 0116 QPainterPath WorksheetElement::shapeFromPath(const QPainterPath &path, const QPen &pen) { 0117 if (path == QPainterPath()) 0118 return path; 0119 0120 // PERFTRACE("WorksheetElement::shapeFromPath()"); 0121 0122 // TODO: We unfortunately need this hack as QPainterPathStroker will set a width of 1.0 0123 // if we pass a value of 0.0 to QPainterPathStroker::setWidth() 0124 const qreal penWidthZero = qreal(1.e-8); 0125 0126 QPainterPathStroker ps; 0127 ps.setCapStyle(pen.capStyle()); 0128 if (pen.widthF() <= 0.0) 0129 ps.setWidth(penWidthZero); 0130 else 0131 ps.setWidth(pen.widthF()); 0132 ps.setJoinStyle(pen.joinStyle()); 0133 ps.setMiterLimit(pen.miterLimit()); 0134 0135 QPainterPath p = ps.createStroke(path); 0136 p.addPath(path); 0137 0138 return p; 0139 } 0140 0141 QMenu* WorksheetElement::createContextMenu() { 0142 QMenu* menu = AbstractAspect::createContextMenu(); 0143 0144 //add the sub-menu for the drawing order 0145 0146 //don't add the drawing order menu for axes and legends, they're always drawn on top of each other elements 0147 if (type() == AspectType::Axis || type() == AspectType::CartesianPlotLegend) 0148 return menu; 0149 0150 //for plots in a worksheet with an active layout the Z-factor is not relevant but we still 0151 //want to use the "Drawing order" menu to be able to change the position/order of the plot in the layout. 0152 //Since the order of the child in the list of children is opposite to the Z-factor, we change 0153 //the names of the menus to adapt to the reversed logic. 0154 if (dynamic_cast<AbstractPlot*>(this) ) { 0155 const Worksheet* w = dynamic_cast<const Worksheet*>(this->parentAspect()); 0156 if (!w) 0157 return menu; 0158 0159 if (w->layout() != Worksheet::Layout::NoLayout) { 0160 m_moveBehindMenu->setTitle(i18n("Move in &front of")); 0161 m_moveBehindMenu->setIcon(QIcon::fromTheme("draw-arrow-up")); 0162 m_moveInFrontOfMenu->setTitle(i18n("Move &behind")); 0163 m_moveInFrontOfMenu->setIcon(QIcon::fromTheme("draw-arrow-down")); 0164 } else { 0165 m_moveBehindMenu->setTitle(i18n("Move &behind")); 0166 m_moveBehindMenu->setIcon(QIcon::fromTheme("draw-arrow-down")); 0167 m_moveInFrontOfMenu->setTitle(i18n("Move in &front of")); 0168 m_moveInFrontOfMenu->setIcon(QIcon::fromTheme("draw-arrow-up")); 0169 } 0170 } 0171 0172 //don't add the drawing order menu if the parent element has no other children 0173 int children = 0; 0174 for (auto* child : parentAspect()->children<WorksheetElement>()) { 0175 if (child->type() != AspectType::Axis && child->type() != AspectType::CartesianPlotLegend) 0176 children++; 0177 } 0178 0179 if (children > 1) { 0180 menu->addSeparator(); 0181 menu->addMenu(m_drawingOrderMenu); 0182 } 0183 0184 return menu; 0185 } 0186 0187 void WorksheetElement::prepareMoveBehindMenu() { 0188 m_moveBehindMenu->clear(); 0189 AbstractAspect* parent = parentAspect(); 0190 int index = parent->indexOfChild<WorksheetElement>(this); 0191 const QVector<WorksheetElement*>& children = parent->children<WorksheetElement>(); 0192 0193 for (int i = 0; i < index; ++i) { 0194 const WorksheetElement* elem = children.at(i); 0195 //axes and legends are always drawn on top of other elements, don't add them to the menu 0196 if (elem->type() != AspectType::Axis && elem->type() != AspectType::CartesianPlotLegend) { 0197 QAction* action = m_moveBehindMenu->addAction(elem->icon(), elem->name()); 0198 action->setData(i); 0199 } 0200 } 0201 0202 //TODO: doesn't always work properly 0203 //hide the "move behind" menu if it doesn't have any entries, show if not shown yet otherwise 0204 //m_moveBehindMenu->menuAction()->setVisible(!m_moveBehindMenu->isEmpty()); 0205 } 0206 0207 void WorksheetElement::prepareMoveInFrontOfMenu() { 0208 m_moveInFrontOfMenu->clear(); 0209 AbstractAspect* parent = parentAspect(); 0210 int index = parent->indexOfChild<WorksheetElement>(this); 0211 const QVector<WorksheetElement*>& children = parent->children<WorksheetElement>(); 0212 0213 for (int i = index + 1; i < children.size(); ++i) { 0214 const WorksheetElement* elem = children.at(i); 0215 //axes and legends are always drawn on top of other elements, don't add them to the menu 0216 if (elem->type() != AspectType::Axis && elem->type() != AspectType::CartesianPlotLegend) { 0217 QAction* action = m_moveInFrontOfMenu->addAction(elem->icon(), elem->name()); 0218 action->setData(i); 0219 } 0220 } 0221 0222 //TODO: doesn't alway work properly 0223 //hide the "move in front" menu if it doesn't have any entries, show if not shown yet otherwise 0224 //m_moveInFrontOfMenu->menuAction()->setVisible(!m_moveInFrontOfMenu->isEmpty()); 0225 } 0226 0227 void WorksheetElement::execMoveInFrontOf(QAction* action) { 0228 AbstractAspect* parent = parentAspect(); 0229 int index = action->data().toInt(); 0230 AbstractAspect* sibling1 = parent->child<WorksheetElement>(index); 0231 AbstractAspect* sibling2 = parent->child<WorksheetElement>(index + 1); 0232 beginMacro(i18n("%1: move behind %2.", name(), sibling1->name())); 0233 remove(); 0234 parent->insertChildBefore(this, sibling2); 0235 endMacro(); 0236 } 0237 0238 void WorksheetElement::execMoveBehind(QAction* action) { 0239 AbstractAspect* parent = parentAspect(); 0240 int index = action->data().toInt(); 0241 AbstractAspect* sibling = parent->child<WorksheetElement>(index); 0242 beginMacro(i18n("%1: move in front of %2.", name(), sibling->name())); 0243 remove(); 0244 parent->insertChildBefore(this, sibling); 0245 endMacro(); 0246 } 0247 0248 void WorksheetElement::loadThemeConfig(const KConfig &) { 0249 } 0250 0251 void WorksheetElement::saveThemeConfig(const KConfig &) { 0252 }