source: smplayer/vendor/current/src/actionseditor.cpp

Last change on this file was 186, checked in by Silvan Scherrer, 8 years ago

SMPlayer: update vendor to 17.1.0

File size: 18.5 KB
Line 
1/* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2017 Ricardo Villalba <rvm@users.sourceforge.net>
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 Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18
19/* This is based on qq14-actioneditor-code.zip from Qt */
20
21
22#include "actionseditor.h"
23
24#include <QTableWidget>
25#include <QHeaderView>
26
27#include <QLayout>
28#include <QObject>
29#include <QPushButton>
30#include <QString>
31#include <QSettings>
32#include <QFile>
33#include <QTextStream>
34#include <QMessageBox>
35#include <QFileInfo>
36#include <QRegExp>
37#include <QApplication>
38#include <QAction>
39#include <QDebug>
40
41#include "images.h"
42#include "filedialog.h"
43#include "paths.h"
44
45#include "shortcutgetter.h"
46
47#if QT_VERSION >= 0x050000
48#include "myscroller.h"
49#endif
50
51/*
52#include <QLineEdit>
53#include <QItemDelegate>
54
55class MyDelegate : public QItemDelegate
56{
57public:
58 MyDelegate(QObject *parent = 0);
59
60 QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
61 const QModelIndex &index) const;
62 virtual void setModelData(QWidget * editor, QAbstractItemModel * model,
63 const QModelIndex & index ) const;
64};
65
66MyDelegate::MyDelegate(QObject *parent) : QItemDelegate(parent)
67{
68}
69
70static QString old_accel_text;
71
72QWidget * MyDelegate::createEditor(QWidget *parent,
73 const QStyleOptionViewItem & option,
74 const QModelIndex & index) const
75{
76 qDebug("MyDelegate::createEditor");
77
78 old_accel_text = index.model()->data(index, Qt::DisplayRole).toString();
79 //qDebug( "text: %s", old_accel_text.toUtf8().data());
80
81 return QItemDelegate::createEditor(parent, option, index);
82}
83
84void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
85 const QModelIndex &index) const
86{
87 QLineEdit *line_edit = static_cast<QLineEdit*>(editor);
88
89 QString accelText = QKeySequence(line_edit->text()).toString();
90 if (accelText.isEmpty() && !line_edit->text().isEmpty()) {
91 model->setData(index, old_accel_text);
92 }
93 else {
94 model->setData(index, accelText);
95 }
96}
97*/
98
99
100#if USE_MULTIPLE_SHORTCUTS
101QString ActionsEditor::shortcutsToString(QList <QKeySequence> shortcuts_list) {
102 QString accelText = "";
103
104 for (int n=0; n < shortcuts_list.count(); n++) {
105 accelText += shortcuts_list[n].toString(QKeySequence::PortableText);
106 if (n < (shortcuts_list.count()-1)) accelText += ", ";
107 }
108
109 //qDebug("ActionsEditor::shortcutsToString: accelText: '%s'", accelText.toUtf8().constData());
110
111 return accelText;
112}
113
114QList <QKeySequence> ActionsEditor::stringToShortcuts(QString shortcuts) {
115 QList <QKeySequence> shortcuts_list;
116
117 QStringList l = shortcuts.split(", ");
118
119 for (int n=0; n < l.count(); n++) {
120 //qDebug("%s", l[n].toUtf8().data());
121#if QT_VERSION >= 0x040300
122 // Qt 4.3 and 4.4 (at least on linux) seems to have a problem when using Traditional Chinese
123 // QKeysequence deletes the arrow key names from the shortcut
124 // so this is a work-around.
125 QString s = l[n].simplified();
126#else
127 QString s = QKeySequence( l[n].simplified() );
128#endif
129
130 //Work-around for Simplified-Chinese
131 s.replace( QString::fromUtf8("å·Š"), "Left");
132 s.replace( QString::fromUtf8("例"), "Down");
133 s.replace( QString::fromUtf8("右"), "Right");
134 s.replace( QString::fromUtf8("侊"), "Up");
135
136 shortcuts_list.append( s );
137 //qDebug("ActionsEditor::stringToShortcuts: shortcut %d: '%s'", n, s.toUtf8().data());
138 }
139
140 return shortcuts_list;
141}
142#endif
143
144
145#define COL_CONFLICTS 0
146#define COL_SHORTCUT 1
147#define COL_DESC 2
148#define COL_NAME 3
149
150ActionsEditor::ActionsEditor(QWidget * parent, Qt::WindowFlags f)
151 : QWidget(parent, f)
152{
153 latest_dir = Paths::shortcutsPath();
154
155 actionsTable = new QTableWidget(0, COL_NAME +1, this);
156 actionsTable->setSelectionMode(QAbstractItemView::SingleSelection);
157 actionsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
158 actionsTable->verticalHeader()->hide();
159
160#if QT_VERSION >= 0x050000
161 MyScroller::setScroller(actionsTable->viewport());
162
163 actionsTable->horizontalHeader()->setSectionResizeMode(COL_DESC, QHeaderView::Stretch);
164 actionsTable->horizontalHeader()->setSectionResizeMode(COL_NAME, QHeaderView::Stretch);
165 actionsTable->horizontalHeader()->setSectionResizeMode(COL_CONFLICTS, QHeaderView::ResizeToContents);
166#else
167 actionsTable->horizontalHeader()->setResizeMode(COL_DESC, QHeaderView::Stretch);
168 actionsTable->horizontalHeader()->setResizeMode(COL_NAME, QHeaderView::Stretch);
169 actionsTable->horizontalHeader()->setResizeMode(COL_CONFLICTS, QHeaderView::ResizeToContents);
170#endif
171
172 actionsTable->setAlternatingRowColors(true);
173 //actionsTable->setItemDelegateForColumn( COL_SHORTCUT, new MyDelegate(actionsTable) );
174
175#if !USE_SHORTCUTGETTER
176 connect(actionsTable, SIGNAL(currentItemChanged(QTableWidgetItem *,QTableWidgetItem *)),
177 this, SLOT(recordAction(QTableWidgetItem *)) );
178 connect(actionsTable, SIGNAL(itemChanged(QTableWidgetItem *)),
179 this, SLOT(validateAction(QTableWidgetItem *)) );
180#else
181 connect(actionsTable, SIGNAL(itemActivated(QTableWidgetItem *)),
182 this, SLOT(editShortcut()) );
183#endif
184
185 saveButton = new QPushButton(this);
186 loadButton = new QPushButton(this);
187
188 connect(saveButton, SIGNAL(clicked()), this, SLOT(saveActionsTable()));
189 connect(loadButton, SIGNAL(clicked()), this, SLOT(loadActionsTable()));
190
191#if USE_SHORTCUTGETTER
192 editButton = new QPushButton(this);
193 connect( editButton, SIGNAL(clicked()), this, SLOT(editShortcut()) );
194#endif
195
196 QHBoxLayout *buttonLayout = new QHBoxLayout;
197 buttonLayout->setSpacing(8);
198#if USE_SHORTCUTGETTER
199 buttonLayout->addWidget(editButton);
200#endif
201 buttonLayout->addStretch(1);
202 buttonLayout->addWidget(loadButton);
203 buttonLayout->addWidget(saveButton);
204
205 QVBoxLayout *mainLayout = new QVBoxLayout(this);
206 mainLayout->setMargin(8);
207 mainLayout->setSpacing(8);
208 mainLayout->addWidget(actionsTable);
209 mainLayout->addLayout(buttonLayout);
210
211 retranslateStrings();
212}
213
214ActionsEditor::~ActionsEditor() {
215}
216
217void ActionsEditor::retranslateStrings() {
218 actionsTable->setHorizontalHeaderLabels( QStringList() << "" <<
219 tr("Shortcut") << tr("Description") << tr("Name") );
220
221 saveButton->setText(tr("&Save"));
222 saveButton->setIcon(Images::icon("save"));
223
224 loadButton->setText(tr("&Load"));
225 loadButton->setIcon(Images::icon("open"));
226
227#if USE_SHORTCUTGETTER
228 editButton->setText(tr("&Change shortcut..."));
229#endif
230
231 //updateView(); // The actions are translated later, so it's useless
232}
233
234bool ActionsEditor::isEmpty() {
235 return actionsList.isEmpty();
236}
237
238void ActionsEditor::clear() {
239 actionsList.clear();
240}
241
242void ActionsEditor::addActions(QWidget *widget) {
243 QAction *action;
244
245 QList<QAction *> actions = widget->findChildren<QAction *>();
246 for (int n=0; n < actions.count(); n++) {
247 action = static_cast<QAction*> (actions[n]);
248 /*
249 if (!action->objectName().isEmpty()) {
250 qDebug("ActionsEditor::addActions: action # %d: '%s' menu: %d", n, action->objectName().toUtf8().constData(), action->menu()!=0);
251 }
252 */
253 if (!action->objectName().isEmpty() && !action->inherits("QWidgetAction") && (action->menu()==0) )
254 actionsList.append(action);
255 }
256
257 updateView();
258}
259
260void ActionsEditor::updateView() {
261 actionsTable->setRowCount( actionsList.count() );
262
263 QAction *action;
264 QString accelText;
265
266#if !USE_SHORTCUTGETTER
267 dont_validate = true;
268#endif
269 //actionsTable->setSortingEnabled(false);
270
271 for (int n=0; n < actionsList.count(); n++) {
272 action = static_cast<QAction*> (actionsList[n]);
273
274#if USE_MULTIPLE_SHORTCUTS
275 accelText = shortcutsToString( action->shortcuts() );
276#else
277 accelText = action->shortcut().toString();
278#endif
279
280 // Conflict column
281 QTableWidgetItem * i_conf = new QTableWidgetItem();
282
283 // Name column
284 QTableWidgetItem * i_name = new QTableWidgetItem(action->objectName());
285
286 // Desc column
287 QTableWidgetItem * i_desc = new QTableWidgetItem(action->text().replace("&",""));
288 i_desc->setIcon( action->icon() );
289
290 // Shortcut column
291 QTableWidgetItem * i_shortcut = new QTableWidgetItem(accelText);
292 int column_height = i_shortcut->sizeHint().height();
293 i_shortcut->setSizeHint(QSize(150, column_height));
294
295 // Set flags
296#if !USE_SHORTCUTGETTER
297 i_conf->setFlags(Qt::ItemIsEnabled);
298 i_name->setFlags(Qt::ItemIsEnabled);
299 i_desc->setFlags(Qt::ItemIsEnabled);
300#else
301 i_conf->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
302 i_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
303 i_desc->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
304 i_shortcut->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
305#endif
306
307 // Add items to table
308 actionsTable->setItem(n, COL_CONFLICTS, i_conf );
309 actionsTable->setItem(n, COL_NAME, i_name );
310 actionsTable->setItem(n, COL_DESC, i_desc );
311 actionsTable->setItem(n, COL_SHORTCUT, i_shortcut );
312
313 }
314 hasConflicts(); // Check for conflicts
315
316 actionsTable->resizeColumnsToContents();
317 actionsTable->setCurrentCell(0, COL_SHORTCUT);
318
319#if !USE_SHORTCUTGETTER
320 dont_validate = false;
321#endif
322 //actionsTable->setSortingEnabled(true);
323}
324
325
326void ActionsEditor::applyChanges() {
327 qDebug("ActionsEditor::applyChanges");
328
329 for (int row = 0; row < (int)actionsList.size(); ++row) {
330 QAction *action = actionsList[row];
331 QTableWidgetItem *i = actionsTable->item(row, COL_SHORTCUT);
332
333#if USE_MULTIPLE_SHORTCUTS
334 action->setShortcuts( stringToShortcuts(i->text()) );
335#else
336 action->setShortcut( QKeySequence(i->text()) );
337#endif
338 }
339}
340
341#if !USE_SHORTCUTGETTER
342void ActionsEditor::recordAction(QTableWidgetItem * i) {
343 //qDebug("ActionsEditor::recordAction");
344
345 //QTableWidgetItem * i = actionsTable->currentItem();
346 if (i->column() == COL_SHORTCUT) {
347 //qDebug("ActionsEditor::recordAction: %d %d %s", i->row(), i->column(), i->text().toUtf8().data());
348 oldAccelText = i->text();
349 }
350}
351
352void ActionsEditor::validateAction(QTableWidgetItem * i) {
353 //qDebug("ActionsEditor::validateAction");
354 if (dont_validate) return;
355
356 if (i->column() == COL_SHORTCUT) {
357 QString accelText = QKeySequence(i->text()).toString();
358
359 if (accelText.isEmpty() && !i->text().isEmpty()) {
360 /*
361 QAction * action = static_cast<QAction*> (actionsList[i->row()]);
362 QString oldAccelText= action->accel().toString();
363 */
364 i->setText(oldAccelText);
365 }
366 else {
367 i->setText(accelText);
368 }
369
370 if (hasConflicts()) qApp->beep();
371 }
372}
373
374#else
375
376void ActionsEditor::editShortcut() {
377 QTableWidgetItem * i = actionsTable->item( actionsTable->currentRow(), COL_SHORTCUT );
378 if (i) {
379 ShortcutGetter d(this);
380 QString result = d.exec( i->text() );
381
382 if (!result.isNull()) {
383 //qDebug("ActionsEditor::editShortcut: result: '%s'", result.toUtf8().constData());
384 QString accelText = QKeySequence(result).toString(QKeySequence::PortableText);
385 i->setText(accelText);
386 if (hasConflicts()) qApp->beep();
387 }
388 }
389}
390#endif
391
392int ActionsEditor::findActionName(const QString & name) {
393 for (int row=0; row < actionsTable->rowCount(); row++) {
394 if (actionsTable->item(row, COL_NAME)->text() == name) return row;
395 }
396 return -1;
397}
398
399bool ActionsEditor::containsShortcut(const QString & accel, const QString & shortcut) {
400 QStringList shortcut_list = accel.split(", ");
401 QString s;
402 foreach(s, shortcut_list) {
403 s = s.trimmed();
404 //qDebug("ActionsEditor::containsShortcut: comparing '%s' with '%s'", s.toUtf8().constData(), shortcut.toUtf8().constData());
405 if (s == shortcut) return true;
406 }
407 return false;
408}
409
410int ActionsEditor::findActionAccel(const QString & accel, int ignoreRow) {
411 QStringList shortcuts = accel.split(", ");
412 QString shortcut;
413
414 for (int row = 0; row < actionsTable->rowCount(); row++) {
415 QTableWidgetItem * i = actionsTable->item(row, COL_SHORTCUT);
416 if (i && row != ignoreRow) {
417 if (!i->text().isEmpty()) {
418 foreach(shortcut, shortcuts) {
419 if (containsShortcut(i->text(), shortcut.trimmed())) {
420 return row;
421 }
422 }
423 }
424 }
425 }
426 return -1;
427}
428
429bool ActionsEditor::hasConflicts() {
430 int found;
431 bool conflict = false;
432
433 QString accelText;
434 QTableWidgetItem *i;
435
436 for (int n = 0; n < actionsTable->rowCount(); n++) {
437 //actionsTable->setText( n, COL_CONFLICTS, " ");
438 i = actionsTable->item( n, COL_CONFLICTS );
439 if (i) i->setIcon( QPixmap() );
440
441 i = actionsTable->item(n, COL_SHORTCUT );
442 if (i) {
443 accelText = i->text();
444 if (!accelText.isEmpty()) {
445 found = findActionAccel( accelText, n );
446 if ( (found != -1) /*&& (found != n)*/ ) {
447 conflict = true;
448 //actionsTable->setText( n, COL_CONFLICTS, "!");
449 actionsTable->item( n, COL_CONFLICTS )->setIcon( Images::icon("conflict") );
450 }
451 }
452 }
453 }
454 //if (conflict) qApp->beep();
455 return conflict;
456}
457
458
459void ActionsEditor::saveActionsTable() {
460 QString s = MyFileDialog::getSaveFileName(
461 this, tr("Choose a filename"),
462 latest_dir,
463 tr("Key files") +" (*.keys)" );
464
465 if (!s.isEmpty()) {
466 // If filename has no extension, add it
467 if (QFileInfo(s).suffix().isEmpty()) {
468 s = s + ".keys";
469 }
470 if (QFileInfo(s).exists()) {
471 int res = QMessageBox::question( this,
472 tr("Confirm overwrite?"),
473 tr("The file %1 already exists.\n"
474 "Do you want to overwrite?").arg(s),
475 QMessageBox::Yes,
476 QMessageBox::No,
477 Qt::NoButton);
478 if (res == QMessageBox::No ) {
479 return;
480 }
481 }
482 latest_dir = QFileInfo(s).absolutePath();
483 bool r = saveActionsTable(s);
484 if (!r) {
485 QMessageBox::warning(this, tr("Error"),
486 tr("The file couldn't be saved"),
487 QMessageBox::Ok, Qt::NoButton);
488 }
489 }
490}
491
492bool ActionsEditor::saveActionsTable(const QString & filename) {
493 qDebug("ActionsEditor::saveActions: '%s'", filename.toUtf8().data());
494
495 QFile f( filename );
496 if ( f.open( QIODevice::WriteOnly ) ) {
497 QTextStream stream( &f );
498 stream.setCodec("UTF-8");
499
500 for (int row=0; row < actionsTable->rowCount(); row++) {
501 stream << actionsTable->item(row, COL_NAME)->text() << "\t"
502 << actionsTable->item(row, COL_SHORTCUT)->text() << "\n";
503 }
504 f.close();
505 return true;
506 }
507 return false;
508}
509
510void ActionsEditor::loadActionsTable() {
511 QString s = MyFileDialog::getOpenFileName(
512 this, tr("Choose a file"),
513 latest_dir, tr("Key files") +" (*.keys)" );
514
515 if (!s.isEmpty()) {
516 latest_dir = QFileInfo(s).absolutePath();
517 bool r = loadActionsTable(s);
518 if (!r) {
519 QMessageBox::warning(this, tr("Error"),
520 tr("The file couldn't be loaded"),
521 QMessageBox::Ok, Qt::NoButton);
522 }
523 }
524}
525
526bool ActionsEditor::loadActionsTable(const QString & filename) {
527 qDebug() << "ActionsEditor::loadActions:" << filename;
528
529 int row;
530
531 QFile f( filename );
532 if ( f.open( QIODevice::ReadOnly ) ) {
533
534#if !USE_SHORTCUTGETTER
535 dont_validate = true;
536#endif
537
538 QTextStream stream( &f );
539 stream.setCodec("UTF-8");
540
541 QString line;
542 while ( !stream.atEnd() ) {
543 line = stream.readLine().trimmed();
544 qDebug() << "ActionsEditor::loadActions: line:" << line;
545 QString name;
546 QString accelText;
547 int pos = line.indexOf(QRegExp("\\t|\\s"));
548 //qDebug() << "ActionsEditor::loadActions: pos:" << pos;
549 if (pos == -1) {
550 name = line;
551 } else {
552 name = line.left(pos);
553 accelText = line.mid(pos+1).trimmed();
554 }
555 qDebug() << "ActionsEditor::loadActions: name:" << name << "accel:" << accelText;
556 if (!name.isEmpty()) {
557 row = findActionName(name);
558 if (row > -1) {
559 qDebug() << "ActionsEditor::loadActions: action found!";
560 actionsTable->item(row, COL_SHORTCUT)->setText(accelText);
561 }
562 } else {
563 qDebug() << "ActionsEditor::loadActions: error in line";
564 }
565 }
566 f.close();
567 hasConflicts(); // Check for conflicts
568
569#if !USE_SHORTCUTGETTER
570 dont_validate = false;
571#endif
572
573 return true;
574 } else {
575 return false;
576 }
577}
578
579
580// Static functions
581
582void ActionsEditor::saveToConfig(QObject *o, QSettings *set) {
583 qDebug("ActionsEditor::saveToConfig");
584
585 set->beginGroup("actions");
586
587 QAction *action;
588 QList<QAction *> actions = o->findChildren<QAction *>();
589 for (int n=0; n < actions.count(); n++) {
590 action = static_cast<QAction*> (actions[n]);
591 if (!action->objectName().isEmpty() && !action->inherits("QWidgetAction")) {
592#if USE_MULTIPLE_SHORTCUTS
593 QString accelText = shortcutsToString(action->shortcuts());
594#else
595 QString accelText = action->shortcut().toString();
596#endif
597 set->setValue(action->objectName(), accelText);
598 }
599 }
600
601 set->endGroup();
602}
603
604
605void ActionsEditor::loadFromConfig(QObject *o, QSettings *set) {
606 qDebug("ActionsEditor::loadFromConfig");
607
608 set->beginGroup("actions");
609
610 QAction *action;
611 QString accelText;
612
613 QList<QAction *> actions = o->findChildren<QAction *>();
614 for (int n=0; n < actions.count(); n++) {
615 action = static_cast<QAction*> (actions[n]);
616 if (!action->objectName().isEmpty() && !action->inherits("QWidgetAction")) {
617#if USE_MULTIPLE_SHORTCUTS
618 QString current = shortcutsToString(action->shortcuts());
619 accelText = set->value(action->objectName(), current).toString();
620 action->setShortcuts( stringToShortcuts( accelText ) );
621#else
622 accelText = set->value(action->objectName(), action->shortcut().toString()).toString();
623 action->setShortcut(QKeySequence(accelText));
624#endif
625 }
626 }
627
628 set->endGroup();
629}
630
631QAction * ActionsEditor::findAction(QObject *o, const QString & name) {
632 QAction *action;
633
634 QList<QAction *> actions = o->findChildren<QAction *>();
635 for (int n=0; n < actions.count(); n++) {
636 action = static_cast<QAction*> (actions[n]);
637 /* qDebug("ActionsEditor::findAction: %s", action->objectName().toLatin1().constData()); */
638 if (name == action->objectName()) return action;
639 }
640
641 return 0;
642}
643
644QStringList ActionsEditor::actionsNames(QObject *o) {
645 QStringList l;
646
647 QAction *action;
648
649 QList<QAction *> actions = o->findChildren<QAction *>();
650 for (int n=0; n < actions.count(); n++) {
651 action = static_cast<QAction*> (actions[n]);
652 //qDebug("action name: '%s'", action->objectName().toUtf8().data());
653 //qDebug("action name: '%s'", action->text().toUtf8().data());
654 if (!action->objectName().isEmpty())
655 l.append( action->objectName() );
656 }
657
658 return l;
659}
660
661
662// Language change stuff
663void ActionsEditor::changeEvent(QEvent *e) {
664 if (e->type() == QEvent::LanguageChange) {
665 retranslateStrings();
666 } else {
667 QWidget::changeEvent(e);
668 }
669}
670
671#include "moc_actionseditor.cpp"
Note: See TracBrowser for help on using the repository browser.