source: smplayer/trunk/src/actionseditor.cpp@ 167

Last change on this file since 167 was 165, checked in by Silvan Scherrer, 11 years ago

SMPlayer: update trunk to latest 0.8.7

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