Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 209516 Details for
Bug 292233
>=kde-base/klipper-4.3.1: actions are not triggered if their count is 0
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
klipper-empty-actions.patch
klipper-empty-actions.patch (text/plain), 40.57 KB, created by
Fabio Rossi
on 2009-11-07 09:48:55 UTC
(
hide
)
Description:
klipper-empty-actions.patch
Filename:
MIME Type:
Creator:
Fabio Rossi
Created:
2009-11-07 09:48:55 UTC
Size:
40.57 KB
patch
obsolete
>--- klipper/CMakeLists.txt 2009/10/10 07:49:10 1033401 >+++ klipper/CMakeLists.txt 2009/10/10 07:52:36 1033402 >@@ -14,6 +14,7 @@ > historyurlitem.cpp > actionstreewidget.cpp > editactiondialog.cpp >+ clipcommandprocess.cpp > ) > > kde4_add_ui_files(libklipper_common_SRCS generalconfig.ui actionsconfig.ui editactiondialog.ui) >--- klipper/editactiondialog.cpp 2009/10/10 07:49:10 1033401 >+++ klipper/editactiondialog.cpp 2009/10/10 07:52:36 1033402 >@@ -25,6 +25,237 @@ > #include "urlgrabber.h" > > #include "ui_editactiondialog.h" >+#include <QItemDelegate> >+#include <QComboBox> >+ >+namespace { >+ static QString output2text(ClipCommand::Output output) { >+ switch(output) { >+ case ClipCommand::IGNORE: >+ return QString(i18n("Ignore")); >+ case ClipCommand::REPLACE: >+ return QString(i18n("Replace")); >+ case ClipCommand::ADD: >+ return QString(i18n("Add")); >+ } >+ return QString(); >+ } >+ >+} >+ >+/** >+ * Show dropdown of editing Output part of commands >+ */ >+class ActionOutputDelegate : public QItemDelegate { >+ public: >+ ActionOutputDelegate(QObject* parent = 0) : QItemDelegate(parent){ >+ } >+ >+ virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const { >+ QComboBox* editor = new QComboBox(parent); >+ editor->setInsertPolicy(QComboBox::NoInsert); >+ editor->addItem(output2text(ClipCommand::IGNORE), QVariant::fromValue<ClipCommand::Output>(ClipCommand::IGNORE)); >+ editor->addItem(output2text(ClipCommand::REPLACE), QVariant::fromValue<ClipCommand::Output>(ClipCommand::REPLACE)); >+ editor->addItem(output2text(ClipCommand::ADD), QVariant::fromValue<ClipCommand::Output>(ClipCommand::ADD)); >+ return editor; >+ >+ } >+ >+ virtual void setEditorData(QWidget* editor, const QModelIndex& index) const { >+ QComboBox* ed = static_cast<QComboBox*>(editor); >+ QVariant data(index.model()->data(index, Qt::EditRole)); >+ ed->setCurrentIndex(static_cast<int>(data.value<ClipCommand::Output>())); >+ } >+ >+ virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { >+ QComboBox* ed = static_cast<QComboBox*>(editor); >+ model->setData(index, ed->itemData(ed->currentIndex())); >+ } >+ >+ virtual void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const { >+ editor->setGeometry(option.rect); >+ } >+}; >+ >+class ActionDetailModel : public QAbstractTableModel { >+ public: >+ ActionDetailModel(ClipAction* action, QObject* parent = 0); >+ virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; >+ virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); >+ virtual Qt::ItemFlags flags(const QModelIndex& index) const; >+ virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; >+ virtual int columnCount(const QModelIndex& parent) const; >+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; >+ const QList<ClipCommand>& commands() const { return m_commands; } >+ void addCommand(const ClipCommand& command); >+ void removeCommand(const QModelIndex& index); >+ >+ private: >+ enum column_t { >+ COMMAND_COL = 0, >+ OUTPUT_COL = 1, >+ DESCRIPTION_COL = 2 >+ }; >+ QList<ClipCommand> m_commands; >+ QVariant displayData(ClipCommand* command, column_t colunm) const; >+ QVariant editData(ClipCommand* command, column_t column) const; >+ QVariant decorationData(ClipCommand* command, column_t column) const; >+ void setIconForCommand(ClipCommand& cmd); >+}; >+ >+ActionDetailModel::ActionDetailModel(ClipAction* action, QObject* parent): >+ QAbstractTableModel(parent), >+ m_commands(action->commands()) >+{ >+ >+} >+ >+Qt::ItemFlags ActionDetailModel::flags(const QModelIndex& /*index*/) const >+{ >+ return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; >+} >+ >+ >+void ActionDetailModel::setIconForCommand(ClipCommand& cmd) >+{ >+ // let's try to update icon of the item according to command >+ QString command = cmd.command; >+ if ( command.contains( ' ' ) ) { >+ // get first word >+ command = command.section( ' ', 0, 0 ); >+ } >+ >+ QPixmap iconPix = KIconLoader::global()->loadIcon( >+ command, KIconLoader::Small, 0, >+ KIconLoader::DefaultState, >+ QStringList(), 0, true /* canReturnNull */ ); >+ >+ if ( !iconPix.isNull() ) { >+ cmd.pixmap = command; >+ } else { >+ cmd.pixmap.clear(); >+ } >+ >+} >+ >+bool ActionDetailModel::setData(const QModelIndex& index, const QVariant& value, int role) >+{ >+ if (role == Qt::EditRole) { >+ ClipCommand cmd = m_commands.at(index.row()); >+ switch (static_cast<column_t>(index.column())) { >+ case COMMAND_COL: >+ cmd.command = value.value<QString>(); >+ setIconForCommand(cmd); >+ break; >+ case OUTPUT_COL: >+ cmd.output = value.value<ClipCommand::Output>(); >+ break; >+ case DESCRIPTION_COL: >+ cmd.description = value.value<QString>(); >+ break; >+ } >+ m_commands.replace(index.row(), cmd); >+ emit dataChanged(index, index); >+ return true; >+ } >+ return false; >+} >+ >+int ActionDetailModel::columnCount(const QModelIndex& /*parent*/) const >+{ >+ return 3; >+} >+ >+int ActionDetailModel::rowCount(const QModelIndex&) const >+{ >+ return m_commands.count(); >+} >+ >+QVariant ActionDetailModel::displayData(ClipCommand* command, ActionDetailModel::column_t column) const >+{ >+ switch (column) { >+ case COMMAND_COL: >+ return command->command; >+ case OUTPUT_COL: >+ return output2text(command->output); >+ case DESCRIPTION_COL: >+ return command->description; >+ } >+ return QVariant(); >+} >+ >+QVariant ActionDetailModel::decorationData(ClipCommand* command, ActionDetailModel::column_t column) const >+{ >+ switch (column) { >+ case COMMAND_COL: >+ return command->pixmap.isEmpty() ? KIcon( "system-run" ) : KIcon( command->pixmap ); >+ case OUTPUT_COL: >+ case DESCRIPTION_COL: >+ break; >+ } >+ return QVariant(); >+ >+} >+ >+QVariant ActionDetailModel::editData(ClipCommand* command, ActionDetailModel::column_t column) const >+{ >+ switch (column) { >+ case COMMAND_COL: >+ return command->command; >+ case OUTPUT_COL: >+ return QVariant::fromValue<ClipCommand::Output>(command->output); >+ case DESCRIPTION_COL: >+ return command->description; >+ } >+ return QVariant(); >+ >+} >+ >+QVariant ActionDetailModel::headerData(int section, Qt::Orientation orientation, int role) const >+{ >+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { >+ switch(static_cast<column_t>(section)) { >+ case COMMAND_COL: >+ return i18n("Command"); >+ case OUTPUT_COL: >+ return i18n("Use Output"); >+ case DESCRIPTION_COL: >+ return i18n("Description"); >+ } >+ } >+ return QAbstractTableModel::headerData(section, orientation, role); >+} >+ >+ >+QVariant ActionDetailModel::data(const QModelIndex& index, int role) const >+{ >+ const int column = index.column(); >+ const int row = index.row(); >+ ClipCommand cmd = m_commands.at(row); >+ switch (role) { >+ case Qt::DisplayRole: >+ return displayData(&cmd, static_cast<column_t>(column)); >+ case Qt::DecorationRole: >+ return decorationData(&cmd, static_cast<column_t>(column)); >+ case Qt::EditRole: >+ return editData(&cmd, static_cast<column_t>(column)); >+ } >+ return QVariant(); >+} >+ >+void ActionDetailModel::addCommand(const ClipCommand& command) { >+ beginInsertRows(QModelIndex(), rowCount(), rowCount()); >+ m_commands << command; >+ endInsertRows(); >+} >+ >+void ActionDetailModel::removeCommand(const QModelIndex& index) { >+ int row = index.row(); >+ beginRemoveRows(QModelIndex(), row, row); >+ m_commands.removeAt(row); >+ endRemoveRows(); >+ >+} > > EditActionDialog::EditActionDialog(QWidget* parent) > : KDialog(parent) >@@ -39,19 +270,14 @@ > m_ui->pbAddCommand->setIcon(KIcon("list-add")); > m_ui->pbRemoveCommand->setIcon(KIcon("list-remove")); > >- m_ui->twCommandList->header()->resizeSection( 0, 170 ); >- >+ // For some reason, the default row height is 30 pixel. Set it to the minimum sectionSize instead, >+ // which is the font height+struts. >+ m_ui->twCommandList->verticalHeader()->setDefaultSectionSize(m_ui->twCommandList->verticalHeader()->minimumSectionSize()); > setMainWidget(dlgWidget); > >- connect(m_ui->twCommandList, SIGNAL(itemSelectionChanged()), SLOT(onSelectionChanged())); >- connect(m_ui->twCommandList, SIGNAL(itemChanged(QTreeWidgetItem*, int)), >- SLOT(onItemChanged(QTreeWidgetItem*, int))); >- > connect(m_ui->pbAddCommand, SIGNAL( clicked() ), SLOT( onAddCommand() ) ); > connect(m_ui->pbRemoveCommand, SIGNAL( clicked() ), SLOT( onRemoveCommand() ) ); > >- // update Remove button >- onSelectionChanged(); > } > > EditActionDialog::~EditActionDialog() >@@ -62,6 +288,10 @@ > void EditActionDialog::setAction(ClipAction* act, int commandIdxToSelect) > { > m_action = act; >+ m_model = new ActionDetailModel(act, this); >+ m_ui->twCommandList->setModel(m_model); >+ m_ui->twCommandList->setItemDelegateForColumn(1, new ActionOutputDelegate); >+ connect(m_ui->twCommandList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(onSelectionChanged())); > > updateWidgets( commandIdxToSelect ); > } >@@ -73,25 +303,12 @@ > return; > } > >- m_ui->twCommandList->clear(); >- > m_ui->leRegExp->setText(m_action->regExp()); >+ m_ui->automatic->setChecked(m_action->automatic()); > m_ui->leDescription->setText(m_action->description()); > >- foreach( const ClipCommand& cmd, m_action->commands() ) { >- QTreeWidgetItem* item = new QTreeWidgetItem; >- item->setFlags( item->flags() | Qt::ItemIsEditable ); >- >- item->setText( 0, cmd.command ); >- QString iconName = cmd.pixmap.isEmpty() ? "system-run" : cmd.pixmap; >- item->setIcon( 0, KIcon( iconName ) ); >- item->setData( 0, Qt::UserRole, iconName ); // store icon name too >- item->setText( 1, cmd.description ); >- m_ui->twCommandList->addTopLevelItem( item ); >- } >- > if (commandIdxToSelect != -1) { >- m_ui->twCommandList->setCurrentItem( m_ui->twCommandList->topLevelItem( commandIdxToSelect ) ); >+ m_ui->twCommandList->setCurrentIndex( m_model->index( commandIdxToSelect ,0 ) ); > } > > // update Remove button >@@ -107,16 +324,12 @@ > > m_action->setRegExp( m_ui->leRegExp->text() ); > m_action->setDescription( m_ui->leDescription->text() ); >+ m_action->setAutomatic( m_ui->automatic->isChecked() ); > > m_action->clearCommands(); > >- int cmdCount = m_ui->twCommandList->topLevelItemCount(); >- for ( int i=0; i<cmdCount; ++i ) { >- QTreeWidgetItem* item = m_ui->twCommandList->topLevelItem( i ); >- // we store icon name in Qt::UserRole in first column >- // (see onItemChanged()) >- QString iconName = item->data( 0, Qt::UserRole ).toString(); >- m_action->addCommand( item->text( 0 ), item->text( 1 ), true, iconName ); >+ foreach ( const ClipCommand& cmd, m_model->commands() ){ >+ m_action->addCommand( cmd ); > } > } > >@@ -131,54 +344,21 @@ > > void EditActionDialog::onAddCommand() > { >- QTreeWidgetItem *item = new QTreeWidgetItem; >- item->setFlags( item->flags() | Qt::ItemIsEditable ); >- item->setText( 0, i18n( "new command" ) ); >- item->setIcon( 0, KIcon( "system-run" ) ); >- item->setText( 1, i18n( "Command Description" ) ); >- >- m_ui->twCommandList->addTopLevelItem( item ); >- m_ui->twCommandList->editItem( item ); >+ m_model->addCommand(ClipCommand(i18n( "new command" ), >+ i18n( "Command Description" ), >+ true, >+ "" )); >+ m_ui->twCommandList->edit( m_model->index( m_model->rowCount()-1, 0 )); > } > > void EditActionDialog::onRemoveCommand() > { >- QTreeWidgetItem* curItem = m_ui->twCommandList->currentItem(); >- delete curItem; >-} >- >-void EditActionDialog::onItemChanged( QTreeWidgetItem* item, int column ) >-{ >- if ( column == 0 ) { >- // let's try to update icon of the item according to command >- QString command = item->text( 0 ); >- if ( command.contains( ' ' ) ) >- // get first word >- command = command.section( ' ', 0, 0 ); >- >- QPixmap iconPix = KIconLoader::global()->loadIcon( >- command, KIconLoader::Small, 0, >- KIconLoader::DefaultState, >- QStringList(), 0, true /* canReturnNull */ ); >- >- // block signals to prevent infinite recursion when setIcon will trigger itemChanged again >- m_ui->twCommandList->blockSignals( true ); >- >- if ( !iconPix.isNull() ) { >- item->setIcon( 0, KIcon( command ) ); >- // let's save icon name in data field (if we found something that is not "system-run") >- item->setData( 0, Qt::UserRole, command ); // command is actually the icon name here :) >- } else { >- item->setIcon( 0, KIcon( "system-run" ) ); >- } >- >- m_ui->twCommandList->blockSignals( false ); >- } >+ m_model->removeCommand(m_ui->twCommandList->selectionModel()->currentIndex()); > } > > void EditActionDialog::onSelectionChanged() > { >- m_ui->pbRemoveCommand->setEnabled( !m_ui->twCommandList->selectedItems().isEmpty() ); >+ m_ui->pbRemoveCommand->setEnabled( m_ui->twCommandList->selectionModel() && m_ui->twCommandList->selectionModel()->hasSelection() ); > } > > #include "editactiondialog.moc" >--- klipper/editactiondialog.h 2009/10/10 07:49:10 1033401 >+++ klipper/editactiondialog.h 2009/10/10 07:52:36 1033402 >@@ -29,7 +29,7 @@ > } > > class ClipAction; >-class QTreeWidgetItem; >+class ActionDetailModel; > > class EditActionDialog : public KDialog > { >@@ -47,7 +47,7 @@ > void onAddCommand(); > void onRemoveCommand(); > void onSelectionChanged(); >- void onItemChanged( QTreeWidgetItem*, int ); >+// void onItemChanged( QTreeWidgetItem*, int ); > > private: > /** >@@ -68,5 +68,6 @@ > Ui::EditActionDialog* m_ui; > > ClipAction* m_action; >+ ActionDetailModel* m_model; > }; > #endif >--- klipper/editactiondialog.ui 2009/10/10 07:49:10 1033401 >+++ klipper/editactiondialog.ui 2009/10/10 07:52:36 1033402 >@@ -56,6 +56,29 @@ > </property> > </widget> > </item> >+ <item row="1" column="1"> >+ <widget class="QLabel" name="label_5"> >+ <property name="text"> >+ <string>Automatic:</string> >+ </property> >+ <property name="alignment"> >+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> >+ </property> >+ <property name="buddy"> >+ <cstring>automatic</cstring> >+ </property> >+ </widget> >+ </item> >+ <item row="1" column="2"> >+ <widget class="QCheckBox" name="automatic"> >+ <property name="layoutDirection"> >+ <enum>Qt::LeftToRight</enum> >+ </property> >+ <property name="text"> >+ <string/> >+ </property> >+ </widget> >+ </item> > </layout> > </item> > <item row="3" column="0" colspan="2"> >@@ -65,23 +88,6 @@ > </property> > </widget> > </item> >- <item row="4" column="1"> >- <widget class="QTreeWidget" name="twCommandList"> >- <property name="toolTip"> >- <string>Double-click an item to edit</string> >- </property> >- <column> >- <property name="text"> >- <string>Command</string> >- </property> >- </column> >- <column> >- <property name="text"> >- <string>Description</string> >- </property> >- </column> >- </widget> >- </item> > <item row="1" column="0"> > <spacer name="horizontalSpacer"> > <property name="orientation"> >@@ -164,8 +170,50 @@ > </property> > </spacer> > </item> >+ <item row="4" column="1"> >+ <widget class="QTableView" name="twCommandList"> >+ <property name="toolTip"> >+ <string>Double-click an item to edit</string> >+ </property> >+ <property name="alternatingRowColors"> >+ <bool>true</bool> >+ </property> >+ <property name="selectionMode"> >+ <enum>QAbstractItemView::SingleSelection</enum> >+ </property> >+ <property name="selectionBehavior"> >+ <enum>QAbstractItemView::SelectRows</enum> >+ </property> >+ <property name="showGrid"> >+ <bool>false</bool> >+ </property> >+ <property name="gridStyle"> >+ <enum>Qt::NoPen</enum> >+ </property> >+ <property name="wordWrap"> >+ <bool>false</bool> >+ </property> >+ <attribute name="horizontalHeaderStretchLastSection"> >+ <bool>true</bool> >+ </attribute> >+ <attribute name="verticalHeaderVisible"> >+ <bool>false</bool> >+ </attribute> >+ <attribute name="verticalHeaderStretchLastSection"> >+ <bool>false</bool> >+ </attribute> >+ </widget> >+ </item> > </layout> > </widget> >+ <tabstops> >+ <tabstop>twCommandList</tabstop> >+ <tabstop>leRegExp</tabstop> >+ <tabstop>automatic</tabstop> >+ <tabstop>leDescription</tabstop> >+ <tabstop>pbRemoveCommand</tabstop> >+ <tabstop>pbAddCommand</tabstop> >+ </tabstops> > <resources/> > <connections/> > </ui> >--- klipper/history.cpp 2009/10/10 07:49:10 1033401 >+++ klipper/history.cpp 2009/10/10 07:52:36 1033402 >@@ -49,9 +49,11 @@ > > m_topIsUserSelected = false; > >- // Optimization: Compare with top item. >+ // OptimizationCompare with top item. If identical, the top isn't changing > if ( !itemList.isEmpty() && *itemList.first() == *item ) { >- delete item; >+ const HistoryItem* top = itemList.first(); >+ itemList.first() = item; >+ delete top; > return; > } > >@@ -85,6 +87,7 @@ > if ( !newItem ) > return; > >+ // TODO: This is rather broken.. it only checks by pointer! > if (itemList.contains(newItem)) { > itemList.removeAll(newItem); > emit changed(); >--- klipper/klipper.cpp 2009/10/10 07:49:10 1033401 >+++ klipper/klipper.cpp 2009/10/10 07:52:36 1033402 >@@ -158,7 +158,7 @@ > /* > * Create URL grabber > */ >- m_myURLGrabber = new URLGrabber(); >+ m_myURLGrabber = new URLGrabber(m_history); > connect( m_myURLGrabber, SIGNAL( sigPopup( QMenu * )), > SLOT( showPopupMenu( QMenu * )) ); > connect( m_myURLGrabber, SIGNAL( sigDisablePopup() ), >@@ -545,7 +545,7 @@ > { > const HistoryStringItem* top = dynamic_cast<const HistoryStringItem*>( history()->first() ); > if ( top ) { >- m_myURLGrabber->invokeAction( top->text() ); >+ m_myURLGrabber->invokeAction( top ); > } > } > >@@ -618,12 +618,15 @@ > return 0; > } > >-void Klipper::applyClipChanges( const QMimeData* clipData ) >+HistoryItem* Klipper::applyClipChanges( const QMimeData* clipData ) > { >- if ( m_locklevel ) >- return; >+ if ( m_locklevel ) { >+ return 0L; >+ } > Ignore lock( m_locklevel ); >- history()->insert( HistoryItem::create( clipData ) ); >+ HistoryItem* item = HistoryItem::create( clipData ); >+ history()->insert( item ); >+ return item; > > } > >@@ -798,44 +801,31 @@ > m_lastClipboard = data->serialNumber(); > #endif > >+ HistoryItem* item = applyClipChanges( data ); >+ if (changed) { >+#ifdef NOISY_KLIPPER >+ kDebug() << "Synchronize?" << m_bSynchronize; >+#endif >+ if ( m_bSynchronize && item ) { >+ setClipboard( *item, selectionMode ? Clipboard : Selection ); >+ } >+ } > QString& lastURLGrabberText = selectionMode > ? m_lastURLGrabberTextSelection : m_lastURLGrabberTextClipboard; >- if( data->hasText() ) >+ if( m_bURLGrabber && item && data->hasText()) > { >- if ( m_bURLGrabber ) >- { >- QString text = data->text(); >+ m_myURLGrabber->checkNewData( item ); > >- // Make sure URLGrabber doesn't repeat all the time if klipper reads the same >- // text all the time (e.g. because XFixes is not available and the application >- // has broken TIMESTAMP target). Using most recent history item may not always >- // work. >- if ( text != lastURLGrabberText ) >- { >- lastURLGrabberText = text; >- if ( m_myURLGrabber->checkNewData( text ) ) >- { >- return; // don't add into the history >- } >- } >+ // Make sure URLGrabber doesn't repeat all the time if klipper reads the same >+ // text all the time (e.g. because XFixes is not available and the application >+ // has broken TIMESTAMP target). Using most recent history item may not always >+ // work. >+ if ( item->text() != lastURLGrabberText ) >+ { >+ lastURLGrabberText = item->text(); > } >- else >- lastURLGrabberText = QString(); >- } >- else >+ } else { > lastURLGrabberText = QString(); >- >- if (changed) { >- applyClipChanges( data ); >-#ifdef NOISY_KLIPPER >- kDebug() << "Synchronize?" << m_bSynchronize; >-#endif >- if ( m_bSynchronize ) { >- const HistoryItem* topItem = history()->first(); >- if ( topItem ) { >- setClipboard( *topItem, selectionMode ? Clipboard : Selection ); >- } >- } > } > } > >--- klipper/klipper.h 2009/10/10 07:49:10 1033401 >+++ klipper/klipper.h 2009/10/10 07:52:36 1033402 >@@ -123,7 +123,7 @@ > /** > * Enter clipboard data in the history. > */ >- void applyClipChanges( const QMimeData* data ); >+ HistoryItem* applyClipChanges( const QMimeData* data ); > > void setClipboard( const HistoryItem& item, int mode ); > bool ignoreClipboardChanges() const; >--- klipper/urlgrabber.cpp 2009/10/10 07:49:10 1033401 >+++ klipper/urlgrabber.cpp 2009/10/10 07:52:36 1033402 >@@ -30,7 +30,6 @@ > #include <ktextedit.h> > #include <klocale.h> > #include <kmenu.h> >-#include <kprocess.h> > #include <kservice.h> > #include <kdebug.h> > #include <kstringhandler.h> >@@ -41,18 +40,21 @@ > > #include "klippersettings.h" > #include "urlgrabber.h" >+#include "clipcommandprocess.h" > > // TODO: > // - script-interface? >+#include "history.h" >+#include "historystringitem.h" > >-URLGrabber::URLGrabber() >+URLGrabber::URLGrabber(History* history): >+ m_myCurrentAction(0L), >+ m_myMenu(0L), >+ m_myPopupKillTimer(new QTimer( this )), >+ m_myPopupKillTimeout(8), >+ m_trimmed(true), >+ m_history(history) > { >- m_myCurrentAction = 0L; >- m_myMenu = 0L; >- m_myPopupKillTimeout = 8; >- m_trimmed = true; >- >- m_myPopupKillTimer = new QTimer( this ); > m_myPopupKillTimer->setSingleShot( true ); > connect( m_myPopupKillTimer, SIGNAL( timeout() ), > SLOT( slotKillPopupMenu() )); >@@ -88,13 +90,9 @@ > // Called from Klipper::slotRepeatAction, i.e. by pressing Ctrl-Alt-R > // shortcut. I.e. never from clipboard monitoring > // >-void URLGrabber::invokeAction( const QString& clip ) >+void URLGrabber::invokeAction( const HistoryItem* item ) > { >- if ( !clip.isEmpty() ) >- m_myClipData = clip; >- if ( m_trimmed ) >- m_myClipData = m_myClipData.trimmed(); >- >+ m_myClipItem = item; > actionMenu( false ); > } > >@@ -153,14 +151,14 @@ > ClipAction* action = new ClipAction( QString(), mimetype->comment() ); > KService::List lst = KMimeTypeTrader::self()->query( mimetype->name(), "Application" ); > foreach( const KService::Ptr &service, lst ) { >- action->addCommand( service->exec(), service->name(), true, service->icon() ); >+ action->addCommand( ClipCommand( service->exec(), service->name(), true, service->icon() ) ); > } > if ( !lst.isEmpty() ) > m_myMatches.append( action ); > } > } > >-const ActionList& URLGrabber::matchingActions( const QString& clipData ) >+const ActionList& URLGrabber::matchingActions( const QString& clipData, bool automatically_invoked ) > { > m_myMatches.clear(); > >@@ -169,41 +167,37 @@ > > // now look for matches in custom user actions > foreach (ClipAction* action, m_myActions) { >- if ( action->matches( clipData ) ) >+ if ( action->matches( clipData ) && (action->automatic() || !automatically_invoked) ) { > m_myMatches.append( action ); >+ } > } > > return m_myMatches; > } > > >-bool URLGrabber::checkNewData( const QString& clipData ) >+void URLGrabber::checkNewData( const HistoryItem* item ) > { > // kDebug() << "** checking new data: " << clipData; >- m_myClipData = clipData; >- if ( m_trimmed ) >- m_myClipData = m_myClipData.trimmed(); >- >- if ( m_myActions.isEmpty() ) >- return false; >+ m_myClipItem = item; > > actionMenu( true ); // also creates m_myMatches >- >- return !m_myMatches.isEmpty(); > } > > >-void URLGrabber::actionMenu( bool wm_class_check ) >+void URLGrabber::actionMenu( bool automatically_invoked ) > { >- if ( m_myClipData.isEmpty() ) >- return; >- >- ActionList matchingActionsList = matchingActions( m_myClipData ); >+ QString text(m_myClipItem->text()); >+ if (m_trimmed) { >+ text.trimmed(); >+ } >+ ActionList matchingActionsList = matchingActions( text, automatically_invoked ); > > if (!matchingActionsList.isEmpty()) { >- // don't react on konqi's/netscape's urls... >- if ( wm_class_check && isAvoidedWindow() ) >+ // don't react on blacklisted (e.g. konqi's/netscape's urls) unless the user explicitly asked for it >+ if ( automatically_invoked && isAvoidedWindow() ) { > return; >+ } > > m_myCommandMapper.clear(); > >@@ -215,7 +209,7 @@ > > foreach (ClipAction* clipAct, matchingActionsList) { > m_myMenu->addTitle(KIcon( "klipper" ), >- i18n("%1 - Actions For: %2", clipAct->description(), KStringHandler::csqueeze(m_myClipData, 45))); >+ i18n("%1 - Actions For: %2", clipAct->description(), KStringHandler::csqueeze(text, 45))); > QList<ClipCommand> cmdList = clipAct->commands(); > int listSize = cmdList.count(); > for (int i=0; i<listSize;++i) { >@@ -240,7 +234,7 @@ > > // only insert this when invoked via clipboard monitoring, not from an > // explicit Ctrl-Alt-R >- if ( wm_class_check ) >+ if ( automatically_invoked ) > { > m_myMenu->addSeparator(); > QAction *disableAction = new QAction(i18n("Disable This Popup"), this); >@@ -297,36 +291,26 @@ > ClipCommand command = action->command(cmdIdx); > > if ( command.isEnabled ) { >- QHash<QChar,QString> map; >- map.insert( 's', m_myClipData ); >- >- // support %u, %U (indicates url param(s)) and %f, %F (file param(s)) >- map.insert( 'u', m_myClipData ); >- map.insert( 'U', m_myClipData ); >- map.insert( 'f', m_myClipData ); >- map.insert( 'F', m_myClipData ); >- >- const QStringList matches = action->regExpMatches(); >- // support only %0 and the first 9 matches... >- const int numMatches = qMin(10, matches.count()); >- for ( int i = 0; i < numMatches; ++i ) >- map.insert( QChar( '0' + i ), matches.at( i ) ); >- >- QString cmdLine = KMacroExpander::expandMacrosShellQuote( command.command, map ); >- >- if ( cmdLine.isEmpty() ) >- return; >- >- KProcess proc; >- proc.setShellCommand(cmdLine.trimmed()); >- if (!proc.startDetached()) >- kDebug() << "Klipper: Could not start process!"; >+ QString text(m_myClipItem->text()); >+ if (m_trimmed) { >+ text.trimmed(); >+ } >+ ClipCommandProcess* proc = new ClipCommandProcess(*action, command, text, m_history, m_myClipItem); >+ if (proc->program().isEmpty()) { >+ delete proc; >+ proc = 0L; >+ } else { >+ proc->start(); >+ } > } > } > > > void URLGrabber::editData() > { >+ if (!m_myClipItem) { >+ return; >+ } > m_myPopupKillTimer->stop(); > KDialog *dlg = new KDialog( 0 ); > dlg->setModal( true ); >@@ -334,14 +318,16 @@ > dlg->setButtons( KDialog::Ok | KDialog::Cancel ); > > KTextEdit *edit = new KTextEdit( dlg ); >- edit->setText( m_myClipData ); >+ edit->setText( m_myClipItem->text() ); > edit->setFocus(); > edit->setMinimumSize( 300, 40 ); > dlg->setMainWidget( edit ); > dlg->adjustSize(); > > if ( dlg->exec() == KDialog::Accepted ) { >- m_myClipData = edit->toPlainText(); >+ QString text = edit->toPlainText(); >+ m_history->remove( m_myClipItem ); >+ m_history->insert( new HistoryStringItem(text) ); > QTimer::singleShot( 0, this, SLOT( slotActionMenu() ) ); > } > else >@@ -454,10 +440,11 @@ > //////// > > ClipCommand::ClipCommand(const QString &_command, const QString &_description, >- bool _isEnabled, const QString &_icon) >+ bool _isEnabled, const QString &_icon, Output _output) > : command(_command), > description(_description), >- isEnabled(_isEnabled) >+ isEnabled(_isEnabled), >+ output(_output) > { > > if (!_icon.isEmpty()) >@@ -481,14 +468,15 @@ > } > > >-ClipAction::ClipAction( const QString& regExp, const QString& description ) >- : m_myRegExp( regExp ), m_myDescription( description ) >+ClipAction::ClipAction( const QString& regExp, const QString& description, bool automatic ) >+ : m_myRegExp( regExp ), m_myDescription( description ), m_automatic(automatic) > { > } > > ClipAction::ClipAction( KSharedConfigPtr kc, const QString& group ) > : m_myRegExp( kc->group(group).readEntry("Regexp") ), >- m_myDescription (kc->group(group).readEntry("Description") ) >+ m_myDescription (kc->group(group).readEntry("Description") ), >+ m_automatic(kc->group(group).readEntry("Automatic", QVariant(true)).toBool() ) > { > KConfigGroup cg(kc, group); > >@@ -499,10 +487,11 @@ > QString _group = group + "/Command_%1"; > KConfigGroup _cg(kc, _group.arg(i)); > >- addCommand( _cg.readPathEntry( "Commandline", QString() ), >- _cg.readEntry( "Description" ), // i18n'ed >- _cg.readEntry( "Enabled" , false), >- _cg.readEntry( "Icon") ); >+ addCommand( ClipCommand(_cg.readPathEntry( "Commandline", QString() ), >+ _cg.readEntry( "Description" ), // i18n'ed >+ _cg.readEntry( "Enabled" , false), >+ _cg.readEntry( "Icon"), >+ static_cast<ClipCommand::Output>(_cg.readEntry( "Output", QVariant(ClipCommand::IGNORE)).toInt()))); > } > } > >@@ -513,13 +502,12 @@ > } > > >-void ClipAction::addCommand( const QString& command, >- const QString& description, bool enabled, const QString& icon ) >+void ClipAction::addCommand( const ClipCommand& cmd ) > { >- if ( command.isEmpty() ) >+ if ( cmd.command.isEmpty() ) > return; > >- m_myCommands.append( ClipCommand(command, description, enabled, icon) ); >+ m_myCommands.append( cmd ); > } > > void ClipAction::replaceCommand( int idx, const ClipCommand& cmd ) >@@ -529,7 +517,7 @@ > return; > } > >- m_myCommands[idx] = cmd; >+ m_myCommands.replace(idx, cmd); > } > > >@@ -540,6 +528,7 @@ > cg.writeEntry( "Description", description() ); > cg.writeEntry( "Regexp", regExp() ); > cg.writeEntry( "Number of commands", m_myCommands.count() ); >+ cg.writeEntry( "Automatic", automatic() ); > > int i=0; > // now iterate over all commands of this action >@@ -551,6 +540,7 @@ > cg.writeEntry( "Description", cmd.description ); > cg.writeEntry( "Enabled", cmd.isEnabled ); > cg.writeEntry( "Icon", cmd.pixmap ); >+ cg.writeEntry( "Output", static_cast<int>(cmd.output) ); > > ++i; > } >--- klipper/urlgrabber.h 2009/10/10 07:49:10 1033401 >+++ klipper/urlgrabber.h 2009/10/10 07:52:36 1033402 >@@ -22,11 +22,17 @@ > > #include <QHash> > #include <QRegExp> >+#include <QStringList> >+#include <ksharedconfig.h> > >+class History; >+class HistoryItem; > class QTimer; > > class KConfig; > class KMenu; >+class QMenu; >+class QAction; > > class ClipAction; > struct ClipCommand; >@@ -37,7 +43,7 @@ > Q_OBJECT > > public: >- URLGrabber(); >+ URLGrabber(History* history); > ~URLGrabber(); > > /** >@@ -46,8 +52,8 @@ > * @returns false if the string should be put into the popupmenu or not, > * otherwise true. > */ >- bool checkNewData( const QString& clipData ); >- void invokeAction( const QString& clip = QString() ); >+ void checkNewData( const HistoryItem* item ); >+ void invokeAction( const HistoryItem* item ); > > ActionList actionList() const { return m_myActions; } > void setActionList( const ActionList& ); >@@ -65,7 +71,7 @@ > void setStripWhiteSpace( bool enable ) { m_trimmed = enable; } > > private: >- const ActionList& matchingActions( const QString& ); >+ const ActionList& matchingActions( const QString&, bool automatically_invoked ); > void execute( const ClipAction *action, int commandIdx ) const; > bool isAvoidedWindow() const; > void actionMenu( bool wm_class_check ); >@@ -74,7 +80,7 @@ > ActionList m_myActions; > ActionList m_myMatches; > QStringList m_myAvoidWindows; >- QString m_myClipData; >+ const HistoryItem* m_myClipItem; > ClipAction *m_myCurrentAction; > > // holds mappings of menu action IDs to action commands (action+cmd index in it) >@@ -83,6 +89,7 @@ > QTimer *m_myPopupKillTimer; > int m_myPopupKillTimeout; > bool m_trimmed; >+ History* m_history; > > private Q_SLOTS: > void slotActionMenu() { actionMenu( true ); } >@@ -90,7 +97,6 @@ > void slotKillPopupMenu(); > void editData(); > >- > Q_SIGNALS: > void sigPopup( QMenu * ); > void sigDisablePopup(); >@@ -100,15 +106,30 @@ > > struct ClipCommand > { >- ClipCommand( const QString & command, const QString & description, >- bool = true, const QString & icon = QString() ); >+ /** >+ * What to do with output of command >+ */ >+ enum Output { >+ IGNORE, // Discard output >+ REPLACE, // Replace clipboard entry with output >+ ADD // Add output as new clipboard element >+ }; >+ >+ ClipCommand( const QString & command, >+ const QString & description, >+ bool enabled= true, >+ const QString & icon = QString(), >+ Output output = IGNORE); > > QString command; > QString description; > bool isEnabled; > QString pixmap; >+ Output output; > }; > >+Q_DECLARE_METATYPE(ClipCommand::Output) >+ > /** > * Represents one configured action. An action consists of one regular > * expression, an (optional) description and a list of ClipCommands >@@ -118,7 +139,8 @@ > { > public: > explicit ClipAction( const QString& regExp = QString(), >- const QString& description = QString() ); >+ const QString& description = QString(), >+ bool automagic = true); > > ClipAction( KSharedConfigPtr kc, const QString& ); > ~ClipAction(); >@@ -133,15 +155,15 @@ > void setDescription( const QString& d) { m_myDescription = d; } > QString description() const { return m_myDescription; } > >+ void setAutomatic( bool automatic ) { m_automatic = automatic; } >+ bool automatic() const { return m_automatic; } >+ > /** > * Removes all ClipCommands associated with this ClipAction. > */ > void clearCommands() { m_myCommands.clear(); } > >- void addCommand( const QString& command, >- const QString& description, >- bool isEnabled = true, >- const QString& icon = QString() ); >+ void addCommand(const ClipCommand& cmd); > > /** > * Replaces command at index @p idx with command @p newCmd >@@ -165,6 +187,7 @@ > QRegExp m_myRegExp; > QString m_myDescription; > QList<ClipCommand> m_myCommands; >+ bool m_automatic; > > }; > >--- /dev/null 2009-11-06 21:46:15.231670585 +0100 >+++ klipper/clipcommandprocess.cpp 2009-11-07 02:00:47.444379231 +0100 >@@ -0,0 +1,82 @@ >+// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- >+/* >+ Copyright 2009 Esben Mose Hansen <kde@mosehansen.dk> >+ >+ This program is free software; you can redistribute it and/or modify >+ it under the terms of the GNU General Public License as published by >+ the Free Software Foundation; either version 2 of the License, or >+ (at your option) any later version. >+ >+ This program is distributed in the hope that it will be useful, >+ but WITHOUT ANY WARRANTY; without even the implied warranty of >+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ GNU General Public License for more details. >+ >+ You should have received a copy of the GNU General Public License along >+ with this program; if not, write to the Free Software Foundation, Inc., >+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+*/ >+ >+#include "clipcommandprocess.h" >+#include "history.h" >+#include "historystringitem.h" >+#include <KCharMacroExpander> >+#include "urlgrabber.h" >+ >+ClipCommandProcess::ClipCommandProcess(const ClipAction& action, const ClipCommand& command, const QString& clip, History* history, const HistoryItem* original_item) : >+ KProcess(), >+ m_history(history), >+ m_historyItem(original_item), >+ m_newhistoryItem() >+{ >+ QHash<QChar,QString> map; >+ map.insert( 's', clip ); >+ >+ // support %u, %U (indicates url param(s)) and %f, %F (file param(s)) >+ map.insert( 'u', clip ); >+ map.insert( 'U', clip ); >+ map.insert( 'f', clip ); >+ map.insert( 'F', clip ); >+ >+ const QStringList matches = action.regExpMatches(); >+ // support only %0 and the first 9 matches... >+ const int numMatches = qMin(10, matches.count()); >+ for ( int i = 0; i < numMatches; ++i ) { >+ map.insert( QChar( '0' + i ), matches.at( i ) ); >+ } >+ >+ setOutputChannelMode(OnlyStdoutChannel); >+ setShellCommand(KMacroExpander::expandMacrosShellQuote( command.command, map ).trimmed()); >+ >+ connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(slotFinished(int,QProcess::ExitStatus))); >+ if (command.output != ClipCommand::IGNORE) { >+ connect(this, SIGNAL(readyRead()), SLOT(slotStdOutputAvailable())); >+ } >+ if (command.output != ClipCommand::REPLACE) { >+ m_historyItem = 0L; // Don't replace >+ } >+ >+} >+ >+void ClipCommandProcess::slotFinished(int /*exitCode*/, QProcess::ExitStatus /*newState*/) >+{ >+ if (m_history) { >+ // If an history item was provided, remove it so that the new item can replace it >+ if (m_historyItem) { >+ m_history->remove(m_historyItem); >+ } >+ if (!m_newhistoryItem.isEmpty()) { >+ m_history->insert(new HistoryStringItem(m_newhistoryItem)); >+ } >+ } >+ deleteLater(); >+} >+ >+void ClipCommandProcess::slotStdOutputAvailable() >+{ >+ m_newhistoryItem.append(QString::fromLocal8Bit(this->readAllStandardOutput().data())); >+} >+ >+ >+#include "clipcommandprocess.moc" >--- /dev/null 2009-11-06 21:46:15.231670585 +0100 >+++ klipper/clipcommandprocess.h 2009-11-07 02:00:47.444379231 +0100 >@@ -0,0 +1,44 @@ >+// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- >+/* >+ Copyright 2009 Esben Mose Hansen <kde@mosehansen.dk> >+ >+ This program is free software; you can redistribute it and/or modify >+ it under the terms of the GNU General Public License as published by >+ the Free Software Foundation; either version 2 of the License, or >+ (at your option) any later version. >+ >+ This program is distributed in the hope that it will be useful, >+ but WITHOUT ANY WARRANTY; without even the implied warranty of >+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ GNU General Public License for more details. >+ >+ You should have received a copy of the GNU General Public License along >+ with this program; if not, write to the Free Software Foundation, Inc., >+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+*/ >+ >+#ifndef CLIPCOMMANDPROCESS_H >+#define CLIPCOMMANDPROCESS_H >+ >+#include <kprocess.h> >+ >+class ClipAction; >+class History; >+class ClipCommand; >+class HistoryItem; >+class ClipCommandProcess : public KProcess >+{ >+ Q_OBJECT >+public: >+ ClipCommandProcess(const ClipAction& action, const ClipCommand& command, const QString& clip, History* history = 0L, const HistoryItem* original_item = 0L); >+public slots: >+ void slotStdOutputAvailable(); >+ void slotFinished(int exitCode, QProcess::ExitStatus newState); >+private: >+ History* m_history; >+ const HistoryItem* m_historyItem; >+ QString m_newhistoryItem; >+}; >+ >+#endif // CLIPCOMMANDPROCESS_H
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 292233
: 209516