File indexing completed on 2024-05-12 16:34:24

0001 /* This file is part of the KDE project
0002    Copyright 2007 Montel Laurent <montel@kde.org>
0003    Copyright 2011 Silvio Heinrich <plassy@web.de>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "PictureTool.h"
0022 #include "PictureShape.h"
0023 #include "ChangeImageCommand.h"
0024 #include "ClipCommand.h"
0025 #include "CropWidget.h"
0026 
0027 #include <QUrl>
0028 #include <QFileDialog>
0029 #include <QImageReader>
0030 
0031 #include <klocalizedstring.h>
0032 #include <KIO/Job>
0033 
0034 #include <KoIcon.h>
0035 #include <KoCanvasBase.h>
0036 #include <KoImageCollection.h>
0037 #include <KoImageData.h>
0038 #include <KoSelection.h>
0039 #include <KoShapeManager.h>
0040 #include <KoShapeController.h>
0041 #include <KoDocumentResourceManager.h>
0042 #include <KoPointerEvent.h>
0043 #include <KoFilterEffect.h>
0044 #include <KoFilterEffectRegistry.h>
0045 #include <KoFilterEffectConfigWidgetBase.h>
0046 #include <KoFilterEffectStack.h>
0047 
0048 #include "ui_wdgPictureTool.h"
0049 
0050 struct PictureToolUI: public QWidget, public Ui::PictureTool
0051 {
0052     PictureToolUI()
0053     {
0054         setupUi(this);
0055     }
0056 
0057     void blockAllSignals(bool block)
0058     {
0059         leftDoubleSpinBox->blockSignals(block);
0060         rightDoubleSpinBox->blockSignals(block);
0061         topDoubleSpinBox->blockSignals(block);
0062         bottomDoubleSpinBox->blockSignals(block);
0063         cropWidget->blockSignals(block);
0064         cbAspect->blockSignals(block);
0065         cmbColorMode->blockSignals(block);
0066     }
0067 };
0068 
0069 // ---------------------------------------------------- //
0070 
0071 PictureTool::PictureTool(KoCanvasBase* canvas)
0072     : KoToolBase(canvas),
0073       m_pictureshape(0),
0074       m_pictureToolUI(0)
0075 {
0076 }
0077 
0078 void PictureTool::activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes)
0079 {
0080     Q_UNUSED(toolActivation);
0081 
0082     foreach (KoShape *shape, shapes) {
0083         if ((m_pictureshape = dynamic_cast<PictureShape*>(shape)))
0084             break;
0085     }
0086 
0087     if (!m_pictureshape) {
0088         emit done();
0089         return;
0090     }
0091 
0092     if (m_pictureToolUI) {
0093         m_pictureToolUI->cropWidget->setPictureShape(m_pictureshape);
0094         updateControlElements();
0095     }
0096 
0097     useCursor(Qt::ArrowCursor);
0098 }
0099 
0100 void PictureTool::deactivate()
0101 {
0102     m_pictureshape = 0;
0103 }
0104 
0105 QWidget *PictureTool::createOptionWidget()
0106 {
0107     m_pictureToolUI = new PictureToolUI();
0108     m_pictureToolUI->cmbColorMode->addItem(i18n("Standard")  , PictureShape::Standard);
0109     m_pictureToolUI->cmbColorMode->addItem(i18n("Greyscale") , PictureShape::Greyscale);
0110     m_pictureToolUI->cmbColorMode->addItem(i18n("Monochrome"), PictureShape::Mono);
0111     m_pictureToolUI->cmbColorMode->addItem(i18n("Watermark") , PictureShape::Watermark);
0112     m_pictureToolUI->bnImageFile->setIcon(koIcon("document-open"));
0113 
0114     updateControlElements();
0115 
0116     connect(m_pictureToolUI->bnImageFile, SIGNAL(clicked(bool)), this, SLOT(changeUrlPressed()));
0117     connect(m_pictureToolUI->cmbColorMode, SIGNAL(currentIndexChanged(int)), this, SLOT(colorModeChanged(int)));
0118     connect(m_pictureToolUI->leftDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(cropEditFieldsChanged()));
0119     connect(m_pictureToolUI->rightDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(cropEditFieldsChanged()));
0120     connect(m_pictureToolUI->topDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(cropEditFieldsChanged()));
0121     connect(m_pictureToolUI->bottomDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(cropEditFieldsChanged()));
0122     connect(m_pictureToolUI->cbAspect, SIGNAL(toggled(bool)), this, SLOT(aspectCheckBoxChanged(bool)));
0123     connect(m_pictureToolUI->bnFill, SIGNAL(pressed()), this, SLOT(fillButtonPressed()));
0124     connect(m_pictureToolUI->cbContour, SIGNAL(toggled(bool)), this, SLOT(contourCheckBoxChanged(bool)));
0125     connect(m_pictureToolUI->cropWidget, SIGNAL(sigCropRegionChanged(QRectF,bool)), this, SLOT(cropRegionChanged(QRectF,bool)));
0126 
0127     return m_pictureToolUI;
0128 }
0129 
0130 void PictureTool::updateControlElements()
0131 {
0132     if (m_pictureshape) {
0133         QSizeF imageSize = m_pictureshape->imageData()->imageSize();
0134         PictureShape::ColorMode mode      = m_pictureshape->colorMode();
0135         ClippingRect clippingRect(m_pictureshape->cropRect());
0136 
0137         clippingRect.right = 1.0 - clippingRect.right;
0138         clippingRect.bottom = 1.0 - clippingRect.bottom;
0139         clippingRect.scale(imageSize);
0140 
0141         m_pictureToolUI->blockAllSignals(true);
0142         m_pictureToolUI->cropWidget->setPictureShape(m_pictureshape);
0143         m_pictureToolUI->cropWidget->setKeepPictureProportion(m_pictureshape->isPictureInProportion());
0144         m_pictureToolUI->cbAspect->setChecked(m_pictureshape->isPictureInProportion());
0145         m_pictureToolUI->cmbColorMode->setCurrentIndex(m_pictureToolUI->cmbColorMode->findData(mode));
0146 
0147         m_pictureToolUI->leftDoubleSpinBox->setRange(0.0, imageSize.width());
0148         m_pictureToolUI->rightDoubleSpinBox->setRange(0.0, imageSize.width());
0149         m_pictureToolUI->topDoubleSpinBox->setRange(0.0, imageSize.height());
0150         m_pictureToolUI->bottomDoubleSpinBox->setRange(0.0, imageSize.height());
0151         m_pictureToolUI->leftDoubleSpinBox->setValue(clippingRect.left);
0152         m_pictureToolUI->rightDoubleSpinBox->setValue(clippingRect.right);
0153         m_pictureToolUI->topDoubleSpinBox->setValue(clippingRect.top);
0154         m_pictureToolUI->bottomDoubleSpinBox->setValue(clippingRect.bottom);
0155         m_pictureToolUI->cbContour->setChecked(m_pictureshape->clipPath() != 0);
0156         m_pictureToolUI->blockAllSignals(false);
0157     }
0158 }
0159 
0160 void PictureTool::changeUrlPressed()
0161 {
0162     if (m_pictureshape == 0)
0163         return;
0164     // TODO: think about using KoFileDialog everywhere, after extending it to support remote urls
0165     QFileDialog *dialog = new QFileDialog();
0166     QStringList imageMimeTypes;
0167     foreach(const QByteArray &mimeType, QImageReader::supportedMimeTypes()) {
0168         imageMimeTypes << QLatin1String(mimeType);
0169     }
0170     dialog->setMimeTypeFilters(imageMimeTypes);
0171     dialog->setFileMode(QFileDialog::ExistingFile);
0172     dialog->setAcceptMode(QFileDialog::AcceptOpen);
0173     dialog->exec();
0174     QUrl url = dialog->selectedUrls().value(0);
0175 
0176     if (!url.isEmpty()) {
0177         // TODO move this to an action in the libs, with a nice dialog or something.
0178         KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::NoReload, 0);
0179         connect(job, SIGNAL(result(KJob*)), this, SLOT(setImageData(KJob*)));
0180     }
0181 }
0182 
0183 void PictureTool::cropEditFieldsChanged()
0184 {
0185     ClippingRect clippingRect;
0186     clippingRect.left = m_pictureToolUI->leftDoubleSpinBox->value();
0187     clippingRect.right = m_pictureToolUI->rightDoubleSpinBox->value();
0188     clippingRect.top = m_pictureToolUI->topDoubleSpinBox->value();
0189     clippingRect.bottom = m_pictureToolUI->bottomDoubleSpinBox->value();
0190     clippingRect.uniform = false;
0191     clippingRect.inverted = true;
0192     clippingRect.normalize(m_pictureshape->imageData()->imageSize());
0193 
0194     m_pictureToolUI->cropWidget->setCropRect(clippingRect.toRect());
0195 }
0196 
0197 void PictureTool::cropRegionChanged(const QRectF& rect, bool undoPrev)
0198 {
0199     if (undoPrev) {
0200         canvas()->shapeController()->resourceManager()->undoStack()->undo();
0201     }
0202 
0203     ChangeImageCommand *cmd = new ChangeImageCommand(m_pictureshape, rect);
0204     // connect before adding the command, so that "updateControlElements()" is executed
0205     // when the command is added to the undo stack.
0206     connect(cmd, SIGNAL(sigExecuted()), this, SLOT(updateControlElements()));
0207     canvas()->addCommand(cmd);
0208 }
0209 
0210 void PictureTool::colorModeChanged(int cmbIndex)
0211 {
0212     PictureShape::ColorMode mode = (PictureShape::ColorMode)m_pictureToolUI->cmbColorMode->itemData(cmbIndex).toInt();
0213     ChangeImageCommand     *cmd  = new ChangeImageCommand(m_pictureshape, mode);
0214     canvas()->addCommand(cmd);
0215     // connect after adding the command to the undo stack to prevent a
0216     // call to "updateControlElements()" at this point
0217     connect(cmd, SIGNAL(sigExecuted()), this, SLOT(updateControlElements()));
0218 }
0219 
0220 void PictureTool::aspectCheckBoxChanged(bool checked)
0221 {
0222     m_pictureToolUI->cropWidget->setKeepPictureProportion(checked);
0223 }
0224 
0225 void PictureTool::contourCheckBoxChanged(bool checked)
0226 {
0227     canvas()->addCommand(new ClipCommand(m_pictureshape, checked));
0228 }
0229 
0230 void PictureTool::fillButtonPressed()
0231 {
0232     m_pictureToolUI->cropWidget->maximizeCroppedArea();
0233 }
0234 
0235 void PictureTool::setImageData(KJob *job)
0236 {
0237     if (m_pictureshape == 0)
0238         return; // ugh, the user deselected the image in between. We should move this code to main anyway redesign it
0239 
0240     KIO::StoredTransferJob *transferJob = qobject_cast<KIO::StoredTransferJob*>(job);
0241     Q_ASSERT(transferJob);
0242     if (m_pictureshape->imageCollection()) {
0243         KoImageData        *data = m_pictureshape->imageCollection()->createImageData(transferJob->data());
0244         ChangeImageCommand *cmd  = new ChangeImageCommand(m_pictureshape, data);
0245         // connect before adding the command, so that "updateControlElements()" is executed
0246         // when the command is added to the undo stack.
0247         connect(cmd, SIGNAL(sigExecuted()), this, SLOT(updateControlElements()));
0248         canvas()->addCommand(cmd);
0249     }
0250 }
0251 
0252 void PictureTool::mousePressEvent(KoPointerEvent *event)
0253 {
0254     if (event->button() == Qt::RightButton) {
0255         event->ignore();
0256     }
0257 }
0258 
0259 void PictureTool::mouseDoubleClickEvent(KoPointerEvent *event)
0260 {
0261     if (canvas()->shapeManager()->shapeAt(event->point) != m_pictureshape) {
0262         event->ignore(); // allow the event to be used by another
0263         return;
0264     }
0265 
0266     changeUrlPressed();
0267 }