#include <QInputDialog>
#include <QDragEnterEvent>
#include <QDropEvent>
-
+#include <QMutexLocker>
#include <KDebug>
#include <KGlobalSettings>
{
setFrame(false);
setReadOnly(true);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
}
void MyEditableLabel::mouseDoubleClickEvent ( QMouseEvent * e )
{
setReadOnly(false);
selectAll();
+ e->accept();
}
-CollapsibleGroup::CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, QString groupName, QWidget * parent) :
- AbstractCollapsibleWidget(parent),
- m_index(ix)
+CollapsibleGroup::CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, const EffectInfo &info, QWidget * parent) :
+ AbstractCollapsibleWidget(parent)
{
- setupUi(this);
+ m_info.groupIndex = ix;
+ m_subWidgets = QList <CollapsibleEffect *> ();
setFont(KGlobalSettings::smallestReadableFont());
- QHBoxLayout *l = static_cast <QHBoxLayout *>(framegroup->layout());
+ frame->setObjectName("framegroup");
+ decoframe->setObjectName("decoframegroup");
+ QHBoxLayout *l = static_cast <QHBoxLayout *>(frame->layout());
m_title = new MyEditableLabel(this);
- l->insertWidget(4, m_title);
- m_title->setText(groupName.isEmpty() ? i18n("Effect Group") : groupName);
+ l->insertWidget(2, m_title);
+ m_title->setText(info.groupName.isEmpty() ? i18n("Effect Group") : info.groupName);
+ m_info.groupName = m_title->text();
connect(m_title, SIGNAL(editingFinished()), this, SLOT(slotRenameGroup()));
buttonUp->setIcon(KIcon("kdenlive-up"));
buttonUp->setToolTip(i18n("Move effect up"));
if (firstGroup) buttonUp->setVisible(false);
if (lastGroup) buttonDown->setVisible(false);
m_menu = new QMenu;
- m_menu->addAction(KIcon("view-refresh"), i18n("Reset effect"), this, SLOT(slotResetEffect()));
- m_menu->addAction(KIcon("document-save"), i18n("Save effect"), this, SLOT(slotSaveEffect()));
+ m_menu->addAction(KIcon("view-refresh"), i18n("Reset Group"), this, SLOT(slotResetGroup()));
+ m_menu->addAction(KIcon("document-save"), i18n("Save Group"), this, SLOT(slotSaveGroup()));
- effecticon->setPixmap(KIcon("folder").pixmap(16,16));
m_menu->addAction(KIcon("list-remove"), i18n("Ungroup"), this, SLOT(slotUnGroup()));
setAcceptDrops(true);
menuButton->setIcon(KIcon("kdenlive-menu"));
menuButton->setMenu(m_menu);
- enabledBox->setChecked(true);
+ enabledButton->setChecked(false);
+ enabledButton->setIcon(KIcon("visible"));
+
+ if (info.groupIsCollapsed) {
+ slotShow(false);
+ }
connect(collapseButton, SIGNAL(clicked()), this, SLOT(slotSwitch()));
- connect(enabledBox, SIGNAL(toggled(bool)), this, SLOT(slotEnable(bool)));
+ connect(enabledButton, SIGNAL(toggled(bool)), this, SLOT(slotEnable(bool)));
connect(buttonUp, SIGNAL(clicked()), this, SLOT(slotEffectUp()));
connect(buttonDown, SIGNAL(clicked()), this, SLOT(slotEffectDown()));
- connect(buttonDel, SIGNAL(clicked()), this, SLOT(slotDeleteEffect()));
+ connect(buttonDel, SIGNAL(clicked()), this, SLOT(slotDeleteGroup()));
}
bool CollapsibleGroup::isActive() const
{
- return decoframegroup->property("active").toBool();
+ return decoframe->property("active").toBool();
}
void CollapsibleGroup::setActive(bool activate)
{
- decoframegroup->setProperty("active", activate);
- decoframegroup->setStyleSheet(decoframegroup->styleSheet());
+ decoframe->setProperty("active", activate);
+ decoframe->setStyleSheet(decoframe->styleSheet());
}
void CollapsibleGroup::mouseDoubleClickEvent ( QMouseEvent * event )
{
- if (framegroup->underMouse() && collapseButton->isEnabled()) slotSwitch();
+ if (frame->underMouse() && collapseButton->isEnabled()) slotSwitch();
QWidget::mouseDoubleClickEvent(event);
}
-void CollapsibleGroup::slotEnable(bool enable)
+void CollapsibleGroup::slotEnable(bool disable, bool emitInfo)
{
- m_title->setEnabled(enable);
- enabledBox->blockSignals(true);
- enabledBox->setChecked(enable);
- enabledBox->blockSignals(false);
- QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
- if (vbox == NULL) return;
- for (int i = 0; i < vbox->count(); i++) {
- CollapsibleGroup *e = static_cast<CollapsibleGroup *>(vbox->itemAt(i)->widget());
- if (e) e->enabledBox->setChecked(enable);// slotEnable(enable);
- }
+ m_title->setEnabled(!disable);
+ enabledButton->blockSignals(true);
+ enabledButton->setChecked(disable);
+ enabledButton->setIcon(disable ? KIcon("novisible") : KIcon("visible"));
+ enabledButton->blockSignals(false);
+ for (int i = 0; i < m_subWidgets.count(); ++i)
+ m_subWidgets.at(i)->slotDisable(disable, emitInfo);
}
-void CollapsibleGroup::slotDeleteEffect()
+void CollapsibleGroup::slotDeleteGroup()
{
- emit deleteGroup(groupIndex());
+ QDomDocument doc;
+ // delete effects from the last one to the first, otherwise each deletion would trigger an update
+ // in other effects's kdenlive_ix index.
+ for (int i = m_subWidgets.count() - 1; i >= 0; --i)
+ doc.appendChild(doc.importNode(m_subWidgets.at(i)->effect(), true));
+ emit deleteGroup(doc);
}
void CollapsibleGroup::slotEffectUp()
{
- emit changeGroupPosition(groupIndex(), true);
+ QList <int> indexes;
+ for (int i = 0; i < m_subWidgets.count(); ++i)
+ indexes << m_subWidgets.at(i)->effectIndex();
+ emit changeEffectPosition(indexes, true);
}
void CollapsibleGroup::slotEffectDown()
{
- emit changeGroupPosition(groupIndex(), false);
+ QList <int> indexes;
+ for (int i = 0; i < m_subWidgets.count(); ++i)
+ indexes << m_subWidgets.at(i)->effectIndex();
+ emit changeEffectPosition(indexes, false);
}
-void CollapsibleGroup::slotSaveEffect()
+void CollapsibleGroup::slotSaveGroup()
{
- QString name = QInputDialog::getText(this, i18n("Save Effect"), i18n("Name for saved effect: "));
+ QString name = QInputDialog::getText(this, i18n("Save Group"), i18n("Name for saved group: "), QLineEdit::Normal, m_title->text());
if (name.isEmpty()) return;
QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
path = path + name + ".xml";
if (QFile::exists(path)) if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", path)) == KMessageBox::No) return;
- /*TODO
- QDomDocument doc;
- QDomElement effect = m_effect.cloneNode().toElement();
- doc.appendChild(doc.importNode(effect, true));
- effect = doc.firstChild().toElement();
- effect.removeAttribute("kdenlive_ix");
- effect.setAttribute("id", name);
- effect.setAttribute("type", "custom");
- QDomElement effectname = effect.firstChildElement("name");
- effect.removeChild(effectname);
- effectname = doc.createElement("name");
- QDomText nametext = doc.createTextNode(name);
- effectname.appendChild(nametext);
- effect.insertBefore(effectname, QDomNode());
- QDomElement effectprops = effect.firstChildElement("properties");
- effectprops.setAttribute("id", name);
- effectprops.setAttribute("type", "custom");
+ QDomDocument doc = effectsData();
+ QDomElement base = doc.documentElement();
+ QDomNodeList effects = base.elementsByTagName("effect");
+ for (int i = 0; i < effects.count(); ++i) {
+ QDomElement eff = effects.at(i).toElement();
+ eff.removeAttribute("kdenlive_ix");
+ EffectInfo info;
+ info.fromString(eff.attribute("kdenlive_info"));
+ // Make sure all effects have the correct new group name
+ info.groupName = name;
+ // Saved effect group should have a group index of -1
+ info.groupIndex = -1;
+ eff.setAttribute("kdenlive_info", info.toString());
+
+ }
+
+ base.setAttribute("name", name);
+ base.setAttribute("id", name);
+ base.setAttribute("type", "custom");
QFile file(path);
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
out << doc.toString();
}
file.close();
- emit reloadEffects();*/
+ emit reloadEffects();
}
-void CollapsibleGroup::slotResetEffect()
+void CollapsibleGroup::slotResetGroup()
{
- //TODO: emit resetEffect(effectIndex());
+ QMutexLocker lock(&m_mutex);
+ for (int i = 0; i < m_subWidgets.count(); ++i)
+ m_subWidgets.at(i)->slotResetEffect();
}
void CollapsibleGroup::slotSwitch()
widgetFrame->setVisible(show);
if (show) {
collapseButton->setArrowType(Qt::DownArrow);
- m_info.isCollapsed = false;
+ m_info.groupIsCollapsed = false;
}
else {
collapseButton->setArrowType(Qt::RightArrow);
- m_info.isCollapsed = true;
+ m_info.groupIsCollapsed = true;
}
- //emit parameterChanged(m_original_effect, m_effect, effectIndex());
+ if (!m_subWidgets.isEmpty()) m_subWidgets.at(0)->groupStateChanged(m_info.groupIsCollapsed);
}
-void CollapsibleGroup::updateGroupIndex(int groupIndex)
+QWidget *CollapsibleGroup::title() const
{
- /*TODO:
- m_info.groupIndex = groupIndex;
- m_effect.setAttribute("kdenlive_info", m_info.toString());
- emit parameterChanged(m_original_effect, m_effect, effectIndex());*/
+ return m_title;
}
void CollapsibleGroup::addGroupEffect(CollapsibleEffect *effect)
{
+ QMutexLocker lock(&m_mutex);
QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
if (vbox == NULL) {
vbox = new QVBoxLayout();
widgetFrame->setLayout(vbox);
}
effect->setGroupIndex(groupIndex());
+ effect->setGroupName(m_title->text());
+ effect->decoframe->setObjectName("decoframesub");
+ m_subWidgets.append(effect);
vbox->addWidget(effect);
}
void CollapsibleGroup::removeGroup(int ix, QVBoxLayout *layout)
{
+ QMutexLocker lock(&m_mutex);
QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
if (vbox == NULL) return;
-
- for (int j = vbox->count() - 1; j >= 0; j--) {
- QLayoutItem *child = vbox->takeAt(j);
- CollapsibleGroup *e = static_cast<CollapsibleGroup *>(child->widget());
- layout->insertWidget(ix, e);
- e->updateGroupIndex(-1);
- delete child;
+ for (int i = m_subWidgets.count() - 1; i >= 0 ; --i) {
+ vbox->removeWidget(m_subWidgets.at(i));
+ layout->insertWidget(ix, m_subWidgets.at(i));
+ m_subWidgets.at(i)->decoframe->setObjectName("decoframe");
+ m_subWidgets.at(i)->removeFromGroup();
}
+ m_subWidgets.clear();
}
int CollapsibleGroup::groupIndex() const
{
- return m_index;
+ return m_info.groupIndex;
}
-
-
bool CollapsibleGroup::isGroup() const
{
return true;
void CollapsibleGroup::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("kdenlive/effectslist")) {
- framegroup->setProperty("active", true);
- framegroup->setStyleSheet(framegroup->styleSheet());
+ frame->setProperty("target", true);
+ frame->setStyleSheet(frame->styleSheet());
event->acceptProposedAction();
}
}
void CollapsibleGroup::dragLeaveEvent(QDragLeaveEvent */*event*/)
{
- framegroup->setProperty("active", false);
- framegroup->setStyleSheet(framegroup->styleSheet());
+ frame->setProperty("target", false);
+ frame->setStyleSheet(frame->styleSheet());
}
void CollapsibleGroup::dropEvent(QDropEvent *event)
{
- framegroup->setProperty("active", false);
- framegroup->setStyleSheet(framegroup->styleSheet());
+ frame->setProperty("target", false);
+ frame->setStyleSheet(frame->styleSheet());
const QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist"));
//event->acceptProposedAction();
QDomDocument doc;
doc.setContent(effects, true);
QDomElement e = doc.documentElement();
int ix = e.attribute("kdenlive_ix").toInt();
- if (ix == 0) {
+ if (ix == 0 || e.tagName() == "effectgroup") {
+ if (e.tagName() == "effectgroup") {
+ // dropped a group on another group
+ QDomNodeList pastedEffects = e.elementsByTagName("effect");
+ if (pastedEffects.isEmpty() || m_subWidgets.isEmpty()) {
+ // Buggy groups, should not happen
+ event->ignore();
+ return;
+ }
+ QList <int> pastedEffectIndexes;
+ QList <int> currentEffectIndexes;
+ EffectInfo pasteInfo;
+ pasteInfo.fromString(pastedEffects.at(0).toElement().attribute("kdenlive_info"));
+ if (pasteInfo.groupIndex == -1) {
+ // Group dropped from effects list, add effect
+ e.setAttribute("kdenlive_ix", m_subWidgets.last()->effectIndex());
+ emit addEffect(e);
+ event->setDropAction(Qt::CopyAction);
+ event->accept();
+ return;
+ }
+ // Moving group
+ for (int i = 0; i < pastedEffects.count(); ++i) {
+ pastedEffectIndexes << pastedEffects.at(i).toElement().attribute("kdenlive_ix").toInt();
+ }
+ for (int i = 0; i < m_subWidgets.count(); ++i) {
+ currentEffectIndexes << m_subWidgets.at(i)->effectIndex();
+ }
+ kDebug()<<"PASTING: "<<pastedEffectIndexes<<" TO "<<currentEffectIndexes;
+ if (pastedEffectIndexes.at(0) < currentEffectIndexes.at(0)) {
+ // Pasting group after current one:
+ emit moveEffect(pastedEffectIndexes, currentEffectIndexes.last(), pasteInfo.groupIndex, pasteInfo.groupName);
+ }
+ else {
+ // Group moved before current one
+ emit moveEffect(pastedEffectIndexes, currentEffectIndexes.first(), pasteInfo.groupIndex, pasteInfo.groupName);
+ }
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+ return;
+ }
// effect dropped from effects list, add it
- e.setAttribute("kdenlive_ix", ix);
+ e.setAttribute("kdenlive_info", m_info.toString());
+ if (!m_subWidgets.isEmpty()) {
+ e.setAttribute("kdenlive_ix", m_subWidgets.at(0)->effectIndex());
+ }
+ emit addEffect(e);
event->setDropAction(Qt::CopyAction);
event->accept();
- emit addEffect(e);
return;
}
- int new_index = -1;
- QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
- if (vbox == NULL) return;
- CollapsibleEffect *effect = static_cast<CollapsibleEffect *>(vbox->itemAt(vbox->count() -1)->widget());
- new_index = effect->effectIndex();
- emit moveEffect(ix, new_index, m_index);
+ if (m_subWidgets.isEmpty()) return;
+ int new_index = m_subWidgets.last()->effectIndex();
+ emit moveEffect(QList <int> () <<ix, new_index, m_info.groupIndex, m_title->text());
event->setDropAction(Qt::MoveAction);
event->accept();
}
{
m_title->setReadOnly(true);
if (m_title->text().isEmpty()) m_title->setText(i18n("Effect Group"));
- QList <CollapsibleEffect*> effects = findChildren<CollapsibleEffect*>();
- for (int j = 0; j < effects.count(); j++) {
- effects.at(j)->setGroupName(m_title->text());
+ for (int j = 0; j < m_subWidgets.count(); j++) {
+ m_subWidgets.at(j)->setGroupName(m_title->text());
}
+ m_info.groupName = m_title->text();
emit groupRenamed(this);
}
QList <CollapsibleEffect*> CollapsibleGroup::effects()
{
- QList <CollapsibleEffect*> result = findChildren<CollapsibleEffect*>();
- return result;
+ QMutexLocker lock(&m_mutex);
+ return m_subWidgets;
+}
+
+QDomDocument CollapsibleGroup::effectsData()
+{
+ QMutexLocker lock(&m_mutex);
+ QDomDocument doc;
+ QDomElement list = doc.createElement("effectgroup");
+ list.setAttribute("name", m_title->text());
+ doc.appendChild(list);
+ for (int j = 0; j < m_subWidgets.count(); j++) {
+ list.appendChild(doc.importNode(m_subWidgets.at(j)->effect(), true));
+ }
+ return doc;
+}
+
+void CollapsibleGroup::adjustEffects()
+{
+ for (int i = 0; i < m_subWidgets.count(); ++i) {
+ m_subWidgets.at(i)->adjustButtons(i, m_subWidgets.count());
+ }
}
+#include "collapsiblegroup.moc"