Commit c2fe82e2 authored by Boudewijn Rempt's avatar Boudewijn Rempt

FEATURE: implement file-backed layers

This is a layer that is loaded from a file and updates when the file
changes. Optionally, the image in the file can be scaled to the current
image's resolution.
parent fc135021
......@@ -204,7 +204,7 @@ bool KisLayer::alphaChannelDisabled() const
void KisLayer::setChannelFlags(const QBitArray & channelFlags)
{
Q_ASSERT(((quint32)channelFlags.count() == colorSpace()->channelCount() || channelFlags.isEmpty()));
Q_ASSERT(channelFlags.isEmpty() ||((quint32)channelFlags.count() == colorSpace()->channelCount()));
m_d->channelFlags = channelFlags;
}
......
......@@ -34,7 +34,7 @@ class KisFilterConfiguration;
/**
* @class KisSelectionBasedLayer describes base behaviour for
* selection base classes like KisAdjustmentLayer and KisGeneratorLayer.
* These clesses should have a persistent selection that controls
* These classes should have a persistent selection that controls
* the area where filter/generators are applied. The area outside
* this selection is not affected by the layer
*/
......
......@@ -235,6 +235,10 @@ KisLayerBox::KisLayerBox()
connect(m_newGeneratorLayerAction, SIGNAL(triggered(bool)), this, SLOT(slotNewGeneratorLayer()));
m_actions.append(m_newGeneratorLayerAction);
m_newFileLayerAction = new KisAction(koIcon("document-open"), i18n("&File Layer"), this);
connect(m_newFileLayerAction, SIGNAL(triggered(bool)), this, SLOT(slotNewFileLayer()));
m_actions.append(m_newFileLayerAction);
m_newTransparencyMaskAction = new KisAction(koIcon("edit-copy"), i18n("&Transparency Mask"), this);
m_newTransparencyMaskAction->setActivationFlags(KisAction::ACTIVE_LAYER);
connect(m_newTransparencyMaskAction, SIGNAL(triggered(bool)), this, SLOT(slotNewTransparencyMask()));
......@@ -265,6 +269,7 @@ KisLayerBox::KisLayerBox()
m_newLayerMenu->addAction(m_newShapeLayerAction);
m_newLayerMenu->addAction(m_newAdjustmentLayerAction);
m_newLayerMenu->addAction(m_newGeneratorLayerAction);
m_newLayerMenu->addAction(m_newFileLayerAction);
m_newLayerMenu->addSeparator();
m_newLayerMenu->addAction(m_newTransparencyMaskAction);
m_newLayerMenu->addAction(m_newEffectMaskAction);
......@@ -535,6 +540,12 @@ void KisLayerBox::slotNewShapeLayer()
m_nodeManager->createNode("KisShapeLayer");
}
void KisLayerBox::slotNewFileLayer()
{
if (!m_canvas) return;
m_nodeManager->createNode("KisFileLayer");
}
void KisLayerBox::slotNewAdjustmentLayer()
{
......
......@@ -100,6 +100,7 @@ private slots:
void slotNewGeneratorLayer();
void slotNewCloneLayer();
void slotNewShapeLayer();
void slotNewFileLayer();
void slotNewTransparencyMask();
void slotNewEffectMask();
void slotNewSelectionMask();
......@@ -138,6 +139,7 @@ private:
KisAction* m_newEffectMaskAction;
KisAction* m_newSelectionMaskAction;
KisAction* m_selectOpaque;
KisAction* m_newFileLayerAction;
};
......
......@@ -36,6 +36,7 @@ set(kritaui_LIB_SRCS
dialogs/kis_dlg_adjustment_layer.cc
dialogs/kis_dlg_filter.cpp
dialogs/kis_dlg_generator_layer.cpp
dialogs/kis_dlg_file_layer.cpp
dialogs/kis_dlg_image_properties.cc
dialogs/kis_dlg_layer_properties.cc
dialogs/kis_dlg_preferences.cc
......@@ -70,6 +71,7 @@ set(kritaui_LIB_SRCS
kis_doc2.cc
kis_part2.cpp
kis_factory2.cc
kis_file_layer.cpp
kis_filter_handler.cc
kis_filter_manager.cc
kis_filters_model.cc
......@@ -270,6 +272,7 @@ kde4_add_ui_files(kritaui_LIB_SRCS
forms/wdgpaintoppresets.ui
forms/wdgpaintopsettings.ui
forms/wdgdlggeneratorlayer.ui
forms/wdgdlgfilelayer.ui
forms/wdgfilterselector.ui
forms/wdgfilternodecreation.ui
forms/wdgpaintactioneditor.ui
......
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2013
*
* 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_dlg_file_layer.h"
#include <QLineEdit>
#include <QCheckBox>
#include <klineedit.h>
#include <klocale.h>
#include <KGlobal>
#include <KStandardDirs>
#include <KFileDialog>
#include <KUrl>
#include <KoFilterManager.h>
#include <KoServiceProvider.h>
#include <kis_config_widget.h>
#include <kis_paint_device.h>
#include <kis_transaction.h>
#include <kis_node.h>
KisDlgFileLayer::KisDlgFileLayer(const QString & name, QWidget * parent)
: KDialog(parent)
, m_customName(false)
, m_freezeName(false)
{
setButtons(Ok | Cancel);
setDefaultButton(Ok);
QWidget * page = new QWidget(this);
dlgWidget.setupUi(page);
setMainWidget(page);
dlgWidget.txtLayerName->setText(name);
connect(dlgWidget.txtLayerName, SIGNAL(textChanged(const QString &)),
this, SLOT(slotNameChanged(const QString &)));
connect(dlgWidget.bnGetFileName, SIGNAL(clicked()), SLOT(slotSelectFile()));
}
void KisDlgFileLayer::slotNameChanged(const QString & text)
{
if (m_freezeName)
return;
m_customName = !text.isEmpty();
enableButtonOk(m_customName);
}
QString KisDlgFileLayer::layerName() const
{
return dlgWidget.txtLayerName->text();
}
bool KisDlgFileLayer::scaleToImageResolution() const
{
return dlgWidget.chkScaleToImageResolution->isChecked();
}
QString KisDlgFileLayer::fileName() const
{
return dlgWidget.txtFileName->text();
}
void KisDlgFileLayer::slotSelectFile()
{
const QStringList mimeFilter = KoFilterManager::mimeFilter(KoServiceProvider::readNativeFormatMimeType(),
KoFilterManager::Import,
KoServiceProvider::readExtraNativeMimeTypes());
QString url = KFileDialog::getOpenFileName(KUrl("kfiledialog:///OpenDialog"),
mimeFilter.join(" "), this, i18n("Select file to use as dynamic file layer."));
dlgWidget.txtFileName->setText(url);
}
#include "kis_dlg_file_layer.moc"
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2013
*
* 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 KIS_DLG_FILE_LAYER_H
#define KIS_DLG_FILE_LAYER_H
#include <kdialog.h>
#include <QString>
class QLabel;
class QGroupBox;
class KisConfigWidget;
class KLineEdit;
#include "ui_wdgdlgfilelayer.h"
/**
* Create a new file layer
*/
class KisDlgFileLayer : public KDialog
{
public:
Q_OBJECT
public:
/**
* Create a new file layer
* @param name the proposed name for this layer
* @param parent the widget parent of this dialog
*/
KisDlgFileLayer(const QString & name, QWidget *parent = 0);
QString fileName() const;
QString layerName() const;
bool scaleToImageResolution() const;
protected slots:
void slotNameChanged(const QString &);
void slotSelectFile();
private:
Ui_WdgDlgFileLayer dlgWidget;
bool m_customName;
bool m_freezeName;
};
#endif
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WdgDlgFileLayer</class>
<widget class="QWidget" name="WdgDlgFileLayer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>440</width>
<height>120</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Layer Name:</string>
</property>
<property name="buddy">
<cstring>txtLayerName</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="KLineEdit" name="txtLayerName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>File:</string>
</property>
<property name="buddy">
<cstring>txtLayerName</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KLineEdit" name="txtFileName"/>
</item>
<item>
<widget class="QToolButton" name="bnGetFileName">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="chkScaleToImageResolution">
<property name="text">
<string>Scale To Image Resolution</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KLineEdit</class>
<extends>QLineEdit</extends>
<header>klineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
/*
* Copyright (c) 2013 Boudewijn Rempt <boud@valdyas.org>
*
* 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_file_layer.h"
#include <QFile>
#include "kis_transform_worker.h"
#include "kis_filter_strategy.h"
#include "kis_doc2.h"
#include "kis_part2.h"
#include "kis_node_progress_proxy.h"
#include "kis_node_visitor.h"
#include <KoProgressUpdater.h>
#include <KoProgressProxy.h>
KisFileLayer::KisFileLayer(KisImageWSP image, const QString &filename, bool scaleToImageResolution, const QString &name, quint8 opacity)
: KisExternalLayer(image, name, opacity)
, m_part(new KisPart2(0))
, m_doc(new KisDoc2(m_part))
, m_filename(filename)
, m_scaleToImageResolution(scaleToImageResolution)
{
m_part->setDocument(m_doc);
Q_ASSERT(QFile::exists(filename));
if (QFile::exists(filename)) {
m_fileWatcher.addPath(filename);
}
connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), SLOT(reloadImage()));
reloadImage();
}
KisFileLayer::~KisFileLayer()
{
delete m_doc;
delete m_part;
}
KisFileLayer::KisFileLayer(const KisFileLayer &rhs)
: KisExternalLayer(rhs)
, m_part(new KisPart2(0))
, m_doc(new KisDoc2(m_part))
{
m_part->setDocument(m_doc);
Q_ASSERT(QFile::exists(rhs.m_filename));
connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), SLOT(reloadImage()));
m_filename = rhs.m_filename;
if (QFile::exists(m_filename)) {
m_fileWatcher.addPath(m_filename);
}
m_scaleToImageResolution = rhs.m_scaleToImageResolution;
reloadImage();
}
void KisFileLayer::resetCache()
{
reloadImage();
}
const KoColorSpace *KisFileLayer::colorSpace() const
{
return m_image->colorSpace();
}
KisPaintDeviceSP KisFileLayer::original() const
{
return m_image;
}
KisPaintDeviceSP KisFileLayer::paintDevice() const
{
return 0;
}
KoDocumentSectionModel::PropertyList KisFileLayer::sectionModelProperties() const
{
KoDocumentSectionModel::PropertyList l = KisLayer::sectionModelProperties();
l << KoDocumentSectionModel::Property(i18n("File"), m_filename);
return l;
}
void KisFileLayer::setFileName(const QString &filename)
{
m_fileWatcher.removePath(m_filename);
m_filename = filename;
m_fileWatcher.addPath(m_filename);
reloadImage();
}
QString KisFileLayer::fileName() const
{
return m_filename;
}
void KisFileLayer::setScaleToImageResolution(bool scale)
{
m_scaleToImageResolution = scale;
reloadImage();
}
bool KisFileLayer::scaleToImageResolution() const
{
return m_scaleToImageResolution;
}
void KisFileLayer::reloadImage()
{
m_doc->openUrl(m_filename);
KisImageWSP importedImage = m_doc->image();
m_image = importedImage->projection();
if (m_scaleToImageResolution && (image()->xRes() != importedImage->xRes()
|| image()->yRes() != importedImage->yRes()))
{
qreal xscale = image()->xRes() / importedImage->xRes();
qreal yscale = image()->yRes() / importedImage->yRes();
KisTransformWorker worker(m_image, xscale, yscale, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0, KisFilterStrategyRegistry::instance()->get("Bicubic"));
worker.run();
}
setDirty();
}
KisNodeSP KisFileLayer::clone() const
{
return KisNodeSP(new KisFileLayer(*this));
}
bool KisFileLayer::allowAsChild(KisNodeSP node) const
{
return node->inherits("KisMask");
}
bool KisFileLayer::accept(KisNodeVisitor& visitor)
{
return visitor.visit(this);
}
void KisFileLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
{
return visitor.visit(this, undoAdapter);
}
/*
* Copyright (c) 2013 Boudewijn Rempt <boud@valdyas.org>
*
* 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_FILE_LAYER_H
#define KIS_FILE_LAYER_H
#include "kis_external_layer_iface.h"
#include <QFileSystemWatcher>
class KisDoc2;
class KisPart2;
/**
* @brief The KisFileLayer class loads a particular file as a layer into the layer stack.
*/
class KisFileLayer : public KisExternalLayer
{
Q_OBJECT
public:
explicit KisFileLayer(KisImageWSP image, const QString &filename, bool scaleToImageResolution, const QString &name, quint8 opacity);
~KisFileLayer();
KisFileLayer(const KisFileLayer& rhs);
void resetCache();
virtual const KoColorSpace *colorSpace() const;
KisPaintDeviceSP original() const;
KisPaintDeviceSP paintDevice() const;
KoDocumentSectionModel::PropertyList sectionModelProperties() const;
void setFileName(const QString &filename);
QString fileName() const;
void setScaleToImageResolution(bool scale);
bool scaleToImageResolution() const;
KisNodeSP clone() const;
bool allowAsChild(KisNodeSP) const;
bool accept(KisNodeVisitor&);
void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter);
public slots:
void reloadImage();
private:
KisPart2 *m_part;
KisDoc2 *m_doc;
QString m_filename;
bool m_scaleToImageResolution;
KisPaintDeviceSP m_image;
QFileSystemWatcher m_fileWatcher;
};
#endif // KIS_FILE_LAYER_H
......@@ -17,6 +17,7 @@
*/
#include "kis_layer_manager.h"
#include <QRect>
#include <QApplication>
#include <QCursor>
......@@ -31,6 +32,7 @@
#include <kstandardaction.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kstandarddirs.h>
#include <kfilewidget.h>
#include <kurl.h>
#include <kdiroperator.h>
......@@ -47,11 +49,14 @@
#include <KoSelection.h>
#include <KoShapeManager.h>
#include <KoProgressUpdater.h>
#include <KoDocument.h>
#include <KoPart.h>
#include <filter/kis_filter_configuration.h>
#include <filter/kis_filter.h>
#include <kis_filter_strategy.h>
#include <generator/kis_generator_layer.h>
#include <kis_file_layer.h>
#include <kis_adjustment_layer.h>
#include <kis_mask.h>
#include <kis_clone_layer.h>
......@@ -65,6 +70,7 @@
#include <kis_painter.h>
#include <metadata/kis_meta_data_store.h>
#include <metadata/kis_meta_data_merge_strategy_registry.h>
#include <kis_file_layer.h>
#include "kis_part2.h"
#include "kis_config.h"
......@@ -73,6 +79,7 @@
#include "dialogs/kis_dlg_adjustment_layer.h"
#include "dialogs/kis_dlg_layer_properties.h"
#include "dialogs/kis_dlg_generator_layer.h"
#include "dialogs/kis_dlg_file_layer.h"
#include "kis_doc2.h"
#include "kis_filter_manager.h"
#include "commands/kis_image_commands.h"
......@@ -91,6 +98,7 @@
#include "kis_node_manager.h"
#include "kis_action.h"
#include "kis_action_manager.h"
#include "kis_part2.h"
class KisSaveGroupVisitor : public KisNodeVisitor
{
......@@ -912,5 +920,50 @@ bool KisLayerManager::activeLayerHasSelection()
}
void KisLayerManager::addFileLayer()
{
addFileLayer(activeLayer()->parent(), activeLayer());
}
void KisLayerManager::addFileLayer(KisNodeSP parent, KisNodeSP above)
{
Q_ASSERT(parent);
KisImageWSP image = m_view->image();
if (!image) return;
KisDlgFileLayer dlg(image->nextLayerName(), m_view);
dlg.resize(dlg.minimumSizeHint());
if (dlg.exec() == QDialog::Accepted) {
QString name = dlg.layerName();
QString fileName = dlg.fileName();