]> git.sesse.net Git - kdenlive/blob - src/effectstack/collapsiblegroup.cpp
Effect groups can now be renamed
[kdenlive] / src / effectstack / collapsiblegroup.cpp
1 /***************************************************************************
2  *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20
21 #include "collapsiblegroup.h"
22
23
24 #include <QMenu>
25 #include <QVBoxLayout>
26 #include <QInputDialog>
27 #include <QDragEnterEvent>
28 #include <QDropEvent>
29
30
31 #include <KDebug>
32 #include <KGlobalSettings>
33 #include <KLocale>
34 #include <KMessageBox>
35 #include <KStandardDirs>
36 #include <KFileDialog>
37 #include <KUrlRequester>
38 #include <KColorScheme>
39
40 MyEditableLabel::MyEditableLabel(QWidget * parent):
41     QLineEdit(parent)
42 {
43     setFrame(false);
44     setReadOnly(true);
45 }
46
47 void MyEditableLabel::mouseDoubleClickEvent ( QMouseEvent * e )
48 {
49     setReadOnly(false);
50     selectAll();
51 }
52
53
54 CollapsibleGroup::CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, QString groupName, QWidget * parent) :
55         AbstractCollapsibleWidget(parent),
56         m_index(ix)
57 {
58     setupUi(this);
59     setFont(KGlobalSettings::smallestReadableFont());
60     QHBoxLayout *l = static_cast <QHBoxLayout *>(frame->layout());
61     m_title = new MyEditableLabel(this);
62     l->insertWidget(4, m_title);
63     m_title->setText(groupName.isEmpty() ? i18n("Effect Group") : groupName);
64     connect(m_title, SIGNAL(editingFinished()), this, SLOT(slotRenameGroup()));
65     buttonUp->setIcon(KIcon("kdenlive-up"));
66     buttonUp->setToolTip(i18n("Move effect up"));
67     buttonDown->setIcon(KIcon("kdenlive-down"));
68     buttonDown->setToolTip(i18n("Move effect down"));
69
70     buttonDel->setIcon(KIcon("kdenlive-deleffect"));
71     buttonDel->setToolTip(i18n("Delete effect"));
72     if (firstGroup) buttonUp->setVisible(false);
73     if (lastGroup) buttonDown->setVisible(false);
74     m_menu = new QMenu;
75     m_menu->addAction(KIcon("view-refresh"), i18n("Reset effect"), this, SLOT(slotResetEffect()));
76     m_menu->addAction(KIcon("document-save"), i18n("Save effect"), this, SLOT(slotSaveEffect()));
77     
78     effecticon->setPixmap(KIcon("folder").pixmap(16,16));
79     m_menu->addAction(KIcon("list-remove"), i18n("Ungroup"), this, SLOT(slotUnGroup()));
80     setAcceptDrops(true);
81     menuButton->setIcon(KIcon("kdenlive-menu"));
82     menuButton->setMenu(m_menu);
83     
84     enabledBox->setChecked(true);
85
86     connect(collapseButton, SIGNAL(clicked()), this, SLOT(slotSwitch()));
87     connect(enabledBox, SIGNAL(toggled(bool)), this, SLOT(slotEnable(bool)));
88     connect(buttonUp, SIGNAL(clicked()), this, SLOT(slotEffectUp()));
89     connect(buttonDown, SIGNAL(clicked()), this, SLOT(slotEffectDown()));
90     connect(buttonDel, SIGNAL(clicked()), this, SLOT(slotDeleteEffect()));
91
92 }
93
94 CollapsibleGroup::~CollapsibleGroup()
95 {
96     delete m_menu;
97 }
98
99 void CollapsibleGroup::slotUnGroup()
100 {
101     emit unGroup(this);
102 }
103
104 bool CollapsibleGroup::isActive() const
105 {
106     return decoframegroup->property("active").toBool();
107 }
108
109 void CollapsibleGroup::setActive(bool activate)
110 {
111     decoframegroup->setProperty("active", activate);
112     decoframegroup->setStyleSheet(decoframegroup->styleSheet());
113 }
114
115 void CollapsibleGroup::mouseDoubleClickEvent ( QMouseEvent * event )
116 {
117     if (frame->underMouse() && collapseButton->isEnabled()) slotSwitch();
118     QWidget::mouseDoubleClickEvent(event);
119 }
120
121
122 void CollapsibleGroup::slotEnable(bool enable)
123 {
124     m_title->setEnabled(enable);
125     enabledBox->blockSignals(true);
126     enabledBox->setChecked(enable);
127     enabledBox->blockSignals(false);
128     QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
129     if (vbox == NULL) return;
130     for (int i = 0; i < vbox->count(); i++) {
131         CollapsibleGroup *e = static_cast<CollapsibleGroup *>(vbox->itemAt(i)->widget());
132         if (e) e->enabledBox->setChecked(enable);// slotEnable(enable);
133     }
134 }
135
136 void CollapsibleGroup::slotDeleteEffect()
137 {
138     emit deleteGroup(groupIndex());
139 }
140
141 void CollapsibleGroup::slotEffectUp()
142 {
143     emit changeGroupPosition(groupIndex(), true);
144 }
145
146 void CollapsibleGroup::slotEffectDown()
147 {
148     emit changeGroupPosition(groupIndex(), false);
149 }
150
151 void CollapsibleGroup::slotSaveEffect()
152 {
153     QString name = QInputDialog::getText(this, i18n("Save Effect"), i18n("Name for saved effect: "));
154     if (name.isEmpty()) return;
155     QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
156     path = path + name + ".xml";
157     if (QFile::exists(path)) if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", path)) == KMessageBox::No) return;
158
159     /*TODO
160     QDomDocument doc;
161     QDomElement effect = m_effect.cloneNode().toElement();
162     doc.appendChild(doc.importNode(effect, true));
163     effect = doc.firstChild().toElement();
164     effect.removeAttribute("kdenlive_ix");
165     effect.setAttribute("id", name);
166     effect.setAttribute("type", "custom");
167     QDomElement effectname = effect.firstChildElement("name");
168     effect.removeChild(effectname);
169     effectname = doc.createElement("name");
170     QDomText nametext = doc.createTextNode(name);
171     effectname.appendChild(nametext);
172     effect.insertBefore(effectname, QDomNode());
173     QDomElement effectprops = effect.firstChildElement("properties");
174     effectprops.setAttribute("id", name);
175     effectprops.setAttribute("type", "custom");
176
177     QFile file(path);
178     if (file.open(QFile::WriteOnly | QFile::Truncate)) {
179         QTextStream out(&file);
180         out << doc.toString();
181     }
182     file.close();
183     emit reloadEffects();*/
184 }
185
186 void CollapsibleGroup::slotResetEffect()
187 {
188     //TODO: emit resetEffect(effectIndex());
189 }
190
191 void CollapsibleGroup::slotSwitch()
192 {
193     bool enable = !widgetFrame->isVisible();
194     slotShow(enable);
195 }
196
197 void CollapsibleGroup::slotShow(bool show)
198 {
199     widgetFrame->setVisible(show);
200     if (show) {
201         collapseButton->setArrowType(Qt::DownArrow);
202         m_info.isCollapsed = false;
203     }
204     else {
205         collapseButton->setArrowType(Qt::RightArrow);
206         m_info.isCollapsed = true;
207     }
208     //emit parameterChanged(m_original_effect, m_effect, effectIndex());   
209 }
210
211 void CollapsibleGroup::updateGroupIndex(int groupIndex)
212 {
213   /*TODO:
214     m_info.groupIndex = groupIndex;
215     m_effect.setAttribute("kdenlive_info", m_info.toString());
216     emit parameterChanged(m_original_effect, m_effect, effectIndex());*/
217 }
218
219 void CollapsibleGroup::addGroupEffect(CollapsibleEffect *effect)
220 {
221     QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
222     if (vbox == NULL) {
223         vbox = new QVBoxLayout();
224         vbox->setContentsMargins(10, 0, 0, 0);
225         vbox->setSpacing(2);
226         widgetFrame->setLayout(vbox);
227     }
228     effect->setGroupIndex(groupIndex());
229     vbox->addWidget(effect);
230 }
231
232 QString CollapsibleGroup::infoString() const
233 {
234     return m_info.toString();
235 }
236
237 void CollapsibleGroup::removeGroup(int ix, QVBoxLayout *layout)
238 {
239     QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
240     if (vbox == NULL) return;
241     
242     for (int j = vbox->count() - 1; j >= 0; j--) {
243         QLayoutItem *child = vbox->takeAt(j);
244         CollapsibleGroup *e = static_cast<CollapsibleGroup *>(child->widget());
245         layout->insertWidget(ix, e);
246         e->updateGroupIndex(-1);
247         delete child;
248     }
249 }
250
251 int CollapsibleGroup::groupIndex() const
252 {
253     return m_index;
254 }
255
256
257
258 bool CollapsibleGroup::isGroup() const
259 {
260     return true;
261 }
262
263 void CollapsibleGroup::updateTimecodeFormat()
264 {
265     QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
266     if (vbox == NULL) return;
267     for (int j = vbox->count() - 1; j >= 0; j--) {
268         CollapsibleEffect *e = static_cast<CollapsibleEffect *>(vbox->itemAt(j)->widget());
269         if (e) e->updateTimecodeFormat();
270     }
271 }
272
273 void CollapsibleGroup::dragEnterEvent(QDragEnterEvent *event)
274 {
275     if (event->mimeData()->hasFormat("kdenlive/effectslist")) {
276         frame->setProperty("active", true);
277         frame->setStyleSheet(frame->styleSheet());
278         event->acceptProposedAction();
279     }
280 }
281
282 void CollapsibleGroup::dragLeaveEvent(QDragLeaveEvent */*event*/)
283 {
284     frame->setProperty("active", false);
285     frame->setStyleSheet(frame->styleSheet());
286 }
287
288 void CollapsibleGroup::dropEvent(QDropEvent *event)
289 {
290     frame->setProperty("active", false);
291     frame->setStyleSheet(frame->styleSheet());
292     const QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist"));
293     //event->acceptProposedAction();
294     QDomDocument doc;
295     doc.setContent(effects, true);
296     QDomElement e = doc.documentElement();
297     int ix = e.attribute("kdenlive_ix").toInt();
298     if (ix == 0) {
299         // effect dropped from effects list, add it
300         e.setAttribute("kdenlive_ix", ix);
301         event->setDropAction(Qt::CopyAction);
302         event->accept();
303         emit addEffect(e);
304         return;
305     }
306     int new_index = -1;
307     QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
308     if (vbox == NULL) return;
309     CollapsibleEffect *effect = static_cast<CollapsibleEffect *>(vbox->itemAt(vbox->count() -1)->widget());
310     new_index = effect->effectIndex();
311     emit moveEffect(ix, new_index, m_index);
312     event->setDropAction(Qt::MoveAction);
313     event->accept();
314 }
315
316 void CollapsibleGroup::slotRenameGroup()
317 {
318     m_title->setReadOnly(true);
319     if (m_title->text().isEmpty()) m_title->setText(i18n("Effect Group"));
320     QList <CollapsibleEffect*> effects = findChildren<CollapsibleEffect*>();
321     for (int j = 0; j < effects.count(); j++) {
322         effects.at(j)->setGroupName(m_title->text());
323     }
324     emit groupRenamed(this);
325 }
326
327 QList <CollapsibleEffect*> CollapsibleGroup::effects()
328 {
329     QList <CollapsibleEffect*> result = findChildren<CollapsibleEffect*>();
330     return result;
331 }
332
333