Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 292233
Collapse All | Expand All

(-)klipper/CMakeLists.txt (+1 lines)
Lines 14-19 Link Here
14
    historyurlitem.cpp
14
    historyurlitem.cpp
15
    actionstreewidget.cpp
15
    actionstreewidget.cpp
16
    editactiondialog.cpp
16
    editactiondialog.cpp
17
    clipcommandprocess.cpp
17
)
18
)
18
19
19
kde4_add_ui_files(libklipper_common_SRCS generalconfig.ui actionsconfig.ui editactiondialog.ui)
20
kde4_add_ui_files(libklipper_common_SRCS generalconfig.ui actionsconfig.ui editactiondialog.ui)
(-)klipper/editactiondialog.cpp (-70 / +250 lines)
Lines 25-30 Link Here
25
#include "urlgrabber.h"
25
#include "urlgrabber.h"
26
26
27
#include "ui_editactiondialog.h"
27
#include "ui_editactiondialog.h"
28
#include <QItemDelegate>
29
#include <QComboBox>
30
31
namespace {
32
    static QString output2text(ClipCommand::Output output) {
33
        switch(output) {
34
            case ClipCommand::IGNORE:
35
                return QString(i18n("Ignore"));
36
            case ClipCommand::REPLACE:
37
                return QString(i18n("Replace"));
38
            case ClipCommand::ADD:
39
                return QString(i18n("Add"));
40
        }
41
        return QString();
42
    }
43
44
}
45
46
/**
47
 * Show dropdown of editing Output part of commands
48
 */
49
class ActionOutputDelegate : public QItemDelegate {
50
    public:
51
        ActionOutputDelegate(QObject* parent = 0) : QItemDelegate(parent){
52
        }
53
54
        virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const {
55
            QComboBox* editor = new QComboBox(parent);
56
            editor->setInsertPolicy(QComboBox::NoInsert);
57
            editor->addItem(output2text(ClipCommand::IGNORE), QVariant::fromValue<ClipCommand::Output>(ClipCommand::IGNORE));
58
            editor->addItem(output2text(ClipCommand::REPLACE), QVariant::fromValue<ClipCommand::Output>(ClipCommand::REPLACE));
59
            editor->addItem(output2text(ClipCommand::ADD), QVariant::fromValue<ClipCommand::Output>(ClipCommand::ADD));
60
            return editor;
61
62
        }
63
64
        virtual void setEditorData(QWidget* editor, const QModelIndex& index) const {
65
            QComboBox* ed = static_cast<QComboBox*>(editor);
66
            QVariant data(index.model()->data(index, Qt::EditRole));
67
            ed->setCurrentIndex(static_cast<int>(data.value<ClipCommand::Output>()));
68
        }
69
70
        virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const {
71
            QComboBox* ed = static_cast<QComboBox*>(editor);
72
            model->setData(index, ed->itemData(ed->currentIndex()));
73
        }
74
75
        virtual void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const {
76
            editor->setGeometry(option.rect);
77
        }
78
};
79
80
class ActionDetailModel : public QAbstractTableModel {
81
    public:
82
        ActionDetailModel(ClipAction* action, QObject* parent = 0);
83
        virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
84
        virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
85
        virtual Qt::ItemFlags flags(const QModelIndex& index) const;
86
        virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
87
        virtual int columnCount(const QModelIndex& parent) const;
88
        virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
89
        const QList<ClipCommand>& commands() const { return m_commands; }
90
        void addCommand(const ClipCommand& command);
91
        void removeCommand(const QModelIndex& index);
92
93
    private:
94
        enum column_t {
95
            COMMAND_COL = 0,
96
            OUTPUT_COL = 1,
97
            DESCRIPTION_COL = 2
98
        };
99
        QList<ClipCommand> m_commands;
100
        QVariant displayData(ClipCommand* command, column_t colunm) const;
101
        QVariant editData(ClipCommand* command, column_t column) const;
102
        QVariant decorationData(ClipCommand* command, column_t column) const;
103
        void setIconForCommand(ClipCommand& cmd);
104
};
105
106
ActionDetailModel::ActionDetailModel(ClipAction* action, QObject* parent):
107
    QAbstractTableModel(parent),
108
    m_commands(action->commands())
109
{
110
111
}
112
113
Qt::ItemFlags ActionDetailModel::flags(const QModelIndex& /*index*/) const
114
{
115
    return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
116
}
117
118
119
void ActionDetailModel::setIconForCommand(ClipCommand& cmd)
120
{
121
    // let's try to update icon of the item according to command
122
    QString command = cmd.command;
123
    if ( command.contains( ' ' ) ) {
124
        // get first word
125
        command = command.section( ' ', 0, 0 );
126
    }
127
128
    QPixmap iconPix = KIconLoader::global()->loadIcon(
129
                                        command, KIconLoader::Small, 0,
130
                                        KIconLoader::DefaultState,
131
                                        QStringList(), 0, true /* canReturnNull */ );
132
133
    if ( !iconPix.isNull() ) {
134
        cmd.pixmap = command;
135
    } else {
136
        cmd.pixmap.clear();
137
    }
138
139
}
140
141
bool ActionDetailModel::setData(const QModelIndex& index, const QVariant& value, int role)
142
{
143
    if (role == Qt::EditRole) {
144
        ClipCommand cmd = m_commands.at(index.row());
145
        switch (static_cast<column_t>(index.column())) {
146
            case COMMAND_COL:
147
                cmd.command = value.value<QString>();
148
                setIconForCommand(cmd);
149
                break;
150
            case OUTPUT_COL:
151
                cmd.output = value.value<ClipCommand::Output>();
152
                break;
153
            case DESCRIPTION_COL:
154
                cmd.description = value.value<QString>();
155
                break;
156
        }
157
        m_commands.replace(index.row(), cmd);
158
        emit dataChanged(index, index);
159
        return true;
160
    }
161
    return false;
162
}
163
164
int ActionDetailModel::columnCount(const QModelIndex& /*parent*/) const
165
{
166
    return 3;
167
}
168
169
int ActionDetailModel::rowCount(const QModelIndex&) const
170
{
171
    return m_commands.count();
172
}
173
174
QVariant ActionDetailModel::displayData(ClipCommand* command, ActionDetailModel::column_t column) const
175
{
176
    switch (column) {
177
        case COMMAND_COL:
178
            return command->command;
179
        case OUTPUT_COL:
180
            return output2text(command->output);
181
        case DESCRIPTION_COL:
182
            return command->description;
183
    }
184
    return QVariant();
185
}
186
187
QVariant ActionDetailModel::decorationData(ClipCommand* command, ActionDetailModel::column_t column) const
188
{
189
    switch (column) {
190
        case COMMAND_COL:
191
            return command->pixmap.isEmpty() ? KIcon( "system-run" ) : KIcon( command->pixmap );
192
        case OUTPUT_COL:
193
        case DESCRIPTION_COL:
194
            break;
195
    }
196
    return QVariant();
197
198
}
199
200
QVariant ActionDetailModel::editData(ClipCommand* command, ActionDetailModel::column_t column) const
201
{
202
    switch (column) {
203
        case COMMAND_COL:
204
            return command->command;
205
        case OUTPUT_COL:
206
            return QVariant::fromValue<ClipCommand::Output>(command->output);
207
        case DESCRIPTION_COL:
208
            return command->description;
209
    }
210
    return QVariant();
211
212
}
213
214
QVariant ActionDetailModel::headerData(int section, Qt::Orientation orientation, int role) const
215
{
216
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
217
        switch(static_cast<column_t>(section)) {
218
        case COMMAND_COL:
219
            return i18n("Command");
220
        case OUTPUT_COL:
221
            return i18n("Use Output");
222
        case DESCRIPTION_COL:
223
            return i18n("Description");
224
        }
225
    }
226
    return QAbstractTableModel::headerData(section, orientation, role);
227
}
228
229
230
QVariant ActionDetailModel::data(const QModelIndex& index, int role) const
231
{
232
    const int column = index.column();
233
    const int row = index.row();
234
    ClipCommand cmd = m_commands.at(row);
235
    switch (role) {
236
        case Qt::DisplayRole:
237
            return displayData(&cmd, static_cast<column_t>(column));
238
        case Qt::DecorationRole:
239
            return decorationData(&cmd, static_cast<column_t>(column));
240
        case Qt::EditRole:
241
            return editData(&cmd, static_cast<column_t>(column));
242
    }
243
    return QVariant();
244
}
245
246
void ActionDetailModel::addCommand(const ClipCommand& command) {
247
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
248
    m_commands << command;
249
    endInsertRows();
250
}
251
252
void ActionDetailModel::removeCommand(const QModelIndex& index) {
253
    int row = index.row();
254
    beginRemoveRows(QModelIndex(), row, row);
255
    m_commands.removeAt(row);
256
    endRemoveRows();
257
258
}
28
259
29
EditActionDialog::EditActionDialog(QWidget* parent)
260
EditActionDialog::EditActionDialog(QWidget* parent)
30
    : KDialog(parent)
261
    : KDialog(parent)
Lines 39-57 Link Here
39
    m_ui->pbAddCommand->setIcon(KIcon("list-add"));
270
    m_ui->pbAddCommand->setIcon(KIcon("list-add"));
40
    m_ui->pbRemoveCommand->setIcon(KIcon("list-remove"));
271
    m_ui->pbRemoveCommand->setIcon(KIcon("list-remove"));
41
272
42
    m_ui->twCommandList->header()->resizeSection( 0, 170 );
273
    // For some reason, the default row height is 30 pixel. Set it to the minimum sectionSize instead,
43
274
    // which is the font height+struts.
275
    m_ui->twCommandList->verticalHeader()->setDefaultSectionSize(m_ui->twCommandList->verticalHeader()->minimumSectionSize());
44
    setMainWidget(dlgWidget);
276
    setMainWidget(dlgWidget);
45
277
46
    connect(m_ui->twCommandList, SIGNAL(itemSelectionChanged()), SLOT(onSelectionChanged()));
47
    connect(m_ui->twCommandList, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
48
            SLOT(onItemChanged(QTreeWidgetItem*, int)));
49
50
    connect(m_ui->pbAddCommand, SIGNAL( clicked() ), SLOT( onAddCommand() ) );
278
    connect(m_ui->pbAddCommand, SIGNAL( clicked() ), SLOT( onAddCommand() ) );
51
    connect(m_ui->pbRemoveCommand, SIGNAL( clicked() ), SLOT( onRemoveCommand() ) );
279
    connect(m_ui->pbRemoveCommand, SIGNAL( clicked() ), SLOT( onRemoveCommand() ) );
52
280
53
    // update Remove button
54
    onSelectionChanged();
55
}
281
}
56
282
57
EditActionDialog::~EditActionDialog()
283
EditActionDialog::~EditActionDialog()
Lines 62-67 Link Here
62
void EditActionDialog::setAction(ClipAction* act, int commandIdxToSelect)
288
void EditActionDialog::setAction(ClipAction* act, int commandIdxToSelect)
63
{
289
{
64
    m_action = act;
290
    m_action = act;
291
    m_model = new ActionDetailModel(act, this);
292
    m_ui->twCommandList->setModel(m_model);
293
    m_ui->twCommandList->setItemDelegateForColumn(1, new ActionOutputDelegate);
294
    connect(m_ui->twCommandList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(onSelectionChanged()));
65
295
66
    updateWidgets( commandIdxToSelect );
296
    updateWidgets( commandIdxToSelect );
67
}
297
}
Lines 73-97 Link Here
73
        return;
303
        return;
74
    }
304
    }
75
305
76
    m_ui->twCommandList->clear();
77
78
    m_ui->leRegExp->setText(m_action->regExp());
306
    m_ui->leRegExp->setText(m_action->regExp());
307
    m_ui->automatic->setChecked(m_action->automatic());
79
    m_ui->leDescription->setText(m_action->description());
308
    m_ui->leDescription->setText(m_action->description());
80
309
81
    foreach( const ClipCommand& cmd, m_action->commands() ) {
82
        QTreeWidgetItem* item = new QTreeWidgetItem;
83
        item->setFlags( item->flags() | Qt::ItemIsEditable );
84
85
        item->setText( 0, cmd.command );
86
        QString iconName = cmd.pixmap.isEmpty() ? "system-run" : cmd.pixmap;
87
        item->setIcon( 0, KIcon( iconName ) );
88
        item->setData( 0, Qt::UserRole, iconName ); // store icon name too
89
        item->setText( 1, cmd.description );
90
        m_ui->twCommandList->addTopLevelItem( item );
91
    }
92
93
    if (commandIdxToSelect != -1) {
310
    if (commandIdxToSelect != -1) {
94
        m_ui->twCommandList->setCurrentItem( m_ui->twCommandList->topLevelItem( commandIdxToSelect ) );
311
        m_ui->twCommandList->setCurrentIndex( m_model->index( commandIdxToSelect ,0 ) );
95
    }
312
    }
96
313
97
    // update Remove button
314
    // update Remove button
Lines 107-122 Link Here
107
324
108
    m_action->setRegExp( m_ui->leRegExp->text() );
325
    m_action->setRegExp( m_ui->leRegExp->text() );
109
    m_action->setDescription( m_ui->leDescription->text() );
326
    m_action->setDescription( m_ui->leDescription->text() );
327
    m_action->setAutomatic( m_ui->automatic->isChecked() );
110
328
111
    m_action->clearCommands();
329
    m_action->clearCommands();
112
330
113
    int cmdCount = m_ui->twCommandList->topLevelItemCount();
331
    foreach ( const ClipCommand& cmd, m_model->commands() ){
114
    for ( int i=0; i<cmdCount; ++i ) {
332
        m_action->addCommand( cmd );
115
        QTreeWidgetItem* item = m_ui->twCommandList->topLevelItem( i );
116
        // we store icon name in Qt::UserRole in first column
117
        // (see onItemChanged())
118
        QString iconName = item->data( 0, Qt::UserRole ).toString();
119
        m_action->addCommand( item->text( 0 ), item->text( 1 ), true, iconName );
120
    }
333
    }
121
}
334
}
122
335
Lines 131-184 Link Here
131
344
132
void EditActionDialog::onAddCommand()
345
void EditActionDialog::onAddCommand()
133
{
346
{
134
    QTreeWidgetItem *item = new QTreeWidgetItem;
347
    m_model->addCommand(ClipCommand(i18n( "new command" ),
135
    item->setFlags( item->flags() | Qt::ItemIsEditable );
348
                                    i18n( "Command Description" ),
136
    item->setText( 0, i18n( "new command" ) );
349
                                    true,
137
    item->setIcon( 0, KIcon( "system-run" ) );
350
                                    "" ));
138
    item->setText( 1, i18n( "Command Description" ) );
351
    m_ui->twCommandList->edit( m_model->index( m_model->rowCount()-1, 0 ));
139
140
    m_ui->twCommandList->addTopLevelItem( item );
141
    m_ui->twCommandList->editItem( item );
142
}
352
}
143
353
144
void EditActionDialog::onRemoveCommand()
354
void EditActionDialog::onRemoveCommand()
145
{
355
{
146
    QTreeWidgetItem* curItem = m_ui->twCommandList->currentItem();
356
    m_model->removeCommand(m_ui->twCommandList->selectionModel()->currentIndex());
147
    delete curItem;
148
}
149
150
void EditActionDialog::onItemChanged( QTreeWidgetItem* item, int column )
151
{
152
    if ( column == 0 ) {
153
        // let's try to update icon of the item according to command
154
        QString command = item->text( 0 );
155
        if ( command.contains( ' ' ) )
156
            // get first word
157
            command = command.section( ' ', 0, 0 );
158
159
        QPixmap iconPix = KIconLoader::global()->loadIcon(
160
                                         command, KIconLoader::Small, 0,
161
                                         KIconLoader::DefaultState,
162
                                         QStringList(), 0, true /* canReturnNull */ );
163
164
        // block signals to prevent infinite recursion when setIcon will trigger itemChanged again
165
        m_ui->twCommandList->blockSignals( true );
166
167
        if ( !iconPix.isNull() ) {
168
            item->setIcon( 0, KIcon( command ) );
169
            // let's save icon name in data field (if we found something that is not "system-run")
170
            item->setData( 0, Qt::UserRole, command ); // command is actually the icon name here :)
171
        } else {
172
            item->setIcon( 0, KIcon( "system-run" ) );
173
        }
174
175
        m_ui->twCommandList->blockSignals( false );
176
    }
177
}
357
}
178
358
179
void EditActionDialog::onSelectionChanged()
359
void EditActionDialog::onSelectionChanged()
180
{
360
{
181
    m_ui->pbRemoveCommand->setEnabled( !m_ui->twCommandList->selectedItems().isEmpty() );
361
    m_ui->pbRemoveCommand->setEnabled( m_ui->twCommandList->selectionModel() && m_ui->twCommandList->selectionModel()->hasSelection() );
182
}
362
}
183
363
184
#include "editactiondialog.moc"
364
#include "editactiondialog.moc"
(-)klipper/editactiondialog.h (-2 / +3 lines)
Lines 29-35 Link Here
29
}
29
}
30
30
31
class ClipAction;
31
class ClipAction;
32
class QTreeWidgetItem;
32
class ActionDetailModel;
33
33
34
class EditActionDialog : public KDialog
34
class EditActionDialog : public KDialog
35
{
35
{
Lines 47-53 Link Here
47
    void onAddCommand();
47
    void onAddCommand();
48
    void onRemoveCommand();
48
    void onRemoveCommand();
49
    void onSelectionChanged();
49
    void onSelectionChanged();
50
    void onItemChanged( QTreeWidgetItem*, int );
50
//    void onItemChanged( QTreeWidgetItem*, int );
51
51
52
private:
52
private:
53
    /**
53
    /**
Lines 68-72 Link Here
68
    Ui::EditActionDialog* m_ui;
68
    Ui::EditActionDialog* m_ui;
69
69
70
    ClipAction* m_action;
70
    ClipAction* m_action;
71
    ActionDetailModel* m_model;
71
};
72
};
72
#endif
73
#endif
(-)klipper/editactiondialog.ui (-17 / +65 lines)
Lines 56-61 Link Here
56
       </property>
56
       </property>
57
      </widget>
57
      </widget>
58
     </item>
58
     </item>
59
     <item row="1" column="1">
60
      <widget class="QLabel" name="label_5">
61
       <property name="text">
62
        <string>Automatic:</string>
63
       </property>
64
       <property name="alignment">
65
        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
66
       </property>
67
       <property name="buddy">
68
        <cstring>automatic</cstring>
69
       </property>
70
      </widget>
71
     </item>
72
     <item row="1" column="2">
73
      <widget class="QCheckBox" name="automatic">
74
       <property name="layoutDirection">
75
        <enum>Qt::LeftToRight</enum>
76
       </property>
77
       <property name="text">
78
        <string/>
79
       </property>
80
      </widget>
81
     </item>
59
    </layout>
82
    </layout>
60
   </item>
83
   </item>
61
   <item row="3" column="0" colspan="2">
84
   <item row="3" column="0" colspan="2">
Lines 65-87 Link Here
65
     </property>
88
     </property>
66
    </widget>
89
    </widget>
67
   </item>
90
   </item>
68
   <item row="4" column="1">
69
    <widget class="QTreeWidget" name="twCommandList">
70
     <property name="toolTip">
71
      <string>Double-click an item to edit</string>
72
     </property>
73
     <column>
74
      <property name="text">
75
       <string>Command</string>
76
      </property>
77
     </column>
78
     <column>
79
      <property name="text">
80
       <string>Description</string>
81
      </property>
82
     </column>
83
    </widget>
84
   </item>
85
   <item row="1" column="0">
91
   <item row="1" column="0">
86
    <spacer name="horizontalSpacer">
92
    <spacer name="horizontalSpacer">
87
     <property name="orientation">
93
     <property name="orientation">
Lines 164-171 Link Here
164
     </property>
170
     </property>
165
    </spacer>
171
    </spacer>
166
   </item>
172
   </item>
173
   <item row="4" column="1">
174
    <widget class="QTableView" name="twCommandList">
175
     <property name="toolTip">
176
      <string>Double-click an item to edit</string>
177
     </property>
178
     <property name="alternatingRowColors">
179
      <bool>true</bool>
180
     </property>
181
     <property name="selectionMode">
182
      <enum>QAbstractItemView::SingleSelection</enum>
183
     </property>
184
     <property name="selectionBehavior">
185
      <enum>QAbstractItemView::SelectRows</enum>
186
     </property>
187
     <property name="showGrid">
188
      <bool>false</bool>
189
     </property>
190
     <property name="gridStyle">
191
      <enum>Qt::NoPen</enum>
192
     </property>
193
     <property name="wordWrap">
194
      <bool>false</bool>
195
     </property>
196
     <attribute name="horizontalHeaderStretchLastSection">
197
      <bool>true</bool>
198
     </attribute>
199
     <attribute name="verticalHeaderVisible">
200
      <bool>false</bool>
201
     </attribute>
202
     <attribute name="verticalHeaderStretchLastSection">
203
      <bool>false</bool>
204
     </attribute>
205
    </widget>
206
   </item>
167
  </layout>
207
  </layout>
168
 </widget>
208
 </widget>
209
 <tabstops>
210
  <tabstop>twCommandList</tabstop>
211
  <tabstop>leRegExp</tabstop>
212
  <tabstop>automatic</tabstop>
213
  <tabstop>leDescription</tabstop>
214
  <tabstop>pbRemoveCommand</tabstop>
215
  <tabstop>pbAddCommand</tabstop>
216
 </tabstops>
169
 <resources/>
217
 <resources/>
170
 <connections/>
218
 <connections/>
171
</ui>
219
</ui>
(-)klipper/history.cpp (-2 / +5 lines)
Lines 49-57 Link Here
49
49
50
    m_topIsUserSelected = false;
50
    m_topIsUserSelected = false;
51
51
52
    // Optimization: Compare with top item.
52
    // OptimizationCompare with top item. If identical, the top isn't changing
53
    if ( !itemList.isEmpty() && *itemList.first() == *item ) {
53
    if ( !itemList.isEmpty() && *itemList.first() == *item ) {
54
        delete item;
54
        const HistoryItem* top = itemList.first();
55
        itemList.first() = item;
56
        delete top;
55
        return;
57
        return;
56
    }
58
    }
57
59
Lines 85-90 Link Here
85
    if ( !newItem )
87
    if ( !newItem )
86
        return;
88
        return;
87
89
90
    // TODO: This is rather broken.. it only checks by pointer!
88
    if (itemList.contains(newItem)) {
91
    if (itemList.contains(newItem)) {
89
        itemList.removeAll(newItem);
92
        itemList.removeAll(newItem);
90
        emit changed();
93
        emit changed();
(-)klipper/klipper.cpp (-38 / +28 lines)
Lines 158-164 Link Here
158
    /*
158
    /*
159
     * Create URL grabber
159
     * Create URL grabber
160
     */
160
     */
161
    m_myURLGrabber = new URLGrabber();
161
    m_myURLGrabber = new URLGrabber(m_history);
162
    connect( m_myURLGrabber, SIGNAL( sigPopup( QMenu * )),
162
    connect( m_myURLGrabber, SIGNAL( sigPopup( QMenu * )),
163
            SLOT( showPopupMenu( QMenu * )) );
163
            SLOT( showPopupMenu( QMenu * )) );
164
    connect( m_myURLGrabber, SIGNAL( sigDisablePopup() ),
164
    connect( m_myURLGrabber, SIGNAL( sigDisablePopup() ),
Lines 545-551 Link Here
545
{
545
{
546
    const HistoryStringItem* top = dynamic_cast<const HistoryStringItem*>( history()->first() );
546
    const HistoryStringItem* top = dynamic_cast<const HistoryStringItem*>( history()->first() );
547
    if ( top ) {
547
    if ( top ) {
548
        m_myURLGrabber->invokeAction( top->text() );
548
        m_myURLGrabber->invokeAction( top );
549
    }
549
    }
550
}
550
}
551
551
Lines 618-629 Link Here
618
    return 0;
618
    return 0;
619
}
619
}
620
620
621
void Klipper::applyClipChanges( const QMimeData* clipData )
621
HistoryItem* Klipper::applyClipChanges( const QMimeData* clipData )
622
{
622
{
623
    if ( m_locklevel )
623
    if ( m_locklevel ) {
624
        return;
624
        return 0L;
625
    }
625
    Ignore lock( m_locklevel );
626
    Ignore lock( m_locklevel );
626
    history()->insert( HistoryItem::create( clipData ) );
627
    HistoryItem* item = HistoryItem::create( clipData );
628
    history()->insert( item );
629
    return item;
627
630
628
}
631
}
629
632
Lines 798-841 Link Here
798
        m_lastClipboard = data->serialNumber();
801
        m_lastClipboard = data->serialNumber();
799
#endif
802
#endif
800
803
804
    HistoryItem* item = applyClipChanges( data );
805
    if (changed) {
806
#ifdef NOISY_KLIPPER
807
        kDebug() << "Synchronize?" << m_bSynchronize;
808
#endif
809
        if ( m_bSynchronize && item ) {
810
            setClipboard( *item, selectionMode ? Clipboard : Selection );
811
        }
812
    }
801
    QString& lastURLGrabberText = selectionMode
813
    QString& lastURLGrabberText = selectionMode
802
        ? m_lastURLGrabberTextSelection : m_lastURLGrabberTextClipboard;
814
        ? m_lastURLGrabberTextSelection : m_lastURLGrabberTextClipboard;
803
    if( data->hasText() )
815
    if( m_bURLGrabber && item && data->hasText())
804
    {
816
    {
805
        if ( m_bURLGrabber )
817
        m_myURLGrabber->checkNewData( item );
806
        {
807
            QString text = data->text();
808
818
809
            // Make sure URLGrabber doesn't repeat all the time if klipper reads the same
819
        // Make sure URLGrabber doesn't repeat all the time if klipper reads the same
810
            // text all the time (e.g. because XFixes is not available and the application
820
        // text all the time (e.g. because XFixes is not available and the application
811
            // has broken TIMESTAMP target). Using most recent history item may not always
821
        // has broken TIMESTAMP target). Using most recent history item may not always
812
            // work.
822
        // work.
813
            if ( text != lastURLGrabberText )
823
        if ( item->text() != lastURLGrabberText )
814
            {
824
        {
815
                lastURLGrabberText = text;
825
            lastURLGrabberText = item->text();
816
                if ( m_myURLGrabber->checkNewData( text ) )
817
                {
818
                    return; // don't add into the history
819
                }
820
            }
821
        }
826
        }
822
        else
827
    } else {
823
            lastURLGrabberText = QString();
824
    }
825
    else
826
        lastURLGrabberText = QString();
828
        lastURLGrabberText = QString();
827
828
    if (changed) {
829
        applyClipChanges( data );
830
#ifdef NOISY_KLIPPER
831
        kDebug() << "Synchronize?" << m_bSynchronize;
832
#endif
833
        if ( m_bSynchronize ) {
834
            const HistoryItem* topItem = history()->first();
835
            if ( topItem ) {
836
                setClipboard( *topItem, selectionMode ? Clipboard : Selection );
837
            }
838
        }
839
    }
829
    }
840
}
830
}
841
831
(-)klipper/klipper.h (-1 / +1 lines)
Lines 123-129 Link Here
123
    /**
123
    /**
124
     * Enter clipboard data in the history.
124
     * Enter clipboard data in the history.
125
     */
125
     */
126
    void applyClipChanges( const QMimeData* data );
126
    HistoryItem* applyClipChanges( const QMimeData* data );
127
127
128
    void setClipboard( const HistoryItem& item, int mode );
128
    void setClipboard( const HistoryItem& item, int mode );
129
    bool ignoreClipboardChanges() const;
129
    bool ignoreClipboardChanges() const;
(-)klipper/urlgrabber.cpp (-75 / +65 lines)
Lines 30-36 Link Here
30
#include <ktextedit.h>
30
#include <ktextedit.h>
31
#include <klocale.h>
31
#include <klocale.h>
32
#include <kmenu.h>
32
#include <kmenu.h>
33
#include <kprocess.h>
34
#include <kservice.h>
33
#include <kservice.h>
35
#include <kdebug.h>
34
#include <kdebug.h>
36
#include <kstringhandler.h>
35
#include <kstringhandler.h>
Lines 41-58 Link Here
41
40
42
#include "klippersettings.h"
41
#include "klippersettings.h"
43
#include "urlgrabber.h"
42
#include "urlgrabber.h"
43
#include "clipcommandprocess.h"
44
44
45
// TODO:
45
// TODO:
46
// - script-interface?
46
// - script-interface?
47
#include "history.h"
48
#include "historystringitem.h"
47
49
48
URLGrabber::URLGrabber()
50
URLGrabber::URLGrabber(History* history):
51
    m_myCurrentAction(0L),
52
    m_myMenu(0L),
53
    m_myPopupKillTimer(new QTimer( this )),
54
    m_myPopupKillTimeout(8),
55
    m_trimmed(true),
56
    m_history(history)
49
{
57
{
50
    m_myCurrentAction = 0L;
51
    m_myMenu = 0L;
52
    m_myPopupKillTimeout = 8;
53
    m_trimmed = true;
54
55
    m_myPopupKillTimer = new QTimer( this );
56
    m_myPopupKillTimer->setSingleShot( true );
58
    m_myPopupKillTimer->setSingleShot( true );
57
    connect( m_myPopupKillTimer, SIGNAL( timeout() ),
59
    connect( m_myPopupKillTimer, SIGNAL( timeout() ),
58
             SLOT( slotKillPopupMenu() ));
60
             SLOT( slotKillPopupMenu() ));
Lines 88-100 Link Here
88
// Called from Klipper::slotRepeatAction, i.e. by pressing Ctrl-Alt-R
90
// Called from Klipper::slotRepeatAction, i.e. by pressing Ctrl-Alt-R
89
// shortcut. I.e. never from clipboard monitoring
91
// shortcut. I.e. never from clipboard monitoring
90
//
92
//
91
void URLGrabber::invokeAction( const QString& clip )
93
void URLGrabber::invokeAction( const HistoryItem* item )
92
{
94
{
93
    if ( !clip.isEmpty() )
95
    m_myClipItem = item;
94
        m_myClipData = clip;
95
    if ( m_trimmed )
96
        m_myClipData = m_myClipData.trimmed();
97
98
    actionMenu( false );
96
    actionMenu( false );
99
}
97
}
100
98
Lines 153-166 Link Here
153
        ClipAction* action = new ClipAction( QString(), mimetype->comment() );
151
        ClipAction* action = new ClipAction( QString(), mimetype->comment() );
154
        KService::List lst = KMimeTypeTrader::self()->query( mimetype->name(), "Application" );
152
        KService::List lst = KMimeTypeTrader::self()->query( mimetype->name(), "Application" );
155
        foreach( const KService::Ptr &service, lst ) {
153
        foreach( const KService::Ptr &service, lst ) {
156
            action->addCommand( service->exec(), service->name(), true, service->icon() );
154
            action->addCommand( ClipCommand( service->exec(), service->name(), true, service->icon() ) );
157
        }
155
        }
158
        if ( !lst.isEmpty() )
156
        if ( !lst.isEmpty() )
159
            m_myMatches.append( action );
157
            m_myMatches.append( action );
160
    }
158
    }
161
}
159
}
162
160
163
const ActionList& URLGrabber::matchingActions( const QString& clipData )
161
const ActionList& URLGrabber::matchingActions( const QString& clipData, bool automatically_invoked )
164
{
162
{
165
    m_myMatches.clear();
163
    m_myMatches.clear();
166
164
Lines 169-209 Link Here
169
167
170
    // now look for matches in custom user actions
168
    // now look for matches in custom user actions
171
    foreach (ClipAction* action, m_myActions) {
169
    foreach (ClipAction* action, m_myActions) {
172
        if ( action->matches( clipData ) )
170
        if ( action->matches( clipData ) && (action->automatic() || !automatically_invoked) ) {
173
            m_myMatches.append( action );
171
            m_myMatches.append( action );
172
	}
174
    }
173
    }
175
174
176
    return m_myMatches;
175
    return m_myMatches;
177
}
176
}
178
177
179
178
180
bool URLGrabber::checkNewData( const QString& clipData )
179
void URLGrabber::checkNewData( const HistoryItem* item )
181
{
180
{
182
    // kDebug() << "** checking new data: " << clipData;
181
    // kDebug() << "** checking new data: " << clipData;
183
    m_myClipData = clipData;
182
    m_myClipItem = item;
184
    if ( m_trimmed )
185
        m_myClipData = m_myClipData.trimmed();
186
187
    if ( m_myActions.isEmpty() )
188
        return false;
189
183
190
    actionMenu( true ); // also creates m_myMatches
184
    actionMenu( true ); // also creates m_myMatches
191
192
    return !m_myMatches.isEmpty();
193
}
185
}
194
186
195
187
196
void URLGrabber::actionMenu( bool wm_class_check )
188
void URLGrabber::actionMenu( bool automatically_invoked )
197
{
189
{
198
    if ( m_myClipData.isEmpty() )
190
    QString text(m_myClipItem->text());
199
        return;
191
    if (m_trimmed) {
200
192
        text.trimmed();
201
    ActionList matchingActionsList = matchingActions( m_myClipData );
193
    }
194
    ActionList matchingActionsList = matchingActions( text, automatically_invoked );
202
195
203
    if (!matchingActionsList.isEmpty()) {
196
    if (!matchingActionsList.isEmpty()) {
204
        // don't react on konqi's/netscape's urls...
197
        // don't react on blacklisted (e.g. konqi's/netscape's urls) unless the user explicitly asked for it
205
        if ( wm_class_check && isAvoidedWindow() )
198
        if ( automatically_invoked && isAvoidedWindow() ) {
206
            return;
199
            return;
200
        }
207
201
208
        m_myCommandMapper.clear();
202
        m_myCommandMapper.clear();
209
203
Lines 215-221 Link Here
215
209
216
        foreach (ClipAction* clipAct, matchingActionsList) {
210
        foreach (ClipAction* clipAct, matchingActionsList) {
217
            m_myMenu->addTitle(KIcon( "klipper" ),
211
            m_myMenu->addTitle(KIcon( "klipper" ),
218
                               i18n("%1 - Actions For: %2", clipAct->description(), KStringHandler::csqueeze(m_myClipData, 45)));
212
                               i18n("%1 - Actions For: %2", clipAct->description(), KStringHandler::csqueeze(text, 45)));
219
            QList<ClipCommand> cmdList = clipAct->commands();
213
            QList<ClipCommand> cmdList = clipAct->commands();
220
            int listSize = cmdList.count();
214
            int listSize = cmdList.count();
221
            for (int i=0; i<listSize;++i) {
215
            for (int i=0; i<listSize;++i) {
Lines 240-246 Link Here
240
234
241
        // only insert this when invoked via clipboard monitoring, not from an
235
        // only insert this when invoked via clipboard monitoring, not from an
242
        // explicit Ctrl-Alt-R
236
        // explicit Ctrl-Alt-R
243
        if ( wm_class_check )
237
        if ( automatically_invoked )
244
        {
238
        {
245
            m_myMenu->addSeparator();
239
            m_myMenu->addSeparator();
246
            QAction *disableAction = new QAction(i18n("Disable This Popup"), this);
240
            QAction *disableAction = new QAction(i18n("Disable This Popup"), this);
Lines 297-332 Link Here
297
    ClipCommand command = action->command(cmdIdx);
291
    ClipCommand command = action->command(cmdIdx);
298
292
299
    if ( command.isEnabled ) {
293
    if ( command.isEnabled ) {
300
        QHash<QChar,QString> map;
294
        QString text(m_myClipItem->text());
301
        map.insert( 's', m_myClipData );
295
        if (m_trimmed) {
302
296
            text.trimmed();
303
        // support %u, %U (indicates url param(s)) and %f, %F (file param(s))
297
        }
304
        map.insert( 'u', m_myClipData );
298
        ClipCommandProcess* proc = new ClipCommandProcess(*action, command, text, m_history, m_myClipItem);
305
        map.insert( 'U', m_myClipData );
299
        if (proc->program().isEmpty()) {
306
        map.insert( 'f', m_myClipData );
300
            delete proc;
307
        map.insert( 'F', m_myClipData );
301
            proc = 0L;
308
302
        } else {
309
        const QStringList matches = action->regExpMatches();
303
            proc->start();
310
        // support only %0 and the first 9 matches...
304
        }
311
        const int numMatches = qMin(10, matches.count());
312
        for ( int i = 0; i < numMatches; ++i )
313
            map.insert( QChar( '0' + i ), matches.at( i ) );
314
315
        QString cmdLine = KMacroExpander::expandMacrosShellQuote( command.command, map );
316
317
        if ( cmdLine.isEmpty() )
318
            return;
319
320
        KProcess proc;
321
        proc.setShellCommand(cmdLine.trimmed());
322
        if (!proc.startDetached())
323
            kDebug() << "Klipper: Could not start process!";
324
    }
305
    }
325
}
306
}
326
307
327
308
328
void URLGrabber::editData()
309
void URLGrabber::editData()
329
{
310
{
311
    if (!m_myClipItem) {
312
        return;
313
    }
330
    m_myPopupKillTimer->stop();
314
    m_myPopupKillTimer->stop();
331
    KDialog *dlg = new KDialog( 0 );
315
    KDialog *dlg = new KDialog( 0 );
332
    dlg->setModal( true );
316
    dlg->setModal( true );
Lines 334-347 Link Here
334
    dlg->setButtons( KDialog::Ok | KDialog::Cancel );
318
    dlg->setButtons( KDialog::Ok | KDialog::Cancel );
335
319
336
    KTextEdit *edit = new KTextEdit( dlg );
320
    KTextEdit *edit = new KTextEdit( dlg );
337
    edit->setText( m_myClipData );
321
    edit->setText( m_myClipItem->text() );
338
    edit->setFocus();
322
    edit->setFocus();
339
    edit->setMinimumSize( 300, 40 );
323
    edit->setMinimumSize( 300, 40 );
340
    dlg->setMainWidget( edit );
324
    dlg->setMainWidget( edit );
341
    dlg->adjustSize();
325
    dlg->adjustSize();
342
326
343
    if ( dlg->exec() == KDialog::Accepted ) {
327
    if ( dlg->exec() == KDialog::Accepted ) {
344
        m_myClipData = edit->toPlainText();
328
        QString text = edit->toPlainText();
329
        m_history->remove( m_myClipItem );
330
        m_history->insert( new HistoryStringItem(text) );
345
        QTimer::singleShot( 0, this, SLOT( slotActionMenu() ) );
331
        QTimer::singleShot( 0, this, SLOT( slotActionMenu() ) );
346
    }
332
    }
347
    else
333
    else
Lines 454-463 Link Here
454
////////
440
////////
455
441
456
ClipCommand::ClipCommand(const QString &_command, const QString &_description,
442
ClipCommand::ClipCommand(const QString &_command, const QString &_description,
457
                         bool _isEnabled, const QString &_icon)
443
                         bool _isEnabled, const QString &_icon, Output _output)
458
    : command(_command),
444
    : command(_command),
459
      description(_description),
445
      description(_description),
460
      isEnabled(_isEnabled)
446
      isEnabled(_isEnabled),
447
      output(_output)
461
{
448
{
462
449
463
    if (!_icon.isEmpty())
450
    if (!_icon.isEmpty())
Lines 481-494 Link Here
481
}
468
}
482
469
483
470
484
ClipAction::ClipAction( const QString& regExp, const QString& description )
471
ClipAction::ClipAction( const QString& regExp, const QString& description, bool automatic )
485
    : m_myRegExp( regExp ), m_myDescription( description )
472
    : m_myRegExp( regExp ), m_myDescription( description ), m_automatic(automatic)
486
{
473
{
487
}
474
}
488
475
489
ClipAction::ClipAction( KSharedConfigPtr kc, const QString& group )
476
ClipAction::ClipAction( KSharedConfigPtr kc, const QString& group )
490
    : m_myRegExp( kc->group(group).readEntry("Regexp") ),
477
    : m_myRegExp( kc->group(group).readEntry("Regexp") ),
491
      m_myDescription (kc->group(group).readEntry("Description") )
478
      m_myDescription (kc->group(group).readEntry("Description") ),
479
      m_automatic(kc->group(group).readEntry("Automatic", QVariant(true)).toBool() )
492
{
480
{
493
    KConfigGroup cg(kc, group);
481
    KConfigGroup cg(kc, group);
494
482
Lines 499-508 Link Here
499
        QString _group = group + "/Command_%1";
487
        QString _group = group + "/Command_%1";
500
        KConfigGroup _cg(kc, _group.arg(i));
488
        KConfigGroup _cg(kc, _group.arg(i));
501
489
502
        addCommand( _cg.readPathEntry( "Commandline", QString() ),
490
        addCommand( ClipCommand(_cg.readPathEntry( "Commandline", QString() ),
503
                    _cg.readEntry( "Description" ), // i18n'ed
491
                                _cg.readEntry( "Description" ), // i18n'ed
504
                    _cg.readEntry( "Enabled" , false),
492
                                _cg.readEntry( "Enabled" , false),
505
                    _cg.readEntry( "Icon") );
493
                                _cg.readEntry( "Icon"),
494
                                static_cast<ClipCommand::Output>(_cg.readEntry( "Output", QVariant(ClipCommand::IGNORE)).toInt())));
506
    }
495
    }
507
}
496
}
508
497
Lines 513-525 Link Here
513
}
502
}
514
503
515
504
516
void ClipAction::addCommand( const QString& command,
505
void ClipAction::addCommand( const ClipCommand& cmd )
517
                             const QString& description, bool enabled, const QString& icon )
518
{
506
{
519
    if ( command.isEmpty() )
507
    if ( cmd.command.isEmpty() )
520
        return;
508
        return;
521
509
522
    m_myCommands.append( ClipCommand(command, description, enabled, icon) );
510
    m_myCommands.append( cmd );
523
}
511
}
524
512
525
void ClipAction::replaceCommand( int idx, const ClipCommand& cmd )
513
void ClipAction::replaceCommand( int idx, const ClipCommand& cmd )
Lines 529-535 Link Here
529
        return;
517
        return;
530
    }
518
    }
531
519
532
    m_myCommands[idx] = cmd;
520
    m_myCommands.replace(idx, cmd);
533
}
521
}
534
522
535
523
Lines 540-545 Link Here
540
    cg.writeEntry( "Description", description() );
528
    cg.writeEntry( "Description", description() );
541
    cg.writeEntry( "Regexp", regExp() );
529
    cg.writeEntry( "Regexp", regExp() );
542
    cg.writeEntry( "Number of commands", m_myCommands.count() );
530
    cg.writeEntry( "Number of commands", m_myCommands.count() );
531
    cg.writeEntry( "Automatic", automatic() );
543
532
544
    int i=0;
533
    int i=0;
545
    // now iterate over all commands of this action
534
    // now iterate over all commands of this action
Lines 551-556 Link Here
551
        cg.writeEntry( "Description", cmd.description );
540
        cg.writeEntry( "Description", cmd.description );
552
        cg.writeEntry( "Enabled", cmd.isEnabled );
541
        cg.writeEntry( "Enabled", cmd.isEnabled );
553
        cg.writeEntry( "Icon", cmd.pixmap );
542
        cg.writeEntry( "Icon", cmd.pixmap );
543
	cg.writeEntry( "Output", static_cast<int>(cmd.output) );
554
544
555
        ++i;
545
        ++i;
556
    }
546
    }
(-)klipper/urlgrabber.h (-13 / +36 lines)
Lines 22-32 Link Here
22
22
23
#include <QHash>
23
#include <QHash>
24
#include <QRegExp>
24
#include <QRegExp>
25
#include <QStringList>
26
#include <ksharedconfig.h>
25
27
28
class History;
29
class HistoryItem;
26
class QTimer;
30
class QTimer;
27
31
28
class KConfig;
32
class KConfig;
29
class KMenu;
33
class KMenu;
34
class QMenu;
35
class QAction;
30
36
31
class ClipAction;
37
class ClipAction;
32
struct ClipCommand;
38
struct ClipCommand;
Lines 37-43 Link Here
37
  Q_OBJECT
43
  Q_OBJECT
38
44
39
public:
45
public:
40
  URLGrabber();
46
  URLGrabber(History* history);
41
  ~URLGrabber();
47
  ~URLGrabber();
42
48
43
  /**
49
  /**
Lines 46-53 Link Here
46
   * @returns false if the string should be put into the popupmenu or not,
52
   * @returns false if the string should be put into the popupmenu or not,
47
   * otherwise true.
53
   * otherwise true.
48
   */
54
   */
49
  bool checkNewData( const QString& clipData );
55
  void checkNewData( const HistoryItem* item );
50
  void invokeAction( const QString& clip = QString() );
56
  void invokeAction( const HistoryItem* item );
51
57
52
  ActionList actionList() const { return m_myActions; }
58
  ActionList actionList() const { return m_myActions; }
53
  void setActionList( const ActionList& );
59
  void setActionList( const ActionList& );
Lines 65-71 Link Here
65
  void setStripWhiteSpace( bool enable ) { m_trimmed = enable; }
71
  void setStripWhiteSpace( bool enable ) { m_trimmed = enable; }
66
72
67
private:
73
private:
68
  const ActionList& matchingActions( const QString& );
74
  const ActionList& matchingActions( const QString&, bool automatically_invoked );
69
  void execute( const ClipAction *action, int commandIdx ) const;
75
  void execute( const ClipAction *action, int commandIdx ) const;
70
  bool isAvoidedWindow() const;
76
  bool isAvoidedWindow() const;
71
  void actionMenu( bool wm_class_check );
77
  void actionMenu( bool wm_class_check );
Lines 74-80 Link Here
74
  ActionList m_myActions;
80
  ActionList m_myActions;
75
  ActionList m_myMatches;
81
  ActionList m_myMatches;
76
  QStringList m_myAvoidWindows;
82
  QStringList m_myAvoidWindows;
77
  QString m_myClipData;
83
  const HistoryItem* m_myClipItem;
78
  ClipAction *m_myCurrentAction;
84
  ClipAction *m_myCurrentAction;
79
85
80
  // holds mappings of menu action IDs to action commands (action+cmd index in it)
86
  // holds mappings of menu action IDs to action commands (action+cmd index in it)
Lines 83-88 Link Here
83
  QTimer *m_myPopupKillTimer;
89
  QTimer *m_myPopupKillTimer;
84
  int m_myPopupKillTimeout;
90
  int m_myPopupKillTimeout;
85
  bool m_trimmed;
91
  bool m_trimmed;
92
  History* m_history;
86
93
87
private Q_SLOTS:
94
private Q_SLOTS:
88
  void slotActionMenu() { actionMenu( true ); }
95
  void slotActionMenu() { actionMenu( true ); }
Lines 90-96 Link Here
90
  void slotKillPopupMenu();
97
  void slotKillPopupMenu();
91
  void editData();
98
  void editData();
92
99
93
94
Q_SIGNALS:
100
Q_SIGNALS:
95
    void sigPopup( QMenu * );
101
    void sigPopup( QMenu * );
96
    void sigDisablePopup();
102
    void sigDisablePopup();
Lines 100-114 Link Here
100
106
101
struct ClipCommand
107
struct ClipCommand
102
{
108
{
103
    ClipCommand( const QString & command, const QString & description,
109
  /**
104
            bool = true, const QString & icon = QString() );
110
   * What to do with output of command
111
   */
112
  enum Output {
113
    IGNORE, // Discard output
114
    REPLACE, // Replace clipboard entry with output
115
    ADD // Add output as new clipboard element
116
  };
117
118
  ClipCommand( const QString & command,
119
               const QString & description,
120
               bool enabled= true,
121
               const QString & icon = QString(),
122
               Output output = IGNORE);
105
123
106
    QString command;
124
    QString command;
107
    QString description;
125
    QString description;
108
    bool isEnabled;
126
    bool isEnabled;
109
    QString pixmap;
127
    QString pixmap;
128
    Output output;
110
};
129
};
111
130
131
Q_DECLARE_METATYPE(ClipCommand::Output)
132
112
/**
133
/**
113
 * Represents one configured action. An action consists of one regular
134
 * Represents one configured action. An action consists of one regular
114
 * expression, an (optional) description and a list of ClipCommands
135
 * expression, an (optional) description and a list of ClipCommands
Lines 118-124 Link Here
118
{
139
{
119
public:
140
public:
120
  explicit ClipAction( const QString& regExp = QString(),
141
  explicit ClipAction( const QString& regExp = QString(),
121
                       const QString& description = QString() );
142
                       const QString& description = QString(),
143
                       bool automagic = true);
122
144
123
  ClipAction( KSharedConfigPtr kc, const QString& );
145
  ClipAction( KSharedConfigPtr kc, const QString& );
124
  ~ClipAction();
146
  ~ClipAction();
Lines 133-147 Link Here
133
  void setDescription( const QString& d) { m_myDescription = d; }
155
  void setDescription( const QString& d) { m_myDescription = d; }
134
  QString description() const            { return m_myDescription; }
156
  QString description() const            { return m_myDescription; }
135
157
158
  void setAutomatic( bool automatic ) { m_automatic = automatic; }
159
  bool automatic() const { return m_automatic; }
160
136
  /**
161
  /**
137
   * Removes all ClipCommands associated with this ClipAction.
162
   * Removes all ClipCommands associated with this ClipAction.
138
   */
163
   */
139
  void clearCommands() { m_myCommands.clear(); }
164
  void clearCommands() { m_myCommands.clear(); }
140
165
141
  void  addCommand( const QString& command,
166
  void  addCommand(const ClipCommand& cmd);
142
                    const QString& description,
143
                    bool isEnabled = true,
144
                    const QString& icon = QString() );
145
167
146
  /**
168
  /**
147
   * Replaces command at index @p idx with command @p newCmd
169
   * Replaces command at index @p idx with command @p newCmd
Lines 165-170 Link Here
165
  QRegExp m_myRegExp;
187
  QRegExp m_myRegExp;
166
  QString m_myDescription;
188
  QString m_myDescription;
167
  QList<ClipCommand> m_myCommands;
189
  QList<ClipCommand> m_myCommands;
190
  bool m_automatic;
168
191
169
};
192
};
170
193
(-) (+82 lines)
Added Link Here
1
// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
2
/*
3
    Copyright 2009 Esben Mose Hansen <kde@mosehansen.dk>
4
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
15
    You should have received a copy of the GNU General Public License along
16
    with this program; if not, write to the Free Software Foundation, Inc.,
17
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19
*/
20
21
#include "clipcommandprocess.h"
22
#include "history.h"
23
#include "historystringitem.h"
24
#include <KCharMacroExpander>
25
#include "urlgrabber.h"
26
27
ClipCommandProcess::ClipCommandProcess(const ClipAction& action, const ClipCommand& command, const QString& clip, History* history, const HistoryItem* original_item) :
28
    KProcess(),
29
    m_history(history),
30
    m_historyItem(original_item),
31
    m_newhistoryItem()
32
{
33
    QHash<QChar,QString> map;
34
    map.insert( 's', clip );
35
36
    // support %u, %U (indicates url param(s)) and %f, %F (file param(s))
37
    map.insert( 'u', clip );
38
    map.insert( 'U', clip );
39
    map.insert( 'f', clip );
40
    map.insert( 'F', clip );
41
42
    const QStringList matches = action.regExpMatches();
43
    // support only %0 and the first 9 matches...
44
    const int numMatches = qMin(10, matches.count());
45
    for ( int i = 0; i < numMatches; ++i ) {
46
        map.insert( QChar( '0' + i ), matches.at( i ) );
47
    }
48
49
    setOutputChannelMode(OnlyStdoutChannel);
50
    setShellCommand(KMacroExpander::expandMacrosShellQuote( command.command, map ).trimmed());
51
52
    connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(slotFinished(int,QProcess::ExitStatus)));
53
    if (command.output != ClipCommand::IGNORE) {
54
        connect(this, SIGNAL(readyRead()), SLOT(slotStdOutputAvailable()));
55
    }
56
    if (command.output != ClipCommand::REPLACE) {
57
        m_historyItem = 0L; // Don't replace
58
    }
59
60
}
61
62
void ClipCommandProcess::slotFinished(int /*exitCode*/, QProcess::ExitStatus /*newState*/)
63
{
64
    if (m_history) {
65
        // If an history item was provided, remove it so that the new item can replace it
66
        if (m_historyItem) {
67
            m_history->remove(m_historyItem);
68
        }
69
        if (!m_newhistoryItem.isEmpty()) {
70
            m_history->insert(new HistoryStringItem(m_newhistoryItem));
71
        }
72
    }
73
    deleteLater();
74
}
75
76
void ClipCommandProcess::slotStdOutputAvailable()
77
{
78
    m_newhistoryItem.append(QString::fromLocal8Bit(this->readAllStandardOutput().data()));
79
}
80
81
82
#include "clipcommandprocess.moc"
(-) (+44 lines)
Added Link Here
1
// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
2
/*
3
    Copyright 2009 Esben Mose Hansen <kde@mosehansen.dk>
4
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
15
    You should have received a copy of the GNU General Public License along
16
    with this program; if not, write to the Free Software Foundation, Inc.,
17
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19
*/
20
21
#ifndef CLIPCOMMANDPROCESS_H
22
#define CLIPCOMMANDPROCESS_H
23
24
#include <kprocess.h>
25
26
class ClipAction;
27
class History;
28
class ClipCommand;
29
class HistoryItem;
30
class ClipCommandProcess : public KProcess
31
{
32
    Q_OBJECT
33
public:
34
    ClipCommandProcess(const ClipAction& action, const ClipCommand& command, const QString& clip, History* history = 0L, const HistoryItem* original_item = 0L);
35
public slots:
36
    void slotStdOutputAvailable();
37
    void slotFinished(int exitCode, QProcess::ExitStatus newState);
38
private:
39
    History* m_history;
40
    const HistoryItem* m_historyItem;
41
    QString m_newhistoryItem;
42
};
43
44
#endif // CLIPCOMMANDPROCESS_H

Return to bug 292233