kedittoolbar.cpp 53.7 KB
Newer Older
Kurt Granroth's avatar
Kurt Granroth committed
1
2
/* This file is part of the KDE libraries
   Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
3
   Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
4
   Copyright     2007 David Faure <faure@kde.org>
Kurt Granroth's avatar
Kurt Granroth committed
5
6
7
8
9
10
11
12
13
14
15
16

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
Nicolas Goutte's avatar
Nicolas Goutte committed
17
18
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
Kurt Granroth's avatar
Kurt Granroth committed
19
20
*/
#include <kedittoolbar.h>
21
#include <kedittoolbar_p.h>
22
#include <QShowEvent>
23

Kurt Granroth's avatar
Kurt Granroth committed
24

25
#include <QtXml/QDomDocument>
Dirk Mueller's avatar
Dirk Mueller committed
26
27
28
#include <QtGui/QLayout>
#include <QtCore/QDir>
#include <QtCore/QFile>
29
#include <QHeaderView>
Dirk Mueller's avatar
Dirk Mueller committed
30
31
32
#include <QtGui/QToolButton>
#include <QtGui/QLabel>
#include <QtGui/QApplication>
33
34
#include <QtGui/QGridLayout>
#include <QtGui/QCheckBox>
35
#include <QMimeData>
Kurt Granroth's avatar
Kurt Granroth committed
36

Dirk Mueller's avatar
Dirk Mueller committed
37
#include <kstandarddirs.h>
38
#include <klistwidgetsearchline.h>
Kurt Granroth's avatar
Kurt Granroth committed
39
#include <klocale.h>
André Wöbbeking's avatar
André Wöbbeking committed
40
#include <kicon.h>
Kurt Granroth's avatar
Kurt Granroth committed
41
#include <kiconloader.h>
42
#include <kcomponentdata.h>
43
#include <kmessagebox.h>
44
#include <kxmlguifactory.h>
45
46
#include <kseparator.h>
#include <kconfig.h>
47
#include <kdebug.h>
48
#include <kpushbutton.h>
49
#include <kprocess.h>
50
#include <ktoolbar.h>
51
#include <kdeversion.h>
Urs Wolfer's avatar
Urs Wolfer committed
52
#include <kcombobox.h>
53
#include <klineedit.h>
Kurt Granroth's avatar
Kurt Granroth committed
54

55
56
57
#include "kaction.h"
#include "kactioncollection.h"

David Faure's avatar
David Faure committed
58
static const char * const separatorstring = I18N_NOOP("--- separator ---");
59

David Faure's avatar
David Faure committed
60
#define SEPARATORSTRING i18n(separatorstring)
61

62
static const char* const s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" };
63

64
typedef QList<QDomElement> ToolBarList;
65

66
67
namespace KDEPrivate {

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
 * Return a list of toolbar elements given a toplevel element
 */
static ToolBarList findToolBars(const QDomElement& start)
{
    static const QString &tagToolBar = KGlobal::staticQString( "ToolBar" );
    static const QString &tagMenuBar = KGlobal::staticQString( "MenuBar" );
    static const QString &attrNoEdit = KGlobal::staticQString( "noEdit" );
    ToolBarList list;

    for( QDomElement elem = start; !elem.isNull(); elem = elem.nextSiblingElement() ) {
        if (elem.tagName() == tagToolBar) {
            if ( elem.attribute( attrNoEdit ) != "true" )
                list.append(elem);
        } else {
            if (elem.tagName() != tagMenuBar) // there are no toolbars inside the menubar :)
                list += findToolBars(elem.firstChildElement()); // recursive
        }
    }

    return list;
}

91
92
93
class XmlData
{
public:
94
    enum XmlType { Shell = 0, Part, Local, Merged };
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    explicit XmlData( XmlType xmlType, const QString& xmlFile, KActionCollection* collection )
        : m_isModified(false),
          m_xmlFile(xmlFile),
          m_type(xmlType),
          m_actionCollection(collection)
    {
    }
    void dump() const
    {
        kDebug(240) << "XmlData" << this << "type" << s_XmlTypeToString[m_type] << "xmlFile:" << m_xmlFile;
        foreach (const QDomElement& element, m_barList) {
            kDebug(240) << "    ToolBar:" << toolBarText( element );
        }
        if ( m_actionCollection )
            kDebug(240) << "    " << m_actionCollection->actions().count() << "actions in the collection.";
        else
            kDebug(240) << "    no action collection.";
    }
    QString xmlFile() const { return m_xmlFile; }
    XmlType type() const { return m_type; }
    KActionCollection* actionCollection() const { return m_actionCollection; }
    void setDomDocument(const QDomDocument& domDoc)
    {
        m_document = domDoc;
        m_barList = findToolBars(m_document.documentElement());
    }
    // Return reference, for e.g. actionPropertiesElement() to modify the document
    QDomDocument& domDocument() { return m_document; }
    const QDomDocument& domDocument() const { return m_document; }

    /**
     * Return the text (user-visible name) of a given toolbar
     */
    QString toolBarText( const QDomElement& it ) const;
130

131
132
133
134
135
136
137
138
139
140
141

    bool         m_isModified;
    ToolBarList& barList() { return m_barList; }
    const ToolBarList& barList() const { return m_barList; }

private:
    ToolBarList  m_barList;
    QString      m_xmlFile;
    QDomDocument m_document;
    XmlType      m_type;
    KActionCollection* m_actionCollection;
142
143
};

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
QString XmlData::toolBarText( const QDomElement& it ) const
{
    static const QString &tagText = KGlobal::staticQString( "text" );
    static const QString &tagText2 = KGlobal::staticQString( "Text" );
    static const QString &attrName = KGlobal::staticQString( "name" );

    QString name;
    QByteArray txt( it.namedItem( tagText ).toElement().text().toUtf8() );
    if ( txt.isEmpty() )
        txt = it.namedItem( tagText2 ).toElement().text().toUtf8();
    if ( txt.isEmpty() )
        name = it.attribute( attrName );
    else
        name = i18n( txt );

    // the name of the toolbar might depend on whether or not
    // it is in kparts
    if ( ( m_type == XmlData::Shell ) ||
         ( m_type == XmlData::Part ) ) {
        QString doc_name(m_document.documentElement().attribute( attrName ));
        name += " <" + doc_name + '>';
    }
    return name;
}


170
typedef QList<XmlData> XmlDataList;
171

172
class ToolBarItem : public QListWidgetItem
Kurt Granroth's avatar
Kurt Granroth committed
173
174
{
public:
175
176
177
178
179
    ToolBarItem(QListWidget *parent, const QString& tag = QString(), const QString& name = QString(), const QString& statusText = QString())
        : QListWidgetItem(parent),
          m_internalTag(tag),
          m_internalName(name),
          m_statusText(statusText),
180
181
          m_isSeparator(false),
          m_isTextAlongsideIconHidden(false)
182
    {
183
184
        // Drop between items, not onto items
        setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled);
185
    }
186

187
188
189
190
    void setInternalTag(const QString &tag) { m_internalTag = tag; }
    void setInternalName(const QString &name) { m_internalName = name; }
    void setStatusText(const QString &text) { m_statusText = text; }
    void setSeparator(bool sep) { m_isSeparator = sep; }
191
    void setTextAlongsideIconHidden(bool hidden) { m_isTextAlongsideIconHidden = hidden; }
192
193
194
195
    QString internalTag() const { return m_internalTag; }
    QString internalName() const { return m_internalName; }
    QString statusText() const { return m_statusText; }
    bool isSeparator() const { return m_isSeparator; }
196
    bool isTextAlongsideIconHidden() const { return m_isTextAlongsideIconHidden; }
197
198
199
200
201
202
203
204

    int index() const { return listWidget()->row(const_cast<ToolBarItem*>(this)); }

private:
    QString m_internalTag;
    QString m_internalName;
    QString m_statusText;
    bool m_isSeparator;
205
    bool m_isTextAlongsideIconHidden;
206
};
207

208
209
210
211
212
static QDataStream & operator<< ( QDataStream & s, const ToolBarItem & item ) {
    s << item.internalTag();
    s << item.internalName();
    s << item.statusText();
    s << item.isSeparator();
213
    s << item.isTextAlongsideIconHidden();
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    return s;
}
static QDataStream & operator>> ( QDataStream & s, ToolBarItem & item ) {
    QString internalTag;
    s >> internalTag;
    item.setInternalTag(internalTag);
    QString internalName;
    s >> internalName;
    item.setInternalName(internalName);
    QString statusText;
    s >> statusText;
    item.setStatusText(statusText);
    bool sep;
    s >> sep;
    item.setSeparator(sep);
229
230
231
    bool hidden;
    s >> hidden;
    item.setTextAlongsideIconHidden(hidden);
232
233
    return s;
}
234

235
////
236

237
238
239
ToolBarListWidget::ToolBarListWidget(QWidget *parent)
    : QListWidget(parent),
      m_activeList(true)
240
{
241
    setDragDropMode(QAbstractItemView::DragDrop); // no internal moves
242
}
Hamish Rodda's avatar
Hamish Rodda committed
243

244
245
246
247
QMimeData* ToolBarListWidget::mimeData(const QList<QListWidgetItem*> items) const
{
    if (items.isEmpty())
        return 0;
248
249
250
251
    QMimeData* mimedata = new QMimeData();

    QByteArray data;
    {
252
253
254
255
        QDataStream stream(&data, QIODevice::WriteOnly);
        // we only support single selection
        ToolBarItem* item = static_cast<ToolBarItem *>(items.first());
        stream << *item;
256
257
258
    }

    mimedata->setData("application/x-kde-action-list", data);
259
    mimedata->setData("application/x-kde-source-treewidget", m_activeList ? "active" : "inactive");
260
261

    return mimedata;
262
263
264
265
266
}

bool ToolBarListWidget::dropMimeData(int index, const QMimeData * mimeData, Qt::DropAction action)
{
    Q_UNUSED(action)
267
    const QByteArray data = mimeData->data("application/x-kde-action-list");
268
269
270
271
272
273
274
275
276
277
278
279
280
281
    if (data.isEmpty())
        return false;
    QDataStream stream(data);
    const bool sourceIsActiveList = mimeData->data("application/x-kde-source-treewidget") == "active";
    ToolBarItem* item = new ToolBarItem(this); // needs parent, use this temporarily
    stream >> *item;
    emit dropped(this, index, item, sourceIsActiveList);
    return true;
}

ToolBarItem* ToolBarListWidget::currentItem() const
{
    return static_cast<ToolBarItem*>(QListWidget::currentItem());
}
Kurt Granroth's avatar
Kurt Granroth committed
282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305

IconTextEditDialog::IconTextEditDialog(QWidget *parent)
    : KDialog(parent)
{
    setCaption(i18n("Change Text"));
    setButtons(Ok | Cancel);
    setDefaultButton(Ok);
    setModal(true);

    QWidget *mainWidget = new QWidget(this);
    QGridLayout *layout = new QGridLayout(mainWidget);
    layout->setMargin(0);

    m_lineEdit = new KLineEdit(mainWidget);
    m_lineEdit->setClearButtonShown(true);
    QLabel *label = new QLabel(i18n("Icon te&xt:"), this);
    label->setBuddy(m_lineEdit);
    layout->addWidget(label, 0, 0);
    layout->addWidget(m_lineEdit, 0, 1);

    m_cbHidden = new QCheckBox(i18n("&Hide text when toolbar shows text alongside icons"), mainWidget);
    layout->addWidget(m_cbHidden, 1, 1);

306
    connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString)));
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339

    m_lineEdit->setFocus();
    setMainWidget(mainWidget);
    setFixedHeight(sizeHint().height());
}

void IconTextEditDialog::setIconText(const QString &text)
{
    m_lineEdit->setText(text);
}

QString IconTextEditDialog::iconText() const
{
    return m_lineEdit->text().trimmed();
}

void IconTextEditDialog::setTextAlongsideIconHidden(bool hidden)
{
    m_cbHidden->setChecked(hidden);
}

bool IconTextEditDialog::textAlongsideIconHidden() const
{
    return m_cbHidden->isChecked();
}

void IconTextEditDialog::slotTextChanged(const QString &text)
{
    // Do not allow empty icon text
    enableButton(Ok, !text.trimmed().isEmpty());
}


340
class KEditToolBarWidgetPrivate
341
342
{
public:
343
344
    /**
     *
345
     * @param collection In the old-style constructor, this is the collection passed
346
     * to the KEditToolBar constructor.
347
     * In the xmlguifactory-based constructor, we let KXMLGUIClient create a dummy one,
348
349
     * but it probably isn't used.
     */
350
351
352
    KEditToolBarWidgetPrivate(KEditToolBarWidget* widget,
                              const KComponentData &cData, KActionCollection* collection)
        : m_collection( collection ),
353
354
          m_widget(widget),
          m_factory(NULL),
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
          m_loadedOnce( false )
    {
        m_componentData = cData;
        m_isPart   = false;
        m_helpArea = 0L;
        m_kdialogProcess = 0;
        // We want items with an icon to align with items without icon
        // So we use an empty QPixmap for that
        const int iconSize = widget->style()->pixelMetric(QStyle::PM_SmallIconSize);
        m_emptyIcon = QPixmap(iconSize, iconSize);
        m_emptyIcon.fill(Qt::transparent);
    }
    ~KEditToolBarWidgetPrivate()
    {
    }
370

371
372
    // private slots
    void slotToolBarSelected(int index);
373

374
375
    void slotInactiveSelectionChanged();
    void slotActiveSelectionChanged();
376

377
378
379
380
    void slotInsertButton();
    void slotRemoveButton();
    void slotUpButton();
    void slotDownButton();
381

382
    void selectActiveItem(const QString&);
383

384
    void slotChangeIcon();
Christoph Feck's avatar
Christoph Feck committed
385
    void slotChangeIconText();
386

387
    void slotProcessExited();
388

389
    void slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList);
390
391


392
    void setupLayout();
393

David Faure's avatar
David Faure committed
394
395
    void initOldStyle( const QString& file, bool global, const QString& defaultToolbar );
    void initFromFactory( KXMLGUIFactory* factory, const QString& defaultToolbar );
396
397
    void loadToolBarCombo( const QString& defaultToolbar );
    void loadActions(const QDomElement& elem);
398

399
400
401
402
403
    QString xmlFile(const QString& xml_file) const
    {
        return xml_file.isEmpty() ? QString(m_componentData.componentName()) + "ui.rc" :
            xml_file;
    }
404

405
406
407
408
    /**
     * Load in the specified XML file and dump the raw xml
     */
    QString loadXMLFile(const QString& _xml_file)
409
    {
410
411
412
        QString raw_xml;
        QString xml_file = xmlFile(_xml_file);
        //kDebug() << "loadXMLFile xml_file=" << xml_file;
413

414
415
416
417
        if ( !QDir::isRelativePath(xml_file) )
            raw_xml = KXMLGUIFactory::readConfigFile(xml_file);
        else
            raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_componentData);
418

419
        return raw_xml;
420
421
    }

422
423
424
425
    /**
     * Look for a given item in the current toolbar
     */
    QDomElement findElementForToolBarItem( const ToolBarItem* item ) const
426
    {
427
428
429
430
431
432
433
434
435
436
437
        static const QString &attrName    = KGlobal::staticQString( "name" );
        //kDebug(240) << "looking for name=" << item->internalName() << "and tag=" << item->internalTag();
        for(QDomNode n = m_currentToolBarElem.firstChild(); !n.isNull(); n = n.nextSibling())
        {
            QDomElement elem = n.toElement();
            if ((elem.attribute(attrName) == item->internalName()) &&
                (elem.tagName() == item->internalTag()))
                return elem;
        }
        //kDebug(240) << "no item found in the DOM with name=" << item->internalName() << "and tag=" << item->internalTag();
        return QDomElement();
438
439
    }

440
441
442
443
    void insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend = false);
    void removeActive(ToolBarItem *item);
    void moveActive(ToolBarItem *item, ToolBarItem *before);
    void updateLocal(QDomElement& elem);
444

445
#ifndef NDEBUG
446
    void dump() const
447
    {
448
449
450
        XmlDataList::const_iterator xit = m_xmlFiles.begin();
        for ( ; xit != m_xmlFiles.end(); ++xit ) {
            (*xit).dump();
451
452
453
454
        }
    }
#endif

Urs Wolfer's avatar
Urs Wolfer committed
455
    KComboBox *m_toolbarCombo;
456

457
458
459
460
    QToolButton *m_upAction;
    QToolButton *m_removeAction;
    QToolButton *m_insertAction;
    QToolButton *m_downAction;
461

462
463
464
    //QValueList<KAction*> m_actionList;
    KActionCollection* m_collection;
    KEditToolBarWidget* m_widget;
465
    KXMLGUIFactory* m_factory;
466
    KComponentData m_componentData;
467

468
469
    QPixmap m_emptyIcon;

470
471
    XmlData*     m_currentXmlData;
    QDomElement m_currentToolBarElem;
472

473
474
475
476
    QString            m_xmlFile;
    QString            m_globalFile;
    QString            m_rcFile;
    QDomDocument       m_localDoc;
477

478
479
480
    ToolBarList        m_barList;
    ToolBarListWidget *m_inactiveList;
    ToolBarListWidget *m_activeList;
481

482
    XmlDataList m_xmlFiles;
483

484
485
486
487
    QLabel     *m_comboLabel;
    KSeparator *m_comboSeparator;
    QLabel * m_helpArea;
    KPushButton* m_changeIcon;
Christoph Feck's avatar
Christoph Feck committed
488
    KPushButton* m_changeIconText;
489
490
491
492
    KProcess* m_kdialogProcess;
    bool m_isPart : 1;
    bool m_hasKDialog : 1;
    bool m_loadedOnce : 1;
493
494
};

495
496
497
498
499
}

using namespace KDEPrivate;


500
class KEditToolBarPrivate {
501
public:
502
503
504
    KEditToolBarPrivate(KEditToolBar *q): q(q),
      m_accept(false), m_global(false),
      m_collection(0), m_factory(0), m_widget(0) {}
505

Tobias Koenig's avatar
Tobias Koenig committed
506
507
508
509
510
511
512
    void init();

    void _k_slotOk();
    void _k_slotApply();
    void _k_acceptOK(bool);
    void _k_slotDefault();

513
    KEditToolBar *q;
514
    bool m_accept;
515
516
517
518
    // Save parameters for recreating widget after resetting toolbar
    bool m_global;
    KActionCollection* m_collection;
    QString m_file;
519
    QString m_defaultToolBar;
520
    KXMLGUIFactory* m_factory;
521
    KEditToolBarWidget *m_widget;
522
};
Kurt Granroth's avatar
Kurt Granroth committed
523

524
K_GLOBAL_STATIC(QString, s_defaultToolBarName)
525

526
527
KEditToolBar::KEditToolBar( KActionCollection *collection,
                            QWidget* parent )
528
  : KDialog(parent),
529
    d(new KEditToolBarPrivate(this))
Kurt Granroth's avatar
Kurt Granroth committed
530
{
531
    d->m_widget = new KEditToolBarWidget( collection, this);
Tobias Koenig's avatar
Tobias Koenig committed
532
    d->init();
533
    d->m_collection = collection;
534
535
}

536
537
KEditToolBar::KEditToolBar( KXMLGUIFactory* factory,
                            QWidget* parent )
538
    : KDialog(parent),
539
      d(new KEditToolBarPrivate(this))
540
{
541
    d->m_widget = new KEditToolBarWidget( this);
Tobias Koenig's avatar
Tobias Koenig committed
542
    d->init();
543
    d->m_factory = factory;
544
545
}

Tobias Koenig's avatar
Tobias Koenig committed
546
void KEditToolBarPrivate::init()
547
{
Tobias Koenig's avatar
Tobias Koenig committed
548
549
    m_accept = false;
    m_factory = 0;
550

Tobias Koenig's avatar
Tobias Koenig committed
551
    q->setDefaultToolBar( QString() );
552

Tobias Koenig's avatar
Tobias Koenig committed
553
554
555
    q->setCaption(i18n("Configure Toolbars"));
    q->setButtons(KDialog::Default|KDialog::Ok|KDialog::Apply|KDialog::Cancel);
    q->setDefaultButton(KDialog::Ok);
556

Tobias Koenig's avatar
Tobias Koenig committed
557
    q->setModal(false);
558

Tobias Koenig's avatar
Tobias Koenig committed
559
    q->setMainWidget(m_widget);
560

Tobias Koenig's avatar
Tobias Koenig committed
561
562
563
    q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
    q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
    q->enableButtonApply(false);
564

Tobias Koenig's avatar
Tobias Koenig committed
565
566
567
    q->connect(q, SIGNAL(okClicked()), SLOT(_k_slotOk()));
    q->connect(q, SIGNAL(applyClicked()), SLOT(_k_slotApply()));
    q->connect(q, SIGNAL(defaultClicked()), SLOT(_k_slotDefault()));
568

Tobias Koenig's avatar
Tobias Koenig committed
569
    q->setMinimumSize(q->sizeHint());
570
571
}

572
573
574
575
576
577
578
void KEditToolBar::setResourceFile( const QString& file, bool global )
{
    d->m_file = file;
    d->m_global = global;
    d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
}

579
KEditToolBar::~KEditToolBar()
580
581
{
    delete d;
582
    s_defaultToolBarName->clear();
583
584
}

585
586
587
void KEditToolBar::setDefaultToolBar( const QString& toolBarName )
{
    if ( toolBarName.isEmpty() ) {
588
        d->m_defaultToolBar = *s_defaultToolBarName;
589
590
591
592
593
    } else {
        d->m_defaultToolBar = toolBarName;
    }
}

Tobias Koenig's avatar
Tobias Koenig committed
594
void KEditToolBarPrivate::_k_acceptOK(bool b)
595
{
Tobias Koenig's avatar
Tobias Koenig committed
596
597
    q->enableButtonOk(b);
    m_accept = b;
598
599
}

Tobias Koenig's avatar
Tobias Koenig committed
600
void KEditToolBarPrivate::_k_slotDefault()
601
{
Malcolm Hunter's avatar
Malcolm Hunter committed
602
    if ( KMessageBox::warningContinueCancel(q, i18n("Do you really want to reset all toolbars of this application to their default? The changes will be applied immediately."), i18n("Reset Toolbars"),KGuiItem(i18n("Reset")))!=KMessageBox::Continue )
603
604
        return;

605
    KEditToolBarWidget * oldWidget = m_widget;
Tobias Koenig's avatar
Tobias Koenig committed
606
607
    m_widget = 0;
    m_accept = false;
608

Tobias Koenig's avatar
Tobias Koenig committed
609
    if ( m_factory )
610
    {
Tobias Koenig's avatar
Tobias Koenig committed
611
        foreach (KXMLGUIClient* client, m_factory->clients())
612
        {
613
614
            const QString file = client->localXMLFile();
            if (file.isEmpty())
615
                continue;
616
617
            kDebug(240) << "Deleting local xml file" << file;
            // << "for client" << client << typeid(*client).name();
618
619
            if ( QFile::exists( file ) )
                if ( !QFile::remove( file ) )
620
                    kWarning() << "Could not delete" << file;
621
622
        }

623
624
625
        // Reload the xml files in all clients, now that the local files are gone
        oldWidget->rebuildKXMLGUIClients();

Tobias Koenig's avatar
Tobias Koenig committed
626
627
        m_widget = new KEditToolBarWidget( q );
        m_widget->load( m_factory, m_defaultToolBar );
628
629
630
    }
    else
    {
Tobias Koenig's avatar
Tobias Koenig committed
631
        int slash = m_file.lastIndexOf('/')+1;
632
        if (slash)
Tobias Koenig's avatar
Tobias Koenig committed
633
634
            m_file = m_file.mid(slash);
        QString xml_file = KStandardDirs::locateLocal("data", KGlobal::mainComponent().componentName() + '/' + m_file);
635
636
637

        if ( QFile::exists( xml_file ) )
            if ( !QFile::remove( xml_file ) )
Laurent Montel's avatar
Laurent Montel committed
638
                kWarning() << "Could not delete " << xml_file;
639

Tobias Koenig's avatar
Tobias Koenig committed
640
641
        m_widget = new KEditToolBarWidget( m_collection, q );
        q->setResourceFile( m_file, m_global );
642
643
    }

644
645
    // Copy the geometry to minimize UI flicker
    m_widget->setGeometry( oldWidget->geometry() );
Tobias Koenig's avatar
Tobias Koenig committed
646
    q->setMainWidget(m_widget);
647
    delete oldWidget;
648

Tobias Koenig's avatar
Tobias Koenig committed
649
650
    q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
    q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
651

Tobias Koenig's avatar
Tobias Koenig committed
652
    q->enableButtonApply(false);
653

Tobias Koenig's avatar
Tobias Koenig committed
654
655
    emit q->newToolBarConfig();
    emit q->newToolbarConfig(); // compat
656
657
}

Tobias Koenig's avatar
Tobias Koenig committed
658
void KEditToolBarPrivate::_k_slotOk()
Kurt Granroth's avatar
Kurt Granroth committed
659
{
Tobias Koenig's avatar
Tobias Koenig committed
660
661
  if (!m_accept) {
      q->reject();
662
663
664
      return;
  }

Tobias Koenig's avatar
Tobias Koenig committed
665
  if (!m_widget->save())
Kurt Granroth's avatar
Kurt Granroth committed
666
667
668
669
  {
    // some error box here is needed
  }
  else
670
  {
671
672
673
674
675
676
    // Do not emit the "newToolBarConfig" signal again here if the "Apply"
    // button was already pressed and no further changes were made.
    if (q->isButtonEnabled(KDialog::Apply)) {
        emit q->newToolBarConfig();
        emit q->newToolbarConfig(); // compat
    }
Tobias Koenig's avatar
Tobias Koenig committed
677
    q->accept();
678
  }
Kurt Granroth's avatar
Kurt Granroth committed
679
680
}

Tobias Koenig's avatar
Tobias Koenig committed
681
void KEditToolBarPrivate::_k_slotApply()
682
{
Tobias Koenig's avatar
Tobias Koenig committed
683
684
685
686
    (void)m_widget->save();
    q->enableButtonApply(false);
    emit q->newToolBarConfig();
    emit q->newToolbarConfig(); // compat
687
688
}

689
void KEditToolBar::setGlobalDefaultToolBar(const char *toolbarName)
690
{
691
    *s_defaultToolBarName = QString::fromLatin1(toolbarName);
692
693
}

694
695
KEditToolBarWidget::KEditToolBarWidget( KActionCollection *collection,
                                        QWidget *parent )
Kurt Granroth's avatar
Kurt Granroth committed
696
  : QWidget(parent),
697
    d(new KEditToolBarWidgetPrivate(this, componentData(), collection))
698
{
699
    d->setupLayout();
700
701
}

702
KEditToolBarWidget::KEditToolBarWidget( QWidget *parent )
703
  : QWidget(parent),
704
    d(new KEditToolBarWidgetPrivate(this, componentData(), KXMLGUIClient::actionCollection() /*create new one*/))
705
{
706
    d->setupLayout();
707
708
}

709
KEditToolBarWidget::~KEditToolBarWidget()
710
{
711
    delete d;
712
713
}

714
void KEditToolBarWidget::load( const QString& file, bool global, const QString& defaultToolBar )
715
{
David Faure's avatar
David Faure committed
716
    d->initOldStyle( file, global, defaultToolBar );
717
718
}

719
void KEditToolBarWidget::load( KXMLGUIFactory* factory, const QString& defaultToolBar )
720
{
David Faure's avatar
David Faure committed
721
    d->initFromFactory( factory, defaultToolBar );
722
723
}

David Faure's avatar
David Faure committed
724
void KEditToolBarWidgetPrivate::initOldStyle( const QString& resourceFile,
725
726
                                              bool global,
                                              const QString& defaultToolBar )
Kurt Granroth's avatar
Kurt Granroth committed
727
{
728
729
730
731
732
733
    //TODO: make sure we can call this multiple times?
    if ( m_loadedOnce ) {
        return;
    }

    m_loadedOnce = true;
734
735
736
737
    //d->m_actionList = collection->actions();

    // handle the merging
    if (global)
738
        m_widget->loadStandardsXmlFile(); // ui_standards.rc
739
740
741
742
743
744
745
746
747
748
749
750
751
752
    const QString localXML = loadXMLFile( resourceFile );
    m_widget->setXML(localXML, global ? true /*merge*/ : false);

    // first, get all of the necessary info for our local xml
    XmlData local(XmlData::Local, xmlFile(resourceFile), m_collection);
    QDomDocument domDoc;
    domDoc.setContent(localXML);
    local.setDomDocument(domDoc);
    m_xmlFiles.append(local);

    // then, the merged one (ui_standards + local xml)
    XmlData merge(XmlData::Merged, QString(), m_collection);
    merge.setDomDocument(m_widget->domDocument());
    m_xmlFiles.append(merge);
753

754
#ifndef NDEBUG
755
    dump();
756
757
#endif

758
759
760
761
    // now load in our toolbar combo box
    loadToolBarCombo( defaultToolBar );
    m_widget->adjustSize();
    m_widget->setMinimumSize( m_widget->sizeHint() );
762
}
Kurt Granroth's avatar
Kurt Granroth committed
763

David Faure's avatar
David Faure committed
764
765
void KEditToolBarWidgetPrivate::initFromFactory(KXMLGUIFactory* factory,
                                                const QString& defaultToolBar)
766
{
767
768
769
770
771
772
773
    //TODO: make sure we can call this multiple times?
    if ( m_loadedOnce ) {
        return;
    }

    m_loadedOnce = true;

774
    m_factory = factory;
775
776

  // add all of the client data
777
778
  bool first = true;
  foreach (KXMLGUIClient* client, factory->clients())
779
  {
780
    if (client->xmlFile().isEmpty())
781
782
      continue;

783
    XmlData::XmlType type = XmlData::Part;
784
    if ( first ) {
785
      type = XmlData::Shell;
786
      first = false;
787
      Q_ASSERT(!client->localXMLFile().isEmpty()); // where would we save changes??
788
    }
789
790

    XmlData data(type, client->localXMLFile(), client->actionCollection());
791
    QDomDocument domDoc = client->domDocument();
792
    data.setDomDocument(domDoc);
793
    m_xmlFiles.append(data);
794

795
    //d->m_actionList += client->actionCollection()->actions();
796
  }
797

798
799
800
801
#ifndef NDEBUG
  //d->dump();
#endif

802
803
804
805
  // now load in our toolbar combo box
  loadToolBarCombo( defaultToolBar );
  m_widget->adjustSize();
  m_widget->setMinimumSize( m_widget->sizeHint() );
806

807
808
809
  m_widget->actionCollection()->addAssociatedWidget( m_widget );
  foreach (QAction* action, m_widget->actionCollection()->actions())
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
Kurt Granroth's avatar
Kurt Granroth committed
810
811
}

812
bool KEditToolBarWidget::save()
Kurt Granroth's avatar
Kurt Granroth committed
813
{
Laurent Montel's avatar
Laurent Montel committed
814
  //kDebug(240) << "KEditToolBarWidget::save";
815
816
817
818
  XmlDataList::Iterator it = d->m_xmlFiles.begin();
  for ( ; it != d->m_xmlFiles.end(); ++it)
  {
    // let's not save non-modified files
Andrew Coles's avatar
   
Andrew Coles committed
819
    if ( !((*it).m_isModified) )
820
821
822
      continue;

    // let's also skip (non-existent) merged files
823
    if ( (*it).type() == XmlData::Merged )
824
825
      continue;

826
827
828
829
830
831
832
833
834
835
    // Add noMerge="1" to all the menus since we are saving the merged data
    QDomNodeList menuNodes = (*it).domDocument().elementsByTagName( "Menu" );
    for (uint i = 0; i < menuNodes.length(); ++i)
    {
        QDomNode menuNode = menuNodes.item(i);
        QDomElement menuElement = menuNode.toElement();
        if (menuElement.isNull()) continue;
        menuElement.setAttribute( "noMerge", "1" );
    }

836
    kDebug() << (*it).domDocument().toString();
Kurt Granroth's avatar
Kurt Granroth committed
837

838
    kDebug(240) << "Saving " << (*it).xmlFile();
839
    // if we got this far, we might as well just save it
840
    KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile());
841
842
  }

843
844
    if (!d->m_factory)
        return true;
845

846
847
848
849
850
  rebuildKXMLGUIClients();

  return true;
}

851
void KEditToolBarWidget::rebuildKXMLGUIClients()
852
{
853
854
    if (!d->m_factory)
        return;
855

856
857
    const QList<KXMLGUIClient*> clients = d->m_factory->clients();
    //kDebug(240) << "factory: " << clients.count() << " clients";
858

859
860
861
    // remove the elements starting from the last going to the first
    if (!clients.count())
        return;
862

863
864
865
866
867
868
869
    QListIterator<KXMLGUIClient*> clientIterator = clients;
    clientIterator.toBack();
    while (clientIterator.hasPrevious()) {
        KXMLGUIClient* client = clientIterator.previous();
        //kDebug(240) << "factory->removeClient " << client;
        d->m_factory->removeClient(client);
    }
870

871
  KXMLGUIClient *firstClient = clients.first();
872

873
  // now, rebuild the gui from the first to the last
Laurent Montel's avatar
Laurent Montel committed
874
  //kDebug(240) << "rebuilding the gui";
875
  foreach (KXMLGUIClient* client, clients)
876
  {
Laurent Montel's avatar
Laurent Montel committed
877
    //kDebug(240) << "updating client " << client << " " << client->componentData().componentName() << "  xmlFile=" << client->xmlFile();
878
879
880
881
882
    QString file( client->xmlFile() ); // before setting ui_standards!
    if ( !file.isEmpty() )
    {
        // passing an empty stream forces the clients to reread the XML
        client->setXMLGUIBuildDocument( QDomDocument() );
883

884
885
        // for the shell, merge in ui_standards.rc
        if ( client == firstClient ) // same assumption as in the ctor: first==shell
886
            client->loadStandardsXmlFile();
887
888
889

        // and this forces it to use the *new* XML file
        client->setXMLFile( file, client == firstClient /* merge if shell */ );
890
891

        // [we can't use reloadXML, it doesn't load ui_standards.rc]
892
    }
893
894
  }

895
896
897
898
899
900
    // Now we can add the clients to the factory
    // We don't do it in the loop above because adding a part automatically
    // adds its plugins, so we must make sure the plugins were updated first.
    foreach(KXMLGUIClient* client, clients) {
        d->m_factory->addClient(client);
    }
901
}
Kurt Granroth's avatar
Kurt Granroth committed
902

903
void KEditToolBarWidgetPrivate::setupLayout()
Kurt Granroth's avatar
Kurt Granroth committed
904
905
{
  // the toolbar name combo
Stephan Binner's avatar
Stephan Binner committed
906
  m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget);
Urs Wolfer's avatar
Urs Wolfer committed
907
  m_toolbarCombo = new KComboBox(m_widget);
908
909
  m_comboLabel->setBuddy(m_toolbarCombo);
  m_comboSeparator = new KSeparator(m_widget);
910
911
  QObject::connect(m_toolbarCombo, SIGNAL(activated(int)),
                   m_widget,       SLOT(slotToolBarSelected(int)));
Kurt Granroth's avatar
Kurt Granroth committed
912

Kurt Granroth's avatar
Kurt Granroth committed
913
//  QPushButton *new_toolbar = new QPushButton(i18n("&New"), this);
914
//  new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall));
Kurt Granroth's avatar
Kurt Granroth committed
915
916
//  new_toolbar->setEnabled(false); // disabled until implemented
//  QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this);
917
//  del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall));
Kurt Granroth's avatar
Kurt Granroth committed
918
//  del_toolbar->setEnabled(false); // disabled until implemented
Kurt Granroth's avatar
Kurt Granroth committed
919
920

  // our list of inactive actions
921
  QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget);
922
  m_inactiveList = new ToolBarListWidget(m_widget);
923
  m_inactiveList->setDragEnabled(true);
924
  m_inactiveList->setActiveList(false);
925
  m_inactiveList->setMinimumSize(180, 250);
926
  m_inactiveList->setDropIndicatorShown(false); // #165663
927
928
929
  inactive_label->setBuddy(m_inactiveList);
  QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()),
                   m_widget,       SLOT(slotInactiveSelectionChanged()));
930
  QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
931
                   m_widget,       SLOT(slotInsertButton()));
932
933
  QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
                   m_widget,       SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
Kurt Granroth's avatar
Kurt Granroth committed
934

935
936
937
  KListWidgetSearchLine *inactiveListSearchLine = new KListWidgetSearchLine(m_widget, m_inactiveList);
  inactiveListSearchLine->setClickMessage(i18n("Filter"));

Kurt Granroth's avatar
Kurt Granroth committed
938
  // our list of active actions
939
  QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget);
940
  m_activeList = new ToolBarListWidget(m_widget);
941
  m_activeList->setDragEnabled(true);
942
  m_activeList->setActiveList(true);
943
  // With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ...
944
945
  m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100);
  active_label->setBuddy(m_activeList);
946