bineditorplugin.cpp 18.7 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
con's avatar
con committed
8
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
**
29
**************************************************************************/
hjk's avatar
hjk committed
30

con's avatar
con committed
31
32
33
34
#include "bineditorplugin.h"
#include "bineditor.h"
#include "bineditorconstants.h"

35
36
#include <coreplugin/icore.h>

37
#include <QCoreApplication>
38
39
40
41
42
43
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QRegExp>
#include <QVariant>
44

45
46
47
48
49
50
51
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QToolBar>
con's avatar
con committed
52

53
#include <coreplugin/actionmanager/actionmanager.h>
con's avatar
con committed
54
#include <coreplugin/coreconstants.h>
55
#include <coreplugin/id.h>
56
#include <coreplugin/editormanager/editormanager.h>
57
#include <coreplugin/editormanager/ieditor.h>
58
#include <coreplugin/icore.h>
59
#include <coreplugin/idocument.h>
con's avatar
con committed
60
#include <coreplugin/mimedatabase.h>
61
#include <extensionsystem/pluginmanager.h>
con's avatar
con committed
62
#include <find/ifindsupport.h>
63
64
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorsettings.h>
con's avatar
con committed
65
#include <utils/reloadpromptutils.h>
66
#include <utils/qtcassert.h>
con's avatar
con committed
67
68
69
70
71
72
73
74
75

using namespace BINEditor;
using namespace BINEditor::Internal;


class BinEditorFind : public Find::IFindSupport
{
    Q_OBJECT
public:
ck's avatar
ck committed
76
77
78
79
80
    BinEditorFind(BinEditor *editor)
    {
        m_editor = editor;
        m_incrementalStartPos = m_contPos = -1;
    }
con's avatar
con committed
81
82
83
    ~BinEditorFind() {}

    bool supportsReplace() const { return false; }
84
    Find::FindFlags supportedFindFlags() const
85
    {
86
        return Find::FindBackward | Find::FindCaseSensitively;
87
88
    }

ck's avatar
ck committed
89
90
91
92
93
    void resetIncrementalSearch()
    {
        m_incrementalStartPos = m_contPos = -1;
    }

94
95
96
97
98
    virtual void highlightAll(const QString &txt, Find::FindFlags findFlags)
    {
        m_editor->highlightSearchResults(txt.toLatin1(), Find::textDocumentFlagsForFindFlags(findFlags));
    }

con's avatar
con committed
99
100
101
102
103
    void clearResults() { m_editor->highlightSearchResults(QByteArray()); }
    QString currentFindString() const { return QString(); }
    QString completedFindString() const { return QString(); }


104
    int find(const QByteArray &pattern, int pos, Find::FindFlags findFlags) {
con's avatar
con committed
105
106
107
108
109
        if (pattern.isEmpty()) {
            m_editor->setCursorPosition(pos);
            return pos;
        }

110
        return m_editor->find(pattern, pos, Find::textDocumentFlagsForFindFlags(findFlags));
con's avatar
con committed
111
112
    }

113
    Result findIncremental(const QString &txt, Find::FindFlags findFlags) {
con's avatar
con committed
114
        QByteArray pattern = txt.toLatin1();
ck's avatar
ck committed
115
116
117
        if (pattern != m_lastPattern)
            resetIncrementalSearch(); // Because we don't search for nibbles.
        m_lastPattern = pattern;
con's avatar
con committed
118
119
        if (m_incrementalStartPos < 0)
            m_incrementalStartPos = m_editor->selectionStart();
ck's avatar
ck committed
120
121
122
123
124
125
        if (m_contPos == -1)
            m_contPos = m_incrementalStartPos;
        int found = find(pattern, m_contPos, findFlags);
        Result result;
        if (found >= 0) {
            result = Found;
126
            m_editor->highlightSearchResults(pattern, Find::textDocumentFlagsForFindFlags(findFlags));
ck's avatar
ck committed
127
128
129
130
131
            m_contPos = -1;
        } else {
            if (found == -2) {
                result = NotYetFound;
                m_contPos +=
132
                        findFlags & Find::FindBackward
ck's avatar
ck committed
133
134
135
136
137
138
139
140
                        ? -BinEditor::SearchStride : BinEditor::SearchStride;
            } else {
                result = NotFound;
                m_contPos = -1;
                m_editor->highlightSearchResults(QByteArray(), 0);
            }
        }
        return result;
con's avatar
con committed
141
142
    }

143
    Result findStep(const QString &txt, Find::FindFlags findFlags) {
con's avatar
con committed
144
145
        QByteArray pattern = txt.toLatin1();
        bool wasReset = (m_incrementalStartPos < 0);
ck's avatar
ck committed
146
147
        if (m_contPos == -1) {
            m_contPos = m_editor->cursorPosition();
148
            if (findFlags & Find::FindBackward)
ck's avatar
ck committed
149
150
151
152
153
154
                m_contPos = m_editor->selectionStart()-1;
        }
        int found = find(pattern, m_contPos, findFlags);
        Result result;
        if (found >= 0) {
            result = Found;
con's avatar
con committed
155
            m_incrementalStartPos = found;
ck's avatar
ck committed
156
157
            m_contPos = -1;
            if (wasReset)
158
                m_editor->highlightSearchResults(pattern, Find::textDocumentFlagsForFindFlags(findFlags));
ck's avatar
ck committed
159
160
        } else if (found == -2) {
            result = NotYetFound;
161
            m_contPos += findFlags & Find::FindBackward
ck's avatar
ck committed
162
163
164
165
166
167
168
                         ? -BinEditor::SearchStride : BinEditor::SearchStride;
        } else {
            result = NotFound;
            m_contPos = -1;
        }

        return result;
con's avatar
con committed
169
    }
ck's avatar
ck committed
170

con's avatar
con committed
171
172
173
private:
    BinEditor *m_editor;
    int m_incrementalStartPos;
ck's avatar
ck committed
174
175
    int m_contPos; // Only valid if last result was NotYetFound.
    QByteArray m_lastPattern;
con's avatar
con committed
176
177
178
};


179
class BinEditorDocument : public Core::IDocument
con's avatar
con committed
180
181
182
{
    Q_OBJECT
public:
183
184
    BinEditorDocument(BinEditor *parent) :
        Core::IDocument(parent)
con's avatar
con committed
185
186
    {
        m_editor = parent;
hjk's avatar
hjk committed
187
        connect(m_editor, SIGNAL(dataRequested(Core::IEditor*,quint64)),
Robert Loehning's avatar
Robert Loehning committed
188
            this, SLOT(provideData(Core::IEditor*,quint64)));
ck's avatar
ck committed
189
190
        connect(m_editor, SIGNAL(newRangeRequested(Core::IEditor*,quint64)),
            this, SLOT(provideNewRange(Core::IEditor*,quint64)));
191
192
193
194
        connect(m_editor, SIGNAL(startOfFileRequested(Core::IEditor*)), this,
            SLOT(handleStartOfFileRequested(Core::IEditor*)));
        connect(m_editor, SIGNAL(endOfFileRequested(Core::IEditor*)), this,
            SLOT(handleEndOfFileRequested(Core::IEditor*)));
con's avatar
con committed
195
    }
196
    ~BinEditorDocument() {}
con's avatar
con committed
197

hjk's avatar
hjk committed
198
199
200
    QString mimeType() const {
        return QLatin1String(Constants::C_BINEDITOR_MIMETYPE);
    }
con's avatar
con committed
201

202
    bool save(QString *errorString, const QString &fileName, bool autoSave)
203
    {
204
        QTC_ASSERT(!autoSave, return true); // bineditor does not support autosave - it would be a bit expensive
205
206
        const QString fileNameToUse
            = fileName.isEmpty() ? m_fileName : fileName;
207
        if (m_editor->save(errorString, m_fileName, fileNameToUse)) {
208
            m_fileName = fileNameToUse;
hjk's avatar
hjk committed
209
            m_editor->editor()->setDisplayName(QFileInfo(fileNameToUse).fileName());
con's avatar
con committed
210
211
            emit changed();
            return true;
ck's avatar
ck committed
212
213
        } else {
            return false;
con's avatar
con committed
214
215
216
        }
    }

dt's avatar
dt committed
217
218
    void rename(const QString &newName) {
        m_fileName = newName;
hjk's avatar
hjk committed
219
        m_editor->editor()->setDisplayName(QFileInfo(fileName()).fileName());
dt's avatar
dt committed
220
221
222
        emit changed();
    }

223
    bool open(QString *errorString, const QString &fileName, quint64 offset = 0) {
con's avatar
con committed
224
        QFile file(fileName);
225
        if (offset >= static_cast<quint64>(file.size())) {
226
227
228
229
230
            QString msg = tr("The Binary Editor can not open empty files.");
            if (errorString)
                *errorString = msg;
            else
                QMessageBox::critical(Core::ICore::mainWindow(), tr("File Error"), msg);
231
            return false;
232
        }
233
        if (file.open(QIODevice::ReadOnly)) {
Daniel Teske's avatar
Daniel Teske committed
234
            file.close();
con's avatar
con committed
235
            m_fileName = fileName;
236
            m_editor->setSizes(offset, file.size());
hjk's avatar
hjk committed
237
            m_editor->editor()->setDisplayName(QFileInfo(fileName).fileName());
con's avatar
con committed
238
239
            return true;
        }
240
241
242
243
244
        QString errStr = tr("Cannot open %1: %2").arg(
                QDir::toNativeSeparators(fileName), file.errorString());
        if (errorString)
            *errorString = errStr;
        else
hjk's avatar
hjk committed
245
            QMessageBox::critical(Core::ICore::mainWindow(), tr("File Error"), errStr);
con's avatar
con committed
246
247
248
        return false;
    }

249
private slots:
250
    void provideData(Core::IEditor *, quint64 block) {
251
252
        if (m_fileName.isEmpty())
            return;
253
254
        QFile file(m_fileName);
        if (file.open(QIODevice::ReadOnly)) {
hjk's avatar
hjk committed
255
            int blockSize = m_editor->dataBlockSize();
256
257
            file.seek(block * blockSize);
            QByteArray data = file.read(blockSize);
258
            file.close();
259
260
261
            const int dataSize = data.size();
            if (dataSize != blockSize)
                data += QByteArray(blockSize - dataSize, 0);
hjk's avatar
hjk committed
262
            m_editor->addData(block, data);
263
        } else {
hjk's avatar
hjk committed
264
            QMessageBox::critical(Core::ICore::mainWindow(), tr("File Error"),
265
266
                                  tr("Cannot open %1: %2").arg(
                                        QDir::toNativeSeparators(m_fileName), file.errorString()));
267
268
        }
    }
269

ck's avatar
ck committed
270
    void provideNewRange(Core::IEditor *, quint64 offset) {
271
        open(0, m_fileName, offset);
272
273
    }

274
    void handleStartOfFileRequested(Core::IEditor *) {
275
        open(0, m_fileName, 0);
276
277
278
    }

    void handleEndOfFileRequested(Core::IEditor *) {
279
        open(0, m_fileName, QFileInfo(m_fileName).size() - 1);
280
281
    }

282
public:
con's avatar
con committed
283
284
285
286
287

    void setFilename(const QString &filename) {
        m_fileName = filename;
    }

hjk's avatar
hjk committed
288
    QString fileName() const { return m_fileName; }
con's avatar
con committed
289
290

    QString defaultPath() const { return QString(); }
hjk's avatar
hjk committed
291

con's avatar
con committed
292
293
    QString suggestedFileName() const { return QString(); }

294
    bool isModified() const { return m_editor->isMemoryView() ? false : m_editor->isModified(); }
hjk's avatar
hjk committed
295

296
    bool isFileReadOnly() const {
297
        if (m_editor->isMemoryView() || m_fileName.isEmpty())
hjk's avatar
hjk committed
298
            return false;
con's avatar
con committed
299
300
301
302
303
304
        const QFileInfo fi(m_fileName);
        return !fi.isWritable();
    }

    bool isSaveAsAllowed() const { return true; }

305
    bool reload(QString *errorString, ReloadFlag flag, ChangeType type) {
306
        if (flag == FlagIgnore)
307
            return true;
308
        if (type == TypePermissions) {
con's avatar
con committed
309
            emit changed();
310
        } else {
311
            emit aboutToReload();
312
313
314
            if (!open(errorString, m_fileName))
                return false;
            emit reloaded();
con's avatar
con committed
315
        }
316
        return true;
con's avatar
con committed
317
318
319
320
321
322
323
324
325
326
327
    }

private:
    BinEditor *m_editor;
    QString m_fileName;
};

class BinEditorInterface : public Core::IEditor
{
    Q_OBJECT
public:
328
    BinEditorInterface(BinEditor *editor)
329
    {
330
        setWidget(editor);
331
        m_editor = editor;
332
        m_file = new BinEditorDocument(m_editor);
333
334
        m_context.add(Core::Constants::K_DEFAULT_BINARY_EDITOR_ID);
        m_context.add(Constants::C_BINEDITOR);
335
336
337
338
339
        m_addressEdit = new QLineEdit;
        QRegExpValidator * const addressValidator
            = new QRegExpValidator(QRegExp(QLatin1String("[0-9a-fA-F]{1,16}")),
                m_addressEdit);
        m_addressEdit->setValidator(addressValidator);
con's avatar
con committed
340
341
342
343
344
345

        QHBoxLayout *l = new QHBoxLayout;
        QWidget *w = new QWidget;
        l->setMargin(0);
        l->setContentsMargins(0, 0, 5, 0);
        l->addStretch(1);
346
        l->addWidget(m_addressEdit);
con's avatar
con committed
347
348
349
350
351
352
        w->setLayout(l);

        m_toolBar = new QToolBar;
        m_toolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
        m_toolBar->addWidget(w);

353
354
        connect(m_editor, SIGNAL(cursorPositionChanged(int)), this,
            SLOT(updateCursorPosition(int)));
dt's avatar
dt committed
355
        connect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
356
357
358
        connect(m_addressEdit, SIGNAL(editingFinished()), this,
            SLOT(jumpToAddress()));
        updateCursorPosition(m_editor->cursorPosition());
con's avatar
con committed
359
    }
360
361
362
    ~BinEditorInterface() {
        delete m_editor;
    }
con's avatar
con committed
363
364

    bool createNew(const QString & /* contents */ = QString()) {
hjk's avatar
hjk committed
365
        m_editor->clear();
con's avatar
con committed
366
367
368
        m_file->setFilename(QString());
        return true;
    }
369
370
    bool open(QString *errorString, const QString &fileName, const QString &realFileName) {
        QTC_ASSERT(fileName == realFileName, return false); // The bineditor can do no autosaving
371
        return m_file->open(errorString, fileName);
con's avatar
con committed
372
    }
373
    Core::IDocument *document() { return m_file; }
hjk's avatar
hjk committed
374
    Core::Id id() const { return Core::Constants::K_DEFAULT_BINARY_EDITOR_ID; }
con's avatar
con committed
375
376
377
378
    QString displayName() const { return m_displayName; }
    void setDisplayName(const QString &title) { m_displayName = title; emit changed(); }

    bool duplicateSupported() const { return false; }
379
    IEditor *duplicate(QWidget * /* parent */) { return 0; }
con's avatar
con committed
380

Eike Ziller's avatar
Eike Ziller committed
381
382
    QByteArray saveState() const { return QByteArray(); } // not supported
    bool restoreState(const QByteArray & /* state */) { return false; }  // not supported
con's avatar
con committed
383

con's avatar
con committed
384
    QWidget *toolBar() { return m_toolBar; }
con's avatar
con committed
385

386
    bool isTemporary() const { return m_editor->isMemoryView(); }
dt's avatar
dt committed
387

388
private slots:
con's avatar
con committed
389
    void updateCursorPosition(int position) {
390
391
392
393
394
395
        m_addressEdit->setText(QString::number(m_editor->baseAddress() + position, 16));
    }

    void jumpToAddress() {
        m_editor->jumpToAddress(m_addressEdit->text().toULongLong(0, 16));
        updateCursorPosition(m_editor->cursorPosition());
con's avatar
con committed
396
397
398
399
400
    }

private:
    BinEditor *m_editor;
    QString m_displayName;
401
    BinEditorDocument *m_file;
con's avatar
con committed
402
    QToolBar *m_toolBar;
403
    QLineEdit *m_addressEdit;
con's avatar
con committed
404
405
406
407
408
409
410
};



///////////////////////////////// BinEditorFactory //////////////////////////////////

BinEditorFactory::BinEditorFactory(BinEditorPlugin *owner) :
hjk's avatar
hjk committed
411
    m_mimeTypes(QLatin1String(Constants::C_BINEDITOR_MIMETYPE)),
con's avatar
con committed
412
413
414
415
    m_owner(owner)
{
}

hjk's avatar
hjk committed
416
Core::Id BinEditorFactory::id() const
con's avatar
con committed
417
{
hjk's avatar
hjk committed
418
    return Core::Constants::K_DEFAULT_BINARY_EDITOR_ID;
419
420
421
422
}

QString BinEditorFactory::displayName() const
{
423
    return qApp->translate("OpenWith::Editors", Constants::C_BINEDITOR_DISPLAY_NAME);
con's avatar
con committed
424
425
426
427
428
429
}

Core::IEditor *BinEditorFactory::createEditor(QWidget *parent)
{
    BinEditor *editor = new BinEditor(parent);
    m_owner->initializeEditor(editor);
hjk's avatar
hjk committed
430
    return editor->editor();
con's avatar
con committed
431
432
433
434
435
436
437
}

QStringList BinEditorFactory::mimeTypes() const
{
    return m_mimeTypes;
}

438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
/*!
   \class BINEditor::BinEditorWidgetFactory
   \brief Service registered with PluginManager to create bin editor widgets for plugins
   without direct linkage.

   \sa ExtensionSystem::PluginManager::getObjectByClassName, ExtensionSystem::invoke
*/

BinEditorWidgetFactory::BinEditorWidgetFactory(QObject *parent) :
    QObject(parent)
{
}

QWidget *BinEditorWidgetFactory::createWidget(QWidget *parent)
{
    return new BinEditor(parent);
}

con's avatar
con committed
456
457
///////////////////////////////// BinEditorPlugin //////////////////////////////////

458
BinEditorPlugin::BinEditorPlugin()
con's avatar
con committed
459
460
461
462
463
464
465
466
{
    m_undoAction = m_redoAction = m_copyAction = m_selectAllAction = 0;
}

BinEditorPlugin::~BinEditorPlugin()
{
}

hjk's avatar
hjk committed
467
QAction *BinEditorPlugin::registerNewAction(Core::Id id, const QString &title)
con's avatar
con committed
468
469
{
    QAction *result = new QAction(title, this);
hjk's avatar
hjk committed
470
    Core::ActionManager::registerAction(result, id, m_context);
con's avatar
con committed
471
472
473
    return result;
}

hjk's avatar
hjk committed
474
QAction *BinEditorPlugin::registerNewAction(Core::Id id,
con's avatar
con committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
                                            QObject *receiver,
                                            const char *slot,
                                            const QString &title)
{
    QAction *rc = registerNewAction(id, title);
    if (!rc)
        return 0;

    connect(rc, SIGNAL(triggered()), receiver, slot);
    return rc;
}

void BinEditorPlugin::initializeEditor(BinEditor *editor)
{
    BinEditorInterface *editorInterface = new BinEditorInterface(editor);
    QObject::connect(editor, SIGNAL(modificationChanged(bool)), editorInterface, SIGNAL(changed()));
hjk's avatar
hjk committed
491
    editor->setEditor(editorInterface);
con's avatar
con committed
492

493
    m_context.add(Constants::C_BINEDITOR);
con's avatar
con committed
494
    if (!m_undoAction) {
hjk's avatar
hjk committed
495
496
497
498
        m_undoAction      = registerNewAction(Core::Constants::UNDO, this, SLOT(undoAction()), tr("&Undo"));
        m_redoAction      = registerNewAction(Core::Constants::REDO, this, SLOT(redoAction()), tr("&Redo"));
        m_copyAction      = registerNewAction(Core::Constants::COPY, this, SLOT(copyAction()));
        m_selectAllAction = registerNewAction(Core::Constants::SELECTALL, this, SLOT(selectAllAction()));
con's avatar
con committed
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    }

    // Font settings
    TextEditor::TextEditorSettings *settings = TextEditor::TextEditorSettings::instance();
    editor->setFontSettings(settings->fontSettings());
    connect(settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
            editor, SLOT(setFontSettings(TextEditor::FontSettings)));

    QObject::connect(editor, SIGNAL(undoAvailable(bool)), this, SLOT(updateActions()));
    QObject::connect(editor, SIGNAL(redoAvailable(bool)), this, SLOT(updateActions()));
    QObject::connect(editor, SIGNAL(copyAvailable(bool)), this, SLOT(updateActions()));

    Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
    BinEditorFind *binEditorFind = new BinEditorFind(editor);
    aggregate->add(binEditorFind);
    aggregate->add(editor);
}

517
bool BinEditorPlugin::initialize(const QStringList &arguments, QString *errorMessage)
con's avatar
con committed
518
{
519
    Q_UNUSED(arguments)
520
    Q_UNUSED(errorMessage)
521

Robert Loehning's avatar
Robert Loehning committed
522
523
    connect(Core::ICore::instance(), SIGNAL(contextAboutToChange(Core::IContext*)),
        this, SLOT(updateCurrentEditor(Core::IContext*)));
con's avatar
con committed
524
525

    addAutoReleasedObject(new BinEditorFactory(this));
526
    addAutoReleasedObject(new BinEditorWidgetFactory);
con's avatar
con committed
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
    return true;
}

void BinEditorPlugin::extensionsInitialized()
{
}

void BinEditorPlugin::updateCurrentEditor(Core::IContext *object)
{
    do {
        if (!object) {
            if (!m_currentEditor)
                return;

            m_currentEditor = 0;
            break;
        }
        BinEditor *editor = qobject_cast<BinEditor *>(object->widget());
        if (!editor) {
            if (!m_currentEditor)
                return;

            m_currentEditor = 0;
            break;
        }

        if (editor == m_currentEditor)
            return;

        m_currentEditor = editor;

    } while (false);
    updateActions();
}

void BinEditorPlugin::updateActions()
{
    bool hasEditor = (m_currentEditor != 0);
    if (m_selectAllAction)
        m_selectAllAction->setEnabled(hasEditor);
    if (m_undoAction)
        m_undoAction->setEnabled(m_currentEditor && m_currentEditor->isUndoAvailable());
    if (m_redoAction)
        m_redoAction->setEnabled(m_currentEditor && m_currentEditor->isRedoAvailable());
    if (m_copyAction)
        m_copyAction->setEnabled(m_currentEditor && m_currentEditor->hasSelection());
}

void BinEditorPlugin::undoAction()
{
    if (m_currentEditor)
        m_currentEditor->undo();
}

void BinEditorPlugin::redoAction()
{
    if (m_currentEditor)
        m_currentEditor->redo();
}

void BinEditorPlugin::copyAction()
{
    if (m_currentEditor)
        m_currentEditor->copy();
}

void BinEditorPlugin::selectAllAction()
{
    if (m_currentEditor)
        m_currentEditor->selectAll();
}


Q_EXPORT_PLUGIN(BinEditorPlugin)

#include "bineditorplugin.moc"