diff --git a/krita/libbrush/kis_brush_server.cpp b/krita/libbrush/kis_brush_server.cpp index a841d42b93..0f36396830 100644 --- a/krita/libbrush/kis_brush_server.cpp +++ b/krita/libbrush/kis_brush_server.cpp @@ -1,165 +1,164 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_server.h" #include #include #include #include #include #include -#include #include #include #include "kis_abr_brush.h" #include "kis_abr_brush_collection.h" #include "kis_gbr_brush.h" #include "kis_imagepipe_brush.h" #include "kis_png_brush.h" #include "kis_svg_brush.h" class BrushResourceServer : public KisBrushResourceServer { public: BrushResourceServer() : KisBrushResourceServer("kis_brushes", "*.gbr:*.gih:*.abr:*.png:*.svg") { } ///Reimplemented virtual bool importResourceFile(const QString& filename, bool fileCreation = true) { QFileInfo fi(filename); if (fi.exists() == false) return false; if (fi.size() == 0) return false; if (fi.suffix().toLower() == "abr") { if (fileCreation) { QFile::copy(filename, saveLocation() + fi.fileName()); } QList collectionResources = createResources(filename); foreach(KisBrushSP brush, collectionResources) { addResource(brush); } } else { return KisBrushResourceServer::importResourceFile(filename, fileCreation); } qApp->processEvents(QEventLoop::AllEvents); return true; } private: ///Reimplemented virtual QList createResources(const QString & filename) { QList brushes; QString fileExtension = QFileInfo(filename).suffix().toLower(); if (fileExtension == "abr") { KisAbrBrushCollection collection(filename); collection.load(); foreach(KisAbrBrush * abrBrush, collection.brushes()) { // abrBrush->setBrushTipImage(QImage()); brushes.append(abrBrush); addTag(abrBrush, collection.filename()); } } else { brushes.append(createResource(filename)); } return brushes; } ///Reimplemented virtual KisBrushSP createResource(const QString & filename) { QString fileExtension = QFileInfo(filename).suffix().toLower(); KisBrushSP brush; if (fileExtension == "gbr") { brush = new KisGbrBrush(filename); } else if (fileExtension == "gih") { brush = new KisImagePipeBrush(filename); } else if (fileExtension == "png") { brush = new KisPngBrush(filename); } else if (fileExtension == "svg") { brush = new KisSvgBrush(filename); } return brush; } }; KisBrushServer::KisBrushServer() { KGlobal::mainComponent().dirs()->addResourceType("kis_brushes", "data", "krita/brushes/"); KGlobal::mainComponent().dirs()->addResourceDir("kis_brushes", "/usr/share/create/brushes/gimp"); KGlobal::mainComponent().dirs()->addResourceDir("kis_brushes", QDir::homePath() + QString("/.create/brushes/gimp")); m_brushServer = new BrushResourceServer(); if (!QFileInfo(m_brushServer->saveLocation()).exists()) { QDir().mkpath(m_brushServer->saveLocation()); } m_brushThread = new KoResourceLoaderThread(m_brushServer); m_brushThread->start(); foreach(KisBrushSP brush, m_brushServer->resources()) { if (!dynamic_cast(brush.data())) { brush->setBrushTipImage(QImage()); } } } KisBrushServer::~KisBrushServer() { dbgRegistry << "deleting KisBrushServer"; delete m_brushThread; delete m_brushServer; } KisBrushServer* KisBrushServer::instance() { K_GLOBAL_STATIC(KisBrushServer, s_instance); return s_instance; } KisBrushResourceServer* KisBrushServer::brushServer(bool block) { if (block) m_brushThread->barrier(); return m_brushServer; } void KisBrushServer::slotRemoveBlacklistedResources() { m_brushServer->removeBlackListedFiles(); } #include "kis_brush_server.moc" diff --git a/krita/plugins/extensions/resourcemanager/resourcebundle_manifest.cpp b/krita/plugins/extensions/resourcemanager/resourcebundle_manifest.cpp index 0694ac5177..b47c10a7bc 100644 --- a/krita/plugins/extensions/resourcemanager/resourcebundle_manifest.cpp +++ b/krita/plugins/extensions/resourcemanager/resourcebundle_manifest.cpp @@ -1,222 +1,221 @@ /* This file is part of the KDE project Copyright (C) 2014, Victor Lafon This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "resourcebundle_manifest.h" #include #include #include #include #include #include #include #include #include #include "KoPattern.h" #include "KoAbstractGradient.h" -#include "KoResourceServerProvider.h" #include "kis_brush_server.h" #include "kis_resource_server_provider.h" #include "kis_paintop_preset.h" #include "kis_workspace_resource.h" QString resourceTypeToManifestType(const QString &type) { if (type.startsWith("ko_")) { return type.mid(3); } else if (type.startsWith("kis_")) { return type.mid(4); } else { return type; } } QString manifestTypeToResourceType(const QString &type) { if (type == "patterns" || type == "gradients" || type == "palettes") { return "ko_" + type; } else { return "kis_" + type; } } ResourceBundleManifest::ResourceBundleManifest() { } ResourceBundleManifest::~ResourceBundleManifest() { } bool ResourceBundleManifest::load(QIODevice *device) { m_resources.clear(); if (!device->isOpen()) { if (!device->open(QIODevice::ReadOnly)) { return false; } } KoXmlDocument manifestDocument; QString errorMessage; int errorLine; int errorColumn; if (!manifestDocument.setContent(device, true, &errorMessage, &errorLine, &errorColumn)) { return false; } if (!errorMessage.isEmpty()) { qWarning() << "Error parsing manifest" << errorMessage << "line" << errorLine << "column" << errorColumn; return false; } // First find the manifest:manifest node. KoXmlNode n = manifestDocument.firstChild(); for (; !n.isNull(); n = n.nextSibling()) { if (!n.isElement()) { continue; } if (n.toElement().localName() == "manifest" && n.toElement().namespaceURI() == KoXmlNS::manifest) { break; } } if (n.isNull()) { // "Could not find manifest:manifest"; return false; } // Now loop through the children of the manifest:manifest and // store all the manifest:file-entry elements. const KoXmlElement manifestElement = n.toElement(); for (n = manifestElement.firstChild(); !n.isNull(); n = n.nextSibling()) { if (!n.isElement()) continue; KoXmlElement el = n.toElement(); if (!(el.localName() == "file-entry" && el.namespaceURI() == KoXmlNS::manifest)) continue; QString fullPath = el.attributeNS(KoXmlNS::manifest, "full-path", QString()); QString mediaType = el.attributeNS(KoXmlNS::manifest, "media-type", QString("")); QString md5sum = el.attributeNS(KoXmlNS::manifest, "md5sum", QString("")); QString version = el.attributeNS(KoXmlNS::manifest, "version", QString()); QStringList tagList; KoXmlNode tagNode = n.firstChildElement().firstChildElement(); while (!tagNode.isNull()) { if (tagNode.firstChild().isText()) { tagList.append(tagNode.firstChild().toText().data()); } tagNode = tagNode.nextSibling(); } // Only if fullPath is valid, should we store this entry. // If not, we don't bother to find out exactly what is wrong, we just skip it. if (!fullPath.isNull() && !mediaType.isEmpty() && !md5sum.isEmpty()) { addResource(mediaType, fullPath, tagList, QByteArray::fromHex(md5sum.toLatin1())); } } return true; } bool ResourceBundleManifest::save(QIODevice *device) { if (!device->isOpen()) { if (!device->open(QIODevice::WriteOnly)) { return false; } } KoXmlWriter manifestWriter(device); manifestWriter.startDocument("manifest:manifest"); manifestWriter.startElement("manifest:manifest"); manifestWriter.addAttribute("xmlns:manifest", KoXmlNS::manifest); manifestWriter.addAttribute("manifest:version", "1.2"); manifestWriter.addManifestEntry("/", "application/x-krita-resourcebundle"); foreach(QString resourceType, m_resources.uniqueKeys()) { foreach(const ResourceReference &resource, m_resources[resourceType].values()) { manifestWriter.startElement("manifest:file-entry"); manifestWriter.addAttribute("manifest:media-type", resourceTypeToManifestType(resourceType)); manifestWriter.addAttribute("manifest:full-path", resourceTypeToManifestType(resourceType) + "/" + QFileInfo(resource.resourcePath).fileName()); manifestWriter.addAttribute("manifest:md5sum", QString(resource.md5sum.toHex())); if (!resource.tagList.isEmpty()) { manifestWriter.startElement("manifest:tags"); foreach(const QString tag, resource.tagList) { manifestWriter.startElement("manifest:tag"); manifestWriter.addTextNode(tag); manifestWriter.endElement(); } manifestWriter.endElement(); } manifestWriter.endElement(); } } manifestWriter.endElement(); manifestWriter.endDocument(); return true; } void ResourceBundleManifest::addResource(const QString &fileTypeName, const QString &fileName, const QStringList &fileTagList, const QByteArray &md5) { ResourceReference ref(fileName, fileTagList, md5); if (!m_resources.contains(fileTypeName)) { m_resources[fileTypeName] = QMap(); } m_resources[fileTypeName].insert(fileName, ref); } QStringList ResourceBundleManifest::types() const { return m_resources.keys(); } QStringList ResourceBundleManifest::tags() const { QSet tags; foreach(const QString &type, m_resources.keys()) { foreach(const ResourceReference &ref, m_resources[type].values()) { tags += ref.tagList.toSet(); } } return QStringList::fromSet(tags); } QList ResourceBundleManifest::files(const QString &type) const { if (!m_resources.contains(type)) { return QList(); } return m_resources[type].values(); } void ResourceBundleManifest::removeFile(QString fileName) { QList tags; foreach(const QString &type, m_resources.keys()) { if (m_resources[type].contains(fileName)) { m_resources[type].remove(fileName); } } } diff --git a/krita/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp b/krita/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp index 7cd3e53382..89f2114dff 100644 --- a/krita/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp +++ b/krita/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp @@ -1,157 +1,156 @@ /* * Copyright (C) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_smudge_radius_option.h" #include #include #include #include "kis_paint_device.h" #include "KoPointerEvent.h" #include "KoCanvasBase.h" #include "kis_random_accessor_ng.h" #include "KoColor.h" -#include "KoResourceServerProvider.h" #include "KoColorSet.h" #include #include #include #include class KisRandomConstAccessorNG; KisSmudgeRadiusOption::KisSmudgeRadiusOption(const QString& name, const QString& label, bool checked, const QString& category): KisRateOption(name, label, checked, category) { setValueRange(0.0,300.0); } void KisSmudgeRadiusOption::apply(KisPainter& painter, const KisPaintInformation& info, qreal scale, qreal posx, qreal posy,KisPaintDeviceSP dev) const { double sliderValue = computeValue(info); int smudgeRadius = ((sliderValue * scale)*0.5)/100.0;//scale is diameter? KoColor color = painter.paintColor(); if (smudgeRadius == 1) { dev->pixel(posx, posy, &color); painter.setPaintColor(color); } else { const KoColorSpace* cs = dev->colorSpace(); int pixelSize = cs->pixelSize(); quint8* data = new quint8[pixelSize]; static quint8** pixels = new quint8*[2]; qint16* weights = new qint16[2]; pixels[1] = new quint8[pixelSize]; pixels[0] = new quint8[pixelSize]; int loop_increment = 1; if(smudgeRadius >= 8) { loop_increment = (2*smudgeRadius)/16; } int i = 0; int k = 0; int j = 0; KisRandomConstAccessorSP accessor = dev->createRandomConstAccessorNG(0, 0); KisCrossDeviceColorPickerInt colorPicker(painter.device(), color); colorPicker.pickColor(posx, posy, color.data()); for (int y = 0; y <= smudgeRadius; y = y + loop_increment) { for (int x = 0; x <= smudgeRadius; x = x + loop_increment) { for(j = 0;j < 2;j++) { if(j == 1) { y = y*(-1); } for(k = 0;k < 2;k++) { if(k == 1) { x = x*(-1); } accessor->moveTo(posx + x, posy + y); memcpy(pixels[1], accessor->rawDataConst(), pixelSize); if(i == 0) { memcpy(pixels[0],accessor->rawDataConst(),pixelSize); } if (x == 0 && y == 0) { // Because the sum of the weights must be 255, // we cheat a bit, and weigh the center pixel differently in order // to sum to 255 in total // It's -(counts -1), because we'll add the center one implicitly // through that calculation weights[1] = (255 - ((i + 1) * (255 /(i+2) )) ); } else { weights[1] = 255 /(i+2); } i++; if (i>smudgeRadius){i=0;} weights[0] = 255 - weights[1]; const quint8** cpixels = const_cast(pixels); cs->mixColorsOp()->mixColors(cpixels, weights,2, data); memcpy(pixels[0],data,pixelSize); } x = x*(-1); } y = y*(-1); } } KoColor color = KoColor(pixels[0],cs); painter.setPaintColor(color); for (int l = 0; l < 2; l++){ delete[] pixels[l]; } // delete[] pixels; delete[] data; } } void KisSmudgeRadiusOption::writeOptionSetting(KisPropertiesConfiguration* setting) const { KisCurveOption::writeOptionSetting(setting); } void KisSmudgeRadiusOption::readOptionSetting(const KisPropertiesConfiguration* setting) { KisCurveOption::readOptionSetting(setting); } diff --git a/krita/plugins/paintops/libpaintop/kis_brush_chooser.cpp b/krita/plugins/paintops/libpaintop/kis_brush_chooser.cpp index 6091330126..cfea661990 100644 --- a/krita/plugins/paintops/libpaintop/kis_brush_chooser.cpp +++ b/krita/plugins/paintops/libpaintop/kis_brush_chooser.cpp @@ -1,308 +1,305 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2009 Sven Langkamp * Copyright (c) 2010 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Srikanth Tiyyagura * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_chooser.h" #include #include #include #include #include #include #include #include #include #include #include -#include -#include -#include #include "kis_brush_registry.h" #include "kis_brush_server.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_multipliers_double_slider_spinbox.h" #include "kis_spacing_selection_widget.h" #include "kis_signals_blocker.h" #include "kis_global.h" #include "kis_gbr_brush.h" #include "kis_debug.h" /// The resource item delegate for rendering the resource preview class KisBrushDelegate : public QAbstractItemDelegate { public: KisBrushDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} virtual ~KisBrushDelegate() {} /// reimplemented virtual void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const { return option.decorationSize; } }; void KisBrushDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (! index.isValid()) return; KisBrush *brush = static_cast(index.internalPointer()); QRect itemRect = option.rect; QImage thumbnail = brush->image(); if (thumbnail.height() > itemRect.height() || thumbnail.width() > itemRect.width()) { thumbnail = thumbnail.scaled(itemRect.size() , Qt::KeepAspectRatio); } painter->save(); int dx = (itemRect.width() - thumbnail.width()) / 2; int dy = (itemRect.height() - thumbnail.height()) / 2; painter->drawImage(itemRect.x() + dx, itemRect.y() + dy, thumbnail); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlight(), 2.0)); painter->drawRect(option.rect); painter->setCompositionMode(QPainter::CompositionMode_HardLight); painter->setOpacity(0.65); painter->fillRect(option.rect, option.palette.highlight()); } painter->restore(); } KisBrushChooser::KisBrushChooser(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); m_lbSize = new QLabel(i18n("Size:"), this); m_slSize = new KisDoubleSliderSpinBox(this); m_slSize->setRange(0, 1000, 2); m_slSize->setValue(5); m_slSize->setExponentRatio(3.0); m_slSize->setSuffix(" px"); m_slSize->setExponentRatio(3.0); QObject::connect(m_slSize, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemSize(qreal))); m_lbRotation = new QLabel(i18n("Rotation:"), this); m_slRotation = new KisDoubleSliderSpinBox(this); m_slRotation->setRange(0, 360, 0); m_slRotation->setValue(0); m_slRotation->setSuffix(QChar(Qt::Key_degree)); QObject::connect(m_slRotation, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemRotation(qreal))); m_lbSpacing = new QLabel(i18n("Spacing:"), this); m_slSpacing = new KisSpacingSelectionWidget(this); m_slSpacing->setSpacing(true, 1.0); connect(m_slSpacing, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); m_chkColorMask = new QCheckBox(i18n("Use color as mask"), this); QObject::connect(m_chkColorMask, SIGNAL(toggled(bool)), this, SLOT(slotSetItemUseColorAsMask(bool))); m_lbName = new QLabel(this); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); QSharedPointer adapter(new KisBrushResourceServerAdapter(rServer)); m_itemChooser = new KoResourceItemChooser(adapter, this); QString knsrcFile = "kritabrushes.knsrc"; m_itemChooser->setKnsrcFile(knsrcFile); m_itemChooser->showGetHotNewStuff(true, true); m_itemChooser->showTaggingBar(true, true); m_itemChooser->setColumnCount(10); m_itemChooser->setRowHeight(30); m_itemChooser->setItemDelegate(new KisBrushDelegate(this)); m_itemChooser->setCurrentItem(0, 0); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource *)), this, SLOT(update(KoResource *))); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setObjectName("main layout"); mainLayout->addWidget(m_lbName); mainLayout->addWidget(m_itemChooser, 10); QGridLayout *spacingLayout = new QGridLayout(); mainLayout->addLayout(spacingLayout, 1); spacingLayout->addWidget(m_lbSize, 1, 0); spacingLayout->addWidget(m_slSize, 1, 1); spacingLayout->addWidget(m_lbRotation, 2, 0); spacingLayout->addWidget(m_slRotation, 2, 1); spacingLayout->addWidget(m_lbSpacing, 3, 0); spacingLayout->addWidget(m_slSpacing, 3, 1); spacingLayout->setColumnStretch(1, 3); QPushButton *resetBrushButton = new QPushButton(i18n("Reset Predefined Tip"), this); resetBrushButton->setToolTip(i18n("Reloads Spacing from file\nSets Scale to 1.0\nSets Rotation to 0.0")); connect(resetBrushButton, SIGNAL(clicked()), SLOT(slotResetBrush())); QHBoxLayout *resetHLayout = new QHBoxLayout(); resetHLayout->addWidget(m_chkColorMask, 0); resetHLayout->addWidget(resetBrushButton, 0, Qt::AlignRight); spacingLayout->addLayout(resetHLayout, 4, 0, 1, 2); slotActivatedBrush(m_itemChooser->currentResource()); update(m_itemChooser->currentResource()); } KisBrushChooser::~KisBrushChooser() { } void KisBrushChooser::setBrush(KisBrushSP _brush) { m_itemChooser->setCurrentResource(_brush.data()); update(_brush.data()); } void KisBrushChooser::slotResetBrush() { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->load(); brush->setScale(1.0); brush->setAngle(0.0); slotActivatedBrush(brush); update(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSetItemSize(qreal sizeValue) { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { int brushWidth = brush->width(); brush->setScale(sizeValue / qreal(brushWidth)); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSetItemRotation(qreal rotationValue) { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->setAngle(rotationValue / 180.0 * M_PI); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSpacingChanged() { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->setSpacing(m_slSpacing->spacing()); brush->setAutoSpacing(m_slSpacing->autoSpacingActive(), m_slSpacing->autoSpacingCoeff()); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSetItemUseColorAsMask(bool useColorAsMask) { KisGbrBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->setUseColorAsMask(useColorAsMask); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::update(KoResource * resource) { KisBrush* brush = dynamic_cast(resource); if (brush) { QString text = QString("%1 (%2 x %3)") .arg(i18n(brush->name().toUtf8().data())) .arg(brush->width()) .arg(brush->height()); m_lbName->setText(text); m_slSpacing->setSpacing(brush->autoSpacingActive(), brush->autoSpacingActive() ? brush->autoSpacingCoeff() : brush->spacing()); m_slRotation->setValue(brush->angle() * 180 / M_PI); m_slSize->setValue(brush->width() * brush->scale()); // useColorAsMask support is only in gimp brush so far KisGbrBrush *gimpBrush = dynamic_cast(resource); if (gimpBrush) { m_chkColorMask->setChecked(gimpBrush->useColorAsMask()); } m_chkColorMask->setEnabled(brush->hasColor() && gimpBrush); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotActivatedBrush(KoResource * resource) { KisBrush* brush = dynamic_cast(resource); if (m_brush != brush) { if (m_brush) { m_brush->clearBrushPyramid(); } m_brush = brush; if (m_brush) { m_brush->prepareBrushPyramid(); } } } void KisBrushChooser::setBrushSize(qreal xPixels, qreal yPixels) { Q_UNUSED(yPixels); qreal oldWidth = m_brush->width() * m_brush->scale(); qreal newWidth = oldWidth + xPixels; newWidth = qMax(newWidth, qreal(0.1)); m_slSize->setValue(newWidth); } #include "kis_brush_chooser.moc" diff --git a/krita/ui/KisViewManager.cpp b/krita/ui/KisViewManager.cpp index 2890a3f6fa..a28b718b4e 100644 --- a/krita/ui/KisViewManager.cpp +++ b/krita/ui/KisViewManager.cpp @@ -1,1287 +1,1286 @@ /* * This file is part of KimageShop^WKrayon^WKrita * * Copyright (c) 1999 Matthias Elter * 1999 Michael Koch * 1999 Carsten Pfeiffer * 2002 Patrick Julien * 2003-2011 Boudewijn Rempt * 2004 Clarence Dang * 2011 José Luis Vergara * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "KisViewManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include "input/kis_input_manager.h" #include "canvas/kis_canvas2.h" #include "canvas/kis_canvas_controller.h" #include "canvas/kis_grid_manager.h" #include "canvas/kis_perspective_grid_manager.h" #include "dialogs/kis_dlg_blacklist_cleanup.h" #include "input/kis_input_profile_manager.h" #include "kis_action_manager.h" #include "kis_action.h" #include "kis_canvas_controls_manager.h" #include "kis_canvas_resource_provider.h" #include "kis_composite_progress_proxy.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_control_frame.h" #include "kis_coordinates_converter.h" #include #include "KisDocument.h" #include "kis_factory2.h" #include "kis_favorite_resource_manager.h" #include "kis_filter_manager.h" #include "kis_group_layer.h" #include #include "kis_image_manager.h" #include #include "KisMainWindow.h" #include "kis_mainwindow_observer.h" #include "kis_mask_manager.h" #include "kis_mimedata.h" #include "kis_mirror_manager.h" #include "kis_node_commands_adapter.h" #include "kis_node.h" #include "kis_node_manager.h" #include "kis_painting_assistants_manager.h" #include #include "kis_paintop_box.h" #include #include "KisPart.h" #include "KisPrintJob.h" #include "kis_progress_widget.h" #include "kis_resource_server_provider.h" #include "kis_selection.h" #include "kis_selection_manager.h" #include "kis_shape_controller.h" #include "kis_shape_layer.h" #include #include "kis_statusbar.h" #include #include #include "kis_tooltip_manager.h" #include #include "KisView.h" #include "kis_zoom_manager.h" #include "kra/kis_kra_loader.h" #include "widgets/kis_floating_message.h" #include "kis_signal_auto_connection.h" class StatusBarItem { public: StatusBarItem() // for QValueList : m_widget(0), m_connected(false), m_hidden(false) {} StatusBarItem(QWidget * widget, int stretch, bool permanent) : m_widget(widget), m_stretch(stretch), m_permanent(permanent), m_connected(false), m_hidden(false) {} bool operator==(const StatusBarItem& rhs) { return m_widget == rhs.m_widget; } bool operator!=(const StatusBarItem& rhs) { return m_widget != rhs.m_widget; } QWidget * widget() const { return m_widget; } void ensureItemShown(KStatusBar * sb) { Q_ASSERT(m_widget); if (!m_connected) { if (m_permanent) sb->addPermanentWidget(m_widget, m_stretch); else sb->addWidget(m_widget, m_stretch); if(!m_hidden) m_widget->show(); m_connected = true; } } void ensureItemHidden(KStatusBar * sb) { if (m_connected) { m_hidden = m_widget->isHidden(); sb->removeWidget(m_widget); m_widget->hide(); m_connected = false; } } private: QWidget * m_widget; int m_stretch; bool m_permanent; bool m_connected; bool m_hidden; }; class BlockingUserInputEventFilter : public QObject { bool eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched); if(dynamic_cast(event) || dynamic_cast(event) || dynamic_cast(event)) { return true; } else { return false; } } }; class KisViewManager::KisViewManagerPrivate { public: KisViewManagerPrivate() : filterManager(0) , statusBar(0) , createTemplate(0) , saveIncremental(0) , saveIncrementalBackup(0) , openResourcesDirectory(0) , rotateCanvasRight(0) , rotateCanvasLeft(0) , wrapAroundAction(0) , showRulersAction(0) , zoomTo100pct(0) , showGuidesAction(0) , selectionManager(0) , controlFrame(0) , nodeManager(0) , imageManager(0) , gridManager(0) , perspectiveGridManager(0) , paintingAssistantsManager(0) , actionManager(0) , mainWindow(0) , showFloatingMessage(true) , currentImageView(0) , canvasResourceProvider(0) , canvasResourceManager(0) , guiUpdateCompressor(0) , actionCollection(0) , mirrorManager(0) { } ~KisViewManagerPrivate() { delete filterManager; delete selectionManager; delete nodeManager; delete imageManager; delete gridManager; delete perspectiveGridManager; delete paintingAssistantsManager; delete statusBar; delete actionManager; delete canvasControlsManager; delete canvasResourceProvider; delete canvasResourceManager; delete mirrorManager; } public: KisFilterManager *filterManager; KisStatusBar *statusBar; KisAction *createTemplate; KisAction *saveIncremental; KisAction *saveIncrementalBackup; KisAction *openResourcesDirectory; KisAction *rotateCanvasRight; KisAction *rotateCanvasLeft; KisAction *wrapAroundAction; KisAction *showRulersAction; KisAction *zoomTo100pct; KisAction *showGuidesAction; KisSelectionManager *selectionManager; KisControlFrame *controlFrame; KisNodeManager *nodeManager; KisImageManager *imageManager; KisGridManager *gridManager; KisCanvasControlsManager *canvasControlsManager; KisPerspectiveGridManager * perspectiveGridManager; KisPaintingAssistantsManager *paintingAssistantsManager; BlockingUserInputEventFilter blockingEventFilter; KisActionManager* actionManager; QMainWindow* mainWindow; QPointer savedFloatingMessage; bool showFloatingMessage; QPointer currentImageView; KisCanvasResourceProvider* canvasResourceProvider; KoCanvasResourceManager* canvasResourceManager; QList statusBarItems; KisSignalCompressor* guiUpdateCompressor; KActionCollection *actionCollection; KisMirrorManager *mirrorManager; QPointer inputManager; KisSignalAutoConnectionsStore viewConnections; }; KisViewManager::KisViewManager(QWidget *parent, KActionCollection *_actionCollection) : d(new KisViewManagerPrivate()) { d->actionCollection = _actionCollection; d->actionManager = new KisActionManager(this); d->mainWindow = dynamic_cast(parent); d->canvasResourceProvider = new KisCanvasResourceProvider(this); d->canvasResourceManager = new KoCanvasResourceManager(); d->canvasResourceProvider->setResourceManager(d->canvasResourceManager); d->guiUpdateCompressor = new KisSignalCompressor(30, KisSignalCompressor::POSTPONE, this); connect(d->guiUpdateCompressor, SIGNAL(timeout()), this, SLOT(guiUpdateTimeout())); createActions(); createManagers(); d->controlFrame = new KisControlFrame(this, parent); //Check to draw scrollbars after "Canvas only mode" toggle is created. this->showHideScrollbars(); KoCanvasController *dummy = new KoDummyCanvasController(actionCollection()); KoToolManager::instance()->registerTools(actionCollection(), dummy); d->statusBar = new KisStatusBar(this); QTimer::singleShot(0, this, SLOT(makeStatusBarVisible())); connect(KoToolManager::instance(), SIGNAL(inputDeviceChanged(KoInputDevice)), d->controlFrame->paintopBox(), SLOT(slotInputDeviceChanged(KoInputDevice))); connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)), d->controlFrame->paintopBox(), SLOT(slotToolChanged(KoCanvasController*,int))); connect(d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), resourceProvider(), SLOT(slotNodeActivated(KisNodeSP))); connect(resourceProvider()->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), d->controlFrame->paintopBox(), SLOT(slotCanvasResourceChanged(int,QVariant))); connect(KisPart::instance(), SIGNAL(sigViewAdded(KisView*)), SLOT(slotViewAdded(KisView*))); connect(KisPart::instance(), SIGNAL(sigViewRemoved(KisView*)), SLOT(slotViewRemoved(KisView*))); KisInputProfileManager::instance()->loadProfiles(); KisConfig cfg; d->showFloatingMessage = cfg.showCanvasMessages(); } KisViewManager::~KisViewManager() { KisConfig cfg; if (resourceProvider() && resourceProvider()->currentPreset()) { cfg.writeEntry("LastPreset", resourceProvider()->currentPreset()->name()); } cfg.writeEntry("baseLength", KoResourceItemChooserSync::instance()->baseLength()); if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } delete d; } KActionCollection *KisViewManager::actionCollection() const { return d->actionCollection; } void KisViewManager::slotViewAdded(KisView *view) { d->inputManager->addTrackedCanvas(view->canvasBase()); } void KisViewManager::slotViewRemoved(KisView *view) { d->inputManager->removeTrackedCanvas(view->canvasBase()); } void KisViewManager::setCurrentView(KisView *view) { bool first = true; if (d->currentImageView) { d->currentImageView->canvasBase()->setCursor(QCursor(Qt::ArrowCursor)); first = false; KisDocument* doc = d->currentImageView->document(); if (doc) { doc->disconnect(this); } d->currentImageView->canvasController()->proxyObject->disconnect(d->statusBar); d->viewConnections.clear(); } QPointerimageView = qobject_cast(view); if (imageView) { d->viewConnections.addUniqueConnection(resourceProvider(), SIGNAL(sigDisplayProfileChanged(const KoColorProfile*)), imageView->canvasBase(), SLOT(slotSetDisplayProfile(const KoColorProfile*))); resourceProvider()->resetDisplayProfile(QApplication::desktop()->screenNumber(mainWindow())); // Wait for the async image to have loaded KisDocument* doc = view->document(); // connect(canvasController()->proxyObject, SIGNAL(documentMousePositionChanged(QPointF)), d->statusBar, SLOT(documentMousePositionChanged(QPointF))); d->currentImageView = imageView; d->viewConnections.addUniqueConnection(d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), doc->image(), SLOT(requestStrokeEnd())); d->viewConnections.addUniqueConnection(d->rotateCanvasRight, SIGNAL(triggered()), dynamic_cast(d->currentImageView->canvasController()), SLOT(rotateCanvasRight15())); d->viewConnections.addUniqueConnection(d->rotateCanvasLeft, SIGNAL(triggered()),dynamic_cast(d->currentImageView->canvasController()), SLOT(rotateCanvasLeft15())); d->viewConnections.addUniqueConnection(d->wrapAroundAction, SIGNAL(toggled(bool)), dynamic_cast(d->currentImageView->canvasController()), SLOT(slotToggleWrapAroundMode(bool))); d->viewConnections.addUniqueConnection(d->currentImageView->canvasController(), SIGNAL(toolOptionWidgetsChanged(QList >)), mainWindow(), SLOT(newOptionWidgets(QList >))); d->viewConnections.addUniqueConnection(d->currentImageView->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), d->controlFrame->paintopBox(), SLOT(slotColorSpaceChanged(const KoColorSpace*))); d->viewConnections.addUniqueConnection(d->showRulersAction, SIGNAL(triggered(bool)), imageView->zoomManager(), SLOT(toggleShowRulers(bool))); d->viewConnections.addUniqueConnection(d->zoomTo100pct, SIGNAL(triggered()), imageView->zoomManager(), SLOT(zoomTo100())); d->viewConnections.addUniqueConnection(d->showGuidesAction, SIGNAL(triggered(bool)), imageView->zoomManager(), SLOT(showGuides(bool))); showHideScrollbars(); } d->filterManager->setView(imageView); d->selectionManager->setView(imageView); d->nodeManager->setView(imageView); d->imageManager->setView(imageView); d->canvasControlsManager->setView(imageView); d->actionManager->setView(imageView); d->gridManager->setView(imageView); d->statusBar->setView(imageView); d->paintingAssistantsManager->setView(imageView); d->perspectiveGridManager->setView(imageView); d->mirrorManager->setView(imageView); if (d->currentImageView) { d->currentImageView->canvasController()->activate(); d->currentImageView->canvasController()->setFocus(); } d->actionManager->updateGUI(); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)), resourceProvider(), SLOT(slotImageSizeChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigResolutionChanged(double,double)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigNodeChanged(KisNodeSP)), this, SLOT(updateGUI())); d->viewConnections.addUniqueConnection( view->zoomManager()->zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); resourceProvider()->slotImageSizeChanged(); resourceProvider()->slotOnScreenResolutionChanged(); // Restore the last used brush preset if (first) { KisConfig cfg; KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); QString lastPreset = cfg.readEntry("LastPreset", QString("Basic_tip_default")); KisPaintOpPresetSP preset = rserver->resourceByName(lastPreset); if (!preset) { preset = rserver->resourceByName("Basic_tip_default"); } if (!preset) { preset = rserver->resources().first(); } if (preset) { paintOpBox()->restoreResource(preset.data()); } } } KoZoomController *KisViewManager::zoomController() const { if (d->currentImageView) { return d->currentImageView->zoomController(); } return 0; } KisImageWSP KisViewManager::image() const { if (document()) { return document()->image(); } return 0; } KisCanvasResourceProvider * KisViewManager::resourceProvider() { return d->canvasResourceProvider; } KisCanvas2 * KisViewManager::canvasBase() const { if (d && d->currentImageView) { return d->currentImageView->canvasBase(); } return 0; } QWidget* KisViewManager::canvas() const { if (d && d->currentImageView && d->currentImageView->canvasBase()->canvasWidget()) { return d->currentImageView->canvasBase()->canvasWidget(); } return 0; } KisStatusBar * KisViewManager::statusBar() const { return d->statusBar; } void KisViewManager::addStatusBarItem(QWidget * widget, int stretch, bool permanent) { if (!mainWindow()) return; StatusBarItem item(widget, stretch, permanent); KStatusBar * sb = mainWindow()->statusBar(); if (sb) { item.ensureItemShown(sb); } d->statusBarItems.append(item); } void KisViewManager::removeStatusBarItem(QWidget * widget) { KStatusBar *sb = mainWindow()->statusBar(); int itemCount = d->statusBarItems.count(); for (int i = itemCount-1; i >= 0; --i) { StatusBarItem &sbItem = d->statusBarItems[i]; if (sbItem.widget() == widget) { if (sb) { sbItem.ensureItemHidden(sb); } d->statusBarItems.removeOne(sbItem); break; } } } KisPaintopBox* KisViewManager::paintOpBox() const { return d->controlFrame->paintopBox(); } KoProgressUpdater* KisViewManager::createProgressUpdater(KoProgressUpdater::Mode mode) { return new KisProgressUpdater(d->statusBar->progress(), document()->progressProxy(), mode); } KisSelectionManager * KisViewManager::selectionManager() { return d->selectionManager; } KisNodeSP KisViewManager::activeNode() { if (d->nodeManager) return d->nodeManager->activeNode(); else return 0; } KisLayerSP KisViewManager::activeLayer() { if (d->nodeManager) return d->nodeManager->activeLayer(); else return 0; } KisPaintDeviceSP KisViewManager::activeDevice() { if (d->nodeManager) return d->nodeManager->activePaintDevice(); else return 0; } KisZoomManager * KisViewManager::zoomManager() { if (d->currentImageView) { return d->currentImageView->zoomManager(); } return 0; } KisFilterManager * KisViewManager::filterManager() { return d->filterManager; } KisImageManager * KisViewManager::imageManager() { return d->imageManager; } KisInputManager* KisViewManager::inputManager() const { return d->inputManager; } KisSelectionSP KisViewManager::selection() { if (d->currentImageView) { return d->currentImageView->selection(); } return 0; } bool KisViewManager::selectionEditable() { KisLayerSP layer = activeLayer(); if (layer) { KoProperties properties; QList masks = layer->childNodes(QStringList("KisSelectionMask"), properties); if (masks.size() == 1) { return masks[0]->isEditable(); } } // global selection is always editable return true; } KisUndoAdapter * KisViewManager::undoAdapter() { if (!document()) return 0; KisImageWSP image = document()->image(); Q_ASSERT(image); return image->undoAdapter(); } void KisViewManager::createActions() { d->saveIncremental = new KisAction(i18n("Save Incremental &Version"), this); d->saveIncremental->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S)); d->saveIncremental->setActivationFlags(KisAction::ACTIVE_IMAGE); actionManager()->addAction("save_incremental_version", d->saveIncremental); connect(d->saveIncremental, SIGNAL(triggered()), this, SLOT(slotSaveIncremental())); d->saveIncrementalBackup = new KisAction(i18n("Save Incremental Backup"), this); d->saveIncrementalBackup->setShortcut(Qt::Key_F4); d->saveIncrementalBackup->setActivationFlags(KisAction::ACTIVE_IMAGE); actionManager()->addAction("save_incremental_backup", d->saveIncrementalBackup); connect(d->saveIncrementalBackup, SIGNAL(triggered()), this, SLOT(slotSaveIncrementalBackup())); connect(mainWindow(), SIGNAL(documentSaved()), this, SLOT(slotDocumentSaved())); d->saveIncremental->setEnabled(false); d->saveIncrementalBackup->setEnabled(false); KisAction *tabletDebugger = new KisAction(i18n("Toggle Tablet Debugger"), this); actionManager()->addAction("tablet_debugger", tabletDebugger ); tabletDebugger->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_T)); connect(tabletDebugger, SIGNAL(triggered()), this, SLOT(toggleTabletLogger())); d->createTemplate = new KisAction( i18n( "&Create Template From Image..." ), this); d->createTemplate->setActivationFlags(KisAction::ACTIVE_IMAGE); actionManager()->addAction("create_template", d->createTemplate); connect(d->createTemplate, SIGNAL(triggered()), this, SLOT(slotCreateTemplate())); d->openResourcesDirectory = new KisAction(i18n("Open Resources Folder"), this); d->openResourcesDirectory->setToolTip(i18n("Opens a file browser at the location Krita saves resources such as brushes to.")); d->openResourcesDirectory->setWhatsThis(i18n("Opens a file browser at the location Krita saves resources such as brushes to.")); actionManager()->addAction("open_resources_directory", d->openResourcesDirectory); connect(d->openResourcesDirectory, SIGNAL(triggered()), SLOT(openResourcesDirectory())); d->rotateCanvasRight = new KisAction(i18n("Rotate Canvas Right"), this); actionManager()->addAction("rotate_canvas_right", d->rotateCanvasRight); d->rotateCanvasRight->setActivationFlags(KisAction::ACTIVE_IMAGE); d->rotateCanvasRight->setShortcut(QKeySequence("Ctrl+]")); d->rotateCanvasLeft = new KisAction(i18n("Rotate Canvas Left"), this); actionManager()->addAction("rotate_canvas_left", d->rotateCanvasLeft); d->rotateCanvasLeft->setActivationFlags(KisAction::ACTIVE_IMAGE); d->rotateCanvasLeft->setShortcut(QKeySequence("Ctrl+[")); d->wrapAroundAction = new KisAction(i18n("Wrap Around Mode"), this); d->wrapAroundAction->setCheckable(true); d->wrapAroundAction->setActivationFlags(KisAction::ACTIVE_IMAGE); actionManager()->addAction("wrap_around_mode", d->wrapAroundAction); d->wrapAroundAction->setShortcut(QKeySequence(Qt::Key_W)); KisAction *tAction = new KisAction(i18n("Show Status Bar"), this); tAction->setCheckable(true); tAction->setChecked(true); tAction->setToolTip(i18n("Shows or hides the status bar")); actionManager()->addAction("showStatusBar", tAction); tAction->setActivationFlags(KisAction::ACTIVE_IMAGE); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool))); tAction = new KisAction(i18n("Show Canvas Only"), this); tAction->setActivationFlags(KisAction::ACTIVE_IMAGE); tAction->setCheckable(true); tAction->setToolTip(i18n("Shows just the canvas or the whole window")); QList shortcuts; shortcuts << QKeySequence(Qt::Key_Tab); tAction->setShortcuts(shortcuts); tAction->setChecked(false); actionManager()->addAction("view_show_just_the_canvas", tAction); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showJustTheCanvas(bool))); //Workaround, by default has the same shortcut as mirrorCanvas KisAction *a = dynamic_cast(actionCollection()->action("format_italic")); if (a) { a->setShortcut(QKeySequence(), KAction::DefaultShortcut); a->setShortcut(QKeySequence(), KAction::ActiveShortcut); a->setActivationConditions(KisAction::SELECTION_EDITABLE); } a = new KisAction(i18n("Cleanup removed files..."), this); actionManager()->addAction("edit_blacklist_cleanup", a); connect(a, SIGNAL(triggered()), this, SLOT(slotBlacklistCleanup())); d->showRulersAction = new KisAction(i18n("Show Rulers"), this); d->showRulersAction->setCheckable(true); d->showRulersAction->setActivationFlags(KisAction::ACTIVE_IMAGE); actionManager()->addAction("view_ruler", d->showRulersAction); d->showRulersAction->setWhatsThis(i18n("The rulers show the horizontal and vertical positions of the mouse on the image " "and can be used to position your mouse at the right place on the canvas.

Uncheck this to hide the rulers.

")); KisConfig cfg; d->showRulersAction->setChecked(cfg.showRulers()); d->showGuidesAction = new KisAction(i18n("Show Guides"), this); d->showGuidesAction->setCheckable(true); d->showGuidesAction->setCheckable(false); d->showGuidesAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->showGuidesAction->setToolTip(i18n("Shows or hides guides")); actionManager()->addAction("view_show_guides", d->showGuidesAction); d->zoomTo100pct = new KisAction(i18n("Reset zoom"), this); d->zoomTo100pct->setActivationFlags(KisAction::ACTIVE_IMAGE); actionManager()->addAction("zoom_to_100pct", d->zoomTo100pct); d->zoomTo100pct->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_0 ) ); } void KisViewManager::createManagers() { // Create the managers for filters, selections, layers etc. // XXX: When the currentlayer changes, call updateGUI on all // managers d->filterManager = new KisFilterManager(this); d->filterManager->setup(actionCollection(), actionManager()); d->selectionManager = new KisSelectionManager(this); d->selectionManager->setup(actionManager()); d->nodeManager = new KisNodeManager(this); d->nodeManager->setup(actionCollection(), actionManager()); d->imageManager = new KisImageManager(this); d->imageManager->setup(actionManager()); d->gridManager = new KisGridManager(this); d->gridManager->setup(this->actionManager()); d->perspectiveGridManager = new KisPerspectiveGridManager(this); d->perspectiveGridManager->setup(actionCollection()); d->paintingAssistantsManager = new KisPaintingAssistantsManager(this); d->paintingAssistantsManager->setup(actionManager()); d->canvasControlsManager = new KisCanvasControlsManager(this); d->canvasControlsManager->setup(actionManager()); d->mirrorManager = new KisMirrorManager(this); d->mirrorManager->setup(actionCollection()); d->inputManager = new KisInputManager(this); } void KisViewManager::updateGUI() { d->guiUpdateCompressor->start(); } void KisViewManager::slotBlacklistCleanup() { KisDlgBlacklistCleanup dialog; dialog.exec(); } KisNodeManager * KisViewManager::nodeManager() const { return d->nodeManager; } KisActionManager* KisViewManager::actionManager() const { return d->actionManager; } KisPerspectiveGridManager* KisViewManager::perspectiveGridManager() const { return d->perspectiveGridManager; } KisGridManager * KisViewManager::gridManager() const { return d->gridManager; } KisPaintingAssistantsManager* KisViewManager::paintingAssistantsManager() const { return d->paintingAssistantsManager; } KisDocument *KisViewManager::document() const { if (d->currentImageView && d->currentImageView->document()) { return d->currentImageView->document(); } return 0; } int KisViewManager::viewCount() const { KisMainWindow *mw = qobject_cast(d->mainWindow); if (mw) { return mw->viewCount(); } return 0; } void KisViewManager::slotCreateTemplate() { if (!document()) return; KisTemplateCreateDia::createTemplate("krita_template", ".kra", KisFactory::componentData(), document(), mainWindow()); } QMainWindow* KisViewManager::qtMainWindow() const { if (d->mainWindow) return d->mainWindow; //Fallback for when we have not yet set the main window. QMainWindow* w = qobject_cast(qApp->activeWindow()); if(w) return w; return mainWindow(); } void KisViewManager::setQtMainWindow(QMainWindow* newMainWindow) { d->mainWindow = newMainWindow; } void KisViewManager::slotDocumentSaved() { d->saveIncremental->setEnabled(true); d->saveIncrementalBackup->setEnabled(true); } void KisViewManager::slotSaveIncremental() { if (!document()) return; bool foundVersion; bool fileAlreadyExists; bool isBackup; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // Find current version filenames // v v Regexp to find incremental versions in the filename, taking our backup scheme into account as well // Considering our incremental version and backup scheme, format is filename_001~001.ext QRegExp regex("_\\d{1,4}[.]|_\\d{1,4}[a-z][.]|_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); foundVersion = matches.at(0).isEmpty() ? false : true; // Ensure compatibility with Save Incremental Backup // If this regex is not kept separate, the entire algorithm needs modification; // It's simpler to just add this. QRegExp regexAux("_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regexAux.indexIn(fileName); // Perform the search QStringList matchesAux = regexAux.capturedTexts(); isBackup = matchesAux.at(0).isEmpty() ? false : true; // If the filename has a version, prepare it for incrementation if (foundVersion) { version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "_" } else { // ...else, simply add a version to it so the next loop works QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(fileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(version); extensionPlusVersion.prepend("_"); fileName.replace(regex2, extensionPlusVersion); } // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("_"); if (!letter.isNull()) newVersion.append(letter); if (isBackup) { newVersion.append("~"); } else { newVersion.append("."); } fileName.replace(regex, newVersion); fileAlreadyExists = KIO::NetAccess::exists(fileName, KIO::NetAccess::DestinationSide, mainWindow()); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental version"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } document()->setSaveInBatchMode(true); document()->saveAs(fileName); document()->setSaveInBatchMode(false); if (mainWindow()) { mainWindow()->updateCaption(); } } void KisViewManager::slotSaveIncrementalBackup() { if (!document()) return; bool workingOnBackup; bool fileAlreadyExists; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // First, discover if working on a backup file, or a normal file QRegExp regex("~\\d{1,4}[.]|~\\d{1,4}[a-z][.]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); workingOnBackup = matches.at(0).isEmpty() ? false : true; if (workingOnBackup) { // Try to save incremental version (of backup), use letter for alt versions version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "~" // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); QString backupFileName = document()->localFilePath(); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("~"); if (!letter.isNull()) newVersion.append(letter); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = KIO::NetAccess::exists(backupFileName, KIO::NetAccess::DestinationSide, mainWindow()); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental backup"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } QFile::copy(fileName, backupFileName); document()->saveAs(fileName); if (mainWindow()) mainWindow()->updateCaption(); } else { // if NOT working on a backup... // Navigate directory searching for latest backup version, ignore letters const quint8 HARDCODED_DIGIT_COUNT = 3; QString baseNewVersion = "000"; QString backupFileName = document()->localFilePath(); QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(backupFileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(baseNewVersion); extensionPlusVersion.prepend("~"); backupFileName.replace(regex2, extensionPlusVersion); // Save version with 1 number higher than the highest version found ignoring letters do { newVersion = baseNewVersion; newVersion.prepend("~"); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = KIO::NetAccess::exists(backupFileName, KIO::NetAccess::DestinationSide, mainWindow()); if (fileAlreadyExists) { // Prepare the base for new version filename, increment by 1 int intVersion = baseNewVersion.toInt(0); ++intVersion; baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < HARDCODED_DIGIT_COUNT) { baseNewVersion.prepend("0"); } } } while (fileAlreadyExists); // Save both as backup and on current file for interapplication workflow document()->setSaveInBatchMode(true); QFile::copy(fileName, backupFileName); document()->saveAs(fileName); document()->setSaveInBatchMode(false); if (mainWindow()) mainWindow()->updateCaption(); } } void KisViewManager::disableControls() { // prevents possible crashes, if somebody changes the paintop during dragging by using the mousewheel // this is for Bug 250944 // the solution blocks all wheel, mouse and key event, while dragging with the freehand tool // see KisToolFreehand::initPaint() and endPaint() d->controlFrame->paintopBox()->installEventFilter(&d->blockingEventFilter); foreach(QObject* child, d->controlFrame->paintopBox()->children()) { child->installEventFilter(&d->blockingEventFilter); } } void KisViewManager::enableControls() { d->controlFrame->paintopBox()->removeEventFilter(&d->blockingEventFilter); foreach(QObject* child, d->controlFrame->paintopBox()->children()) { child->removeEventFilter(&d->blockingEventFilter); } } void KisViewManager::showStatusBar(bool toggled) { if (d->currentImageView && d->currentImageView->statusBar()) { d->currentImageView->statusBar()->setVisible(toggled); } } #if defined HAVE_OPENGL && defined Q_OS_WIN32 #include #endif void KisViewManager::showJustTheCanvas(bool toggled) { KisConfig cfg; KisMainWindow* main = mainWindow(); if(!main) { dbgUI << "Unable to switch to canvas-only mode, main window not found"; return; } if (cfg.hideStatusbarFullscreen()) { if(main->statusBar() && main->statusBar()->isVisible() == toggled) { main->statusBar()->setVisible(!toggled); } } if (cfg.hideDockersFullscreen()) { KisAction* action = qobject_cast(main->actionCollection()->action("view_toggledockers")); action->setCheckable(true); if (action && action->isChecked() == toggled) { action->setChecked(!toggled); } } if (cfg.hideTitlebarFullscreen()) { if(toggled) { main->setWindowState( main->windowState() | Qt::WindowFullScreen); } else { main->setWindowState( main->windowState() & ~Qt::WindowFullScreen); } } if (cfg.hideMenuFullscreen()) { if (main->menuBar()->isVisible() == toggled) { main->menuBar()->setVisible(!toggled); } } if (cfg.hideToolbarFullscreen()) { QList toolBars = main->findChildren(); foreach(QToolBar* toolbar, toolBars) { if (toolbar->isVisible() == toggled) { toolbar->setVisible(!toggled); } } } showHideScrollbars(); if (toggled) { // show a fading heads-up display about the shortcut to go back showFloatingMessage(i18n("Going into Canvas-Only mode.\nPress %1 to go back.", actionCollection()->action("view_show_just_the_canvas")->shortcut().toString()), QIcon()); } } void KisViewManager::toggleTabletLogger() { d->inputManager->toggleTabletLogger(); } void KisViewManager::openResourcesDirectory() { QString dir = KStandardDirs::locateLocal("data", "krita"); QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); } void KisViewManager::updateIcons() { #if QT_VERSION >= 0x040700 QColor background = mainWindow()->palette().background().color(); bool useDarkIcons = background.value() > 100; QString prefix = useDarkIcons ? QString("dark_") : QString("light_"); QStringList whitelist; whitelist << "ToolBox" << "KisLayerBox"; QStringList blacklistedIcons; blacklistedIcons << "editpath" << "artistictext-tool" << "view-choose"; if (mainWindow()) { QList dockers = mainWindow()->dockWidgets(); foreach(QDockWidget* dock, dockers) { kDebug() << "name " << dock->objectName(); KoDockWidgetTitleBar* titlebar = dynamic_cast(dock->titleBarWidget()); if (titlebar) { titlebar->updateIcons(); } if (!whitelist.contains(dock->objectName())) { continue; } QObjectList objects; objects.append(dock); while (!objects.isEmpty()) { QObject* object = objects.takeFirst(); objects.append(object->children()); QAbstractButton* button = dynamic_cast(object); if (button && !button->icon().name().isEmpty()) { QString name = button->icon().name(); name = name.remove("dark_").remove("light_"); if (!blacklistedIcons.contains(name)) { QString iconName = prefix + name; KIcon icon = koIcon(iconName.toLatin1()); button->setIcon(icon); } } } } } #endif } void KisViewManager::makeStatusBarVisible() { d->mainWindow->statusBar()->setVisible(true); } void KisViewManager::guiUpdateTimeout() { d->nodeManager->updateGUI(); d->selectionManager->updateGUI(); d->filterManager->updateGUI(); if (zoomManager()) { zoomManager()->updateGUI(); } d->gridManager->updateGUI(); d->perspectiveGridManager->updateGUI(); d->actionManager->updateGUI(); } void KisViewManager::showFloatingMessage(const QString message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment) { if(d->showFloatingMessage && qtMainWindow()) { if (d->savedFloatingMessage) { d->savedFloatingMessage->tryOverrideMessage(message, icon, timeout, priority, alignment); } else { if(d->currentImageView) { d->savedFloatingMessage = new KisFloatingMessage(message, d->currentImageView->canvasBase()->canvasWidget(), false, timeout, priority, alignment); d->savedFloatingMessage->setShowOverParent(true); d->savedFloatingMessage->setIcon(icon); d->savedFloatingMessage->showMessage(); } } } #if QT_VERSION >= 0x040700 emit floatingMessageRequested(message, icon.name()); #endif } KisMainWindow *KisViewManager::mainWindow() const { return qobject_cast(d->mainWindow); } void KisViewManager::showHideScrollbars() { if (!d->currentImageView) return; if (!d->currentImageView->canvasController()) return; KisConfig cfg; bool toggled = actionCollection()->action("view_show_just_the_canvas")->isChecked(); if ( (toggled && cfg.hideScrollbarsFullscreen()) || (!toggled && cfg.hideScrollbars()) ) { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } else { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); } } void KisViewManager::setShowFloatingMessage(bool show) { d->showFloatingMessage = show; } #include "KisViewManager.moc" diff --git a/krita/ui/dialogs/kis_dlg_layer_style.cpp b/krita/ui/dialogs/kis_dlg_layer_style.cpp index cd9a3e6caa..e7520809e9 100644 --- a/krita/ui/dialogs/kis_dlg_layer_style.cpp +++ b/krita/ui/dialogs/kis_dlg_layer_style.cpp @@ -1,1364 +1,1365 @@ /* * Copyright (c) 2014 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_dlg_layer_style.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include #include "kis_config.h" #include "kis_cmb_contour.h" #include "kis_cmb_gradient.h" #include "kis_resource_server_provider.h" #include "kis_psd_layer_style_resource.h" #include "kis_psd_layer_style.h" #include "kis_signals_blocker.h" #include "kis_signal_compressor.h" #include "kis_canvas_resource_provider.h" #include KoAbstractGradient* fetchGradientLazy(KoAbstractGradient *gradient, KisCanvasResourceProvider *resourceProvider) { if (!gradient) { gradient = resourceProvider->currentGradient(); } return gradient; } KisDlgLayerStyle::KisDlgLayerStyle(KisPSDLayerStyleSP layerStyle, KisCanvasResourceProvider *resourceProvider, QWidget *parent) : KDialog(parent) , m_layerStyle(layerStyle) , m_initialLayerStyle(layerStyle->clone()) , m_isSwitchingPredefinedStyle(false) , m_sanityLayerStyleDirty(false) { setCaption(i18n("Layer Styles")); setButtons(Ok | Cancel); setDefaultButton(Ok); m_configChangedCompressor = new KisSignalCompressor(1000, KisSignalCompressor::POSTPONE, this); connect(m_configChangedCompressor, SIGNAL(timeout()), SIGNAL(configChanged())); QWidget *page = new QWidget(this); wdgLayerStyles.setupUi(page); setMainWidget(page); connect(wdgLayerStyles.lstStyleSelector, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(notifyGuiConfigChanged())); m_stylesSelector = new StylesSelector(this); connect(m_stylesSelector, SIGNAL(styleSelected(KisPSDLayerStyleSP)), SLOT(notifyPredefinedStyleSelected(KisPSDLayerStyleSP))); wdgLayerStyles.stylesStack->addWidget(m_stylesSelector); m_blendingOptions = new BlendingOptions(this); wdgLayerStyles.stylesStack->addWidget(m_blendingOptions); m_dropShadow = new DropShadow(DropShadow::DropShadowMode, this); wdgLayerStyles.stylesStack->addWidget(m_dropShadow); connect(m_dropShadow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_innerShadow = new DropShadow(DropShadow::InnerShadowMode, this); wdgLayerStyles.stylesStack->addWidget(m_innerShadow); connect(m_innerShadow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_outerGlow = new InnerGlow(InnerGlow::OuterGlowMode, resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_outerGlow); connect(m_outerGlow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_innerGlow = new InnerGlow(InnerGlow::InnerGlowMode, resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_innerGlow); connect(m_innerGlow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_contour = new Contour(this); m_texture = new Texture(this); m_bevelAndEmboss = new BevelAndEmboss(m_contour, m_texture, this); wdgLayerStyles.stylesStack->addWidget(m_bevelAndEmboss); wdgLayerStyles.stylesStack->addWidget(m_contour); wdgLayerStyles.stylesStack->addWidget(m_texture); connect(m_bevelAndEmboss, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_satin = new Satin(this); wdgLayerStyles.stylesStack->addWidget(m_satin); connect(m_satin, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_colorOverlay = new ColorOverlay(this); wdgLayerStyles.stylesStack->addWidget(m_colorOverlay); connect(m_colorOverlay, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_gradientOverlay = new GradientOverlay(resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_gradientOverlay); connect(m_gradientOverlay, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_patternOverlay = new PatternOverlay(this); wdgLayerStyles.stylesStack->addWidget(m_patternOverlay); connect(m_patternOverlay, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_stroke = new Stroke(resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_stroke); connect(m_stroke, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); KisConfig cfg; wdgLayerStyles.stylesStack->setCurrentIndex(cfg.readEntry("KisDlgLayerStyle::current", 1)); wdgLayerStyles.lstStyleSelector->setCurrentRow(cfg.readEntry("KisDlgLayerStyle::current", 1)); connect(wdgLayerStyles.lstStyleSelector, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); notifyPredefinedStyleSelected(layerStyle); connect(wdgLayerStyles.btnNewStyle, SIGNAL(clicked()), SLOT(slotNewStyle())); connect(wdgLayerStyles.btnLoadStyle, SIGNAL(clicked()), SLOT(slotLoadStyle())); connect(wdgLayerStyles.btnSaveStyle, SIGNAL(clicked()), SLOT(slotSaveStyle())); connect(this, SIGNAL(accepted()), SLOT(slotNotifyOnAccept())); connect(this, SIGNAL(rejected()), SLOT(slotNotifyOnReject())); } KisDlgLayerStyle::~KisDlgLayerStyle() { } void KisDlgLayerStyle::notifyGuiConfigChanged() { if (m_isSwitchingPredefinedStyle) return; m_configChangedCompressor->start(); m_layerStyle->setUuid(QUuid::createUuid()); m_sanityLayerStyleDirty = true; m_stylesSelector->notifyExternalStyleChanged(m_layerStyle->name(), m_layerStyle->uuid()); } void KisDlgLayerStyle::notifyPredefinedStyleSelected(KisPSDLayerStyleSP style) { m_isSwitchingPredefinedStyle = true; setStyle(style); m_isSwitchingPredefinedStyle = false; m_configChangedCompressor->start(); } void KisDlgLayerStyle::slotNotifyOnAccept() { if (m_configChangedCompressor->isActive()) { m_configChangedCompressor->stop(); emit configChanged(); } } void KisDlgLayerStyle::slotNotifyOnReject() { notifyPredefinedStyleSelected(m_initialLayerStyle); m_configChangedCompressor->stop(); emit configChanged(); } bool checkCustomNameAvailable(const QString &name) { const QString customName = "CustomStyles.asl"; KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); KoResource *resource = server->resourceByName(customName); if (!resource) return true; KisPSDLayerStyleCollectionResource *collection = dynamic_cast(resource); foreach(KisPSDLayerStyleSP style, collection->layerStyles()) { if (style->name() == name) { return false; } } return true; } QString selectAvailableStyleName(const QString &name) { QString finalName = name; if (checkCustomNameAvailable(finalName)) { return finalName; } int i = 0; do { finalName = QString("%1%2").arg(name).arg(i++); } while (!checkCustomNameAvailable(finalName)); return finalName; } void KisDlgLayerStyle::slotNewStyle() { QString styleName = QInputDialog::getText(this, i18nc("@title:window", "Enter new style name"), i18nc("@label:textbox", "Name:"), QLineEdit::Normal, i18nc("Default name for a new style", "New Style")); KisPSDLayerStyleSP style = this->style(); style->setName(selectAvailableStyleName(styleName)); m_stylesSelector->addNewStyle(style->clone()); } void KisDlgLayerStyle::slotLoadStyle() { QString filename; // default value? KoFileDialog dialog(this, KoFileDialog::OpenFile, "krita/layerstyle"); dialog.setCaption(i18n("Select ASL file")); //dialog.setDefaultDir(QDir::cleanPath(filename)); dialog.setNameFilter(i18n("Layer style library (*.asl)")); filename = dialog.url(); m_stylesSelector->loadCollection(filename); wdgLayerStyles.lstStyleSelector->setCurrentRow(0); } void KisDlgLayerStyle::slotSaveStyle() { QString filename; // default value? KoFileDialog dialog(this, KoFileDialog::SaveFile, "krita/layerstyle"); dialog.setCaption(i18n("Select ASL file")); //dialog.setDefaultDir(QDir::cleanPath(filename)); dialog.setNameFilter(i18n("Layer style configuration (*.asl)")); filename = dialog.url(); QScopedPointer collection( new KisPSDLayerStyleCollectionResource(filename)); KisPSDLayerStyleSP newStyle = style()->clone(); newStyle->setName(QFileInfo(filename).baseName()); KisPSDLayerStyleCollectionResource::StylesVector vector = collection->layerStyles(); vector << newStyle; collection->setLayerStyles(vector); collection->save(); } void KisDlgLayerStyle::changePage(QListWidgetItem *current, QListWidgetItem *previous) { if (!current) { current = previous; } wdgLayerStyles.stylesStack->setCurrentIndex(wdgLayerStyles.lstStyleSelector->row(current)); } void KisDlgLayerStyle::setStyle(KisPSDLayerStyleSP style) { *m_layerStyle = *style; m_sanityLayerStyleDirty = false; m_stylesSelector->notifyExternalStyleChanged(m_layerStyle->name(), m_layerStyle->uuid()); QListWidgetItem *item; item = wdgLayerStyles.lstStyleSelector->item(2); item->setCheckState(m_layerStyle->dropShadow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(3); item->setCheckState(m_layerStyle->innerShadow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(4); item->setCheckState(m_layerStyle->outerGlow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(5); item->setCheckState(m_layerStyle->innerGlow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(6); item->setCheckState(m_layerStyle->bevelAndEmboss()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(7); item->setCheckState(m_layerStyle->bevelAndEmboss()->contourEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(8); item->setCheckState(m_layerStyle->bevelAndEmboss()->textureEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(9); item->setCheckState(m_layerStyle->satin()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(10); item->setCheckState(m_layerStyle->colorOverlay()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(11); item->setCheckState(m_layerStyle->gradientOverlay()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(12); item->setCheckState(m_layerStyle->patternOverlay()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(13); item->setCheckState(m_layerStyle->stroke()->effectEnabled() ? Qt::Checked : Qt::Unchecked); m_dropShadow->setShadow(m_layerStyle->dropShadow()); m_innerShadow->setShadow(m_layerStyle->innerShadow()); m_outerGlow->setConfig(m_layerStyle->outerGlow()); m_innerGlow->setConfig(m_layerStyle->innerGlow()); m_bevelAndEmboss->setBevelAndEmboss(m_layerStyle->bevelAndEmboss()); m_satin->setSatin(m_layerStyle->satin()); m_colorOverlay->setColorOverlay(m_layerStyle->colorOverlay()); m_gradientOverlay->setGradientOverlay(m_layerStyle->gradientOverlay()); m_patternOverlay->setPatternOverlay(m_layerStyle->patternOverlay()); m_stroke->setStroke(m_layerStyle->stroke()); } KisPSDLayerStyleSP KisDlgLayerStyle::style() const { m_layerStyle->dropShadow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(2)->checkState() == Qt::Checked); m_layerStyle->innerShadow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(3)->checkState() == Qt::Checked); m_layerStyle->outerGlow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(4)->checkState() == Qt::Checked); m_layerStyle->innerGlow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(5)->checkState() == Qt::Checked); m_layerStyle->bevelAndEmboss()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(6)->checkState() == Qt::Checked); m_layerStyle->bevelAndEmboss()->setContourEnabled(wdgLayerStyles.lstStyleSelector->item(7)->checkState() == Qt::Checked); m_layerStyle->bevelAndEmboss()->setTextureEnabled(wdgLayerStyles.lstStyleSelector->item(8)->checkState() == Qt::Checked); m_layerStyle->satin()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(9)->checkState() == Qt::Checked); m_layerStyle->colorOverlay()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(10)->checkState() == Qt::Checked); m_layerStyle->gradientOverlay()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(11)->checkState() == Qt::Checked); m_layerStyle->patternOverlay()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(12)->checkState() == Qt::Checked); m_layerStyle->stroke()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(13)->checkState() == Qt::Checked); m_dropShadow->fetchShadow(m_layerStyle->dropShadow()); m_innerShadow->fetchShadow(m_layerStyle->innerShadow()); m_outerGlow->fetchConfig(m_layerStyle->outerGlow()); m_innerGlow->fetchConfig(m_layerStyle->innerGlow()); m_bevelAndEmboss->fetchBevelAndEmboss(m_layerStyle->bevelAndEmboss()); m_satin->fetchSatin(m_layerStyle->satin()); m_colorOverlay->fetchColorOverlay(m_layerStyle->colorOverlay()); m_gradientOverlay->fetchGradientOverlay(m_layerStyle->gradientOverlay()); m_patternOverlay->fetchPatternOverlay(m_layerStyle->patternOverlay()); m_stroke->fetchStroke(m_layerStyle->stroke()); m_sanityLayerStyleDirty = false; m_stylesSelector->notifyExternalStyleChanged(m_layerStyle->name(), m_layerStyle->uuid()); return m_layerStyle; } /********************************************************************/ /***** Styles Selector **********************************************/ /********************************************************************/ class StyleItem : public QListWidgetItem { public: StyleItem(KisPSDLayerStyleSP style) : QListWidgetItem(style->name()) , m_style(style) { } public: KisPSDLayerStyleSP m_style; }; StylesSelector::StylesSelector(QWidget *parent) : QWidget(parent) { ui.setupUi(this); connect(ui.cmbStyleCollections, SIGNAL(activated(QString)), this, SLOT(loadStyles(QString))); connect(ui.listStyles, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(selectStyle(QListWidgetItem*,QListWidgetItem*))); refillCollections(); if (ui.cmbStyleCollections->count()) { ui.cmbStyleCollections->setCurrentIndex(0); loadStyles(ui.cmbStyleCollections->currentText()); } } void StylesSelector::refillCollections() { QString previousCollection = ui.cmbStyleCollections->currentText(); ui.cmbStyleCollections->clear(); foreach(KoResource *res, KisResourceServerProvider::instance()->layerStyleCollectionServer()->resources()) { ui.cmbStyleCollections->addItem(res->name()); } if (!previousCollection.isEmpty()) { KisSignalsBlocker blocker(this); int index = ui.cmbStyleCollections->findText(previousCollection); ui.cmbStyleCollections->setCurrentIndex(index); } } void StylesSelector::notifyExternalStyleChanged(const QString &name, const QUuid &uuid) { int currentIndex = -1; for (int i = 0; i < ui.listStyles->count(); i++ ) { StyleItem *item = dynamic_cast(ui.listStyles->item(i)); QString itemName = item->m_style->name(); if (itemName == name) { bool isDirty = item->m_style->uuid() != uuid; if (isDirty) { itemName += "*"; } currentIndex = i; } item->setText(itemName); } ui.listStyles->setCurrentRow(currentIndex); } void StylesSelector::loadStyles(const QString &name) { ui.listStyles->clear(); KoResource *res = KisResourceServerProvider::instance()->layerStyleCollectionServer()->resourceByName(name); KisPSDLayerStyleCollectionResource *collection = dynamic_cast(res); if (collection) { foreach(KisPSDLayerStyleSP style, collection->layerStyles()) { // XXX: also use the preview image, when we have one ui.listStyles->addItem(new StyleItem(style)); } } } void StylesSelector::selectStyle(QListWidgetItem *current, QListWidgetItem* /*previous*/) { StyleItem *item = dynamic_cast(current); if (item) { emit styleSelected(item->m_style); } } void StylesSelector::loadCollection(const QString &fileName) { if (!QFileInfo(fileName).exists()) { qWarning() << "Loaded style collection doesn't exist!"; return; } KisPSDLayerStyleCollectionResource *collection = new KisPSDLayerStyleCollectionResource(fileName); collection->load(); KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); collection->setFilename(server->saveLocation() + QDir::separator() + collection->name()); server->addResource(collection); refillCollections(); int index = ui.cmbStyleCollections->findText(collection->name()); ui.cmbStyleCollections->setCurrentIndex(index); loadStyles(collection->name()); } void StylesSelector::addNewStyle(KisPSDLayerStyleSP style) { KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); // NOTE: not translatable, since it is a key! const QString customName = "CustomStyles.asl"; const QString saveLocation = server->saveLocation(); const QString fullFilename = saveLocation + customName; KoResource *resource = server->resourceByName(customName); KisPSDLayerStyleCollectionResource *collection = 0; if (!resource) { collection = new KisPSDLayerStyleCollectionResource(""); collection->setName(customName); collection->setFilename(fullFilename); KisPSDLayerStyleCollectionResource::StylesVector vector; vector << style; collection->setLayerStyles(vector); server->addResource(collection); } else { collection = dynamic_cast(resource); KisPSDLayerStyleCollectionResource::StylesVector vector; vector = collection->layerStyles(); vector << style; collection->setLayerStyles(vector); collection->save(); } refillCollections(); // select in gui int index = ui.cmbStyleCollections->findText(customName); KIS_ASSERT_RECOVER_RETURN(index >= 0); ui.cmbStyleCollections->setCurrentIndex(index); loadStyles(customName); notifyExternalStyleChanged(style->name(), style->uuid()); } /********************************************************************/ /***** Bevel and Emboss *********************************************/ /********************************************************************/ BevelAndEmboss::BevelAndEmboss(Contour *contour, Texture *texture, QWidget *parent) : QWidget(parent) , m_contour(contour) , m_texture(texture) { ui.setupUi(this); // Structure ui.intDepth->setRange(0, 100); ui.intDepth->setSuffix(" %"); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(" px"); ui.intSoften->setRange(0, 18); ui.intSoften->setSuffix(" px"); connect(ui.cmbStyle, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.cmbTechnique, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intDepth, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbDirection, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSoften, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // Shading ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intOpacity2->setRange(0, 100); ui.intOpacity2->setSuffix(" %"); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), ui.dialAngle, SLOT(setDisabled(bool))); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), ui.intAngle, SLOT(setDisabled(bool))); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intAltitude, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbHighlightMode, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnHighlightColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbShadowMode, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnShadowColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); connect(ui.intOpacity2, SIGNAL(valueChanged(int)), SIGNAL(configChanged()));; // Contour m_contour->ui.intRange->setRange(0, 100); m_contour->ui.intRange->setSuffix(" %"); connect(m_contour->ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(m_contour->ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(m_contour->ui.intRange, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // Texture m_texture->ui.intScale->setRange(0, 100); m_texture->ui.intScale->setSuffix(" %"); m_texture->ui.intDepth->setRange(-1000, 1000); m_texture->ui.intDepth->setSuffix(" %"); connect(m_texture->ui.patternChooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(configChanged())); connect(m_texture->ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(m_texture->ui.intDepth, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(m_texture->ui.chkInvert, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(m_texture->ui.chkLinkWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); } void BevelAndEmboss::setBevelAndEmboss(const psd_layer_effects_bevel_emboss *bevelAndEmboss) { ui.cmbStyle->setCurrentIndex((int)bevelAndEmboss->style()); ui.cmbTechnique->setCurrentIndex((int)bevelAndEmboss->technique()); ui.intDepth->setValue(bevelAndEmboss->depth()); ui.cmbDirection->setCurrentIndex((int)bevelAndEmboss->direction()); ui.intSize->setValue(bevelAndEmboss->size()); ui.intSoften->setValue(bevelAndEmboss->soften()); ui.dialAngle->setValue(bevelAndEmboss->angle()); ui.intAngle->setValue(bevelAndEmboss->angle()); ui.intAltitude->setValue(bevelAndEmboss->altitude()); // FIXME: curve editing // ui.cmbContour; ui.chkAntiAliased->setChecked(bevelAndEmboss->glossAntiAliased()); ui.cmbHighlightMode->selectCompositeOp(KoID(bevelAndEmboss->highlightBlendMode())); ui.bnHighlightColor->setColor(bevelAndEmboss->highlightColor()); ui.intOpacity->setValue(bevelAndEmboss->highlightOpacity()); ui.cmbShadowMode->selectCompositeOp(KoID(bevelAndEmboss->shadowBlendMode())); ui.bnShadowColor->setColor(bevelAndEmboss->shadowColor()); ui.intOpacity2->setValue(bevelAndEmboss->shadowOpacity()); // FIXME: curve editing // m_contour->ui.cmbContour; m_contour->ui.chkAntiAliased->setChecked(bevelAndEmboss->antiAliased()); m_contour->ui.intRange->setValue(bevelAndEmboss->contourRange()); m_texture->ui.patternChooser->setCurrentPattern(bevelAndEmboss->texturePattern()); m_texture->ui.intScale->setValue(bevelAndEmboss->textureScale()); m_texture->ui.intDepth->setValue(bevelAndEmboss->textureDepth()); m_texture->ui.chkInvert->setChecked(bevelAndEmboss->textureInvert()); m_texture->ui.chkLinkWithLayer->setChecked(bevelAndEmboss->textureAlignWithLayer()); } void BevelAndEmboss::fetchBevelAndEmboss(psd_layer_effects_bevel_emboss *bevelAndEmboss) const { bevelAndEmboss->setStyle((psd_bevel_style)ui.cmbStyle->currentIndex()); bevelAndEmboss->setTechnique((psd_technique_type)ui.cmbTechnique->currentIndex()); bevelAndEmboss->setDepth(ui.intDepth->value()); bevelAndEmboss->setDirection((psd_direction)ui.cmbDirection->currentIndex()); bevelAndEmboss->setSize(ui.intSize->value()); bevelAndEmboss->setSoften(ui.intSoften->value()); bevelAndEmboss->setAngle(ui.dialAngle->value()); bevelAndEmboss->setAltitude(ui.intAltitude->value()); bevelAndEmboss->setGlossAntiAliased(ui.chkAntiAliased->isChecked()); bevelAndEmboss->setHighlightBlendMode(ui.cmbHighlightMode->selectedCompositeOp().id()); bevelAndEmboss->setHighlightColor(ui.bnHighlightColor->color()); bevelAndEmboss->setHighlightOpacity(ui.intOpacity->value()); bevelAndEmboss->setShadowBlendMode(ui.cmbShadowMode->selectedCompositeOp().id()); bevelAndEmboss->setShadowColor(ui.bnShadowColor->color()); bevelAndEmboss->setShadowOpacity(ui.intOpacity2->value()); // FIXME: curve editing bevelAndEmboss->setAntiAliased(m_contour->ui.chkAntiAliased->isChecked()); bevelAndEmboss->setContourRange(m_contour->ui.intRange->value()); bevelAndEmboss->setTexturePattern(static_cast(m_texture->ui.patternChooser->currentResource())); bevelAndEmboss->setTextureScale(m_texture->ui.intScale->value()); bevelAndEmboss->setTextureDepth(m_texture->ui.intDepth->value()); bevelAndEmboss->setTextureInvert(m_texture->ui.chkInvert->isChecked()); bevelAndEmboss->setTextureAlignWithLayer(m_texture->ui.chkLinkWithLayer->isChecked()); } void BevelAndEmboss::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void BevelAndEmboss::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } /********************************************************************/ /***** Texture *********************************************/ /********************************************************************/ Texture::Texture(QWidget *parent) : QWidget(parent) { ui.setupUi(this); } /********************************************************************/ /***** Contour *********************************************/ /********************************************************************/ Contour::Contour(QWidget *parent) : QWidget(parent) { ui.setupUi(this); } /********************************************************************/ /***** Blending Options *********************************************/ /********************************************************************/ BlendingOptions::BlendingOptions(QWidget *parent) : QWidget(parent) { ui.setupUi(this); // FIXME: Blend options are not implemented yet ui.grpBlendingOptions->setTitle(QString("%1 (%2)").arg(ui.grpBlendingOptions->title()).arg(i18n("Not Implemented Yet"))); ui.grpBlendingOptions->setEnabled(false); } /********************************************************************/ /***** Color Overlay *********************************************/ /********************************************************************/ ColorOverlay::ColorOverlay(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); } void ColorOverlay::setColorOverlay(const psd_layer_effects_color_overlay *colorOverlay) { ui.cmbCompositeOp->selectCompositeOp(KoID(colorOverlay->blendMode())); ui.intOpacity->setValue(colorOverlay->opacity()); ui.bnColor->setColor(colorOverlay->color()); } void ColorOverlay::fetchColorOverlay(psd_layer_effects_color_overlay *colorOverlay) const { colorOverlay->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); colorOverlay->setOpacity(ui.intOpacity->value()); colorOverlay->setColor(ui.bnColor->color()); } /********************************************************************/ /***** Drop Shadow **************************************************/ /********************************************************************/ DropShadow::DropShadow(Mode mode, QWidget *parent) : QWidget(parent), m_mode(mode) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intDistance->setRange(0, 30000); ui.intDistance->setSuffix(" px"); ui.intSpread->setRange(0, 100); ui.intSpread->setSuffix(" %"); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(" px"); ui.intNoise->setRange(0, 100); ui.intNoise->setSuffix(" %"); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), ui.dialAngle, SLOT(setDisabled(bool))); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), ui.intAngle, SLOT(setDisabled(bool))); // connect everything to configChanged() signal connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intDistance, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSpread, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intNoise, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.chkLayerKnocksOutDropShadow, SIGNAL(toggled(bool)), SIGNAL(configChanged())); if (m_mode == InnerShadowMode) { ui.chkLayerKnocksOutDropShadow->setVisible(false); ui.grpMain->setTitle(i18n("Inner Shadow")); ui.lblSpread->setText(i18n("Choke")); } } void DropShadow::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void DropShadow::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } void DropShadow::setShadow(const psd_layer_effects_shadow_common *shadow) { ui.cmbCompositeOp->selectCompositeOp(KoID(shadow->blendMode())); ui.intOpacity->setValue(shadow->opacity()); ui.bnColor->setColor(shadow->color()); ui.dialAngle->setValue(shadow->angle()); ui.intAngle->setValue(shadow->angle()); ui.chkUseGlobalLight->setChecked(shadow->useGlobalLight()); ui.intDistance->setValue(shadow->distance()); ui.intSpread->setValue(shadow->spread()); ui.intSize->setValue(shadow->size()); // FIXME: curve editing // ui.cmbContour; ui.chkAntiAliased->setChecked(shadow->antiAliased()); ui.intNoise->setValue(shadow->noise()); if (m_mode == DropShadowMode) { const psd_layer_effects_drop_shadow *realDropShadow = dynamic_cast(shadow); KIS_ASSERT_RECOVER_NOOP(realDropShadow); ui.chkLayerKnocksOutDropShadow->setChecked(shadow->knocksOut()); } } void DropShadow::fetchShadow(psd_layer_effects_shadow_common *shadow) const { shadow->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); shadow->setOpacity(ui.intOpacity->value()); shadow->setColor(ui.bnColor->color()); shadow->setAngle(ui.dialAngle->value()); shadow->setUseGlobalLight(ui.chkUseGlobalLight->isChecked()); shadow->setDistance(ui.intDistance->value()); shadow->setSpread(ui.intSpread->value()); shadow->setSize(ui.intSize->value()); // FIXME: curve editing // ui.cmbContour; shadow->setAntiAliased(ui.chkAntiAliased->isChecked()); shadow->setNoise(ui.intNoise->value()); if (m_mode == DropShadowMode) { psd_layer_effects_drop_shadow *realDropShadow = dynamic_cast(shadow); KIS_ASSERT_RECOVER_NOOP(realDropShadow); realDropShadow->setKnocksOut(ui.chkLayerKnocksOutDropShadow->isChecked()); } } class GradientPointerConverter { public: static KoAbstractGradientSP resourceToStyle(KoAbstractGradient *gradient) { return gradient ? KoAbstractGradientSP(gradient->clone()) : KoAbstractGradientSP(); } static KoAbstractGradient* styleToResource(KoAbstractGradientSP gradient) { if (!gradient) return 0; KoResourceServer *server = KoResourceServerProvider::instance()->gradientServer(); KoAbstractGradient *resource = server->resourceByMD5(gradient->md5()); if (!resource) { KoAbstractGradient *clone = gradient->clone(); clone->setName(findAvailableName(gradient->name())); server->addResource(clone, false); resource = clone; } return resource; } private: static QString findAvailableName(const QString &name) { KoResourceServer *server = KoResourceServerProvider::instance()->gradientServer(); QString newName = name; int i = 0; while (server->resourceByName(newName)) { newName = QString("%1%2").arg(name).arg(i++); } return newName; } }; /********************************************************************/ /***** Gradient Overlay *********************************************/ /********************************************************************/ GradientOverlay::GradientOverlay(KisCanvasResourceProvider *resourceProvider, QWidget *parent) : QWidget(parent), m_resourceProvider(resourceProvider) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intScale->setRange(0, 100); ui.intScale->setSuffix(" %"); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbGradient, SIGNAL(gradientChanged(KoAbstractGradient*)), SIGNAL(configChanged())); connect(ui.chkReverse, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbStyle, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAlignWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); } void GradientOverlay::setGradientOverlay(const psd_layer_effects_gradient_overlay *config) { ui.cmbCompositeOp->selectCompositeOp(KoID(config->blendMode())); ui.intOpacity->setValue(config->opacity()); KoAbstractGradient *gradient = fetchGradientLazy( GradientPointerConverter::styleToResource(config->gradient()), m_resourceProvider); if (gradient) { ui.cmbGradient->setGradient(gradient); } ui.chkReverse->setChecked(config->antiAliased()); ui.cmbStyle->setCurrentIndex((int)config->style()); ui.chkAlignWithLayer->setCheckable(config->alignWithLayer()); ui.dialAngle->setValue(config->angle()); ui.intAngle->setValue(config->angle()); ui.intScale->setValue(config->scale()); } void GradientOverlay::fetchGradientOverlay(psd_layer_effects_gradient_overlay *config) const { config->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); config->setOpacity(ui.intOpacity->value()); config->setGradient(GradientPointerConverter::resourceToStyle(ui.cmbGradient->gradient())); config->setReverse(ui.chkReverse->isChecked()); config->setStyle((psd_gradient_style)ui.cmbStyle->currentIndex()); config->setAlignWithLayer(ui.chkAlignWithLayer->isChecked()); config->setAngle(ui.dialAngle->value()); config->setScale(ui.intScale->value()); } void GradientOverlay::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void GradientOverlay::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } /********************************************************************/ /***** Innner Glow *********************************************/ /********************************************************************/ InnerGlow::InnerGlow(Mode mode, KisCanvasResourceProvider *resourceProvider, QWidget *parent) : QWidget(parent), m_mode(mode), m_resourceProvider(resourceProvider) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intNoise->setRange(0, 100); ui.intNoise->setSuffix(" %"); ui.intChoke->setRange(0, 100); ui.intChoke->setSuffix(" %"); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(" px"); ui.intRange->setRange(0, 100); ui.intRange->setSuffix(" %"); ui.intJitter->setRange(0, 100); ui.intJitter->setSuffix(" %"); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intNoise, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.radioColor, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); connect(ui.radioGradient, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbGradient, SIGNAL(gradientChanged(KoAbstractGradient*)), SIGNAL(configChanged())); connect(ui.cmbTechnique, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.cmbSource, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intChoke, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intRange, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intJitter, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); if (m_mode == OuterGlowMode) { ui.cmbSource->hide(); ui.lblSource->hide(); ui.lblChoke->setText(i18nc("layer styles parameter", "Spread")); } } void InnerGlow::setConfig(const psd_layer_effects_glow_common *config) { ui.cmbCompositeOp->selectCompositeOp(KoID(config->blendMode())); ui.intOpacity->setValue(config->opacity()); ui.intNoise->setValue(config->noise()); ui.radioColor->setChecked(config->fillType() == psd_fill_solid_color); ui.bnColor->setColor(config->color()); ui.radioGradient->setChecked(config->fillType() == psd_fill_gradient); KoAbstractGradient *gradient = fetchGradientLazy( GradientPointerConverter::styleToResource(config->gradient()), m_resourceProvider); if (gradient) { ui.cmbGradient->setGradient(gradient); } ui.cmbTechnique->setCurrentIndex((int)config->technique()); ui.intChoke->setValue(config->spread()); ui.intSize->setValue(config->size()); if (m_mode == InnerGlowMode) { const psd_layer_effects_inner_glow *iglow = dynamic_cast(config); KIS_ASSERT_RECOVER_RETURN(iglow); ui.cmbSource->setCurrentIndex(iglow->source() == psd_glow_edge); } // FIXME: Curve editing //ui.cmbContour; ui.chkAntiAliased->setChecked(config->antiAliased()); ui.intRange->setValue(config->range()); ui.intJitter->setValue(config->jitter()); } void InnerGlow::fetchConfig(psd_layer_effects_glow_common *config) const { config->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); config->setOpacity(ui.intOpacity->value()); config->setNoise(ui.intNoise->value()); if (ui.radioColor->isChecked()) { config->setFillType(psd_fill_solid_color); } else { config->setFillType(psd_fill_gradient); } config->setColor(ui.bnColor->color()); config->setGradient(GradientPointerConverter::resourceToStyle(ui.cmbGradient->gradient())); config->setTechnique((psd_technique_type)ui.cmbTechnique->currentIndex()); config->setSpread(ui.intChoke->value()); config->setSize(ui.intSize->value()); if (m_mode == InnerGlowMode) { psd_layer_effects_inner_glow *iglow = dynamic_cast(config); KIS_ASSERT_RECOVER_RETURN(iglow); iglow->setSource((psd_glow_source)ui.cmbSource->currentIndex()); } // FIXME: Curve editing //ui.cmbContour; config->setAntiAliased(ui.chkAntiAliased->isChecked()); config->setRange(ui.intRange->value()); config->setJitter(ui.intJitter->value()); } /********************************************************************/ /***** Pattern Overlay *********************************************/ /********************************************************************/ PatternOverlay::PatternOverlay(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intScale->setRange(0, 100); ui.intScale->setSuffix(" %"); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.patternChooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(configChanged())); connect(ui.chkLinkWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); } void PatternOverlay::setPatternOverlay(const psd_layer_effects_pattern_overlay *pattern) { ui.cmbCompositeOp->selectCompositeOp(KoID(pattern->blendMode())); ui.intOpacity->setValue(pattern->opacity()); ui.patternChooser->setCurrentPattern(pattern->pattern()); ui.chkLinkWithLayer->setChecked(pattern->alignWithLayer()); ui.intScale->setValue(pattern->scale()); } void PatternOverlay::fetchPatternOverlay(psd_layer_effects_pattern_overlay *pattern) const { pattern->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); pattern->setOpacity(ui.intOpacity->value()); pattern->setPattern(static_cast(ui.patternChooser->currentResource())); pattern->setAlignWithLayer(ui.chkLinkWithLayer->isChecked()); pattern->setScale(ui.intScale->value()); } /********************************************************************/ /***** Satin *********************************************/ /********************************************************************/ Satin::Satin(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intDistance->setRange(0, 250); ui.intDistance->setSuffix(" px"); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(" px"); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intDistance, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.chkInvert, SIGNAL(toggled(bool)), SIGNAL(configChanged())); } void Satin::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void Satin::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } void Satin::setSatin(const psd_layer_effects_satin *satin) { ui.cmbCompositeOp->selectCompositeOp(KoID(satin->blendMode())); ui.bnColor->setColor(satin->color()); ui.intOpacity->setValue(satin->opacity()); ui.dialAngle->setValue(satin->angle()); ui.intAngle->setValue(satin->angle()); ui.intDistance->setValue(satin->distance()); ui.intSize->setValue(satin->size()); // FIXME: Curve editing //ui.cmbContour; ui.chkAntiAliased->setChecked(satin->antiAliased()); ui.chkInvert->setChecked(satin->invert()); } void Satin::fetchSatin(psd_layer_effects_satin *satin) const { satin->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); satin->setOpacity(ui.intOpacity->value()); satin->setColor(ui.bnColor->color()); satin->setAngle(ui.dialAngle->value()); satin->setDistance(ui.intDistance->value()); satin->setSize(ui.intSize->value()); // FIXME: curve editing // ui.cmbContour; satin->setAntiAliased(ui.chkAntiAliased->isChecked()); satin->setInvert(ui.chkInvert->isChecked()); } /********************************************************************/ /***** Stroke *********************************************/ /********************************************************************/ Stroke::Stroke(KisCanvasResourceProvider *resourceProvider, QWidget *parent) : QWidget(parent), m_resourceProvider(resourceProvider) { ui.setupUi(this); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(" px"); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(" %"); ui.intScale->setRange(0, 100); ui.intScale->setSuffix(" %"); ui.intScale_2->setRange(0, 100); ui.intScale_2->setSuffix(" %"); connect(ui.cmbFillType, SIGNAL(currentIndexChanged(int)), ui.fillStack, SLOT(setCurrentIndex(int))); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbPosition, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbFillType, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(QColor)), SIGNAL(configChanged())); connect(ui.cmbGradient, SIGNAL(gradientChanged(KoAbstractGradient*)), SIGNAL(configChanged())); connect(ui.chkReverse, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbStyle, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAlignWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.patternChooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(configChanged())); connect(ui.chkLinkWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intScale_2, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // cold initialization ui.fillStack->setCurrentIndex(ui.cmbFillType->currentIndex()); } void Stroke::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void Stroke::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } void Stroke::setStroke(const psd_layer_effects_stroke *stroke) { ui.intSize->setValue(stroke->size()); ui.cmbPosition->setCurrentIndex((int)stroke->position()); ui.cmbCompositeOp->selectCompositeOp(KoID(stroke->blendMode())); ui.intOpacity->setValue(stroke->opacity()); ui.cmbFillType->setCurrentIndex((int)stroke->fillType()); ui.bnColor->setColor(stroke->color()); KoAbstractGradient *gradient = fetchGradientLazy(GradientPointerConverter::styleToResource(stroke->gradient()), m_resourceProvider); if (gradient) { ui.cmbGradient->setGradient(gradient); } ui.chkReverse->setChecked(stroke->antiAliased()); ui.cmbStyle->setCurrentIndex((int)stroke->style()); ui.chkAlignWithLayer->setCheckable(stroke->alignWithLayer()); ui.dialAngle->setValue(stroke->angle()); ui.intAngle->setValue(stroke->angle()); ui.intScale->setValue(stroke->scale()); ui.patternChooser->setCurrentPattern(stroke->pattern()); ui.chkLinkWithLayer->setChecked(stroke->alignWithLayer()); ui.intScale_2->setValue(stroke->scale()); } void Stroke::fetchStroke(psd_layer_effects_stroke *stroke) const { stroke->setSize(ui.intSize->value()); stroke->setPosition((psd_stroke_position)ui.cmbPosition->currentIndex()); stroke->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); stroke->setOpacity(ui.intOpacity->value()); stroke->setFillType((psd_fill_type)ui.cmbFillType->currentIndex()); stroke->setColor(ui.bnColor->color()); stroke->setGradient(GradientPointerConverter::resourceToStyle(ui.cmbGradient->gradient())); stroke->setReverse(ui.chkReverse->isChecked()); stroke->setStyle((psd_gradient_style)ui.cmbStyle->currentIndex()); stroke->setAlignWithLayer(ui.chkAlignWithLayer->isChecked()); stroke->setAngle(ui.dialAngle->value()); stroke->setScale(ui.intScale->value()); stroke->setPattern(static_cast(ui.patternChooser->currentResource())); stroke->setAlignWithLayer(ui.chkLinkWithLayer->isChecked()); stroke->setScale(ui.intScale->value()); } diff --git a/krita/ui/kis_control_frame.cpp b/krita/ui/kis_control_frame.cpp index 1f22c8571e..c1491da2b6 100644 --- a/krita/ui/kis_control_frame.cpp +++ b/krita/ui/kis_control_frame.cpp @@ -1,208 +1,207 @@ /* * kis_control_frame.cc - part of Krita * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Sven Langkamp * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.g * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_control_frame.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include "KoPattern.h" #include "kis_resource_server_provider.h" #include "kis_canvas_resource_provider.h" #include "widgets/kis_iconwidget.h" #include "widgets/kis_gradient_chooser.h" #include "KisViewManager.h" #include "kis_config.h" #include "kis_paintop_box.h" #include "kis_custom_pattern.h" #include "widgets/kis_pattern_chooser.h" #include "kis_favorite_resource_manager.h" #include "kis_display_color_converter.h" #include KisControlFrame::KisControlFrame(KisViewManager *view, QWidget *parent, const char* name) : QObject(view) , m_viewManager(view) , m_patternWidget(0) , m_gradientWidget(0) , m_patternChooserPopup(0) , m_gradientChooserPopup(0) , m_paintopBox(0) { setObjectName(name); KisConfig cfg; m_font = KGlobalSettings::generalFont(); m_patternWidget = new KisIconWidget(parent, "patterns"); m_patternWidget->setText(i18n("Fill Patterns")); m_patternWidget->setToolTip(i18n("Fill Patterns")); m_patternWidget->setFixedSize(26, 26); KAction * action = new KAction(i18n("&Patterns"), this); view->actionCollection()->addAction("patterns", action); action->setDefaultWidget(m_patternWidget); m_gradientWidget = new KisIconWidget(parent, "gradients"); m_gradientWidget->setText(i18n("Gradients")); m_gradientWidget->setToolTip(i18n("Gradients")); m_gradientWidget->setFixedSize(26, 26); action = new KAction(i18n("&Gradients"), this); view->actionCollection()->addAction("gradients", action); action->setDefaultWidget(m_gradientWidget); KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(false); QSharedPointer adapter (new KoResourceServerAdapter(rserver)); m_gradientWidget->setResourceAdapter(adapter); // XXX: KOMVC we don't have a canvas here yet, needs a setImageView const KoColorDisplayRendererInterface *displayRenderer = KisDisplayColorConverter::dumbConverterInstance()->displayRendererInterface(); KoDualColorButton * dual = new KoDualColorButton(view->resourceProvider()->fgColor(), view->resourceProvider()->bgColor(), displayRenderer, view->mainWindow(), view->mainWindow()); dual->setPopDialog(true); action = new KAction(i18n("&Color"), this); view->actionCollection()->addAction("dual", action); action->setDefaultWidget(dual); connect(dual, SIGNAL(foregroundColorChanged(KoColor)), view->resourceProvider(), SLOT(slotSetFGColor(KoColor))); connect(dual, SIGNAL(backgroundColorChanged(KoColor)), view->resourceProvider(), SLOT(slotSetBGColor(KoColor))); connect(view->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), dual, SLOT(setForegroundColor(KoColor))); connect(view->resourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), dual, SLOT(setBackgroundColor(KoColor))); dual->setFixedSize(26, 26); createPatternsChooser(m_viewManager); createGradientsChooser(m_viewManager); m_patternWidget->setPopupWidget(m_patternChooserPopup); m_gradientWidget->setPopupWidget(m_gradientChooserPopup); m_paintopBox = new KisPaintopBox(view, parent, "paintopbox"); action = new KAction(i18n("&Painter's Tools"), this); view->actionCollection()->addAction("paintops", action); action->setDefaultWidget(m_paintopBox); } void KisControlFrame::slotSetPattern(KoPattern * pattern) { m_patternWidget->slotSetItem(pattern); m_patternChooser->setCurrentPattern(pattern); } void KisControlFrame::slotSetGradient(KoAbstractGradient * gradient) { m_gradientWidget->slotSetItem(gradient); } void KisControlFrame::createPatternsChooser(KisViewManager * view) { m_patternChooserPopup = new QWidget(m_patternWidget); m_patternChooserPopup->setObjectName("pattern_chooser_popup"); QHBoxLayout * l2 = new QHBoxLayout(m_patternChooserPopup); l2->setObjectName("patternpopuplayout"); m_patternsTab = new QTabWidget(m_patternChooserPopup); m_patternsTab->setObjectName("patternstab"); m_patternsTab->setFocusPolicy(Qt::NoFocus); m_patternsTab->setFont(m_font); l2->addWidget(m_patternsTab); m_patternChooser = new KisPatternChooser(m_patternChooserPopup); m_patternChooser->setFont(m_font); QWidget *patternChooserPage = new QWidget(m_patternChooserPopup); QHBoxLayout *patternChooserPageLayout = new QHBoxLayout(patternChooserPage); patternChooserPageLayout->addWidget(m_patternChooser); m_patternsTab->addTab(patternChooserPage, i18n("Patterns")); KisCustomPattern* customPatterns = new KisCustomPattern(0, "custompatterns", i18n("Custom Pattern"), m_viewManager); customPatterns->setFont(m_font); m_patternsTab->addTab(customPatterns, i18n("Custom Pattern")); connect(m_patternChooser, SIGNAL(resourceSelected(KoResource*)), view->resourceProvider(), SLOT(slotPatternActivated(KoResource*))); connect(customPatterns, SIGNAL(activatedResource(KoResource*)), view->resourceProvider(), SLOT(slotPatternActivated(KoResource*))); connect(view->resourceProvider(), SIGNAL(sigPatternChanged(KoPattern*)), this, SLOT(slotSetPattern(KoPattern*))); m_patternChooser->setCurrentItem(0, 0); if (m_patternChooser->currentResource() && view->resourceProvider()) { view->resourceProvider()->slotPatternActivated(m_patternChooser->currentResource()); } } void KisControlFrame::createGradientsChooser(KisViewManager * view) { m_gradientChooserPopup = new QWidget(m_gradientWidget); m_gradientChooserPopup->setObjectName("gradient_chooser_popup"); QHBoxLayout * l2 = new QHBoxLayout(m_gradientChooserPopup); l2->setObjectName("gradientpopuplayout"); m_gradientTab = new QTabWidget(m_gradientChooserPopup); m_gradientTab->setObjectName("gradientstab"); m_gradientTab->setFocusPolicy(Qt::NoFocus); m_gradientTab->setFont(m_font); l2->addWidget(m_gradientTab); m_gradientChooser = new KisGradientChooser(m_gradientChooserPopup); m_gradientChooser->setFont(m_font); m_gradientTab->addTab(m_gradientChooser, i18n("Gradients")); connect(m_gradientChooser, SIGNAL(resourceSelected(KoResource*)), view->resourceProvider(), SLOT(slotGradientActivated(KoResource*))); connect(view->resourceProvider(), SIGNAL(sigGradientChanged(KoAbstractGradient*)), this, SLOT(slotSetGradient(KoAbstractGradient*))); m_gradientChooser->setCurrentItem(0, 0); if (m_gradientChooser->currentResource() && view->resourceProvider()) view->resourceProvider()->slotGradientActivated(m_gradientChooser->currentResource()); } #include "kis_control_frame.moc" diff --git a/krita/ui/kis_popup_palette.cpp b/krita/ui/kis_popup_palette.cpp index aeb87c8e48..8fc9949483 100644 --- a/krita/ui/kis_popup_palette.cpp +++ b/krita/ui/kis_popup_palette.cpp @@ -1,563 +1,561 @@ /* This file is part of the KDE project Copyright 2009 Vera Lukman Copyright 2011 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_config.h" #include "kis_popup_palette.h" #include "kis_paintop_box.h" #include "kis_favorite_resource_manager.h" #include "KoIcon.h" #include "kis_paintop_preset.h" #include "kis_resource_server_provider.h" #include #include "KoColorSpaceRegistry.h" -#include "KoResource.h" -#include #include #include #include #include #include #include #include "kis_signal_compressor.h" #define brushInnerRadius 94.0 #define brushOuterRadius 145.0 #define colorInnerRadius 72.0 #define colorOuterRadius 92.0 #define brushRadius (brushInnerRadius+brushOuterRadius)/2 class PopupColorTriangle : public KoTriangleColorSelector { public: PopupColorTriangle(const KoColorDisplayRendererInterface *displayRenderer, QWidget* parent) : KoTriangleColorSelector(displayRenderer, parent) , m_dragging(false) { } virtual ~PopupColorTriangle() {} void tabletEvent(QTabletEvent* event) { event->accept(); QMouseEvent* mouseEvent = 0; switch (event->type()) { case QEvent::TabletPress: mouseEvent = new QMouseEvent(QEvent::MouseButtonPress, event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); m_dragging = true; mousePressEvent(mouseEvent); break; case QEvent::TabletMove: mouseEvent = new QMouseEvent(QEvent::MouseMove, event->pos(), (m_dragging) ? Qt::LeftButton : Qt::NoButton, (m_dragging) ? Qt::LeftButton : Qt::NoButton, event->modifiers()); mouseMoveEvent(mouseEvent); break; case QEvent::TabletRelease: mouseEvent = new QMouseEvent(QEvent::MouseButtonRelease, event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); m_dragging = false; mouseReleaseEvent(mouseEvent); break; default: break; } delete mouseEvent; } private: bool m_dragging; }; KisPopupPalette::KisPopupPalette(KisFavoriteResourceManager* manager, const KoColorDisplayRendererInterface *displayRenderer, QWidget *parent) : QWidget(parent, Qt::FramelessWindowHint) , m_resourceManager(manager) , m_triangleColorSelector(0) , m_timer(0) , m_displayRenderer(displayRenderer) , m_colorChangeCompressor(new KisSignalCompressor(50, KisSignalCompressor::POSTPONE)) { m_triangleColorSelector = new PopupColorTriangle(displayRenderer, this); m_triangleColorSelector->move(77, 77); m_triangleColorSelector->resize(136, 136); m_triangleColorSelector->setVisible(true); setAutoFillBackground(true); setAttribute(Qt::WA_ContentsPropagated, true); //setAttribute(Qt::WA_TranslucentBackground, true); connect(m_triangleColorSelector, SIGNAL(realColorChanged(KoColor)), m_colorChangeCompressor, SLOT(start())); connect(m_colorChangeCompressor, SIGNAL(timeout()), SLOT(slotEmitColorChanged())); connect(m_resourceManager, SIGNAL(sigChangeFGColorSelector(KoColor)), SLOT(slotExternalFgColorChanged(KoColor))); connect(this, SIGNAL(sigChangefGColor(KoColor)), m_resourceManager, SIGNAL(sigSetFGColor(KoColor))); connect(this, SIGNAL(sigChangeActivePaintop(int)), m_resourceManager, SLOT(slotChangeActivePaintop(int))); connect(this, SIGNAL(sigUpdateRecentColor(int)), m_resourceManager, SLOT(slotUpdateRecentColor(int))); connect(m_resourceManager, SIGNAL(setSelectedColor(int)), SLOT(slotSetSelectedColor(int))); connect(m_resourceManager, SIGNAL(updatePalettes()), SLOT(slotUpdate())); connect(m_resourceManager, SIGNAL(hidePalettes()), SLOT(slotHide())); // This is used to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible m_timer = new QTimer(this); m_timer->setSingleShot(true); connect(this, SIGNAL(sigTriggerTimer()), this, SLOT(slotTriggerTimer())); connect(m_timer, SIGNAL(timeout()), this, SLOT(slotEnableChangeFGColor())); connect(this, SIGNAL(sigEnableChangeFGColor(bool)), m_resourceManager, SIGNAL(sigEnableChangeColor(bool))); setMouseTracking(true); setHoveredPreset(-1); setHoveredColor(-1); setSelectedColor(-1); setVisible(true); setVisible(false); } void KisPopupPalette::slotExternalFgColorChanged(const KoColor &color) { m_triangleColorSelector->setRealColor(color); } void KisPopupPalette::slotEmitColorChanged() { if (isVisible()) { update(); emit sigChangefGColor(m_triangleColorSelector->realColor()); } } //setting KisPopupPalette properties int KisPopupPalette::hoveredPreset() const { return m_hoveredPreset; } void KisPopupPalette::setHoveredPreset(int x) { m_hoveredPreset = x; } int KisPopupPalette::hoveredColor() const { return m_hoveredColor; } void KisPopupPalette::setHoveredColor(int x) { m_hoveredColor = x; } int KisPopupPalette::selectedColor() const { return m_selectedColor; } void KisPopupPalette::setSelectedColor(int x) { m_selectedColor = x; } void KisPopupPalette::slotTriggerTimer() { m_timer->start(750); } void KisPopupPalette::slotEnableChangeFGColor() { emit sigEnableChangeFGColor(true); } void KisPopupPalette::showPopupPalette(const QPoint &p) { if (!isVisible() && parentWidget()) { QSize parentSize(parentWidget()->size()); QPoint pointPalette(p.x() - width() / 2, p.y() - height() / 2); //setting offset point in case the widget is shown outside of canvas region int offsetX = 0, offsetY = 0; if ((offsetX = pointPalette.x() + width() - parentSize.width()) > 0 || (offsetX = pointPalette.x()) < 0) { pointPalette.setX(pointPalette.x() - offsetX); } if ((offsetY = pointPalette.y() + height() - parentSize.height()) > 0 || (offsetY = pointPalette.y()) < 0) { pointPalette.setY(pointPalette.y() - offsetY); } move(pointPalette); } showPopupPalette(!isVisible()); } void KisPopupPalette::showPopupPalette(bool show) { if (show) { emit sigEnableChangeFGColor(!show); QApplication::setOverrideCursor(Qt::ArrowCursor); } else { emit sigTriggerTimer(); QApplication::restoreOverrideCursor(); } setVisible(show); } //redefinition of setVariable function to change the scope to private void KisPopupPalette::setVisible(bool b) { QWidget::setVisible(b); } QSize KisPopupPalette::sizeHint() const { return QSize(290, 290); } void KisPopupPalette::resizeEvent(QResizeEvent*) { int side = qMin(width(), height()); int fgball = 66; int sball = 40; QRegion maskedRegion(width() / 2 - side / 2, height() / 2 - side / 2, side, side, QRegion::Ellipse); maskedRegion = maskedRegion.united( QRegion(50 - fgball / 2, 32 - fgball / 2 , fgball, fgball, QRegion::Ellipse) ); maskedRegion = maskedRegion.united( QRegion(24 - (fgball - 20 ) / 2, 60 - (fgball - 20 ) / 2 , (fgball - 20 ), (fgball - 20 ), QRegion::Ellipse) ); maskedRegion = maskedRegion.united( QRegion(width() / 2 + side / 2 - sball, height() / 2 + side / 2 - sball, sball , sball, QRegion::Ellipse) ); setMask(maskedRegion); } void KisPopupPalette::paintEvent(QPaintEvent* e) { float rotationAngle = 0.0; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(e->rect(), palette().brush(QPalette::Window)); painter.translate(width() / 2, height() / 2); //painting background color QPainterPath bgColor; bgColor.addEllipse(QPoint(-width() / 2 + 24, -height() / 2 + 60), 20, 20); painter.fillPath(bgColor, m_displayRenderer->toQColor(m_resourceManager->bgColor())); painter.drawPath(bgColor); //painting foreground color QPainterPath fgColor; fgColor.addEllipse(QPoint(-width() / 2 + 50, -height() / 2 + 32), 30, 30); painter.fillPath(fgColor, m_displayRenderer->toQColor(m_triangleColorSelector->realColor())); painter.drawPath(fgColor); //painting favorite brushes QList images(m_resourceManager->favoritePresetImages()); //painting favorite brushes pixmap/icon QPainterPath path; for (int pos = 0; pos < images.size(); pos++) { painter.save(); path = pathFromPresetIndex(pos); painter.setClipPath(path); QRect bounds = path.boundingRect().toAlignedRect(); painter.drawImage(bounds.topLeft(), images.at(pos).scaled(bounds.size(), Qt::KeepAspectRatioByExpanding)); painter.restore(); } if (hoveredPreset() > -1) { path = pathFromPresetIndex(hoveredPreset()); QPen pen(palette().color(QPalette::Highlight)); pen.setWidth(3); painter.setPen(pen); painter.drawPath(path); } //painting recent colors painter.setPen(Qt::NoPen); rotationAngle = -360.0 / m_resourceManager->recentColorsTotal(); KoColor kocolor; for (int pos = 0; pos < m_resourceManager->recentColorsTotal(); pos++) { QPainterPath path(drawDonutPathAngle(colorInnerRadius, colorOuterRadius, m_resourceManager->recentColorsTotal())); //accessing recent color of index pos kocolor = m_resourceManager->recentColorAt(pos); painter.fillPath(path, m_displayRenderer->toQColor(kocolor)); painter.drawPath(path); painter.rotate(rotationAngle); } painter.setBrush(Qt::transparent); if (m_resourceManager->recentColorsTotal() == 0) { QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, colorInnerRadius, colorOuterRadius)); painter.setPen(QPen(palette().color(QPalette::Window).darker(130), 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); painter.drawPath(path_ColorDonut); } //painting hovered color if (hoveredColor() > -1) { painter.setPen(QPen(palette().color(QPalette::Highlight), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); if (m_resourceManager->recentColorsTotal() == 1) { QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, colorInnerRadius, colorOuterRadius)); painter.drawPath(path_ColorDonut); } else { painter.rotate((m_resourceManager->recentColorsTotal() + hoveredColor()) *rotationAngle); QPainterPath path(drawDonutPathAngle(colorInnerRadius, colorOuterRadius, m_resourceManager->recentColorsTotal())); painter.drawPath(path); painter.rotate(hoveredColor() * -1 * rotationAngle); } } //painting selected color if (selectedColor() > -1) { painter.setPen(QPen(palette().color(QPalette::Highlight).darker(130), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); if (m_resourceManager->recentColorsTotal() == 1) { QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, colorInnerRadius, colorOuterRadius)); painter.drawPath(path_ColorDonut); } else { painter.rotate((m_resourceManager->recentColorsTotal() + selectedColor()) *rotationAngle); QPainterPath path(drawDonutPathAngle(colorInnerRadius, colorOuterRadius, m_resourceManager->recentColorsTotal())); painter.drawPath(path); painter.rotate(selectedColor() * -1 * rotationAngle); } } int side = qMin(width(), height()); QPixmap settingIcon = koIcon("configure").pixmap(QSize(22,22)); painter.drawPixmap(side / 2 - 40 + 9, side / 2 - 40 + 9, settingIcon); } QPainterPath KisPopupPalette::drawDonutPathFull(int x, int y, int inner_radius, int outer_radius) { QPainterPath path; path.addEllipse(QPointF(x, y), outer_radius, outer_radius); path.addEllipse(QPointF(x, y), inner_radius, inner_radius); path.setFillRule(Qt::OddEvenFill); return path; } QPainterPath KisPopupPalette::drawDonutPathAngle(int inner_radius, int outer_radius, int limit) { QPainterPath path; path.moveTo(-0.999 * outer_radius * sin(M_PI / limit), 0.999 * outer_radius * cos(M_PI / limit)); path.arcTo(-1 * outer_radius, -1 * outer_radius, 2 * outer_radius, 2 * outer_radius, -90.0 - 180.0 / limit, 360.0 / limit); path.arcTo(-1 * inner_radius, -1 * inner_radius, 2 * inner_radius, 2 * inner_radius, -90.0 + 180.0 / limit, - 360.0 / limit); path.closeSubpath(); return path; } void KisPopupPalette::mouseMoveEvent(QMouseEvent* event) { QPointF point = event->posF(); event->accept(); QPainterPath pathBrush(drawDonutPathFull(width() / 2, height() / 2, brushInnerRadius, brushOuterRadius)); QPainterPath pathColor(drawDonutPathFull(width() / 2, height() / 2, colorInnerRadius, colorOuterRadius)); setToolTip(""); setHoveredPreset(-1); setHoveredColor(-1); if (pathBrush.contains(point)) { //in favorite brushes area int pos = calculatePresetIndex(point, m_resourceManager->numFavoritePresets()); if (pos >= 0 && pos < m_resourceManager->numFavoritePresets()) { setToolTip(m_resourceManager->favoritePresetList().at(pos).data()->name()); setHoveredPreset(pos); } } else if (pathColor.contains(point)) { int pos = calculateIndex(point, m_resourceManager->recentColorsTotal()); if (pos >= 0 && pos < m_resourceManager->recentColorsTotal()) { setHoveredColor(pos); } } update(); } void KisPopupPalette::mousePressEvent(QMouseEvent* event) { QPointF point = event->posF(); event->accept(); if (event->button() == Qt::LeftButton) { QPainterPath pathBrush(drawDonutPathFull(width() / 2, height() / 2, brushInnerRadius, brushOuterRadius)); if (pathBrush.contains(point)) { //in favorite brushes area int pos = calculateIndex(point, m_resourceManager->numFavoritePresets()); if (pos >= 0 && pos < m_resourceManager->numFavoritePresets() && isPointInPixmap(point, pos)) { //setSelectedBrush(pos); update(); } } else { int side = qMin(width(), height()); QPainterPath settingCircle; settingCircle.addEllipse(width() / 2 + side / 2 - 40, height() / 2 + side / 2 - 40, 40, 40); if (settingCircle.contains(point)) { KisPaintOpPresetResourceServer* rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QStringList tags = rServer->tagNamesList(); qSort(tags); if (!tags.isEmpty()) { QMenu menu; foreach(const QString& tag, tags) { menu.addAction(tag); } QAction* action = menu.exec(event->globalPos()); if (action) { m_resourceManager->setCurrentTag(action->text()); } } else { QWhatsThis::showText(event->globalPos(), i18n("There are no tags available to show in this popup. To add presets, you need to tag them and then select the tag here.")); } } } } } void KisPopupPalette::mouseReleaseEvent(QMouseEvent * event) { QPointF point = event->posF(); event->accept(); if (event->button() == Qt::LeftButton) { QPainterPath pathBrush(drawDonutPathFull(width() / 2, height() / 2, brushInnerRadius, brushOuterRadius)); QPainterPath pathColor(drawDonutPathFull(width() / 2, height() / 2, colorInnerRadius, colorOuterRadius)); if (pathBrush.contains(point)) { //in favorite brushes area if (hoveredPreset() > -1) { //setSelectedBrush(hoveredBrush()); emit sigChangeActivePaintop(hoveredPreset()); } } else if (pathColor.contains(point)) { int pos = calculateIndex(point, m_resourceManager->recentColorsTotal()); if (pos >= 0 && pos < m_resourceManager->recentColorsTotal()) { emit sigUpdateRecentColor(pos); } } } else if (event->button() == Qt::RightButton) { showPopupPalette(false); } } int KisPopupPalette::calculateIndex(QPointF point, int n) { calculatePresetIndex(point, n); //translate to (0,0) point.setX(point.x() - width() / 2); point.setY(point.y() - height() / 2); //rotate float smallerAngle = M_PI / 2 + M_PI / n - atan2(point.y(), point.x()); float radius = sqrt((float)point.x() * point.x() + point.y() * point.y()); point.setX(radius * cos(smallerAngle)); point.setY(radius * sin(smallerAngle)); //calculate brush index int pos = floor(acos(point.x() / radius) * n / (2 * M_PI)); if (point.y() < 0) pos = n - pos - 1; return pos; } bool KisPopupPalette::isPointInPixmap(QPointF& point, int pos) { if (pathFromPresetIndex(pos).contains(point + QPointF(-width() / 2, -height() / 2))) { return true; } return false; } KisPopupPalette::~KisPopupPalette() { } QPainterPath KisPopupPalette::pathFromPresetIndex(int index) { QRect outerRect(-width() / 2, -height() / 2, width(), height()); outerRect.adjust(3, 3, -3, -3); int ringSize = brushOuterRadius - colorOuterRadius - 6; QRect innerRect = outerRect.adjusted(ringSize, ringSize, -ringSize, -ringSize); qreal angleLength = 360.0 / numSlots(); qreal angle = index * angleLength; QPainterPath path; path.moveTo(brushOuterRadius * cos(angle / 180 * M_PI), -brushOuterRadius * sin(angle / 180 * M_PI)); path.arcTo(outerRect, angle, angleLength); path.arcTo(innerRect, angle + angleLength, -angleLength); path.closeSubpath(); return path; } int KisPopupPalette::calculatePresetIndex(QPointF point, int /*n*/) { int x = point.x() - width() / 2; int y = point.y() - height() / 2; qreal radius = sqrt((qreal) x * x + y * y); qreal angle; // y coordinate is the reverse of the cartesian one if (y < 0) { angle = acos(x / radius); } else { angle = 2 * M_PI - acos(x / radius); } int pos = floor(angle / (2 * M_PI / numSlots())); return pos; } int KisPopupPalette::numSlots() { KisConfig config; return qMax(config.favoritePresets(), 10); } #include "kis_popup_palette.moc" diff --git a/krita/ui/kis_resource_server_provider.h b/krita/ui/kis_resource_server_provider.h index e3541e10b5..6e854ad1f4 100644 --- a/krita/ui/kis_resource_server_provider.h +++ b/krita/ui/kis_resource_server_provider.h @@ -1,84 +1,76 @@ /* * kis_resource_server_provider.h - part of KImageShop * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2005 Sven Langkamp * Copyright (c) 2003-2008 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_RESOURCESERVERPROVIDER_H_ #define KIS_RESOURCESERVERPROVIDER_H_ -#include -#include -#include - -#include #include -#include #include #include #include -class KoResource; class KoResourceLoaderThread; -class KisPaintOpPreset; class KisWorkspaceResource; class KisPSDLayerStyleCollectionResource; typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer; typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter; class KRITAUI_EXPORT KisResourceServerProvider : public QObject { Q_OBJECT public: virtual ~KisResourceServerProvider(); static KisResourceServerProvider* instance(); KisPaintOpPresetResourceServer* paintOpPresetServer(bool block = true); KoResourceServer* workspaceServer(bool block = true); KoResourceServer* layerStyleCollectionServer(bool block = true); void brushBlacklistCleanup(); Q_SIGNALS: void notifyBrushBlacklistCleanup(); private: KisResourceServerProvider(); KisResourceServerProvider(const KisResourceServerProvider&); KisResourceServerProvider operator=(const KisResourceServerProvider&); KisPaintOpPresetResourceServer* m_paintOpPresetServer; KoResourceServer* m_workspaceServer; KoResourceServer* m_layerStyleCollectionServer; private: KoResourceLoaderThread *m_paintOpPresetThread; KoResourceLoaderThread *m_workspaceThread; KoResourceLoaderThread *m_layerStyleCollectionThread; }; #endif // KIS_RESOURCESERVERPROVIDER_H_ diff --git a/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp b/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp index 17233cdf32..a86c2dcfa7 100644 --- a/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp +++ b/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp @@ -1,130 +1,129 @@ /* This file is part of the KDE project * Copyright (c) 2010 Sven Langkamp * Copyright 2011 Srikanth Tiyyagura * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_paintop_presets_chooser_popup.h" #include #include #include -#include #include #include #include #include #include #include #include #include "kis_paintop_settings.h" struct KisPaintOpPresetsChooserPopup::Private { public: Ui_WdgPaintOpPresets uiWdgPaintOpPresets; bool firstShown; }; KisPaintOpPresetsChooserPopup::KisPaintOpPresetsChooserPopup(QWidget * parent) : QWidget(parent) , m_d(new Private()) { m_d->uiWdgPaintOpPresets.setupUi(this); KMenu* menu = new KMenu(this); QActionGroup *actionGroup = new QActionGroup(this); KisPresetChooser::ViewMode mode = (KisPresetChooser::ViewMode)KisConfig().presetChooserViewMode(); QAction* action = menu->addAction(koIcon("view-preview"), i18n("Thumbnails"), this, SLOT(slotThumbnailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::THUMBNAIL); action->setActionGroup(actionGroup); action = menu->addAction(koIcon("view-list-details"), i18n("Details"), this, SLOT(slotDetailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::DETAIL); action->setActionGroup(actionGroup); m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(mode); m_d->uiWdgPaintOpPresets.wdgPresetChooser->showTaggingBar(true, true); m_d->uiWdgPaintOpPresets.wdgPresetChooser->itemChooser()->setViewModeButtonVisible(true); QToolButton *viewModeButton = m_d->uiWdgPaintOpPresets.wdgPresetChooser->itemChooser()->viewModeButton(); viewModeButton->setMenu(menu); connect(m_d->uiWdgPaintOpPresets.wdgPresetChooser, SIGNAL(resourceSelected(KoResource*)), this, SIGNAL(resourceSelected(KoResource*))); m_d->firstShown = true; } KisPaintOpPresetsChooserPopup::~KisPaintOpPresetsChooserPopup() { delete m_d; } void KisPaintOpPresetsChooserPopup::slotThumbnailMode() { KisConfig().setPresetChooserViewMode(KisPresetChooser::THUMBNAIL); m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(KisPresetChooser::THUMBNAIL); } void KisPaintOpPresetsChooserPopup::slotDetailMode() { KisConfig().setPresetChooserViewMode(KisPresetChooser::DETAIL); m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(KisPresetChooser::DETAIL); } void KisPaintOpPresetsChooserPopup::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); //Workaround to get the column and row size right if(m_d->firstShown) { m_d->uiWdgPaintOpPresets.wdgPresetChooser->updateViewSettings(); m_d->firstShown = false; } } void KisPaintOpPresetsChooserPopup::showButtons(bool show) { m_d->uiWdgPaintOpPresets.wdgPresetChooser->showButtons(show); } void KisPaintOpPresetsChooserPopup::canvasResourceChanged(KoResource* resource , KisPaintOpPresetSP preset2 ) { Q_UNUSED(preset2); if (resource) { blockSignals(true); KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP preset = rserver->resourceByName(resource->name()); m_d->uiWdgPaintOpPresets.wdgPresetChooser->itemChooser()->setCurrentResource(preset.data()); blockSignals(false); } m_d->uiWdgPaintOpPresets.wdgPresetChooser->updateViewSettings(); } void KisPaintOpPresetsChooserPopup::updateViewSettings() { m_d->uiWdgPaintOpPresets.wdgPresetChooser->updateViewSettings(); } diff --git a/krita/ui/widgets/kis_pattern_chooser.h b/krita/ui/widgets/kis_pattern_chooser.h index 7c41a50753..e7dff07097 100644 --- a/krita/ui/widgets/kis_pattern_chooser.h +++ b/krita/ui/widgets/kis_pattern_chooser.h @@ -1,62 +1,63 @@ /* * Copyright (c) 2004 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PATTERN_CHOOSER_H_ #define KIS_PATTERN_CHOOSER_H_ #include -#include #include class QLabel; +class KoResourceItemChooser; +class KoResource; class KRITAUI_EXPORT KisPatternChooser : public QFrame { Q_OBJECT public: KisPatternChooser(QWidget *parent = 0); virtual ~KisPatternChooser(); /// Gets the currently selected resource /// @returns the selected resource, 0 is no resource is selected KoResource *currentResource(); void setCurrentPattern(KoResource *resource); void setCurrentItem(int row, int column); void setGrayscalePreview(bool grayscale); /// determines whether the preview right or below the splitter void setPreviewOrientation(Qt::Orientation orientation); Q_SIGNALS: /// Emitted when a resource was selected void resourceSelected(KoResource *resource); void updateItemSize(); private Q_SLOTS: void update(KoResource *resource); private: QLabel *m_lbName; KoResourceItemChooser *m_itemChooser; }; #endif // KIS_PATTERN_CHOOSER_H_ diff --git a/krita/ui/widgets/kis_workspace_chooser.cpp b/krita/ui/widgets/kis_workspace_chooser.cpp index de4413b118..51b865cfc0 100644 --- a/krita/ui/widgets/kis_workspace_chooser.cpp +++ b/krita/ui/widgets/kis_workspace_chooser.cpp @@ -1,172 +1,173 @@ /* This file is part of the KDE project * Copyright (C) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_workspace_chooser.h" #include #include #include #include +#include #include #include #include #include #include #include #include "KoPattern.h" #include "kis_resource_server_provider.h" #include "kis_workspace_resource.h" #include "KisViewManager.h" #include #include #include class KisWorkspaceDelegate : public QAbstractItemDelegate { public: KisWorkspaceDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} virtual ~KisWorkspaceDelegate() {} /// reimplemented virtual void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const { return option.decorationSize; } }; void KisWorkspaceDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (!index.isValid()) return; KisWorkspaceResource* workspace = static_cast(index.internalPointer()); QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Active : QPalette::Disabled; QPalette::ColorRole cr = (option.state & QStyle::State_Selected) ? QPalette::HighlightedText : QPalette::Text; painter->setPen(option.palette.color(cg, cr)); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } else { painter->fillRect(option.rect, option.palette.base()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, workspace->name()); } KisWorkspaceChooser::KisWorkspaceChooser(KisViewManager * view, QWidget* parent): QWidget(parent), m_view(view) { KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(false); QSharedPointer adapter(new KoResourceServerAdapter(rserver)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setItemDelegate(new KisWorkspaceDelegate(this)); m_itemChooser->setFixedSize(250, 250); m_itemChooser->setRowHeight(30); m_itemChooser->setColumnCount(1); m_itemChooser->showTaggingBar(false, false); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); QPushButton* saveButton = new QPushButton(i18n("Save")); connect(saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSave())); m_nameEdit = new KLineEdit(this); m_nameEdit->setClickMessage(i18n("Insert name")); m_nameEdit->setClearButtonShown(true); QGridLayout* layout = new QGridLayout(this); layout->addWidget(m_itemChooser, 0, 0, 1, 2); layout->addWidget(m_nameEdit, 1, 0, 1, 1); layout->addWidget(saveButton, 1, 1, 1, 1); } KisWorkspaceChooser::~KisWorkspaceChooser() { } void KisWorkspaceChooser::slotSave() { if (!m_view->qtMainWindow()) { return; } KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResource* workspace = new KisWorkspaceResource(""); workspace->setDockerState(m_view->qtMainWindow()->saveState()); m_view->resourceProvider()->notifySavingWorkspace(workspace); workspace->setValid(true); QString saveLocation = rserver->saveLocation(); QString name = m_nameEdit->text(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Workspace"); } QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + workspace->defaultFileExtension()); i++; } workspace->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Workspace %1", i); } workspace->setName(name); rserver->addResource(workspace); } void KisWorkspaceChooser::resourceSelected(KoResource* resource) { if (!m_view->qtMainWindow()) { return; } KisWorkspaceResource* workspace = static_cast(resource); QMap dockWidgetMap; foreach(QDockWidget *docker, m_view->mainWindow()->dockWidgets()) { dockWidgetMap[docker] = docker->property("Locked").toBool(); } KisMainWindow *mainWindow = qobject_cast(m_view->qtMainWindow()); mainWindow->restoreWorkspace(workspace->dockerState()); m_view->resourceProvider()->notifyLoadingWorkspace(workspace); foreach(QDockWidget *docker, dockWidgetMap.keys()) { if (docker->isVisible()) { docker->setProperty("Locked", dockWidgetMap[docker]); docker->updateGeometry(); } else { docker->setProperty("Locked", false); // Unlock invisible dockers docker->toggleViewAction()->setEnabled(true); } } } diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt index db7100f7d4..08ae8e3085 100644 --- a/libs/widgets/CMakeLists.txt +++ b/libs/widgets/CMakeLists.txt @@ -1,170 +1,169 @@ add_subdirectory( tests ) add_subdirectory( pics ) include_directories(${KOTEXT_INCLUDES} ${KOODF_INCLUDES} ${PIGMENT_INCLUDES}) include_directories(${CMAKE_SOURCE_DIR}/libs/widgetutils) if (LIBATTICA_FOUND) include_directories(${LIBATTICA_INCLUDE_DIR}) endif () set(kowidgets_LIB_SRCS KoGlobal.cpp KoZoomWidget.cpp KoTagToolButton.cpp KoTagChooserWidget.cpp KoTagFilterWidget.cpp KoResourceTaggingManager.cpp KoResourceItemChooserContextMenu.cpp KoAspectButton.cpp KoCsvImportDialog.cpp KoPageLayoutDialog.cpp KoPageLayoutWidget.cpp KoPagePreviewWidget.cpp KoPositionSelector.cpp KoSliderCombo.cpp KoColorPopupButton.cpp KoUnitDoubleSpinBox.cpp KoZoomAction.cpp KoZoomController.cpp KoZoomInput.cpp KoZoomHandler.cpp KoZoomMode.cpp KoDpi.cpp KoGlobal.cpp KoFileDialog.cpp KoColorPatch.cpp KoColorPopupAction.cpp KoColorSetWidget.cpp KoColorSlider.cpp KoDualColorButton.cpp KoEditColorSetDialog.cpp KoTriangleColorSelector.cpp KoResourcePopupAction.cpp KoStrokeConfigWidget.cpp KoFillConfigWidget.cpp KoShadowConfigWidget.cpp KoIconToolTip.cpp KoResourceItemChooser.cpp KoResourceItemChooserSync.cpp KoResourceSelector.cpp KoResourceModel.cpp KoResourceItemDelegate.cpp KoResourceItemView.cpp KoResourceTagStore.cpp KoRuler.cpp KoRulerController.cpp KoItemToolTip.cpp KoCheckerBoardPainter.cpp KoResourceServerAdapter.cpp KoResourceServerProvider.cpp KoLineStyleSelector.cpp KoLineStyleItemDelegate.cpp KoLineStyleModel.cpp KoMarkerModel.cpp KoMarkerItemDelegate.cpp KoMarkerSelector.cpp KoDockWidgetTitleBar.cpp KoDockWidgetTitleBarButton.cpp KoViewItemContextBar.cpp KoContextBarButton.cpp KoResourceFiltering.cpp KoResourceModelBase.cpp KoToolBox.cpp KoToolBoxDocker.cpp KoToolBoxFactory.cpp KoToolDocker.cpp KoModeBox.cpp KoModeBoxDocker.cpp KoModeBoxFactory.cpp KoDocumentInfoDlg.cpp KoDocumentInfoPropsPage.cpp KoGlobal.cpp ) kde4_add_ui_files( kowidgets_LIB_SRCS KoCsvImportDialog.ui koDocumentInfoAboutWidget.ui koDocumentInfoAuthorWidget.ui KoEditColorSet.ui KoPageLayoutWidget.ui KoShadowConfigWidget.ui ) kde4_add_library(kowidgets SHARED ${kowidgets_LIB_SRCS}) if(GHNS) target_link_libraries(kowidgets kotext pigmentcms kowidgetutils ${KDE4_KNEWSTUFF3_LIBS}) else() target_link_libraries(kowidgets kotext pigmentcms kowidgetutils) endif () target_link_libraries(kowidgets LINK_INTERFACE_LIBRARIES kotext pigmentcms kowidgetutils ${KDE4_KDEUI_LIBS}) set_target_properties(kowidgets PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS kowidgets ${INSTALL_TARGETS_DEFAULT_ARGS}) install( FILES KoGlobal.h KoResourceItemChooserContextMenu.h - KoResourceTaggingManager.h KoGenericRegistryModel.h KoPageLayoutDialog.h KoPageLayoutWidget.h KoPagePreviewWidget.h KoPositionSelector.h kowidgets_export.h KoZoomAction.h KoZoomController.h KoZoomInput.h KoDpi.h KoZoomHandler.h KoZoomMode.h KoGlobal.h KoFileDialog.h KoColorPatch.h KoStrokeConfigWidget.h KoFillConfigWidget.h KoShadowConfigWidget.h KoColorPopupAction.h KoColorSetWidget.h KoColorSlider.h KoDualColorButton.h KoEditColorSetDialog.h KoTriangleColorSelector.h KoResourceItemChooser.h KoResourceSelector.h KoResourceServer.h KoResourceServerAdapter.h KoResourceServerObserver.h KoResourceServerProvider.h KoResourceTagStore.h KoLineStyleSelector.h KoDockWidgetTitleBar.h KoDockWidgetTitleBarButton.h KoResourceModelBase.h KoGlobal.h DESTINATION ${INCLUDE_INSTALL_DIR}/calligra COMPONENT Devel) set(filedialogtester_SRCS KoFileDialogTester.cpp main.cpp ) kde4_add_ui_files(filedialogtester_SRCS KoFileDialogTester.ui ) kde4_add_executable(filedialogtester ${filedialogtester_SRCS}) target_link_libraries(filedialogtester kowidgets) diff --git a/libs/widgets/KoColorSetWidget_p.h b/libs/widgets/KoColorSetWidget_p.h index d981baeecd..13b1f0165d 100644 --- a/libs/widgets/KoColorSetWidget_p.h +++ b/libs/widgets/KoColorSetWidget_p.h @@ -1,71 +1,69 @@ /* This file is part of the KDE project Copyright (c) 2007, 2012 C. Boemann Copyright (c) 2007-2008 Fredy Yanardi This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KoColorSetWidget_p_h #define KoColorSetWidget_p_h #include "KoColorSetWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include class KoColorPatch; class KoColorSetWidget::KoColorSetWidgetPrivate { public: KoColorSetWidget *thePublic; QPointer colorSet; QTimer m_timer; QVBoxLayout *mainLayout; bool firstShowOfContainer; QWidget *colorSetContainer; QScrollArea *scrollArea; QGridLayout *colorSetLayout; QHBoxLayout *recentsLayout; KoColorPatch *recentPatches[6]; QToolButton *addRemoveButton; int numRecents; void colorTriggered(KoColorPatch *patch); void addRecent(const KoColor &); void activateRecent(int i); void fillColors(); void addRemoveColors(); }; #endif diff --git a/libs/widgets/KoResourceFiltering.cpp b/libs/widgets/KoResourceFiltering.cpp index e10b70af64..18a0a9a41b 100644 --- a/libs/widgets/KoResourceFiltering.cpp +++ b/libs/widgets/KoResourceFiltering.cpp @@ -1,257 +1,261 @@ /* This file is part of the KDE project Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "KoResourceFiltering.h" #include "KoResourceServer.h" +#include +#include + + class KoResourceFiltering::Private { public: Private() : isTag("\\[([\\w\\s]+)\\]") , isExactMatch("\"([\\w\\s]+)\"") , searchTokenizer("\\s*,+\\s*") , hasNewFilters(false) , name(true) , filename(true) , resourceServer(0) {} QRegExp isTag; QRegExp isExactMatch; QRegExp searchTokenizer; bool hasNewFilters; bool name,filename; KoResourceServerBase *resourceServer; QStringList tagSetFilenames; QStringList includedNames; QStringList excludedNames; QString currentTag; }; KoResourceFiltering::KoResourceFiltering() : d(new Private()) {} KoResourceFiltering::~KoResourceFiltering() { delete d; } void KoResourceFiltering::configure(int filterType, bool enable) { switch (filterType) { case 0: d->name=true; d->filename=enable; break; case 1: d->name=enable; break; case 2: d->filename=enable; break; } } void KoResourceFiltering::setChanged() { d->hasNewFilters = true; } void KoResourceFiltering::setTagSetFilenames(const QStringList& filenames) { d->tagSetFilenames = filenames; d->excludedNames.clear(); d->includedNames.clear(); setChanged(); } bool KoResourceFiltering::matchesResource(const QStringList &filteredList,const QStringList &filterList) const { Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive; foreach (QString filter, filterList) { if (!filter.startsWith('"')) { foreach (QString filtered, filteredList) { if (filtered.contains(filter,sensitivity)) { return true; } } } else if (d->name) { filter.remove('"'); if (!filteredList.at(0).compare(filter)) { return true; } } } return false; } void KoResourceFiltering::sanitizeExclusionList() { if(!d->includedNames.isEmpty()) { foreach (const QString &exclusion, d->excludedNames) { if (!excludeFilterIsValid(exclusion)) d->excludedNames.removeAll(exclusion); } } } QStringList KoResourceFiltering::tokenizeSearchString(const QString& searchString) const { return searchString.split(d->searchTokenizer, QString::SkipEmptyParts); } void KoResourceFiltering::populateIncludeExcludeFilters(const QStringList& filteredNames) { foreach (QString name, filteredNames) { QStringList* target; if(name.startsWith('!')) { name.remove('!'); target = &d->excludedNames; } else { target = &d->includedNames; } if(!name.isEmpty()) { if (name.startsWith('[')) { if (d->isTag.exactMatch(name) && d->resourceServer) { name = d->isTag.cap(1); (*target) += d->resourceServer->queryResources(name); } } else if (name.startsWith('"')) { if (d->isExactMatch.exactMatch(name)) { target->push_back(name); } } else { target->push_back(name); } } } sanitizeExclusionList(); } bool KoResourceFiltering::hasFilters() const { return (!d->tagSetFilenames.isEmpty() || !d->includedNames.isEmpty() || !d->excludedNames.isEmpty()); } bool KoResourceFiltering::filtersHaveChanged() const { return d->hasNewFilters; } void KoResourceFiltering::setFilters(const QString &searchString) { d->excludedNames.clear(); d->includedNames.clear(); QStringList filteredNames = tokenizeSearchString(searchString); populateIncludeExcludeFilters(filteredNames); setChanged(); } bool KoResourceFiltering::presetMatchesSearch(KoResource * resource) const { QList filteredList; QString resourceFileName = resource->shortFilename(); QString resourceName = resource->name(); if (d->name) { filteredList.push_front(resourceName); } if (d->filename) { filteredList.push_back(resourceFileName); } if (matchesResource(filteredList,d->excludedNames)) { return false; } if (matchesResource(filteredList,d->includedNames)) { return true; } foreach (const QString &filter, d->tagSetFilenames) { if (!resourceFileName.compare(filter) || !resourceName.compare(filter)) { return true; } } return false; } void KoResourceFiltering::setInclusions(const QStringList &inclusions) { d->includedNames = inclusions; setChanged(); } void KoResourceFiltering::setExclusions(const QStringList &exclusions) { d->excludedNames = exclusions; setChanged(); } bool KoResourceFiltering::excludeFilterIsValid(const QString &exclusion) { foreach(const QString &inclusion, d->includedNames) { if ((inclusion.startsWith(exclusion) && exclusion.size() <= inclusion.size())) { return false; } } return true; } QList< KoResource* > KoResourceFiltering::filterResources(QList< KoResource* > resources) { foreach(KoResource* resource, resources) { if(!presetMatchesSearch(resource)) { resources.removeAll(resource); } } setDoneFiltering(); return resources; } void KoResourceFiltering::setDoneFiltering() { d->hasNewFilters = false; } void KoResourceFiltering::rebuildCurrentTagFilenames() { d->tagSetFilenames = d->resourceServer->queryResources(d->currentTag); } void KoResourceFiltering::setCurrentTag(const QString& tagSet) { d->currentTag = tagSet; rebuildCurrentTagFilenames(); } void KoResourceFiltering::setResourceServer(KoResourceServerBase* resourceServer) { d->resourceServer = resourceServer; } diff --git a/libs/widgets/KoResourceFiltering.h b/libs/widgets/KoResourceFiltering.h index 1300a1b5b9..6506213f23 100644 --- a/libs/widgets/KoResourceFiltering.h +++ b/libs/widgets/KoResourceFiltering.h @@ -1,67 +1,67 @@ /* This file is part of the KDE project Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KORESOURCEFILTER_H #define KORESOURCEFILTER_H -#include -#include - -#include "KoResource.h" - #include "kowidgets_export.h" +#include + class KoResourceServerBase; +class KoResource; +class QStringList; +class QString; class KOWIDGETS_EXPORT KoResourceFiltering { public: KoResourceFiltering(); virtual ~KoResourceFiltering(); void configure(int filterType, bool enable); bool hasFilters() const; bool filtersHaveChanged() const; void setTagSetFilenames(const QStringList& filenames); void setCurrentTag(const QString& tagSet); void rebuildCurrentTagFilenames(); void setResourceServer(KoResourceServerBase *resourceServer); void setFilters(const QString& searchString); QList filterResources(QList< KoResource* > resources); void setInclusions(const QStringList &inclusions); void setExclusions(const QStringList &exclusions); private: void setDoneFiltering(); bool presetMatchesSearch(KoResource * resource) const; void setChanged(); bool excludeFilterIsValid(const QString &exclusion); bool matchesResource(const QStringList& filtered,const QStringList &filterList) const; void populateIncludeExcludeFilters(const QStringList& filteredNames); void sanitizeExclusionList(); QStringList tokenizeSearchString(const QString& searchString) const; class Private; Private * const d; }; #endif // KORESOURCEFILTER_H diff --git a/libs/widgets/KoResourceItemChooser.cpp b/libs/widgets/KoResourceItemChooser.cpp index 9c830442dc..a3c064be69 100644 --- a/libs/widgets/KoResourceItemChooser.cpp +++ b/libs/widgets/KoResourceItemChooser.cpp @@ -1,614 +1,616 @@ /* This file is part of the KDE project Copyright (c) 2002 Patrick Julien Copyright (c) 2007 Jan Hambrecht Copyright (c) 2007 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2011 José Luis Vergara Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceItemChooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef GHNS #include #include #include #endif #include #include #include "KoResourceServerAdapter.h" #include "KoResourceItemView.h" #include "KoResourceItemDelegate.h" #include "KoResourceModel.h" #include "KoResource.h" #include "KoResourceTaggingManager.h" +#include "KoTagFilterWidget.h" +#include "KoTagChooserWidget.h" #include "KoResourceItemChooserSync.h" class KoResourceItemChooser::Private { public: Private() : model(0) , view(0) , buttonGroup(0) , viewModeButton(0) , usePreview(false) , previewScroller(0) , previewLabel(0) , splitter(0) , tiledPreview(false) , grayscalePreview(false) , synced(false) , updatesBlocked(false) , savedResourceWhileReset(0) {} KoResourceModel* model; KoResourceTaggingManager* tagManager; KoResourceItemView* view; QButtonGroup* buttonGroup; QToolButton *viewModeButton; QString knsrcFile; bool usePreview; QScrollArea *previewScroller; QLabel *previewLabel; QSplitter *splitter; bool tiledPreview; bool grayscalePreview; bool synced; bool updatesBlocked; KoResource *savedResourceWhileReset; }; KoResourceItemChooser::KoResourceItemChooser(QSharedPointer resourceAdapter, QWidget *parent, bool usePreview) : QWidget( parent ) , d( new Private() ) { Q_ASSERT(resourceAdapter); d->splitter = new QSplitter(this); d->model = new KoResourceModel(resourceAdapter, this); connect(d->model, SIGNAL(beforeResourcesLayoutReset(KoResource*)), SLOT(slotBeforeResourcesLayoutReset(KoResource*))); connect(d->model, SIGNAL(afterResourcesLayoutReset()), SLOT(slotAfterResourcesLayoutReset())); d->view = new KoResourceItemView(this); d->view->setModel(d->model); d->view->setItemDelegate( new KoResourceItemDelegate( this ) ); d->view->setSelectionMode( QAbstractItemView::SingleSelection ); d->view->viewport()->installEventFilter(this); connect(d->view, SIGNAL(currentResourceChanged(QModelIndex)), this, SLOT(activated(QModelIndex))); connect (d->view, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint))); connect (d->view, SIGNAL(sigSizeChanged()), this, SLOT(updateView())); d->splitter->addWidget(d->view); d->splitter->setStretchFactor(0, 2); d->usePreview = usePreview; if (d->usePreview) { d->previewScroller = new QScrollArea(this); d->previewScroller->setWidgetResizable(true); d->previewScroller->setBackgroundRole(QPalette::Dark); d->previewScroller->setVisible(true); d->previewScroller->setAlignment(Qt::AlignCenter); d->previewLabel = new QLabel(this); d->previewScroller->setWidget(d->previewLabel); d->splitter->addWidget(d->previewScroller); if (d->splitter->count() == 2) { d->splitter->setSizes(QList() << 280 << 160); } } d->splitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); connect(d->splitter, SIGNAL(splitterMoved(int,int)), SIGNAL(splitterMoved())); d->buttonGroup = new QButtonGroup(this); d->buttonGroup->setExclusive(false); QGridLayout* layout = new QGridLayout(this); QGridLayout* buttonLayout = new QGridLayout; QPushButton *button = new QPushButton(this); button->setIcon(koIcon("document-open")); button->setToolTip(i18nc("@info:tooltip", "Import resource")); button->setEnabled(true); d->buttonGroup->addButton(button, Button_Import); buttonLayout->addWidget(button, 0, 0); button = new QPushButton(this); button->setIcon(koIcon("trash-empty")); button->setToolTip(i18nc("@info:tooltip", "Delete resource")); button->setEnabled(false); d->buttonGroup->addButton(button, Button_Remove); buttonLayout->addWidget(button, 0, 1); button = new QPushButton(this); button->setIcon(koIcon("download")); button->setToolTip(i18nc("@info:tooltip", "Download resource")); button->setEnabled(true); button->hide(); d->buttonGroup->addButton(button, Button_GhnsDownload); buttonLayout->addWidget(button, 0, 3); button = new QPushButton(this); button->setIcon(koIcon("go-up")); button->setToolTip(i18nc("@info:tooltip", "Share Resource")); button->setEnabled(false); button->hide(); d->buttonGroup->addButton( button, Button_GhnsUpload); buttonLayout->addWidget(button, 0, 4); connect( d->buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotButtonClicked(int))); buttonLayout->setColumnStretch(0, 1); buttonLayout->setColumnStretch(1, 1); buttonLayout->setColumnStretch(2, 2); buttonLayout->setSpacing(0); buttonLayout->setMargin(0); d->viewModeButton = new QToolButton(this); d->viewModeButton->setIcon(koIcon("view-choose")); d->viewModeButton->setPopupMode(QToolButton::InstantPopup); d->viewModeButton->setVisible(false); d->tagManager = new KoResourceTaggingManager(d->model, this); layout->addWidget(d->tagManager->tagChooserWidget(), 0, 0); layout->addWidget(d->viewModeButton, 0, 1); layout->addWidget(d->splitter, 1, 0, 1, 2); layout->addWidget(d->tagManager->tagFilterWidget(), 2, 0, 1, 2); layout->addLayout(buttonLayout, 3, 0, 1, 2); layout->setMargin(0); layout->setSpacing(0); updateButtonState(); showTaggingBar(false,false); activated(d->model->index(0, 0)); } KoResourceItemChooser::~KoResourceItemChooser() { disconnect(); delete d; } void KoResourceItemChooser::slotButtonClicked( int button ) { if (button == Button_Import ) { QString extensions = d->model->extensions(); QString filter = QString("%1") .arg(extensions.replace(QString(":"), QString(" "))); KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setNameFilter(filter); dialog.setCaption(i18nc("@title:window", "Choose File to Add")); QString filename = dialog.url(); d->model->importResourceFile(filename); } else if( button == Button_Remove ) { QModelIndex index = d->view->currentIndex(); int row = index.row(); int column = index.column(); if( index.isValid() ) { KoResource * resource = resourceFromModelIndex(index); if( resource ) { d->model->removeResource(resource); } } if (column == 0) { int rowMin = --row; row = qBound(0, rowMin, row); } int columnMin = --column; column = qBound(0, columnMin, column); setCurrentItem(row, column); activated(d->model->index(row, column)); } #ifdef GHNS else if (button == Button_GhnsDownload) { KNS3::DownloadDialog dialog(d->knsrcFile, this); dialog.exec(); foreach (const KNS3::Entry& e, dialog.changedEntries()) { foreach(const QString &file, e.installedFiles()) { QFileInfo fi(file); d->model->importResourceFile( fi.absolutePath()+'/'+fi.fileName() , false ); } foreach(const QString &file, e.uninstalledFiles()) { QFileInfo fi(file); d->model->removeResourceFile(fi.absolutePath()+'/'+fi.fileName()); } } } else if (button == Button_GhnsUpload) { QModelIndex index = d->view->currentIndex(); if( index.isValid() ) { KoResource * resource = resourceFromModelIndex(index); if( resource ) { KNS3::UploadDialog dialog(d->knsrcFile, this); dialog.setUploadFile(KUrl::fromLocalFile(resource->filename())); dialog.setUploadName(resource->name()); dialog.exec(); } } } #endif updateButtonState(); } void KoResourceItemChooser::showButtons( bool show ) { foreach( QAbstractButton * button, d->buttonGroup->buttons() ) show ? button->show() : button->hide(); } void KoResourceItemChooser::showGetHotNewStuff( bool showDownload, bool showUpload ) { #ifdef GHNS QAbstractButton *button = d->buttonGroup->button(Button_GhnsDownload); showDownload ? button->show() : button->hide(); // attica < 2.9 is broken for upload, so don't show the upload button. 2.9 is released as 3.0 // because of binary incompatibility with 2.x. if (LIBATTICA_VERSION_MAJOR < 3) return; button = d->buttonGroup->button(Button_GhnsUpload); showUpload ? button->show() : button->hide(); #else Q_UNUSED(showDownload); Q_UNUSED(showUpload); #endif } void KoResourceItemChooser::showTaggingBar(bool showSearchBar, bool showOpBar) { d->tagManager->showTaggingBar(showSearchBar, showOpBar); } void KoResourceItemChooser::setRowCount( int rowCount ) { int resourceCount = d->model->resourcesCount(); d->model->setColumnCount( static_cast(resourceCount) / rowCount ); //Force an update to get the right row height (in theory) QRect geometry = d->view->geometry(); d->view->setViewMode(KoResourceItemView::FIXED_ROWS); d->view->setGeometry(geometry.adjusted(0, 0, 0, 1)); d->view->setGeometry(geometry); } void KoResourceItemChooser::setColumnCount( int columnCount ) { d->model->setColumnCount( columnCount ); } void KoResourceItemChooser::setRowHeight( int rowHeight ) { d->view->verticalHeader()->setDefaultSectionSize( rowHeight ); } void KoResourceItemChooser::setColumnWidth( int columnWidth ) { d->view->horizontalHeader()->setDefaultSectionSize( columnWidth ); } void KoResourceItemChooser::setItemDelegate( QAbstractItemDelegate * delegate ) { d->view->setItemDelegate(delegate); } KoResource * KoResourceItemChooser::currentResource() const { QModelIndex index = d->view->currentIndex(); if (index.isValid()) { return resourceFromModelIndex(index); } return 0; } void KoResourceItemChooser::setCurrentResource(KoResource* resource) { // don't update if the change came from the same chooser if (d->updatesBlocked) { return; } QModelIndex index = d->model->indexFromResource(resource); if( !index.isValid() ) return; d->view->setCurrentIndex(index); updatePreview(resource); } void KoResourceItemChooser::slotBeforeResourcesLayoutReset(KoResource *activateAfterReset) { d->savedResourceWhileReset = activateAfterReset ? activateAfterReset : currentResource(); } void KoResourceItemChooser::slotAfterResourcesLayoutReset() { if (d->savedResourceWhileReset) { this->blockSignals(true); setCurrentResource(d->savedResourceWhileReset); this->blockSignals(false); } } void KoResourceItemChooser::setPreviewOrientation(Qt::Orientation orientation) { d->splitter->setOrientation(orientation); } void KoResourceItemChooser::setPreviewTiled(bool tiled) { d->tiledPreview = tiled; } void KoResourceItemChooser::setGrayscalePreview(bool grayscale) { d->grayscalePreview = grayscale; } void KoResourceItemChooser::setCurrentItem(int row, int column) { QModelIndex index = d->model->index(row, column); if( !index.isValid() ) return; d->view->setCurrentIndex(index); if (index.isValid()) { updatePreview(resourceFromModelIndex(index)); } } void KoResourceItemChooser::setProxyModel( QAbstractProxyModel* proxyModel ) { proxyModel->setSourceModel(d->model); d->view->setModel(proxyModel); } void KoResourceItemChooser::activated(const QModelIndex &/*index*/) { KoResource* resource = currentResource(); if (resource) { d->updatesBlocked = true; emit resourceSelected( resource ); d->updatesBlocked = false; updatePreview(resource); updateButtonState(); } } void KoResourceItemChooser::updateButtonState() { QAbstractButton * removeButton = d->buttonGroup->button( Button_Remove ); if( ! removeButton ) return; QAbstractButton * uploadButton = d->buttonGroup->button(Button_GhnsUpload); if(!uploadButton) return; KoResource * resource = currentResource(); if( resource ) { removeButton->setEnabled( true ); uploadButton->setEnabled(resource->removable()); return; } removeButton->setEnabled( false ); uploadButton->setEnabled(false); } void KoResourceItemChooser::updatePreview(KoResource *resource) { if (!d->usePreview || !resource) return; QImage image = resource->image(); if (image.format()!= QImage::Format_RGB32 || image.format() != QImage::Format_ARGB32 || image.format() != QImage::Format_ARGB32_Premultiplied) { image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); } if (d->tiledPreview) { int width = d->previewScroller->width() * 4; int height = d->previewScroller->height() * 4; QImage img(width, height, image.format()); QPainter gc(&img); gc.fillRect(img.rect(), Qt::white); gc.setPen(Qt::NoPen); gc.setBrush(QBrush(image)); gc.drawRect(img.rect()); image = img; } // Only convert to grayscale if it is rgb. Otherwise, it's gray already. if (d->grayscalePreview && !image.isGrayscale()) { QRgb* pixel = reinterpret_cast( image.bits() ); for (int row = 0; row < image.height(); ++row ) { for (int col = 0; col < image.width(); ++col ){ const QRgb currentPixel = pixel[row * image.width() + col]; const int red = qRed(currentPixel); const int green = qGreen(currentPixel); const int blue = qBlue(currentPixel); const int grayValue = (red * 11 + green * 16 + blue * 5) / 32; pixel[row * image.width() + col] = qRgb(grayValue, grayValue, grayValue); } } } d->previewLabel->setPixmap(QPixmap::fromImage(image)); } KoResource* KoResourceItemChooser::resourceFromModelIndex(const QModelIndex& index) const { if(!index.isValid()) return 0; const QAbstractProxyModel* proxyModel = dynamic_cast(index.model()); if(proxyModel) { //Get original model index, because proxy models destroy the internalPointer QModelIndex originalIndex = proxyModel->mapToSource(index); return static_cast( originalIndex.internalPointer() ); } return static_cast( index.internalPointer() ); } void KoResourceItemChooser::setKnsrcFile(const QString& knsrcFileArg) { d->knsrcFile = knsrcFileArg; } QSize KoResourceItemChooser::viewSize() const { return d->view->size(); } KoResourceItemView *KoResourceItemChooser::itemView() const { return d->view; } void KoResourceItemChooser::contextMenuRequested(const QPoint& pos) { d->tagManager->contextMenuRequested(currentResource(), pos); } void KoResourceItemChooser::setViewModeButtonVisible(bool visible) { d->viewModeButton->setVisible(visible); } QToolButton* KoResourceItemChooser::viewModeButton() const { return d->viewModeButton; } void KoResourceItemChooser::setSynced(bool sync) { d->synced = sync; KoResourceItemChooserSync* chooserSync = KoResourceItemChooserSync::instance(); if (sync) { connect(chooserSync, SIGNAL(baseLenghtChanged(int)), SLOT(baseLengthChanged(int))); baseLengthChanged(chooserSync->baseLength()); } else { chooserSync->disconnect(this); } } void KoResourceItemChooser::baseLengthChanged(int length) { if (d->synced) { int resourceCount = d->model->resourcesCount(); int width = d->view->width(); int maxColums = width/length; int cols = width/(2*length) + 1; while(cols <= maxColums) { int size = width/cols; int rows = ceil(resourceCount/(double)cols); if(rows*size < (d->view->height()-5)) { break; } cols++; } setColumnCount(cols); } d->view->updateView(); } bool KoResourceItemChooser::eventFilter(QObject* object, QEvent* event) { if (d->synced && event->type() == QEvent::Wheel) { KoResourceItemChooserSync* chooserSync = KoResourceItemChooserSync::instance(); QWheelEvent* qwheel = dynamic_cast(event); if (qwheel->modifiers() & Qt::ControlModifier) { int degrees = qwheel->delta() / 8; int newBaseLength = chooserSync->baseLength() + degrees/15 * 10; chooserSync->setBaseLength(newBaseLength); return true; } } return QObject::eventFilter(object, event); } void KoResourceItemChooser::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); updateView(); } void KoResourceItemChooser::showEvent(QShowEvent* event) { QWidget::showEvent(event); updateView(); } void KoResourceItemChooser::updateView() { if (d->synced) { KoResourceItemChooserSync* chooserSync = KoResourceItemChooserSync::instance(); baseLengthChanged(chooserSync->baseLength()); } } #include diff --git a/libs/widgets/KoResourceItemChooser.h b/libs/widgets/KoResourceItemChooser.h index c31a09ae96..b79658facb 100644 --- a/libs/widgets/KoResourceItemChooser.h +++ b/libs/widgets/KoResourceItemChooser.h @@ -1,152 +1,149 @@ /* This file is part of the KDE project Copyright (c) 2002 Patrick Julien Copyright (c) 2007 Jan Hambrecht Copyright (c) 2007 Sven Langkamp Copyright (c) 2010 Boudewijn Rempt Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2011 José Luis Vergara Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_RESOURCE_ITEM_CHOOSER #define KO_RESOURCE_ITEM_CHOOSER #include -#include -#include -#include #include "kowidgets_export.h" -#include +class QModelIndex; class QAbstractProxyModel; class QAbstractItemDelegate; class QToolButton; class KoAbstractResourceServerAdapter; class KoResourceItemView; class KoResource; /** * A widget that contains a KoResourceChooser as well * as an import/export button */ class KOWIDGETS_EXPORT KoResourceItemChooser : public QWidget { Q_OBJECT public: enum Buttons { Button_Import, Button_Remove, Button_GhnsDownload, Button_GhnsUpload }; /// \p usePreview shows the aside preview with the resource's image explicit KoResourceItemChooser( QSharedPointer resourceAdapter, QWidget *parent = 0, bool usePreview = false); ~KoResourceItemChooser(); /// Sets number of columns in the view and causes the number of rows to be calculated accordingly void setColumnCount( int columnCount ); /// Sets number of rows in the view and causes the number of columns to be calculated accordingly void setRowCount( int rowCount ); /// Sets the height of the view rows void setRowHeight( int rowHeight ); /// Sets the width of the view columns void setColumnWidth( int columnWidth ); /// Sets a custom delegate for the view void setItemDelegate( QAbstractItemDelegate * delegate ); /// Gets the currently selected resource /// @returns the selected resource, 0 is no resource is selected KoResource *currentResource() const; /// Sets the item representing the resource as selected void setCurrentResource(KoResource* resource); /** * Sets the sected resource, does nothing if there is no valid item * @param row row of the item * @param column column of the item */ void setCurrentItem(int row, int column); void showButtons( bool show ); /// determines whether the preview right or below the splitter void setPreviewOrientation(Qt::Orientation orientation); /// determines whether the preview should tile the resource's image or not void setPreviewTiled(bool tiled); /// shows the preview converted to grayscale void setGrayscalePreview(bool grayscale); void showGetHotNewStuff( bool showDownload, bool showUpload); /// sets the visibilty of tagging KlineEdits. void showTaggingBar( bool showSearchBar, bool showOpBar ); ///Set a proxy model with will be used to filter the resources void setProxyModel( QAbstractProxyModel* proxyModel ); void setKnsrcFile(const QString& knsrcFileArg); QSize viewSize() const; KoResourceItemView *itemView() const; void setViewModeButtonVisible(bool visible); QToolButton *viewModeButton() const; void setSynced(bool sync); virtual bool eventFilter(QObject* object, QEvent* event); Q_SIGNALS: /// Emitted when a resource was selected void resourceSelected( KoResource * resource ); void splitterMoved(); public Q_SLOTS: void slotButtonClicked( int button ); private Q_SLOTS: void activated ( const QModelIndex & index ); void contextMenuRequested(const QPoint &pos); void baseLengthChanged(int length); void slotBeforeResourcesLayoutReset(KoResource *activateAfterReset); void slotAfterResourcesLayoutReset(); void updateView(); protected: virtual void showEvent(QShowEvent* event); private: void updateButtonState(); void updatePreview(KoResource *resource); virtual void resizeEvent(QResizeEvent* event); /// Resource for a given model index /// @returns the resource pointer, 0 is index not valid KoResource* resourceFromModelIndex(const QModelIndex & index ) const; class Private; Private * const d; }; #endif // KO_RESOURCE_ITEM_CHOOSER diff --git a/libs/widgets/KoResourceModel.cpp b/libs/widgets/KoResourceModel.cpp index ea93059dc6..589033e84e 100644 --- a/libs/widgets/KoResourceModel.cpp +++ b/libs/widgets/KoResourceModel.cpp @@ -1,317 +1,318 @@ /* This file is part of the KDE project * Copyright (C) 2008-2009 Jan Hambrecht * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceModel.h" #include +#include #include #include KoResourceModel::KoResourceModel(QSharedPointer resourceAdapter, QObject * parent) : KoResourceModelBase(parent) , m_resourceAdapter(resourceAdapter) , m_columnCount(4) { Q_ASSERT(m_resourceAdapter); m_resourceAdapter->connectToResourceServer(); connect(m_resourceAdapter.data(), SIGNAL(resourceAdded(KoResource*)), this, SLOT(resourceAdded(KoResource*))); connect(m_resourceAdapter.data(), SIGNAL(removingResource(KoResource*)), this, SLOT(resourceRemoved(KoResource*))); connect(m_resourceAdapter.data(), SIGNAL(resourceChanged(KoResource*)), this, SLOT(resourceChanged(KoResource*))); connect(m_resourceAdapter.data(), SIGNAL(tagsWereChanged()), this, SLOT(tagBoxEntryWasModified())); connect(m_resourceAdapter.data(), SIGNAL(tagCategoryWasAdded(QString)), this, SLOT(tagBoxEntryWasAdded(QString))); connect(m_resourceAdapter.data(), SIGNAL(tagCategoryWasRemoved(QString)), this, SLOT(tagBoxEntryWasRemoved(QString))); } KoResourceModel::~KoResourceModel() { if (!m_currentTag.isEmpty()) { KConfigGroup group = KGlobal::config()->group("SelectedTags"); group.writeEntry(serverType(), m_currentTag); } } int KoResourceModel::rowCount( const QModelIndex &/*parent*/ ) const { int resourceCount = m_resourceAdapter->resources().count(); if (!resourceCount) return 0; return static_cast(ceil(static_cast(resourceCount) / m_columnCount)); } int KoResourceModel::columnCount ( const QModelIndex & ) const { return m_columnCount; } QVariant KoResourceModel::data( const QModelIndex &index, int role ) const { if( ! index.isValid() ) return QVariant(); switch( role ) { case Qt::DisplayRole: { KoResource * resource = static_cast(index.internalPointer()); if( ! resource ) return QVariant(); QString resName = i18n( resource->name().toUtf8().data()); if (m_resourceAdapter->assignedTagsList(resource).count()) { QString taglist = m_resourceAdapter->assignedTagsList(resource).join("] , ["); QString tagListToolTip = QString(" - %1: [%2]").arg(i18n("Tags"), taglist); return QVariant( resName + tagListToolTip ); } return QVariant( resName ); } case Qt::DecorationRole: { KoResource * resource = static_cast(index.internalPointer()); if( ! resource ) return QVariant(); return QVariant( resource->image() ); } case KoResourceModel::LargeThumbnailRole: { KoResource * resource = static_cast(index.internalPointer()); if( ! resource ) return QVariant(); QSize imageSize = resource->image().size(); QSize thumbSize( 100, 100 ); if(imageSize.height() > thumbSize.height() || imageSize.width() > thumbSize.width()) { qreal scaleW = static_cast( thumbSize.width() ) / static_cast( imageSize.width() ); qreal scaleH = static_cast( thumbSize.height() ) / static_cast( imageSize.height() ); qreal scale = qMin( scaleW, scaleH ); int thumbW = static_cast( imageSize.width() * scale ); int thumbH = static_cast( imageSize.height() * scale ); return QVariant(resource->image().scaled( thumbW, thumbH, Qt::IgnoreAspectRatio )); } else return QVariant(resource->image()); } default: return QVariant(); } } QModelIndex KoResourceModel::index ( int row, int column, const QModelIndex & ) const { int index = row * m_columnCount + column; const QList resources = m_resourceAdapter->resources(); if( index >= resources.count() || index < 0) return QModelIndex(); return createIndex( row, column, resources[index] ); } void KoResourceModel::doSafeLayoutReset(KoResource *activateAfterReformat) { emit beforeResourcesLayoutReset(activateAfterReformat); reset(); emit afterResourcesLayoutReset(); } void KoResourceModel::setColumnCount( int columnCount ) { if (columnCount != m_columnCount) { emit beforeResourcesLayoutReset(0); m_columnCount = columnCount; reset(); emit afterResourcesLayoutReset(); } } void KoResourceModel::resourceAdded(KoResource *resource) { int newIndex = m_resourceAdapter->resources().indexOf(resource); if (newIndex >= 0) { doSafeLayoutReset(0); } } void KoResourceModel::resourceRemoved(KoResource *resource) { Q_UNUSED(resource); KoResource *first = !m_resourceAdapter->resources().isEmpty() ? m_resourceAdapter->resources().first() : 0; doSafeLayoutReset(first); } void KoResourceModel::resourceChanged(KoResource* resource) { int resourceIndex = m_resourceAdapter->resources().indexOf(resource); int row = resourceIndex / columnCount(); int column = resourceIndex % columnCount(); QModelIndex modelIndex = index(row, column); if (!modelIndex.isValid()) { return; } emit dataChanged(modelIndex, modelIndex); } void KoResourceModel::tagBoxEntryWasModified() { m_resourceAdapter->updateServer(); emit tagBoxEntryModified(); } void KoResourceModel::tagBoxEntryWasAdded(const QString& tag) { emit tagBoxEntryAdded(tag); } void KoResourceModel::tagBoxEntryWasRemoved(const QString& tag) { emit tagBoxEntryRemoved(tag); } QModelIndex KoResourceModel::indexFromResource(KoResource* resource) const { int resourceIndex = m_resourceAdapter->resources().indexOf(resource); int row = resourceIndex / columnCount(); int column = resourceIndex % columnCount(); return index(row, column); } QString KoResourceModel::extensions() const { return m_resourceAdapter->extensions(); } void KoResourceModel::importResourceFile(const QString &filename) { m_resourceAdapter->importResourceFile(filename); } void KoResourceModel::importResourceFile(const QString & filename, bool fileCreation) { m_resourceAdapter->importResourceFile(filename, fileCreation); } bool KoResourceModel::removeResource(KoResource* resource) { return m_resourceAdapter->removeResource(resource); } void KoResourceModel::removeResourceFile(const QString &filename) { m_resourceAdapter->removeResourceFile(filename); } QStringList KoResourceModel::assignedTagsList(KoResource *resource) const { return m_resourceAdapter->assignedTagsList(resource); } void KoResourceModel::addTag(KoResource* resource, const QString& tag) { m_resourceAdapter->addTag(resource, tag); emit tagBoxEntryAdded(tag); } void KoResourceModel::deleteTag(KoResource *resource, const QString &tag) { m_resourceAdapter->deleteTag(resource, tag); } QStringList KoResourceModel::tagNamesList() const { return m_resourceAdapter->tagNamesList(); } QStringList KoResourceModel::searchTag(const QString& lineEditText) { return m_resourceAdapter->searchTag(lineEditText); } void KoResourceModel::searchTextChanged(const QString& searchString) { m_resourceAdapter->searchTextChanged(searchString); } void KoResourceModel::enableResourceFiltering(bool enable) { m_resourceAdapter->enableResourceFiltering(enable); } void KoResourceModel::setCurrentTag(const QString& currentTag) { m_currentTag = currentTag; m_resourceAdapter->setCurrentTag(currentTag); } void KoResourceModel::updateServer() { m_resourceAdapter->updateServer(); } int KoResourceModel::resourcesCount() const { return m_resourceAdapter->resources().count(); } QList KoResourceModel::currentlyVisibleResources() const { return m_resourceAdapter->resources(); } void KoResourceModel::tagCategoryMembersChanged() { m_resourceAdapter->tagCategoryMembersChanged(); } void KoResourceModel::tagCategoryAdded(const QString& tag) { m_resourceAdapter->tagCategoryAdded(tag); } void KoResourceModel::tagCategoryRemoved(const QString& tag) { m_resourceAdapter->tagCategoryRemoved(tag); } QString KoResourceModel::serverType() const { return m_resourceAdapter->serverType(); } QList< KoResource* > KoResourceModel::serverResources() const { return m_resourceAdapter->serverResources(); } #include diff --git a/libs/widgets/KoResourcePopupAction.cpp b/libs/widgets/KoResourcePopupAction.cpp index df8b78930b..b8c00fed82 100644 --- a/libs/widgets/KoResourcePopupAction.cpp +++ b/libs/widgets/KoResourcePopupAction.cpp @@ -1,190 +1,191 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2012 Jean-Nicolas Artaud * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourcePopupAction.h" -#include "KoResourceServerProvider.h" #include "KoResourceServerAdapter.h" #include "KoResourceItemView.h" #include "KoResourceModel.h" #include "KoResourceItemDelegate.h" #include "KoResource.h" #include "KoCheckerBoardPainter.h" #include "KoShapeBackground.h" +#include +#include #include #include #include #include #include #include #include #include #include #include class KoResourcePopupAction::Private { public: Private() : resourceList(0), background(0), checkerPainter(4) {} QMenu *menu; KoResourceItemView *resourceList; QSharedPointer background; KoCheckerBoardPainter checkerPainter; }; KoResourcePopupAction::KoResourcePopupAction(QSharedPointerresourceAdapter, QObject *parent) : KAction(parent) , d(new Private()) { Q_ASSERT(resourceAdapter); d->menu = new QMenu(); QWidget *widget = new QWidget(d->menu); QWidgetAction *wdgAction = new QWidgetAction(widget); d->resourceList = new KoResourceItemView(widget); d->resourceList->setModel(new KoResourceModel(resourceAdapter, widget)); d->resourceList->setItemDelegate(new KoResourceItemDelegate(widget)); KoResourceModel * resourceModel = qobject_cast(d->resourceList->model()); if (resourceModel) { resourceModel->setColumnCount(1); } KoResource *resource = 0; if (resourceAdapter->resources().count() > 0) { resource = resourceAdapter->resources().at(0); } KoAbstractGradient *gradient = dynamic_cast(resource); KoPattern *pattern = dynamic_cast(resource); if (gradient) { QGradient *qg = gradient->toQGradient(); qg->setCoordinateMode(QGradient::ObjectBoundingMode); d->background = QSharedPointer(new KoGradientBackground(qg)); } else if (pattern) { KoImageCollection *collection = new KoImageCollection(); d->background = QSharedPointer(new KoPatternBackground(collection)); static_cast(d->background.data())->setPattern(pattern->pattern()); } QHBoxLayout *layout = new QHBoxLayout(widget); layout->addWidget(d->resourceList); widget->setLayout(layout); wdgAction->setDefaultWidget(widget); d->menu->addAction(wdgAction); setMenu(d->menu); new QHBoxLayout(d->menu); d->menu->layout()->addWidget(widget); d->menu->layout()->setMargin(0); connect(d->resourceList, SIGNAL(clicked(QModelIndex)), this, SLOT(indexChanged(QModelIndex))); updateIcon(); } KoResourcePopupAction::~KoResourcePopupAction() { delete d; } QSharedPointer KoResourcePopupAction::currentBackground() const { return d->background; } void KoResourcePopupAction::setCurrentBackground(QSharedPointer background) { d->background = background; updateIcon(); } void KoResourcePopupAction::indexChanged(const QModelIndex &modelIndex) { if (! modelIndex.isValid()) { return; } d->menu->hide(); KoResource *resource = static_cast(modelIndex.internalPointer()); if(resource) { KoAbstractGradient *gradient = dynamic_cast(resource); KoPattern *pattern = dynamic_cast(resource); if (gradient) { QGradient *qg = gradient->toQGradient(); qg->setCoordinateMode(QGradient::ObjectBoundingMode); d->background = QSharedPointer(new KoGradientBackground(qg)); } else if (pattern) { KoImageCollection *collection = new KoImageCollection(); d->background = QSharedPointer(new KoPatternBackground(collection)); qSharedPointerDynamicCast(d->background)->setPattern(pattern->pattern()); } emit resourceSelected(d->background); updateIcon(); } } void KoResourcePopupAction::updateIcon() { QSize iconSize; QToolButton *toolButton = dynamic_cast(parentWidget()); if (toolButton) { iconSize = QSize(toolButton->iconSize()); } else { iconSize = QSize(16, 16); } // This must be a QImage, as drawing to a QPixmap outside the // UI thread will cause sporadic crashes. QImage pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied); pm.fill(Qt::transparent); QPainter p(&pm); QSharedPointer gradientBackground = qSharedPointerDynamicCast(d->background); QSharedPointer patternBackground = qSharedPointerDynamicCast(d->background); if (gradientBackground) { QRect innerRect(0, 0, iconSize.width(), iconSize.height()); QLinearGradient paintGradient; paintGradient.setStops(gradientBackground->gradient()->stops()); paintGradient.setStart(innerRect.topLeft()); paintGradient.setFinalStop(innerRect.topRight()); d->checkerPainter.paint(p, innerRect); p.fillRect(innerRect, QBrush(paintGradient)); } else if (patternBackground) { d->checkerPainter.paint(p, QRect(QPoint(),iconSize)); p.fillRect(0, 0, iconSize.width(), iconSize.height(), patternBackground->pattern()); } p.end(); setIcon(QIcon(QPixmap::fromImage(pm))); } #include diff --git a/libs/widgets/KoResourceServer.h b/libs/widgets/KoResourceServer.h index 1ca9e3af97..fa4e0f33b8 100644 --- a/libs/widgets/KoResourceServer.h +++ b/libs/widgets/KoResourceServer.h @@ -1,707 +1,704 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp Copyright (c) 2007 Jan Hambrecht Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KORESOURCESERVER_H #define KORESOURCESERVER_H #include -#include #include #include #include #include #include -#include #include #include #include -#include #include #include #include "KoResource.h" #include "KoResourceServerPolicies.h" #include "KoResourceServerObserver.h" #include "KoResourceTagStore.h" #include "kowidgets_export.h" #include class KoResource; /** * KoResourceServerBase is the base class of all resource servers */ class KOWIDGETS_EXPORT KoResourceServerBase { public: /** * Constructs a KoResourceServerBase * @param resource type, has to be the same as used by KStandardDirs * @param extensions the file extensions separate by ':', e.g. "*.kgr:*.svg:*.ggr" */ KoResourceServerBase(const QString& type, const QString& extensions) : m_type(type) , m_extensions(extensions) { } virtual ~KoResourceServerBase() {} virtual int resourceCount() const = 0; virtual void loadResources(QStringList filenames) = 0; virtual QStringList blackListedFiles() const = 0; virtual QStringList queryResources(const QString &query) const = 0; QString type() const { return m_type; } /** * File extensions for resources of the server * @returns the file extensions separated by ':', e.g. "*.kgr:*.svg:*.ggr" */ QString extensions() const { return m_extensions; } QStringList fileNames() const { QStringList extensionList = m_extensions.split(':'); QStringList fileNames; foreach (const QString &extension, extensionList) { fileNames += KGlobal::mainComponent().dirs()->findAllResources(type().toLatin1(), extension, KStandardDirs::Recursive | KStandardDirs::NoDuplicates); } return fileNames; } protected: friend class KoResourceTagStore; virtual KoResource *byMd5(const QByteArray &md5) const = 0; virtual KoResource *byFileName(const QString &fileName) const = 0; private: QString m_type; QString m_extensions; protected: QMutex m_loadLock; }; /** * KoResourceServer manages the resources of one type. It stores, * loads and saves the resources. To keep track of changes the server * can be observed with a KoResourceServerObserver * * The \p Policy template parameter defines the way how the lifetime * of a resource is handled. There are to predefined policies: * * o PointerStroragePolicy --- usual pointers with ownership over * the resource. * o SharedPointerStroragePolicy --- shared pointers. The server does no * extra handling for the lifetime of * the resource. * * Use the former for usual resources and the latter for shared pointer based * ones. */ template > class KoResourceServer : public KoResourceServerBase { public: typedef typename Policy::PointerType PointerType; typedef KoResourceServerObserver ObserverType; KoResourceServer(const QString& type, const QString& extensions) : KoResourceServerBase(type, extensions) { m_blackListFile = KStandardDirs::locateLocal("data", "krita/" + type + ".blacklist"); m_blackListFileNames = readBlackListFile(); m_tagStore = new KoResourceTagStore(this); } virtual ~KoResourceServer() { if (m_tagStore) { delete m_tagStore; } foreach(ObserverType* observer, m_observers) { observer->unsetResourceServer(); } foreach(PointerType res, m_resources) { Policy::deleteResource(res); } m_resources.clear(); } int resourceCount() const { return m_resources.size(); } /** * Loads a set of resources and adds them to the resource server. * If a filename appears twice the resource will only be added once. Resources that can't * be loaded or and invalid aren't added to the server. * @param filenames list of filenames to be loaded */ void loadResources(QStringList filenames) { QStringList uniqueFiles; while (!filenames.empty()) { QString front = filenames.first(); filenames.pop_front(); QString fname = QFileInfo(front).fileName(); // XXX: Don't load resources with the same filename. Actually, we should look inside // the resource to find out whether they are really the same, but for now this // will prevent the same brush etc. showing up twice. if (uniqueFiles.empty() || uniqueFiles.indexOf(fname) == -1) { m_loadLock.lock(); uniqueFiles.append(fname); QList resources = createResources(front); foreach(PointerType resource, resources) { Q_CHECK_PTR(resource); if (resource->load() && resource->valid() && !resource->md5().isEmpty()) { QByteArray md5 = resource->md5(); m_resourcesByMd5[md5] = resource; m_resourcesByFilename[resource->shortFilename()] = resource; if ( resource->name().isEmpty() ) { resource->setName( fname ); } if (m_resourcesByName.contains(resource->name())) { resource->setName(resource->name() + "(" + resource->shortFilename() + ")"); } m_resourcesByName[resource->name()] = resource; notifyResourceAdded(resource); } else { kWarning() << "Loading resource " << front << "failed"; Policy::deleteResource(resource); } } m_loadLock.unlock(); } } m_resources = sortedResources(); m_tagStore->loadTags(); foreach(ObserverType* observer, m_observers) { observer->syncTaggedResourceView(); } kDebug(30009) << "done loading resources for type " << type(); } /// Adds an already loaded resource to the server bool addResource(PointerType resource, bool save = true, bool infront = false) { if (!resource->valid()) { kWarning(30009) << "Tried to add an invalid resource!"; return false; } if (save) { QFileInfo fileInfo(resource->filename()); if (fileInfo.exists()) { QString filename = fileInfo.path() + "/" + fileInfo.baseName() + "XXXXXX" + "." + fileInfo.suffix(); kDebug() << "fileName is " << filename; QTemporaryFile file(filename); if (file.open()) { kDebug() << "now " << file.fileName(); resource->setFilename(file.fileName()); } } if (!resource->save()) { kWarning(30009) << "Could not save resource!"; return false; } } Q_ASSERT(!resource->filename().isEmpty() || !resource->name().isEmpty()); if (resource->filename().isEmpty()) { resource->setFilename(resource->name()); } else if (resource->name().isEmpty()) { resource->setName(resource->filename()); } m_resourcesByFilename[resource->shortFilename()] = resource; m_resourcesByMd5[resource->md5()] = resource; m_resourcesByName[resource->name()] = resource; if (infront) { m_resources.insert(0, resource); } else { m_resources.append(resource); } notifyResourceAdded(resource); return true; } /*Removes a given resource from the blacklist. */ bool removeFromBlacklist(PointerType resource) { if (m_blackListFileNames.contains(resource->filename())) { m_blackListFileNames.removeAll(resource->filename()); writeBlackListFile(); } else{ kWarning(30009)<<"Doesn't contain filename"; return false; } //then return true// return true; } /// Remove a resource from Resource Server but not from a file bool removeResourceFromServer(PointerType resource){ if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } m_resourcesByMd5.remove(resource->md5()); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); Policy::deleteResource(resource); return true; } /// Remove a resource from the resourceserver and blacklist it bool removeResourceAndBlacklist(PointerType resource) { if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } m_resourcesByMd5.remove(resource->md5()); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); m_blackListFileNames.append(resource->filename()); writeBlackListFile(); Policy::deleteResource(resource); return true; } QList resources() { m_loadLock.lock(); QList resourceList = m_resources; foreach(PointerType r, m_resourceBlackList) { resourceList.removeOne(r); } m_loadLock.unlock(); return resourceList; } /// Returns path where to save user defined and imported resources to virtual QString saveLocation() { return KGlobal::mainComponent().dirs()->saveLocation(type().toLatin1()); } /** * Creates a new resource from a given file and adds them to the resource server * The base implementation does only load one resource per file, override to implement collections * @param filename file name of the resource file to be imported * @param fileCreation decides whether to create the file in the saveLocation() directory */ virtual bool importResourceFile(const QString & filename , bool fileCreation=true) { QFileInfo fi(filename); if (!fi.exists()) return false; if ( fi.size() == 0) return false; PointerType resource = createResource( filename ); resource->load(); if (!resource->valid()) { kWarning(30009) << "Import failed! Resource is not valid"; Policy::deleteResource(resource); return false; } if (fileCreation) { Q_ASSERT(!resource->defaultFileExtension().isEmpty()); Q_ASSERT(!saveLocation().isEmpty()); QString newFilename = saveLocation() + fi.baseName() + resource->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation() + fi.baseName() + QString("%1").arg(i) + resource->defaultFileExtension()); i++; } resource->setFilename(fileInfo.filePath()); } if(!addResource(resource)) { Policy::deleteResource(resource); } return true; } /// Removes the resource file from the resource server virtual void removeResourceFile(const QString & filename) { QFileInfo fi(filename); PointerType resource = resourceByFilename(fi.fileName()); if (!resource) { kWarning(30009) << "Resource file do not exist "; return; } if (!removeResourceFromServer(resource)) return; } /** * Addes an observer to the server * @param observer the observer to be added * @param notifyLoadedResources determines if the observer should be notified about the already loaded resources */ void addObserver(ObserverType* observer, bool notifyLoadedResources = true) { m_loadLock.lock(); if(observer && !m_observers.contains(observer)) { m_observers.append(observer); if(notifyLoadedResources) { foreach(PointerType resource, m_resourcesByFilename) { observer->resourceAdded(resource); } } } m_loadLock.unlock(); } /** * Removes an observer from the server * @param observer the observer to be removed */ void removeObserver(ObserverType* observer) { int index = m_observers.indexOf( observer ); if( index < 0 ) return; m_observers.removeAt( index ); } PointerType resourceByFilename(const QString& filename) const { if (m_resourcesByFilename.contains(filename)) { return m_resourcesByFilename[filename]; } return 0; } PointerType resourceByName( const QString& name ) const { if (m_resourcesByName.contains(name)) { return m_resourcesByName[name]; } return 0; } PointerType resourceByMD5(const QByteArray& md5) const { return m_resourcesByMd5.value(md5); } /** * Call after changing the content of a resource; * Notifies the connected views. */ void updateResource( PointerType resource ) { notifyResourceChanged(resource); } QStringList blackListedFiles() const { return m_blackListFileNames; } void removeBlackListedFiles() { QStringList remainingFiles; // Files that can't be removed e.g. no rights will stay blacklisted foreach(const QString &filename, m_blackListFileNames) { QFile file( filename ); if( ! file.remove() ) { remainingFiles.append(filename); } } m_blackListFileNames = remainingFiles; writeBlackListFile(); } QStringList tagNamesList() const { return m_tagStore->tagNamesList(); } // don't use these method directly since it doesn't update views! void addTag( KoResource* resource,const QString& tag) { m_tagStore->addTag(resource,tag); } // don't use these method directly since it doesn't update views! void delTag( KoResource* resource,const QString& tag) { m_tagStore->delTag(resource,tag); } QStringList searchTag(const QString& lineEditText) { return m_tagStore->searchTag(lineEditText); } void tagCategoryAdded(const QString& tag) { m_tagStore->serializeTags(); foreach(ObserverType* observer, m_observers) { observer->syncTagAddition(tag); } } void tagCategoryRemoved(const QString& tag) { m_tagStore->delTag(tag); m_tagStore->serializeTags(); foreach(ObserverType* observer, m_observers) { observer->syncTagRemoval(tag); } } void tagCategoryMembersChanged() { m_tagStore->serializeTags(); foreach(ObserverType* observer, m_observers) { observer->syncTaggedResourceView(); } } QStringList queryResources(const QString &query) const { return m_tagStore->searchTag(query); } QStringList assignedTagsList(KoResource* resource) const { return m_tagStore->assignedTagsList(resource); } /** * Create one or more resources from a single file. By default one resource is created. * Overide to create more resources from the file. * @param filename the filename of the resource or resource collection */ virtual QList createResources( const QString & filename ) { QList createdResources; createdResources.append(createResource(filename)); return createdResources; } virtual PointerType createResource( const QString & filename ) = 0; /// Return the currently stored resources in alphabetical order, overwrite for customized sorting virtual QList sortedResources() { QMap sortedNames; foreach(const QString &name, m_resourcesByName.keys()) { sortedNames.insert(name.toLower(), m_resourcesByName[name]); } return sortedNames.values(); } protected: void notifyResourceAdded(PointerType resource) { foreach(ObserverType* observer, m_observers) { observer->resourceAdded(resource); } } void notifyRemovingResource(PointerType resource) { foreach(ObserverType* observer, m_observers) { observer->removingResource(resource); } } void notifyResourceChanged(PointerType resource) { foreach(ObserverType* observer, m_observers) { observer->resourceChanged(resource); } } /// Reads the xml file and returns the filenames as a list QStringList readBlackListFile() { QStringList filenameList; QFile f(m_blackListFile); if (!f.open(QIODevice::ReadOnly)) { return filenameList; } QDomDocument doc; if (!doc.setContent(&f)) { kWarning() << "The file could not be parsed."; return filenameList; } QDomElement root = doc.documentElement(); if (root.tagName() != "resourceFilesList") { kWarning() << "The file doesn't seem to be of interest."; return filenameList; } QDomElement file = root.firstChildElement("file"); while (!file.isNull()) { QDomNode n = file.firstChild(); QDomElement e = n.toElement(); if (e.tagName() == "name") { filenameList.append((e.text()).replace(QString("~"),QDir::homePath())); } file = file.nextSiblingElement("file"); } return filenameList; } /// write the blacklist file entries to an xml file void writeBlackListFile() { QFile f(m_blackListFile); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { kWarning() << "Cannot write meta information to '" << m_blackListFile << "'." << endl; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("m_blackListFile"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("resourceFilesList"); doc.appendChild(root); foreach(QString filename, m_blackListFileNames) { QDomElement fileEl = doc.createElement("file"); QDomElement nameEl = doc.createElement("name"); QDomText nameText = doc.createTextNode(filename.replace(QDir::homePath(),QString("~"))); nameEl.appendChild(nameText); fileEl.appendChild(nameEl); root.appendChild(fileEl); } QTextStream metastream(&f); metastream << doc.toByteArray(); f.close(); } protected: KoResource* byMd5(const QByteArray &md5) const { return Policy::toResourcePointer(resourceByMD5(md5)); } KoResource* byFileName(const QString &fileName) const { return Policy::toResourcePointer(resourceByFilename(fileName)); } private: QHash m_resourcesByName; QHash m_resourcesByFilename; QHash m_resourcesByMd5; QList m_resourceBlackList; QList m_resources; ///< list of resources in order of addition QList m_observers; QString m_blackListFile; QStringList m_blackListFileNames; KoResourceTagStore* m_tagStore; }; template > class KoResourceServerSimpleConstruction : public KoResourceServer { public: KoResourceServerSimpleConstruction(const QString& type, const QString& extensions) : KoResourceServer(type, extensions) { } typename KoResourceServer::PointerType createResource( const QString & filename ) { return new T(filename); } }; #endif // KORESOURCESERVER_H diff --git a/libs/widgets/KoResourceTagStore.cpp b/libs/widgets/KoResourceTagStore.cpp index 76eabae726..2e1888b9c5 100644 --- a/libs/widgets/KoResourceTagStore.cpp +++ b/libs/widgets/KoResourceTagStore.cpp @@ -1,374 +1,376 @@ /* This file is part of the KDE project Copyright (c) 2011 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "KoResourceTagStore.h" #include #include #include #include #include #include +#include + class KoResourceTagStore::Private { public: QMultiHash md5ToTag; QMultiHash identifierToTag; QHash tagList; KoResourceServerBase *resourceServer; }; KoResourceTagStore::KoResourceTagStore(KoResourceServerBase *resourceServer) : d(new Private) { d->resourceServer = resourceServer; } KoResourceTagStore::~KoResourceTagStore() { serializeTags(); delete d; } QStringList KoResourceTagStore::assignedTagsList(const KoResource* resource) const { if (!resource) return QStringList(); QStringList tags = d->md5ToTag.values(resource->md5()); tags += d->identifierToTag.values(resource->filename()); tags.removeDuplicates(); return tags; } void KoResourceTagStore::removeResource(const KoResource *resource) { QStringList tags = assignedTagsList(resource); d->md5ToTag.remove(resource->md5()); d->identifierToTag.remove(resource->filename()); foreach(const QString &tag, tags) { if (d->tagList.contains(tag)) { if (d->tagList[tag] > 0) { d->tagList[tag]--; } } } } QStringList KoResourceTagStore::tagNamesList() const { return d->tagList.uniqueKeys(); } void KoResourceTagStore::addTag(KoResource* resource, const QString& tag) { if (!resource) { d->tagList.insert(tag, 0); return; } bool added = false; if (!d->md5ToTag.contains(resource->md5(), tag)) { added = true; d->md5ToTag.insert(resource->md5(), tag); } if (!d->identifierToTag.contains(resource->filename())) { added = true; d->identifierToTag.insert(resource->filename(), tag); } if (added) { if (d->tagList.contains(tag)) { d->tagList[tag]++; } else { d->tagList.insert(tag, 1); } } } void KoResourceTagStore::delTag(KoResource* resource, const QString& tag) { int res = d->md5ToTag.remove(resource->md5(), tag); res += d->identifierToTag.remove(resource->filename(), tag); if (res > 0) { // decrease the usecount for this tag if (d->tagList.contains(tag)) { if (d->tagList[tag] > 0) { d->tagList[tag]--; } } } } void KoResourceTagStore::delTag(const QString& tag) { Q_ASSERT(!d->md5ToTag.values().contains(tag)); Q_ASSERT(!d->identifierToTag.values().contains(tag)); d->tagList.remove(tag); } QStringList KoResourceTagStore::searchTag(const QString& query) const { QStringList tagsList = query.split(QRegExp("[,]\\s*"), QString::SkipEmptyParts); if (tagsList.isEmpty()) { return QStringList(); } QSet resources; foreach (QString tag, tagsList) { foreach(const QByteArray &md5, d->md5ToTag.keys(tag)) { KoResource *res = d->resourceServer->byMd5(md5); if (res) resources << res; } foreach(const QString &identifier, d->identifierToTag.keys(tag)) { KoResource *res = d->resourceServer->byFileName(identifier); if (res) resources << res; } } QStringList filenames; foreach (const KoResource *res, resources) { if (res) { filenames << adjustedFileName(res->shortFilename()); } } return removeAdjustedFileNames(filenames); } void KoResourceTagStore::loadTags() { QStringList tagFiles = KGlobal::dirs()->findAllResources("data", "krita/tags/" + d->resourceServer->type() + "_tags.xml"); foreach(const QString &tagFile, tagFiles) { readXMLFile(tagFile); } } void KoResourceTagStore::writeXMLFile(const QString &tagstore) { QFile f(tagstore); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { kWarning() << "Cannot write meta information to '" << tagstore << "'."; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("tags"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("tags"); doc.appendChild(root); QSet taggedResources; foreach (const QByteArray &md5, d->md5ToTag.keys()) { KoResource *res = d->resourceServer->byMd5(md5); if (res) { taggedResources << res; } } foreach (const QString &identifier, d->identifierToTag.keys()) { KoResource *res = d->resourceServer->byFileName(identifier); if (res) { taggedResources << res; } } foreach (const KoResource *res, taggedResources) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", res->filename().replace(QDir::homePath(), QString("~"))); resourceEl.setAttribute("md5", QString(res->md5().toBase64())); foreach (const QString &tag, assignedTagsList(res)) { QDomElement tagEl = doc.createElement("tag"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); } root.appendChild(resourceEl); } // Now write empty tags foreach (const QString &tag, d->tagList.uniqueKeys()) { if (d->tagList[tag] == 0) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", "dummy"); QDomElement tagEl = doc.createElement("tag"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); root.appendChild(resourceEl); } } QTextStream metastream(&f); metastream << doc.toString(); f.close(); } void KoResourceTagStore::readXMLFile(const QString &tagstore) { QString inputFile; if (QFile::exists(tagstore)) { inputFile = tagstore; } else { inputFile = KStandardDirs::locateLocal("data", "krita/tags.xml"); } QFile f(inputFile); if (!f.open(QIODevice::ReadOnly)) { return; } QDomDocument doc; if (!doc.setContent(&f)) { kWarning() << "The file could not be parsed."; return; } QDomElement root = doc.documentElement(); if (root.tagName() != "tags") { kWarning() << "The file doesn't seem to be of interest."; return; } QDomNodeList resourceNodesList = root.childNodes(); for (int i = 0; i < resourceNodesList.count(); i++) { QByteArray resourceMD5; QString identifier; QDomElement element = resourceNodesList.at(i).toElement(); if (element.tagName() == "resource") { KoResource *resByMd5 = 0; KoResource *resByFileName = 0; if (element.hasAttribute("md5")) { resourceMD5 = QByteArray::fromBase64(element.attribute("md5").toLatin1()); resByMd5 = d->resourceServer->byMd5(resourceMD5); } if (element.hasAttribute("identifier")) { identifier = element.attribute("identifier"); QFileInfo fi(identifier); resByFileName = d->resourceServer->byFileName(fi.fileName()); } if (identifier == "dummy" || isServerResource(identifier)) { QDomNodeList tagNodesList = resourceNodesList.at(i).childNodes(); for (int j = 0; j < tagNodesList.count() ; j++) { QDomElement tagEl = tagNodesList.at(j).toElement(); if (identifier != "dummy") { QFileInfo fi(identifier); KoResource *res = d->resourceServer->byFileName(fi.fileName()); addTag(res, tagEl.text()); } else { addTag(0, tagEl.text()); } d->md5ToTag.insert(resourceMD5, tagEl.text()); d->identifierToTag.insert(identifier, tagEl.text()); } } else { KoResource *res = 0; if (resByMd5 && resByFileName && (resByMd5 != resByFileName)) { kWarning() << "MD5sum and filename point to different resources -- was the resource renamed? We go with md5"; res = resByMd5; } else if (!resByMd5 && resByFileName) { // We didn't find the resource by md5, but did find it by filename, so take that one res = resByFileName; } else { res = resByMd5; } QDomNodeList tagNodesList = resourceNodesList.at(i).childNodes(); for (int j = 0; j < tagNodesList.count() ; j++) { QDomElement tagEl = tagNodesList.at(j).toElement(); if (res) { addTag(res, tagEl.text()); } d->md5ToTag.insert(resourceMD5, tagEl.text()); d->identifierToTag.insert(identifier, tagEl.text()); } } } } } bool KoResourceTagStore::isServerResource(const QString &resourceName) const { bool removeChild = false; QStringList extensionsList = d->resourceServer->extensions().split(':'); foreach (QString extension, extensionsList) { if (resourceName.contains(extension.remove('*'))) { removeChild = true; break; } } return removeChild; } QString KoResourceTagStore::adjustedFileName(const QString &fileName) const { if (!isServerResource(fileName)) { return fileName + "-krita" + d->resourceServer->extensions().split(':').takeFirst().remove('*'); } return fileName; } QStringList KoResourceTagStore::removeAdjustedFileNames(QStringList fileNamesList) const { foreach (const QString & fileName, fileNamesList) { if (fileName.contains("-krita")) { fileNamesList.append(fileName.split("-krita").takeFirst()); fileNamesList.removeAll(fileName); } } return fileNamesList; } void KoResourceTagStore::serializeTags() { writeXMLFile(KStandardDirs::locateLocal("data", "krita/tags/" + d->resourceServer->type() + "_tags.xml")); } diff --git a/libs/widgets/KoResourceTagStore.h b/libs/widgets/KoResourceTagStore.h index f61fa265a8..84b5574a8b 100644 --- a/libs/widgets/KoResourceTagStore.h +++ b/libs/widgets/KoResourceTagStore.h @@ -1,91 +1,90 @@ /* This file is part of the KDE project Copyright (c) 2011 Sven Langkamp Copyright (c) 2011 Srikanth Tiyyagura This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KORESOURCETAGSTORE_H #define KORESOURCETAGSTORE_H #include -#include -#include #include "kowidgets_export.h" -#include -#include class KoResourceServerBase; +class KoResource; +class QStringList; +class QString; /** * KoResourceTagging allows to add and delete tags to resources and also search reources using tags */ class KOWIDGETS_EXPORT KoResourceTagStore { public: /** * Constructs a KoResourceTagging object * */ explicit KoResourceTagStore(KoResourceServerBase *resourceServer); ~KoResourceTagStore(); QStringList assignedTagsList(const KoResource *resource) const; /// remote the given resource from the tagstore void removeResource(const KoResource *resource); /// Add the given tag to the tag store. The resource can be empty, in which case /// the tag is added but unused void addTag(KoResource* resource, const QString& tag); /// Remove the given tag for the given resource. void delTag(KoResource* resource, const QString& tag); void delTag(const QString& tag); /// @return a list of all the tags in this store QStringList tagNamesList() const; /// Return a list of filenames for the given tag QStringList searchTag(const QString& query) const; void loadTags(); void serializeTags(); private: friend class KoResourceTaggingTest; void readXMLFile(const QString &tagstore); void writeXMLFile(const QString &tagstore); /// To check whether the resource belongs to the present server or not bool isServerResource(const QString &resourceName) const; /// If resource filenames have no extensions, then we add "-krita.extension". QString adjustedFileName(const QString &fileName) const; /// Removes the adjustements before going to the server QStringList removeAdjustedFileNames(QStringList fileNamesList) const; class Private; Private * const d; }; #endif // KORESOURCETAGSTORE_H diff --git a/libs/widgets/KoResourceTaggingManager.cpp b/libs/widgets/KoResourceTaggingManager.cpp index 009ba1151b..1e5a56f635 100644 --- a/libs/widgets/KoResourceTaggingManager.cpp +++ b/libs/widgets/KoResourceTaggingManager.cpp @@ -1,384 +1,386 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceTaggingManager.h" #include #include #include #include #include #include +#include "KoTagFilterWidget.h" +#include "KoTagChooserWidget.h" #include "KoResourceModel.h" #include "KoResource.h" #include "KoResourceItemChooserContextMenu.h" #include class TaggedResourceSet { public: TaggedResourceSet() {} TaggedResourceSet(const QString& tagName, const QList& resources) : tagName(tagName) , resources(resources) {} QString tagName; QList resources; }; class KoResourceTaggingManager::Private { public: QString currentTag; QList originalResources; TaggedResourceSet lastDeletedTag; KoTagChooserWidget* tagChooser; KoTagFilterWidget* tagFilter; QCompleter* tagCompleter; QPointer model; }; void KoResourceTaggingManager::showTaggingBar(bool showSearchBar, bool showOpBar) { showSearchBar ? d->tagFilter->show() : d->tagFilter->hide(); showOpBar ? d->tagChooser->show() : d->tagChooser->hide(); } void KoResourceTaggingManager::purgeTagUndeleteList() { d->lastDeletedTag = TaggedResourceSet(); d->tagChooser->setUndeletionCandidate(QString()); } void KoResourceTaggingManager::undeleteTag(const QString & tagToUndelete) { QString tagName = tagToUndelete; QStringList allTags = availableTags(); if (allTags.contains(tagName)) { bool ok; tagName = QInputDialog::getText( d->tagChooser, i18n("Unable to undelete tag"), i18n("The tag you are trying to undelete already exists in tag list.
Please enter a new, unique name for it.
"), QLineEdit::Normal, tagName, &ok); if (!ok || allTags.contains(tagName) || tagName.isEmpty()) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setText(i18n("Tag was not undeleted.")); msgBox.exec(); return; } } QList serverResources = d->model->serverResources(); foreach(KoResource * resource, d->lastDeletedTag.resources) { if (serverResources.contains(resource)) { addResourceTag(resource, tagName); } } d->model->tagCategoryAdded(tagName); d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tagName)); d->tagChooser->setUndeletionCandidate(QString()); d->lastDeletedTag = TaggedResourceSet(); } QStringList KoResourceTaggingManager::availableTags() const { return d->tagChooser->allTags(); } void KoResourceTaggingManager::addResourceTag(KoResource* resource, const QString& tagName) { QStringList tagsList = d->model->assignedTagsList(resource); if (tagsList.isEmpty()) { d->model->addTag(resource, tagName); } else { foreach(const QString & tag, tagsList) { if (tag.compare(tagName)) { d->model->addTag(resource, tagName); } } } } void KoResourceTaggingManager::syncTagBoxEntryAddition(const QString& tag) { d->tagChooser->insertItem(tag); } void KoResourceTaggingManager::contextCreateNewTag(const QString& tag) { if (!tag.isEmpty()) { d->model->addTag(0, tag); d->model->tagCategoryAdded(tag); d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tag)); updateTaggedResourceView(); } } void KoResourceTaggingManager::contextCreateNewTag(KoResource* resource , const QString& tag) { if (!tag.isEmpty()) { d->model->tagCategoryAdded(tag); if (resource) { addResourceTag(resource, tag); } } } void KoResourceTaggingManager::syncTagBoxEntryRemoval(const QString& tag) { d->tagChooser->removeItem(tag); } void KoResourceTaggingManager::syncTagBoxEntries() { QList tags = d->model->tagNamesList(); foreach (QString tag, tags) { d->tagChooser->insertItem(tag); } } void KoResourceTaggingManager::contextAddTagToResource(KoResource* resource, const QString& tag) { addResourceTag(resource, tag); d->model->tagCategoryMembersChanged(); updateTaggedResourceView(); } void KoResourceTaggingManager::contextRemoveTagFromResource(KoResource* resource, const QString& tag) { removeResourceTag(resource, tag); d->model->tagCategoryMembersChanged(); updateTaggedResourceView(); } void KoResourceTaggingManager::removeTagFromComboBox(const QString &tag) { QList resources = d->model->currentlyVisibleResources(); foreach(KoResource * resource, resources) { removeResourceTag(resource, tag); } d->model->tagCategoryRemoved(tag); d->lastDeletedTag = TaggedResourceSet(tag, resources); d->tagChooser->setUndeletionCandidate(tag); } void KoResourceTaggingManager::removeResourceTag(KoResource* resource, const QString& tagName) { QStringList tagsList = d->model->assignedTagsList(resource); foreach(const QString & oldName, tagsList) { if (!oldName.compare(tagName)) { d->model->deleteTag(resource, oldName); } } } void KoResourceTaggingManager::renameTag(const QString &oldName, const QString& newName) { if (!d->model->tagNamesList().contains(newName)) { QList resources = d->model->currentlyVisibleResources(); foreach(KoResource * resource, resources) { removeResourceTag(resource, oldName); addResourceTag(resource, newName); } contextCreateNewTag(newName); d->model->tagCategoryRemoved(oldName); d->model->tagCategoryAdded(newName); } } void KoResourceTaggingManager::updateTaggedResourceView() { d->model->setCurrentTag(d->currentTag); d->model->updateServer(); d->originalResources = d->model->currentlyVisibleResources(); } void KoResourceTaggingManager::tagChooserIndexChanged(const QString& lineEditText) { if (!d->tagChooser->selectedTagIsReadOnly()) { d->currentTag = lineEditText; d->tagFilter->allowSave(true); d->model->enableResourceFiltering(true); } else { d->model->enableResourceFiltering(false); d->tagFilter->allowSave(false); d->currentTag.clear(); } d->tagFilter->clear(); updateTaggedResourceView(); } QString KoResourceTaggingManager::currentTag() { return d->tagChooser->currentlySelectedTag(); } void KoResourceTaggingManager::tagSearchLineEditTextChanged(const QString& lineEditText) { if (d->tagChooser->selectedTagIsReadOnly()) { d->model->enableResourceFiltering(!lineEditText.isEmpty()); } else { d->model->enableResourceFiltering(true); } d->model->searchTextChanged(lineEditText); d->model->updateServer(); ///FIXME: fix completer // d->tagCompleter = new QCompleter(tagNamesList(lineEditText),this); // d->tagSearchLineEdit->setCompleter(d->tagCompleter); } void KoResourceTaggingManager::tagSaveButtonPressed() { if (!d->tagChooser->selectedTagIsReadOnly()) { QList newResources = d->model->currentlyVisibleResources(); foreach(KoResource * oldRes, d->originalResources) { if (!newResources.contains(oldRes)) removeResourceTag(oldRes, d->currentTag); } foreach(KoResource * newRes, newResources) { if (!d->originalResources.contains(newRes)) addResourceTag(newRes, d->currentTag); } d->model->tagCategoryMembersChanged(); } updateTaggedResourceView(); } void KoResourceTaggingManager::contextMenuRequested(KoResource* resource, const QStringList& resourceTags, const QPoint& pos) { /* no visible tag chooser usually means no intended tag interaction, * context menu makes no sense then either */ if (!resource || !d->tagChooser->isVisible()) return; KoResourceItemChooserContextMenu menu(resource, resourceTags, d->tagChooser->currentlySelectedTag(), d->tagChooser->allTags()); connect(&menu, SIGNAL(resourceTagAdditionRequested(KoResource*, QString)), this, SLOT(contextAddTagToResource(KoResource*, QString))); connect(&menu, SIGNAL(resourceTagRemovalRequested(KoResource*, QString)), this, SLOT(contextRemoveTagFromResource(KoResource*, QString))); connect(&menu, SIGNAL(resourceAssignmentToNewTagRequested(KoResource*, QString)), this, SLOT(contextCreateNewTag(KoResource*, QString))); menu.exec(pos); } void KoResourceTaggingManager::contextMenuRequested(KoResource* currentResource, QPoint pos) { if (currentResource) { contextMenuRequested(currentResource, d->model->assignedTagsList(currentResource), pos); } } KoTagChooserWidget* KoResourceTaggingManager::tagChooserWidget() { return d->tagChooser; } KoTagFilterWidget* KoResourceTaggingManager::tagFilterWidget() { return d->tagFilter; } KoResourceTaggingManager::KoResourceTaggingManager(KoResourceModel *model, QWidget* parent) : QObject(parent) , d(new Private()) { d->model = model; d->tagChooser = new KoTagChooserWidget(parent); d->tagChooser->addReadOnlyItem(i18n("All")); d->tagChooser->addItems(d->model->tagNamesList()); d->tagFilter = new KoTagFilterWidget(parent); connect(d->tagChooser, SIGNAL(tagChosen(QString)), this, SLOT(tagChooserIndexChanged(QString))); connect(d->tagChooser, SIGNAL(newTagRequested(QString)), this, SLOT(contextCreateNewTag(QString))); connect(d->tagChooser, SIGNAL(tagDeletionRequested(QString)), this, SLOT(removeTagFromComboBox(QString))); connect(d->tagChooser, SIGNAL(tagRenamingRequested(QString, QString)), this, SLOT(renameTag(QString, QString))); connect(d->tagChooser, SIGNAL(tagUndeletionRequested(QString)), this, SLOT(undeleteTag(QString))); connect(d->tagChooser, SIGNAL(tagUndeletionListPurgeRequested()), this, SLOT(purgeTagUndeleteList())); connect(d->tagFilter, SIGNAL(saveButtonClicked()), this, SLOT(tagSaveButtonPressed())); connect(d->tagFilter, SIGNAL(filterTextChanged(QString)), this, SLOT(tagSearchLineEditTextChanged(QString))); connect(d->model, SIGNAL(tagBoxEntryAdded(QString)), this, SLOT(syncTagBoxEntryAddition(QString))); connect(d->model, SIGNAL(tagBoxEntryRemoved(QString)), this, SLOT(syncTagBoxEntryRemoval(QString))); connect(d->model, SIGNAL(tagBoxEntryModified()), this, SLOT(syncTagBoxEntries())); // FIXME: fix tag completer // d->tagCompleter = new QCompleter(this); // d->tagSearchLineEdit->setCompleter(d->tagCompleter); KConfigGroup group = KGlobal::config()->group("SelectedTags"); QString tag = group.readEntry(d->model->serverType(), ""); if (!tag.isEmpty()) { d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tag)); } } KoResourceTaggingManager::~KoResourceTaggingManager() { delete d; } diff --git a/libs/widgets/KoResourceTaggingManager.h b/libs/widgets/KoResourceTaggingManager.h index 8c0eae702f..28358b395d 100644 --- a/libs/widgets/KoResourceTaggingManager.h +++ b/libs/widgets/KoResourceTaggingManager.h @@ -1,77 +1,81 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCETAGGINGMANAGER_H #define KORESOURCETAGGINGMANAGER_H -#include "KoTagFilterWidget.h" -#include "KoTagChooserWidget.h" +#include -#include "kowidgets_export.h" +class QWidget; +class QStringList; +class QString; +class QPoint; +class KoTagFilterWidget; +class KoTagChooserWidget; class KoResourceModel; class KoResource; -class KOWIDGETS_EXPORT KoResourceTaggingManager : public QObject +class KoResourceTaggingManager : public QObject { Q_OBJECT public: explicit KoResourceTaggingManager(KoResourceModel* model, QWidget* parent); ~KoResourceTaggingManager(); void showTaggingBar(bool showSearchBar, bool showOpBar); QStringList availableTags() const; QString currentTag(); void contextMenuRequested(KoResource* currentResource, QPoint pos); KoTagFilterWidget* tagFilterWidget(); KoTagChooserWidget* tagChooserWidget(); private Q_SLOTS: void undeleteTag(const QString& tagToUndelete); void purgeTagUndeleteList(); void contextCreateNewTag(KoResource* resource, const QString& tag); void contextCreateNewTag(const QString& tag); void syncTagBoxEntryRemoval(const QString& tag); void syncTagBoxEntryAddition(const QString& tag); void syncTagBoxEntries(); void tagSaveButtonPressed(); void contextRemoveTagFromResource(KoResource* resource, const QString& tag); void contextAddTagToResource(KoResource* resource, const QString& tag); void renameTag(const QString &oldName, const QString &newName); void tagChooserIndexChanged(const QString& lineEditText); void tagSearchLineEditTextChanged(const QString& lineEditText); void removeTagFromComboBox(const QString& tag); private: void contextMenuRequested(KoResource* resource, const QStringList& resourceTags, const QPoint& pos); void enableContextMenu(bool enable); void removeResourceTag(KoResource* resource, const QString& tagName); void addResourceTag(KoResource* resource, const QString& tagName); void updateTaggedResourceView(); class Private; Private* const d; }; #endif // KORESOURCETAGGINGINTERFACE_H