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

Last change on this file since 119 was 119, checked in by Silvan Scherrer, 14 years ago

SMPlayer: latest svn update

  • Property svn:eol-style set to LF
File size: 17.0 KB
Line 
1/* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2011 Ricardo Villalba <rvm@escomposlinux.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 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 actionsTable->horizontalHeader()->setResizeMode(COL_DESC, QHeaderView::Stretch);
154 actionsTable->horizontalHeader()->setResizeMode(COL_NAME, QHeaderView::Stretch);
155
156 actionsTable->setAlternatingRowColors(true);
157#if USE_SHORTCUTGETTER
158 actionsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
159 actionsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
160#endif
161 //actionsTable->setItemDelegateForColumn( COL_SHORTCUT, new MyDelegate(actionsTable) );
162
163#if !USE_SHORTCUTGETTER
164 connect(actionsTable, SIGNAL(currentItemChanged(QTableWidgetItem *,QTableWidgetItem *)),
165 this, SLOT(recordAction(QTableWidgetItem *)) );
166 connect(actionsTable, SIGNAL(itemChanged(QTableWidgetItem *)),
167 this, SLOT(validateAction(QTableWidgetItem *)) );
168#else
169 connect(actionsTable, SIGNAL(itemActivated(QTableWidgetItem *)),
170 this, SLOT(editShortcut()) );
171#endif
172
173 saveButton = new QPushButton(this);
174 loadButton = new QPushButton(this);
175
176 connect(saveButton, SIGNAL(clicked()), this, SLOT(saveActionsTable()));
177 connect(loadButton, SIGNAL(clicked()), this, SLOT(loadActionsTable()));
178
179#if USE_SHORTCUTGETTER
180 editButton = new QPushButton(this);
181 connect( editButton, SIGNAL(clicked()), this, SLOT(editShortcut()) );
182#endif
183
184 QHBoxLayout *buttonLayout = new QHBoxLayout;
185 buttonLayout->setSpacing(8);
186#if USE_SHORTCUTGETTER
187 buttonLayout->addWidget(editButton);
188#endif
189 buttonLayout->addStretch(1);
190 buttonLayout->addWidget(loadButton);
191 buttonLayout->addWidget(saveButton);
192
193 QVBoxLayout *mainLayout = new QVBoxLayout(this);
194 mainLayout->setMargin(8);
195 mainLayout->setSpacing(8);
196 mainLayout->addWidget(actionsTable);
197 mainLayout->addLayout(buttonLayout);
198
199 retranslateStrings();
200}
201
202ActionsEditor::~ActionsEditor() {
203}
204
205void ActionsEditor::retranslateStrings() {
206 actionsTable->setHorizontalHeaderLabels( QStringList() << "" <<
207 tr("Shortcut") << tr("Description") << tr("Name") );
208
209 saveButton->setText(tr("&Save"));
210 saveButton->setIcon(Images::icon("save"));
211
212 loadButton->setText(tr("&Load"));
213 loadButton->setIcon(Images::icon("open"));
214
215#if USE_SHORTCUTGETTER
216 editButton->setText(tr("&Change shortcut..."));
217#endif
218
219 //updateView(); // The actions are translated later, so it's useless
220}
221
222bool ActionsEditor::isEmpty() {
223 return actionsList.isEmpty();
224}
225
226void ActionsEditor::clear() {
227 actionsList.clear();
228}
229
230void ActionsEditor::addActions(QWidget *widget) {
231 QAction *action;
232
233 QList<QAction *> actions = widget->findChildren<QAction *>();
234 for (int n=0; n < actions.count(); n++) {
235 action = static_cast<QAction*> (actions[n]);
236 /*
237 if (!action->objectName().isEmpty()) {
238 qDebug("ActionsEditor::addActions: action # %d: '%s' menu: %d", n, action->objectName().toUtf8().constData(), action->menu()!=0);
239 }
240 */
241 if (!action->objectName().isEmpty() && !action->inherits("QWidgetAction") && (action->menu()==0) )
242 actionsList.append(action);
243 }
244
245 updateView();
246}
247
248void ActionsEditor::updateView() {
249 actionsTable->setRowCount( actionsList.count() );
250
251 QAction *action;
252 QString accelText;
253
254#if !USE_SHORTCUTGETTER
255 dont_validate = true;
256#endif
257 //actionsTable->setSortingEnabled(false);
258
259 for (int n=0; n < actionsList.count(); n++) {
260 action = static_cast<QAction*> (actionsList[n]);
261
262#if USE_MULTIPLE_SHORTCUTS
263 accelText = shortcutsToString( action->shortcuts() );
264#else
265 accelText = action->shortcut().toString();
266#endif
267
268 // Conflict column
269 QTableWidgetItem * i_conf = new QTableWidgetItem();
270
271 // Name column
272 QTableWidgetItem * i_name = new QTableWidgetItem(action->objectName());
273
274 // Desc column
275 QTableWidgetItem * i_desc = new QTableWidgetItem(action->text().replace("&",""));
276 i_desc->setIcon( action->icon() );
277
278 // Shortcut column
279 QTableWidgetItem * i_shortcut = new QTableWidgetItem(accelText);
280
281 // Set flags
282#if !USE_SHORTCUTGETTER
283 i_conf->setFlags(Qt::ItemIsEnabled);
284 i_name->setFlags(Qt::ItemIsEnabled);
285 i_desc->setFlags(Qt::ItemIsEnabled);
286#else
287 i_conf->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
288 i_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
289 i_desc->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
290 i_shortcut->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
291#endif
292
293 // Add items to table
294 actionsTable->setItem(n, COL_CONFLICTS, i_conf );
295 actionsTable->setItem(n, COL_NAME, i_name );
296 actionsTable->setItem(n, COL_DESC, i_desc );
297 actionsTable->setItem(n, COL_SHORTCUT, i_shortcut );
298
299 }
300 hasConflicts(); // Check for conflicts
301
302 actionsTable->resizeColumnsToContents();
303 actionsTable->setCurrentCell(0, COL_SHORTCUT);
304
305#if !USE_SHORTCUTGETTER
306 dont_validate = false;
307#endif
308 //actionsTable->setSortingEnabled(true);
309}
310
311
312void ActionsEditor::applyChanges() {
313 qDebug("ActionsEditor::applyChanges");
314
315 for (int row = 0; row < (int)actionsList.size(); ++row) {
316 QAction *action = actionsList[row];
317 QTableWidgetItem *i = actionsTable->item(row, COL_SHORTCUT);
318
319#if USE_MULTIPLE_SHORTCUTS
320 action->setShortcuts( stringToShortcuts(i->text()) );
321#else
322 action->setShortcut( QKeySequence(i->text()) );
323#endif
324 }
325}
326
327#if !USE_SHORTCUTGETTER
328void ActionsEditor::recordAction(QTableWidgetItem * i) {
329 //qDebug("ActionsEditor::recordAction");
330
331 //QTableWidgetItem * i = actionsTable->currentItem();
332 if (i->column() == COL_SHORTCUT) {
333 //qDebug("ActionsEditor::recordAction: %d %d %s", i->row(), i->column(), i->text().toUtf8().data());
334 oldAccelText = i->text();
335 }
336}
337
338void ActionsEditor::validateAction(QTableWidgetItem * i) {
339 //qDebug("ActionsEditor::validateAction");
340 if (dont_validate) return;
341
342 if (i->column() == COL_SHORTCUT) {
343 QString accelText = QKeySequence(i->text()).toString();
344
345 if (accelText.isEmpty() && !i->text().isEmpty()) {
346 /*
347 QAction * action = static_cast<QAction*> (actionsList[i->row()]);
348 QString oldAccelText= action->accel().toString();
349 */
350 i->setText(oldAccelText);
351 }
352 else {
353 i->setText(accelText);
354 }
355
356 if (hasConflicts()) qApp->beep();
357 }
358}
359
360#else
361
362void ActionsEditor::editShortcut() {
363 QTableWidgetItem * i = actionsTable->item( actionsTable->currentRow(), COL_SHORTCUT );
364 if (i) {
365 ShortcutGetter d(this);
366 QString result = d.exec( i->text() );
367
368 if (!result.isNull()) {
369 QString accelText = QKeySequence(result).toString(QKeySequence::PortableText);
370 i->setText(accelText);
371 if (hasConflicts()) qApp->beep();
372 }
373 }
374}
375#endif
376
377int ActionsEditor::findActionName(const QString & name) {
378 for (int row=0; row < actionsTable->rowCount(); row++) {
379 if (actionsTable->item(row, COL_NAME)->text() == name) return row;
380 }
381 return -1;
382}
383
384int ActionsEditor::findActionAccel(const QString & accel, int ignoreRow) {
385 for (int row=0; row < actionsTable->rowCount(); row++) {
386 QTableWidgetItem * i = actionsTable->item(row, COL_SHORTCUT);
387 if ( (i) && (i->text() == accel) ) {
388 if (ignoreRow == -1) return row;
389 else
390 if (ignoreRow != row) return row;
391 }
392 }
393 return -1;
394}
395
396bool ActionsEditor::hasConflicts() {
397 int found;
398 bool conflict = false;
399
400 QString accelText;
401 QTableWidgetItem *i;
402
403 for (int n=0; n < actionsTable->rowCount(); n++) {
404 //actionsTable->setText( n, COL_CONFLICTS, " ");
405 i = actionsTable->item( n, COL_CONFLICTS );
406 if (i) i->setIcon( QPixmap() );
407
408 i = actionsTable->item(n, COL_SHORTCUT );
409 if (i) {
410 accelText = i->text();
411 if (!accelText.isEmpty()) {
412 found = findActionAccel( accelText, n );
413 if ( (found != -1) && (found != n) ) {
414 conflict = true;
415 //actionsTable->setText( n, COL_CONFLICTS, "!");
416 actionsTable->item( n, COL_CONFLICTS )->setIcon( Images::icon("conflict") );
417 }
418 }
419 }
420 }
421 //if (conflict) qApp->beep();
422 return conflict;
423}
424
425
426void ActionsEditor::saveActionsTable() {
427 QString s = MyFileDialog::getSaveFileName(
428 this, tr("Choose a filename"),
429 latest_dir,
430 tr("Key files") +" (*.keys)" );
431
432 if (!s.isEmpty()) {
433 // If filename has no extension, add it
434 if (QFileInfo(s).suffix().isEmpty()) {
435 s = s + ".keys";
436 }
437 if (QFileInfo(s).exists()) {
438 int res = QMessageBox::question( this,
439 tr("Confirm overwrite?"),
440 tr("The file %1 already exists.\n"
441 "Do you want to overwrite?").arg(s),
442 QMessageBox::Yes,
443 QMessageBox::No,
444 Qt::NoButton);
445 if (res == QMessageBox::No ) {
446 return;
447 }
448 }
449 latest_dir = QFileInfo(s).absolutePath();
450 bool r = saveActionsTable(s);
451 if (!r) {
452 QMessageBox::warning(this, tr("Error"),
453 tr("The file couldn't be saved"),
454 QMessageBox::Ok, Qt::NoButton);
455 }
456 }
457}
458
459bool ActionsEditor::saveActionsTable(const QString & filename) {
460 qDebug("ActionsEditor::saveActions: '%s'", filename.toUtf8().data());
461
462 QFile f( filename );
463 if ( f.open( QIODevice::WriteOnly ) ) {
464 QTextStream stream( &f );
465 stream.setCodec("UTF-8");
466
467 for (int row=0; row < actionsTable->rowCount(); row++) {
468 stream << actionsTable->item(row, COL_NAME)->text() << "\t"
469 << actionsTable->item(row, COL_SHORTCUT)->text() << "\n";
470 }
471 f.close();
472 return true;
473 }
474 return false;
475}
476
477void ActionsEditor::loadActionsTable() {
478 QString s = MyFileDialog::getOpenFileName(
479 this, tr("Choose a file"),
480 latest_dir, tr("Key files") +" (*.keys)" );
481
482 if (!s.isEmpty()) {
483 latest_dir = QFileInfo(s).absolutePath();
484 bool r = loadActionsTable(s);
485 if (!r) {
486 QMessageBox::warning(this, tr("Error"),
487 tr("The file couldn't be loaded"),
488 QMessageBox::Ok, Qt::NoButton);
489 }
490 }
491}
492
493bool ActionsEditor::loadActionsTable(const QString & filename) {
494 qDebug("ActionsEditor::loadActions: '%s'", filename.toUtf8().data());
495
496 QRegExp rx("^(.*)\\t(.*)");
497 int row;
498
499 QFile f( filename );
500 if ( f.open( QIODevice::ReadOnly ) ) {
501
502#if !USE_SHORTCUTGETTER
503 dont_validate = true;
504#endif
505
506 QTextStream stream( &f );
507 stream.setCodec("UTF-8");
508
509 QString line;
510 while ( !stream.atEnd() ) {
511 line = stream.readLine();
512 qDebug("line: '%s'", line.toUtf8().data());
513 if (rx.indexIn(line) > -1) {
514 QString name = rx.cap(1);
515 QString accelText = rx.cap(2);
516 qDebug(" name: '%s' accel: '%s'", name.toUtf8().data(), accelText.toUtf8().data());
517 row = findActionName(name);
518 if (row > -1) {
519 qDebug("Action found!");
520 actionsTable->item(row, COL_SHORTCUT)->setText(accelText);
521 }
522 } else {
523 qDebug(" wrong line");
524 }
525 }
526 f.close();
527 hasConflicts(); // Check for conflicts
528
529#if !USE_SHORTCUTGETTER
530 dont_validate = false;
531#endif
532
533 return true;
534 } else {
535 return false;
536 }
537}
538
539
540// Static functions
541
542void ActionsEditor::saveToConfig(QObject *o, QSettings *set) {
543 qDebug("ActionsEditor::saveToConfig");
544
545 set->beginGroup("actions");
546
547 QAction *action;
548 QList<QAction *> actions = o->findChildren<QAction *>();
549 for (int n=0; n < actions.count(); n++) {
550 action = static_cast<QAction*> (actions[n]);
551 if (!action->objectName().isEmpty() && !action->inherits("QWidgetAction")) {
552#if USE_MULTIPLE_SHORTCUTS
553 QString accelText = shortcutsToString(action->shortcuts());
554#else
555 QString accelText = action->shortcut().toString();
556#endif
557 set->setValue(action->objectName(), accelText);
558 }
559 }
560
561 set->endGroup();
562}
563
564
565void ActionsEditor::loadFromConfig(QObject *o, QSettings *set) {
566 qDebug("ActionsEditor::loadFromConfig");
567
568 set->beginGroup("actions");
569
570 QAction *action;
571 QString accelText;
572
573 QList<QAction *> actions = o->findChildren<QAction *>();
574 for (int n=0; n < actions.count(); n++) {
575 action = static_cast<QAction*> (actions[n]);
576 if (!action->objectName().isEmpty() && !action->inherits("QWidgetAction")) {
577#if USE_MULTIPLE_SHORTCUTS
578 QString current = shortcutsToString(action->shortcuts());
579 accelText = set->value(action->objectName(), current).toString();
580 action->setShortcuts( stringToShortcuts( accelText ) );
581#else
582 accelText = set->value(action->objectName(), action->shortcut().toString()).toString();
583 action->setShortcut(QKeySequence(accelText));
584#endif
585 }
586 }
587
588 set->endGroup();
589}
590
591QAction * ActionsEditor::findAction(QObject *o, const QString & name) {
592 QAction *action;
593
594 QList<QAction *> actions = o->findChildren<QAction *>();
595 for (int n=0; n < actions.count(); n++) {
596 action = static_cast<QAction*> (actions[n]);
597 if (name == action->objectName()) return action;
598 }
599
600 return 0;
601}
602
603QStringList ActionsEditor::actionsNames(QObject *o) {
604 QStringList l;
605
606 QAction *action;
607
608 QList<QAction *> actions = o->findChildren<QAction *>();
609 for (int n=0; n < actions.count(); n++) {
610 action = static_cast<QAction*> (actions[n]);
611 //qDebug("action name: '%s'", action->objectName().toUtf8().data());
612 //qDebug("action name: '%s'", action->text().toUtf8().data());
613 if (!action->objectName().isEmpty())
614 l.append( action->objectName() );
615 }
616
617 return l;
618}
619
620
621// Language change stuff
622void ActionsEditor::changeEvent(QEvent *e) {
623 if (e->type() == QEvent::LanguageChange) {
624 retranslateStrings();
625 } else {
626 QWidget::changeEvent(e);
627 }
628}
629
630#include "moc_actionseditor.cpp"
Note: See TracBrowser for help on using the repository browser.