kdelibs/kdeui/dialogs/kedittoolbar.cpp

1696 lines
53 KiB
C++
Raw Permalink Normal View History

2014-11-13 01:04:59 +02:00
/* This file is part of the KDE libraries
Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
Copyright 2007 David Faure <faure@kde.org>
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
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <kedittoolbar.h>
#include <kedittoolbar_p.h>
#include <QtGui/qevent.h>
2014-11-13 01:04:59 +02:00
#include <QtXml/qdom.h>
2014-11-13 01:04:59 +02:00
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QProcess>
#include <QtCore/QMimeData>
#include <QtGui/QHeaderView>
2014-11-13 01:04:59 +02:00
#include <QtGui/QToolButton>
#include <QtGui/QLabel>
#include <QtGui/QApplication>
#include <QtGui/QGridLayout>
#include <QtGui/QCheckBox>
#include <QtGui/QLayout>
2014-11-13 01:04:59 +02:00
#include <kstandarddirs.h>
#include <klistwidgetsearchline.h>
#include <klocale.h>
#include <kicon.h>
#include <kiconloader.h>
#include <kcomponentdata.h>
#include <kmessagebox.h>
#include <kxmlguifactory.h>
#include <kseparator.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kpushbutton.h>
#include <ktoolbar.h>
#include <kdeversion.h>
#include <kcombobox.h>
#include <klineedit.h>
#include "kaction.h"
#include "kactioncollection.h"
static const char * const separatorstring = I18N_NOOP("--- separator ---");
#define SEPARATORSTRING i18n(separatorstring)
static const char* const s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" };
typedef QList<QDomElement> ToolBarList;
namespace KDEPrivate {
/**
* Return a list of toolbar elements given a toplevel element
*/
static ToolBarList findToolBars(const QDomElement& start)
{
static const QString tagToolBar = QString::fromLatin1( "ToolBar" );
static const QString tagMenuBar = QString::fromLatin1( "MenuBar" );
static const QString attrNoEdit = QString::fromLatin1( "noEdit" );
2014-11-13 01:04:59 +02:00
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;
}
class XmlData
{
public:
enum XmlType { Shell = 0, Part, Local, Merged };
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() << "XmlData" << this << "type" << s_XmlTypeToString[m_type] << "xmlFile:" << m_xmlFile;
2014-11-13 01:04:59 +02:00
foreach (const QDomElement& element, m_barList) {
kDebug() << " ToolBar:" << toolBarText( element );
2014-11-13 01:04:59 +02:00
}
if ( m_actionCollection )
kDebug() << " " << m_actionCollection->actions().count() << "actions in the collection.";
2014-11-13 01:04:59 +02:00
else
kDebug() << " no action collection.";
2014-11-13 01:04:59 +02:00
}
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.cloneNode().toDocument();
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;
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;
};
QString XmlData::toolBarText( const QDomElement& it ) const
{
static const QString tagText = QString::fromLatin1( "text" );
static const QString tagText2 = QString::fromLatin1( "Text" );
static const QString attrName = QString::fromLatin1( "name" );
2014-11-13 01:04:59 +02:00
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;
}
typedef QList<XmlData> XmlDataList;
class ToolBarItem : public QListWidgetItem
{
public:
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),
m_isSeparator(false),
m_isTextAlongsideIconHidden(false)
{
// Drop between items, not onto items
setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled);
}
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; }
void setTextAlongsideIconHidden(bool hidden) { m_isTextAlongsideIconHidden = hidden; }
QString internalTag() const { return m_internalTag; }
QString internalName() const { return m_internalName; }
QString statusText() const { return m_statusText; }
bool isSeparator() const { return m_isSeparator; }
bool isTextAlongsideIconHidden() const { return m_isTextAlongsideIconHidden; }
int index() const { return listWidget()->row(const_cast<ToolBarItem*>(this)); }
private:
QString m_internalTag;
QString m_internalName;
QString m_statusText;
bool m_isSeparator;
bool m_isTextAlongsideIconHidden;
};
static QDataStream & operator<< ( QDataStream & s, const ToolBarItem & item ) {
s << item.internalTag();
s << item.internalName();
s << item.statusText();
s << item.isSeparator();
s << item.isTextAlongsideIconHidden();
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);
bool hidden;
s >> hidden;
item.setTextAlongsideIconHidden(hidden);
return s;
}
////
ToolBarListWidget::ToolBarListWidget(QWidget *parent)
: QListWidget(parent),
m_activeList(true)
{
setDragDropMode(QAbstractItemView::DragDrop); // no internal moves
}
QMimeData* ToolBarListWidget::mimeData(const QList<QListWidgetItem*> items) const
{
if (items.isEmpty())
return 0;
QMimeData* mimedata = new QMimeData();
QByteArray data;
{
QDataStream stream(&data, QIODevice::WriteOnly);
// we only support single selection
ToolBarItem* item = static_cast<ToolBarItem *>(items.first());
stream << *item;
}
mimedata->setData("application/x-kde-action-list", data);
mimedata->setData("application/x-kde-source-treewidget", m_activeList ? "active" : "inactive");
return mimedata;
}
bool ToolBarListWidget::dropMimeData(int index, const QMimeData * mimeData, Qt::DropAction action)
{
Q_UNUSED(action)
const QByteArray data = mimeData->data("application/x-kde-action-list");
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());
}
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);
connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString)));
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());
}
class KEditToolBarWidgetPrivate
{
public:
/**
*
* @param collection In the old-style constructor, this is the collection passed
* to the KEditToolBar constructor.
* In the xmlguifactory-based constructor, we let KXMLGUIClient create a dummy one,
* but it probably isn't used.
*/
KEditToolBarWidgetPrivate(KEditToolBarWidget* widget,
const KComponentData &cData, KActionCollection* collection)
: m_collection( collection ),
m_widget(widget),
m_factory(NULL),
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()
{
}
// private slots
void slotToolBarSelected(int index);
void slotInactiveSelectionChanged();
void slotActiveSelectionChanged();
void slotInsertButton();
void slotRemoveButton();
void slotUpButton();
void slotDownButton();
void selectActiveItem(const QString&);
void slotChangeIcon();
void slotChangeIconText();
void slotProcessExited();
void slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList);
void setupLayout();
void initOldStyle( const QString& file, bool global, const QString& defaultToolbar );
void initFromFactory( KXMLGUIFactory* factory, const QString& defaultToolbar );
void loadToolBarCombo( const QString& defaultToolbar );
void loadActions(const QDomElement& elem);
QString xmlFile(const QString& xml_file) const
{
return xml_file.isEmpty() ? QString(m_componentData.componentName()) + "ui.rc" :
xml_file;
}
/**
* Load in the specified XML file and dump the raw xml
*/
QString loadXMLFile(const QString& _xml_file)
{
QString raw_xml;
QString xml_file = xmlFile(_xml_file);
//kDebug() << "loadXMLFile xml_file=" << xml_file;
if ( !QDir::isRelativePath(xml_file) )
raw_xml = KXMLGUIFactory::readConfigFile(xml_file);
else
raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_componentData);
return raw_xml;
}
/**
* Look for a given item in the current toolbar
*/
QDomElement findElementForToolBarItem( const ToolBarItem* item ) const
{
static const QString attrName = QString::fromLatin1( "name" );
// kDebug() << "looking for name=" << item->internalName() << "and tag=" << item->internalTag();
2014-11-13 01:04:59 +02:00
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() << "no item found in the DOM with name=" << item->internalName() << "and tag=" << item->internalTag();
2014-11-13 01:04:59 +02:00
return QDomElement();
}
void insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend = false);
void removeActive(ToolBarItem *item);
void moveActive(ToolBarItem *item, ToolBarItem *before);
void updateLocal(QDomElement& elem);
#ifndef NDEBUG
void dump() const
{
XmlDataList::const_iterator xit = m_xmlFiles.begin();
for ( ; xit != m_xmlFiles.end(); ++xit ) {
(*xit).dump();
}
}
#endif
KComboBox *m_toolbarCombo;
QToolButton *m_upAction;
QToolButton *m_removeAction;
QToolButton *m_insertAction;
QToolButton *m_downAction;
//QValueList<KAction*> m_actionList;
KActionCollection* m_collection;
KEditToolBarWidget* m_widget;
KXMLGUIFactory* m_factory;
KComponentData m_componentData;
QPixmap m_emptyIcon;
XmlData* m_currentXmlData;
QDomElement m_currentToolBarElem;
QString m_xmlFile;
QString m_globalFile;
QString m_rcFile;
QDomDocument m_localDoc;
ToolBarList m_barList;
ToolBarListWidget *m_inactiveList;
ToolBarListWidget *m_activeList;
XmlDataList m_xmlFiles;
QLabel *m_comboLabel;
KSeparator *m_comboSeparator;
QLabel * m_helpArea;
KPushButton* m_changeIcon;
KPushButton* m_changeIconText;
QProcess* m_kdialogProcess;
2014-11-13 01:04:59 +02:00
bool m_isPart : 1;
bool m_hasKDialog : 1;
bool m_loadedOnce : 1;
};
}
using namespace KDEPrivate;
class KEditToolBarPrivate {
public:
KEditToolBarPrivate(KEditToolBar *q): q(q),
m_accept(false), m_global(false),
m_collection(0), m_factory(0), m_widget(0) {}
void init();
void _k_slotOk();
void _k_slotApply();
void _k_acceptOK(bool);
void _k_slotDefault();
KEditToolBar *q;
bool m_accept;
// Save parameters for recreating widget after resetting toolbar
bool m_global;
KActionCollection* m_collection;
QString m_file;
QString m_defaultToolBar;
KXMLGUIFactory* m_factory;
KEditToolBarWidget *m_widget;
};
K_GLOBAL_STATIC(QString, s_defaultToolBarName)
KEditToolBar::KEditToolBar( KActionCollection *collection,
QWidget* parent )
: KDialog(parent),
d(new KEditToolBarPrivate(this))
{
d->m_widget = new KEditToolBarWidget( collection, this);
d->init();
d->m_collection = collection;
}
KEditToolBar::KEditToolBar( KXMLGUIFactory* factory,
QWidget* parent )
: KDialog(parent),
d(new KEditToolBarPrivate(this))
{
d->m_widget = new KEditToolBarWidget( this);
d->init();
d->m_factory = factory;
}
void KEditToolBarPrivate::init()
{
m_accept = false;
m_factory = 0;
q->setDefaultToolBar( QString() );
q->setCaption(i18n("Configure Toolbars"));
q->setButtons(KDialog::Default|KDialog::Ok|KDialog::Apply|KDialog::Cancel);
q->setDefaultButton(KDialog::Ok);
q->setModal(false);
q->setMainWidget(m_widget);
q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
q->enableButtonApply(false);
q->connect(q, SIGNAL(okClicked()), SLOT(_k_slotOk()));
q->connect(q, SIGNAL(applyClicked()), SLOT(_k_slotApply()));
q->connect(q, SIGNAL(defaultClicked()), SLOT(_k_slotDefault()));
q->setMinimumSize(q->sizeHint());
}
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 );
}
KEditToolBar::~KEditToolBar()
{
delete d;
s_defaultToolBarName->clear();
}
void KEditToolBar::setDefaultToolBar( const QString& toolBarName )
{
if ( toolBarName.isEmpty() ) {
d->m_defaultToolBar = *s_defaultToolBarName;
} else {
d->m_defaultToolBar = toolBarName;
}
}
void KEditToolBarPrivate::_k_acceptOK(bool b)
{
q->enableButtonOk(b);
m_accept = b;
}
void KEditToolBarPrivate::_k_slotDefault()
{
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 )
return;
KEditToolBarWidget * oldWidget = m_widget;
m_widget = 0;
m_accept = false;
if ( m_factory )
{
foreach (KXMLGUIClient* client, m_factory->clients())
{
const QString file = client->localXMLFile();
if (file.isEmpty())
continue;
kDebug() << "Deleting local xml file" << file;
2014-11-13 01:04:59 +02:00
// << "for client" << client << typeid(*client).name();
if ( QFile::exists( file ) )
if ( !QFile::remove( file ) )
kWarning() << "Could not delete" << file;
}
// Reload the xml files in all clients, now that the local files are gone
oldWidget->rebuildKXMLGUIClients();
m_widget = new KEditToolBarWidget( q );
m_widget->load( m_factory, m_defaultToolBar );
}
else
{
int slash = m_file.lastIndexOf('/')+1;
if (slash)
m_file = m_file.mid(slash);
QString xml_file = KStandardDirs::locateLocal("data", KGlobal::mainComponent().componentName() + '/' + m_file);
if ( QFile::exists( xml_file ) )
if ( !QFile::remove( xml_file ) )
kWarning() << "Could not delete " << xml_file;
m_widget = new KEditToolBarWidget( m_collection, q );
q->setResourceFile( m_file, m_global );
}
// Copy the geometry to minimize UI flicker
m_widget->setGeometry( oldWidget->geometry() );
q->setMainWidget(m_widget);
delete oldWidget;
q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool)));
q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(enableButtonApply(bool)));
q->enableButtonApply(false);
emit q->newToolBarConfig();
}
void KEditToolBarPrivate::_k_slotOk()
{
if (!m_accept) {
q->reject();
return;
}
if (!m_widget->save())
{
// some error box here is needed
}
else
{
// 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();
}
q->accept();
}
}
void KEditToolBarPrivate::_k_slotApply()
{
(void)m_widget->save();
q->enableButtonApply(false);
emit q->newToolBarConfig();
}
void KEditToolBar::setGlobalDefaultToolBar(const char *toolbarName)
{
*s_defaultToolBarName = QString::fromLatin1(toolbarName);
}
KEditToolBarWidget::KEditToolBarWidget( KActionCollection *collection,
QWidget *parent )
: QWidget(parent),
d(new KEditToolBarWidgetPrivate(this, componentData(), collection))
{
d->setupLayout();
}
KEditToolBarWidget::KEditToolBarWidget( QWidget *parent )
: QWidget(parent),
d(new KEditToolBarWidgetPrivate(this, componentData(), KXMLGUIClient::actionCollection() /*create new one*/))
{
d->setupLayout();
}
KEditToolBarWidget::~KEditToolBarWidget()
{
delete d;
}
void KEditToolBarWidget::load( const QString& file, bool global, const QString& defaultToolBar )
{
d->initOldStyle( file, global, defaultToolBar );
}
void KEditToolBarWidget::load( KXMLGUIFactory* factory, const QString& defaultToolBar )
{
d->initFromFactory( factory, defaultToolBar );
}
void KEditToolBarWidgetPrivate::initOldStyle( const QString& resourceFile,
bool global,
const QString& defaultToolBar )
{
//TODO: make sure we can call this multiple times?
if ( m_loadedOnce ) {
return;
}
m_loadedOnce = true;
//d->m_actionList = collection->actions();
// handle the merging
if (global)
m_widget->loadStandardsXmlFile(); // ui_standards.rc
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);
#ifndef NDEBUG
dump();
#endif
// now load in our toolbar combo box
loadToolBarCombo( defaultToolBar );
m_widget->adjustSize();
m_widget->setMinimumSize( m_widget->sizeHint() );
}
void KEditToolBarWidgetPrivate::initFromFactory(KXMLGUIFactory* factory,
const QString& defaultToolBar)
{
//TODO: make sure we can call this multiple times?
if ( m_loadedOnce ) {
return;
}
m_loadedOnce = true;
m_factory = factory;
// add all of the client data
bool first = true;
foreach (KXMLGUIClient* client, factory->clients())
{
if (client->xmlFile().isEmpty())
continue;
XmlData::XmlType type = XmlData::Part;
if ( first ) {
type = XmlData::Shell;
first = false;
Q_ASSERT(!client->localXMLFile().isEmpty()); // where would we save changes??
}
XmlData data(type, client->localXMLFile(), client->actionCollection());
QDomDocument domDoc = client->domDocument();
data.setDomDocument(domDoc);
m_xmlFiles.append(data);
//d->m_actionList += client->actionCollection()->actions();
}
#ifndef NDEBUG
//d->dump();
#endif
// now load in our toolbar combo box
loadToolBarCombo( defaultToolBar );
m_widget->adjustSize();
m_widget->setMinimumSize( m_widget->sizeHint() );
m_widget->actionCollection()->addAssociatedWidget( m_widget );
foreach (QAction* action, m_widget->actionCollection()->actions())
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
}
bool KEditToolBarWidget::save()
{
//kDebug() << "KEditToolBarWidget::save";
2014-11-13 01:04:59 +02:00
XmlDataList::Iterator it = d->m_xmlFiles.begin();
for ( ; it != d->m_xmlFiles.end(); ++it)
{
// let's not save non-modified files
if ( !((*it).m_isModified) )
continue;
// let's also skip (non-existent) merged files
if ( (*it).type() == XmlData::Merged )
continue;
// Add noMerge="1" to all the menus since we are saving the merged data
QDomNodeList menuNodes = (*it).domDocument().elementsByTagName( "Menu" );
for (int i = 0; i < menuNodes.length(); ++i)
2014-11-13 01:04:59 +02:00
{
QDomNode menuNode = menuNodes.item(i);
QDomElement menuElement = menuNode.toElement();
if (menuElement.isNull()) continue;
menuElement.setAttribute( "noMerge", "1" );
}
kDebug() << (*it).domDocument().toString();
kDebug() << "Saving " << (*it).xmlFile();
2014-11-13 01:04:59 +02:00
// if we got this far, we might as well just save it
KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile());
}
if (!d->m_factory)
return true;
rebuildKXMLGUIClients();
return true;
}
void KEditToolBarWidget::rebuildKXMLGUIClients()
{
if (!d->m_factory)
return;
const QList<KXMLGUIClient*> clients = d->m_factory->clients();
// kDebug() << "factory: " << clients.count() << " clients";
2014-11-13 01:04:59 +02:00
// remove the elements starting from the last going to the first
if (!clients.count())
return;
QListIterator<KXMLGUIClient*> clientIterator = clients;
clientIterator.toBack();
while (clientIterator.hasPrevious()) {
KXMLGUIClient* client = clientIterator.previous();
// kDebug() << "factory->removeClient " << client;
2014-11-13 01:04:59 +02:00
d->m_factory->removeClient(client);
}
KXMLGUIClient *firstClient = clients.first();
// now, rebuild the gui from the first to the last
// kDebug() << "rebuilding the gui";
2014-11-13 01:04:59 +02:00
foreach (KXMLGUIClient* client, clients)
{
//kDebug() << "updating client " << client << " " << client->componentData().componentName() << " xmlFile=" << client->xmlFile();
2014-11-13 01:04:59 +02:00
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() );
// for the shell, merge in ui_standards.rc
if ( client == firstClient ) // same assumption as in the ctor: first==shell
client->loadStandardsXmlFile();
// and this forces it to use the *new* XML file
client->setXMLFile( file, client == firstClient /* merge if shell */ );
// [we can't use reloadXML, it doesn't load ui_standards.rc]
}
}
// 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);
}
}
void KEditToolBarWidgetPrivate::setupLayout()
{
// the toolbar name combo
m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget);
m_toolbarCombo = new KComboBox(m_widget);
m_comboLabel->setBuddy(m_toolbarCombo);
m_comboSeparator = new KSeparator(m_widget);
QObject::connect(m_toolbarCombo, SIGNAL(activated(int)),
m_widget, SLOT(slotToolBarSelected(int)));
// QPushButton *new_toolbar = new QPushButton(i18n("&New"), this);
// new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall));
// new_toolbar->setEnabled(false); // disabled until implemented
// QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this);
// del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall));
// del_toolbar->setEnabled(false); // disabled until implemented
// our list of inactive actions
QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget);
m_inactiveList = new ToolBarListWidget(m_widget);
m_inactiveList->setDragEnabled(true);
m_inactiveList->setActiveList(false);
m_inactiveList->setMinimumSize(180, 250);
m_inactiveList->setDropIndicatorShown(false); // #165663
inactive_label->setBuddy(m_inactiveList);
QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()),
m_widget, SLOT(slotInactiveSelectionChanged()));
QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
m_widget, SLOT(slotInsertButton()));
QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
KListWidgetSearchLine *inactiveListSearchLine = new KListWidgetSearchLine(m_widget, m_inactiveList);
inactiveListSearchLine->setClickMessage(i18n("Filter"));
// our list of active actions
QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget);
m_activeList = new ToolBarListWidget(m_widget);
m_activeList->setDragEnabled(true);
m_activeList->setActiveList(true);
// With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ...
m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100);
active_label->setBuddy(m_activeList);
QObject::connect(m_activeList, SIGNAL(itemSelectionChanged()),
m_widget, SLOT(slotActiveSelectionChanged()));
QObject::connect(m_activeList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
m_widget, SLOT(slotRemoveButton()));
QObject::connect(m_activeList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)),
m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool)));
KListWidgetSearchLine *activeListSearchLine = new KListWidgetSearchLine(m_widget, m_activeList);
activeListSearchLine->setClickMessage(i18n("Filter"));
// "change icon" button
m_changeIcon = new KPushButton(i18n( "Change &Icon..." ), m_widget);
m_changeIcon->setIcon(KIcon("preferences-desktop-icons"));
QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
m_hasKDialog = !kdialogExe.isEmpty();
m_changeIcon->setEnabled(m_hasKDialog && m_activeList->currentItem());
QObject::connect( m_changeIcon, SIGNAL(clicked()),
m_widget, SLOT(slotChangeIcon()) );
// "change icon text" button
m_changeIconText = new KPushButton(i18n( "Change Te&xt..." ), m_widget);
m_changeIconText->setIcon(KIcon("edit-rename"));
m_changeIconText->setEnabled(m_activeList->currentItem() != 0);
QObject::connect( m_changeIconText, SIGNAL(clicked()),
m_widget, SLOT(slotChangeIconText()) );
// The buttons in the middle
m_upAction = new QToolButton(m_widget);
m_upAction->setIcon( KIcon("go-up") );
m_upAction->setEnabled(false);
m_upAction->setAutoRepeat(true);
QObject::connect(m_upAction, SIGNAL(clicked()), m_widget, SLOT(slotUpButton()));
m_insertAction = new QToolButton(m_widget);
m_insertAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-previous" : "go-next") );
m_insertAction->setEnabled(false);
QObject::connect(m_insertAction, SIGNAL(clicked()), m_widget, SLOT(slotInsertButton()));
m_removeAction = new QToolButton(m_widget);
m_removeAction->setIcon( KIcon(QApplication::isRightToLeft() ? "go-next" : "go-previous") );
m_removeAction->setEnabled(false);
QObject::connect(m_removeAction, SIGNAL(clicked()), m_widget, SLOT(slotRemoveButton()));
m_downAction = new QToolButton(m_widget);
m_downAction->setIcon( KIcon("go-down") );
m_downAction->setEnabled(false);
m_downAction->setAutoRepeat(true);
QObject::connect(m_downAction, SIGNAL(clicked()), m_widget, SLOT(slotDownButton()));
m_helpArea = new QLabel(m_widget);
m_helpArea->setWordWrap(true);
// now start with our layouts
QVBoxLayout *top_layout = new QVBoxLayout(m_widget);
top_layout->setMargin(0);
QVBoxLayout *name_layout = new QVBoxLayout();
QHBoxLayout *list_layout = new QHBoxLayout();
QVBoxLayout *inactive_layout = new QVBoxLayout();
QVBoxLayout *active_layout = new QVBoxLayout();
QHBoxLayout *changeIcon_layout = new QHBoxLayout();
QGridLayout *button_layout = new QGridLayout();
name_layout->addWidget(m_comboLabel);
name_layout->addWidget(m_toolbarCombo);
// name_layout->addWidget(new_toolbar);
// name_layout->addWidget(del_toolbar);
button_layout->setSpacing( 0 );
button_layout->setRowStretch( 0, 10 );
button_layout->addWidget(m_upAction, 1, 1);
button_layout->addWidget(m_removeAction, 2, 0);
button_layout->addWidget(m_insertAction, 2, 2);
button_layout->addWidget(m_downAction, 3, 1);
button_layout->setRowStretch( 4, 10 );
inactive_layout->addWidget(inactive_label);
inactive_layout->addWidget(inactiveListSearchLine);
inactive_layout->addWidget(m_inactiveList, 1);
active_layout->addWidget(active_label);
active_layout->addWidget(activeListSearchLine);
active_layout->addWidget(m_activeList, 1);
active_layout->addLayout(changeIcon_layout);
changeIcon_layout->addWidget(m_changeIcon);
changeIcon_layout->addStretch( 1 );
changeIcon_layout->addWidget(m_changeIconText);
list_layout->addLayout(inactive_layout);
list_layout->addLayout(button_layout);
list_layout->addLayout(active_layout);
top_layout->addLayout(name_layout);
top_layout->addWidget(m_comboSeparator);
top_layout->addLayout(list_layout,10);
top_layout->addWidget(m_helpArea);
top_layout->addWidget(new KSeparator(m_widget));
}
void KEditToolBarWidgetPrivate::loadToolBarCombo( const QString& defaultToolBar )
{
const QLatin1String attrName( "name" );
// just in case, we clear our combo
m_toolbarCombo->clear();
int defaultToolBarId = -1;
int count = 0;
// load in all of the toolbar names into this combo box
XmlDataList::const_iterator xit = m_xmlFiles.constBegin();
for ( ; xit != m_xmlFiles.constEnd(); ++xit)
{
// skip the merged one in favor of the local one,
// so that we can change icons
// This also makes the app-defined named for "mainToolBar" appear rather than the ui_standards-defined name.
if ( (*xit).type() == XmlData::Merged )
continue;
// each xml file may have any number of toolbars
ToolBarList::const_iterator it = (*xit).barList().begin();
for ( ; it != (*xit).barList().constEnd(); ++it)
{
const QString text = (*xit).toolBarText( *it );
m_toolbarCombo->addItem( text );
const QString name = (*it).attribute(attrName);
if (defaultToolBarId == -1 && name == defaultToolBar)
defaultToolBarId = count;
count++;
}
}
const bool showCombo = (count > 1);
m_comboLabel->setVisible(showCombo);
m_comboSeparator->setVisible(showCombo);
m_toolbarCombo->setVisible(showCombo);
if (defaultToolBarId == -1)
defaultToolBarId = 0;
// we want to the specified item selected and its actions loaded
m_toolbarCombo->setCurrentIndex(defaultToolBarId);
slotToolBarSelected(m_toolbarCombo->currentIndex());
}
void KEditToolBarWidgetPrivate::loadActions(const QDomElement& elem)
{
const QLatin1String tagSeparator( "Separator" );
const QLatin1String tagMerge( "Merge" );
const QLatin1String tagActionList( "ActionList" );
const QLatin1String tagAction( "Action" );
const QLatin1String attrName( "name" );
int sep_num = 0;
QString sep_name("separator_%1");
// clear our lists
m_inactiveList->clear();
m_activeList->clear();
m_insertAction->setEnabled(false);
m_removeAction->setEnabled(false);
m_upAction->setEnabled(false);
m_downAction->setEnabled(false);
// We'll use this action collection
KActionCollection* actionCollection = m_currentXmlData->actionCollection();
// store the names of our active actions
QSet<QString> active_list;
// Filtering message requested by translators (scripting).
KLocalizedString nameFilter = ki18nc("@item:intable Action name in toolbar editor", "%1");
// see if our current action is in this toolbar
QDomNode n = elem.firstChild();
for( ; !n.isNull(); n = n.nextSibling() )
{
QDomElement it = n.toElement();
if (it.isNull()) continue;
if (it.tagName() == tagSeparator)
{
ToolBarItem *act = new ToolBarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString());
act->setSeparator(true);
act->setText(SEPARATORSTRING);
it.setAttribute( attrName, act->internalName() );
continue;
}
if (it.tagName() == tagMerge)
{
// Merge can be named or not - use the name if there is one
QString name = it.attribute( attrName );
ToolBarItem *act = new ToolBarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component."));
if ( name.isEmpty() )
act->setText(i18n("<Merge>"));
else
act->setText(i18n("<Merge %1>", name));
continue;
}
if (it.tagName() == tagActionList)
{
ToolBarItem *act = new ToolBarItem(m_activeList, tagActionList, it.attribute(attrName), i18n("This is a dynamic list of actions. You can move it, but if you remove it you will not be able to re-add it.") );
act->setText(i18n("ActionList: %1", it.attribute(attrName)));
continue;
}
// iterate through this client's actions
// This used to iterate through _all_ actions, but we don't support
// putting any action into any client...
foreach (QAction* action, actionCollection->actions())
{
// do we have a match?
if (it.attribute( attrName ) == action->objectName())
{
// we have a match!
ToolBarItem *act = new ToolBarItem(m_activeList, it.tagName(), action->objectName(), action->toolTip());
act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->iconText())).toString());
act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
act->setTextAlongsideIconHidden(action->priority() < QAction::NormalPriority);
active_list.insert(action->objectName());
break;
}
}
}
// go through the rest of the collection
foreach (QAction* action, actionCollection->actions())
{
// skip our active ones
if (active_list.contains(action->objectName()))
continue;
ToolBarItem *act = new ToolBarItem(m_inactiveList, tagAction, action->objectName(), action->toolTip());
act->setText(nameFilter.subs(KGlobal::locale()->removeAcceleratorMarker(action->text())).toString());
act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon);
}
m_inactiveList->sortItems(Qt::AscendingOrder);
// finally, add default separators to the inactive list
ToolBarItem *act = new ToolBarItem(0L, tagSeparator, sep_name.arg(sep_num++), QString());
act->setSeparator(true);
act->setText(SEPARATORSTRING);
m_inactiveList->insertItem(0, act);
}
KActionCollection *KEditToolBarWidget::actionCollection() const
{
return d->m_collection;
}
void KEditToolBarWidgetPrivate::slotToolBarSelected(int index)
{
const QLatin1String attrName( "name" );
// We need to find the XmlData and toolbar element for this index
// To do that, we do the same iteration as the one which filled in the combobox.
int toolbarNumber = 0;
XmlDataList::iterator xit = m_xmlFiles.begin();
for ( ; xit != m_xmlFiles.end(); ++xit) {
// skip the merged one in favor of the local one,
// so that we can change icons
if ( (*xit).type() == XmlData::Merged )
continue;
// each xml file may have any number of toolbars
ToolBarList::Iterator it = (*xit).barList().begin();
for ( ; it != (*xit).barList().end(); ++it) {
// is this our toolbar?
if (toolbarNumber == index) {
// save our current settings
m_currentXmlData = & (*xit);
m_currentToolBarElem = *it;
kDebug() << "found toolbar" << m_currentXmlData->toolBarText(*it) << "m_currentXmlData set to";
m_currentXmlData->dump();
// If this is a Merged xmldata, clicking the "change icon" button would assert...
Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
// load in our values
loadActions(m_currentToolBarElem);
if ((*xit).type() == XmlData::Part || (*xit).type() == XmlData::Shell)
m_widget->setDOMDocument( (*xit).domDocument() );
return;
}
++toolbarNumber;
}
}
}
void KEditToolBarWidgetPrivate::slotInactiveSelectionChanged()
{
if (m_inactiveList->selectedItems().count())
{
m_insertAction->setEnabled(true);
QString statusText = static_cast<ToolBarItem*>(m_inactiveList->selectedItems().first())->statusText();
m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
}
else
{
m_insertAction->setEnabled(false);
m_helpArea->setText( QString() );
}
}
void KEditToolBarWidgetPrivate::slotActiveSelectionChanged()
{
ToolBarItem* toolitem = 0;
if (!m_activeList->selectedItems().isEmpty())
toolitem = static_cast<ToolBarItem *>(m_activeList->selectedItems().first());
m_removeAction->setEnabled( toolitem );
m_changeIcon->setEnabled( toolitem &&
m_hasKDialog &&
toolitem->internalTag() == "Action" );
m_changeIconText->setEnabled( toolitem &&
toolitem->internalTag() == "Action" );
if (toolitem)
{
m_upAction->setEnabled(toolitem->index() != 0);
m_downAction->setEnabled(toolitem->index() != toolitem->listWidget()->count() - 1);
QString statusText = toolitem->statusText();
m_helpArea->setText( i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText) );
}
else
{
m_upAction->setEnabled(false);
m_downAction->setEnabled(false);
m_helpArea->setText( QString() );
}
}
void KEditToolBarWidgetPrivate::slotInsertButton()
{
QString internalName = static_cast<ToolBarItem *>(m_inactiveList->currentItem())->internalName();
insertActive(m_inactiveList->currentItem(), m_activeList->currentItem(), false);
// we're modified, so let this change
emit m_widget->enableOk(true);
slotToolBarSelected( m_toolbarCombo->currentIndex() );
selectActiveItem( internalName );
}
void KEditToolBarWidgetPrivate::selectActiveItem(const QString& internalName)
{
int activeItemCount = m_activeList->count();
for(int i = 0; i < activeItemCount; i++)
{
ToolBarItem * item = static_cast<ToolBarItem *>(m_activeList->item(i));
if (item->internalName()==internalName)
{
m_activeList->setCurrentItem(item);
break;
}
}
}
void KEditToolBarWidgetPrivate::slotRemoveButton()
{
removeActive( m_activeList->currentItem() );
slotToolBarSelected( m_toolbarCombo->currentIndex() );
}
void KEditToolBarWidgetPrivate::insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend)
{
if (!item)
return;
static const QString tagAction = QString::fromLatin1( "Action" );
static const QString tagSeparator = QString::fromLatin1( "Separator" );
static const QString attrName = QString::fromLatin1( "name" );
static const QString attrNoMerge = QString::fromLatin1( "noMerge" );
2014-11-13 01:04:59 +02:00
QDomElement new_item;
// let's handle the separator specially
if (item->isSeparator())
new_item = m_widget->domDocument().createElement(tagSeparator);
else
new_item = m_widget->domDocument().createElement(tagAction);
new_item.setAttribute(attrName, item->internalName());
Q_ASSERT(!m_currentToolBarElem.isNull());
if (before)
{
// we have the item in the active list which is before the new
// item.. so let's try our best to add our new item right after it
QDomElement elem = findElementForToolBarItem( before );
Q_ASSERT( !elem.isNull() );
m_currentToolBarElem.insertAfter(new_item, elem);
}
else
{
// simply put it at the beginning or the end of the list.
if (prepend)
m_currentToolBarElem.insertBefore(new_item, m_currentToolBarElem.firstChild());
else
m_currentToolBarElem.appendChild(new_item);
}
// and set this container as a noMerge
m_currentToolBarElem.setAttribute( attrNoMerge, "1");
// update the local doc
updateLocal(m_currentToolBarElem);
}
void KEditToolBarWidgetPrivate::removeActive(ToolBarItem *item)
{
if (!item)
return;
static const QString attrNoMerge = QString::fromLatin1( "noMerge" );
2014-11-13 01:04:59 +02:00
// we're modified, so let this change
emit m_widget->enableOk(true);
// now iterate through to find the child to nuke
QDomElement elem = findElementForToolBarItem( item );
if ( !elem.isNull() )
{
// nuke myself!
m_currentToolBarElem.removeChild(elem);
// and set this container as a noMerge
m_currentToolBarElem.setAttribute( attrNoMerge, "1");
// update the local doc
updateLocal(m_currentToolBarElem);
}
}
void KEditToolBarWidgetPrivate::slotUpButton()
{
ToolBarItem *item = m_activeList->currentItem();
if (!item) {
Q_ASSERT(false);
return;
}
int row = item->listWidget()->row(item) - 1;
// make sure we're not the top item already
if (row < 0) {
Q_ASSERT(false);
return;
}
// we're modified, so let this change
emit m_widget->enableOk(true);
moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(row - 1)) );
}
void KEditToolBarWidgetPrivate::moveActive( ToolBarItem* item, ToolBarItem* before )
{
QDomElement e = findElementForToolBarItem( item );
if ( e.isNull() )
return;
// remove item
m_activeList->takeItem(m_activeList->row(item));
// put it where it's supposed to go
m_activeList->insertItem(m_activeList->row(before) + 1, item);
// make it selected again
m_activeList->setCurrentItem(item);
// and do the real move in the DOM
if ( !before )
m_currentToolBarElem.insertBefore(e, m_currentToolBarElem.firstChild() );
else
m_currentToolBarElem.insertAfter(e, findElementForToolBarItem( (ToolBarItem*)before ));
// and set this container as a noMerge
static const QString attrNoMerge = QString::fromLatin1( "noMerge" );
2014-11-13 01:04:59 +02:00
m_currentToolBarElem.setAttribute( attrNoMerge, "1");
// update the local doc
updateLocal(m_currentToolBarElem);
}
void KEditToolBarWidgetPrivate::slotDownButton()
{
ToolBarItem *item = m_activeList->currentItem();
if (!item) {
Q_ASSERT(false);
return;
}
// make sure we're not the bottom item already
int newRow = item->listWidget()->row(item) + 1;
if (newRow >= item->listWidget()->count()) {
Q_ASSERT(false);
return;
}
// we're modified, so let this change
emit m_widget->enableOk(true);
moveActive( item, static_cast<ToolBarItem*>(item->listWidget()->item(newRow)) );
}
void KEditToolBarWidgetPrivate::updateLocal(QDomElement& elem)
{
static const QString attrName = QString::fromLatin1( "name" );
2014-11-13 01:04:59 +02:00
XmlDataList::Iterator xit = m_xmlFiles.begin();
for ( ; xit != m_xmlFiles.end(); ++xit)
{
if ( (*xit).type() == XmlData::Merged )
continue;
if ( (*xit).type() == XmlData::Shell ||
(*xit).type() == XmlData::Part )
{
if ( m_currentXmlData->xmlFile() == (*xit).xmlFile() )
{
(*xit).m_isModified = true;
return;
}
continue;
}
(*xit).m_isModified = true;
ToolBarList::Iterator it = (*xit).barList().begin();
for ( ; it != (*xit).barList().end(); ++it)
{
QString name( (*it).attribute( attrName ) );
QString tag( (*it).tagName() );
if ( (tag != elem.tagName()) || (name != elem.attribute(attrName)) )
continue;
QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
toolbar.replaceChild(elem, (*it));
return;
}
// just append it
QDomElement toolbar = (*xit).domDocument().documentElement().toElement();
Q_ASSERT(!toolbar.isNull());
toolbar.appendChild(elem);
}
}
void KEditToolBarWidgetPrivate::slotChangeIcon()
{
// We can't use KIconDialog here, since it's in libkio
// ##### KDE4: reconsider this, e.g. move KEditToolBar to libkio
2014-11-13 01:04:59 +02:00
//if the process is already running (e.g. when somebody clicked the change button twice (see #127149)) - do nothing...
//otherwise m_kdialogProcess will be overwritten and set to zero in slotProcessExited()...crash!
if ( m_kdialogProcess && m_kdialogProcess->state() == QProcess::Running )
return;
m_currentXmlData->dump();
Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
m_kdialogProcess = new QProcess();
2014-11-13 01:04:59 +02:00
QString kdialogExe = KStandardDirs::findExe(QLatin1String("kdialog"));
QStringList kdialogArgs;
kdialogArgs << "--caption";
kdialogArgs << i18n( "Change Icon" );
kdialogArgs << "--embed";
kdialogArgs << QString::number( (quintptr)m_widget->window()->winId() );
kdialogArgs << "--geticon";
kdialogArgs << "Toolbar";
kdialogArgs << "Actions";
m_kdialogProcess->setReadChannel(QProcess::StandardOutput);
m_kdialogProcess->start(kdialogExe, kdialogArgs, QIODevice::ReadOnly | QIODevice::Text);
2014-11-13 01:04:59 +02:00
if ( !m_kdialogProcess->waitForStarted() ) {
kError() << "Can't run " << kdialogExe;
2014-11-13 01:04:59 +02:00
delete m_kdialogProcess;
m_kdialogProcess = 0;
return;
}
m_activeList->setEnabled( false ); // don't change the current item
m_toolbarCombo->setEnabled( false ); // don't change the current toolbar
QObject::connect( m_kdialogProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
m_widget, SLOT(slotProcessExited()) );
}
void KEditToolBarWidgetPrivate::slotChangeIconText()
{
m_currentXmlData->dump();
ToolBarItem *item = m_activeList->currentItem();
if(item){
QString iconText = item->text();
bool hidden = item->isTextAlongsideIconHidden();
IconTextEditDialog dialog(m_widget);
dialog.setIconText(iconText);
dialog.setTextAlongsideIconHidden(hidden);
bool ok = dialog.exec() == KDialog::Accepted;
iconText = dialog.iconText();
hidden = dialog.textAlongsideIconHidden();
bool hiddenChanged = hidden != item->isTextAlongsideIconHidden();
bool iconTextChanged = iconText != item->text();
if (!ok || (!hiddenChanged && !iconTextChanged))
return;
item->setText(iconText);
item->setTextAlongsideIconHidden(hidden);
Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
m_currentXmlData->m_isModified = true;
// Get hold of ActionProperties tag
QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
// Find or create an element for this action
QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
Q_ASSERT( !act_elem.isNull() );
if (iconTextChanged)
act_elem.setAttribute( "iconText", iconText );
if (hiddenChanged)
act_elem.setAttribute( "priority", hidden ? QAction::LowPriority : QAction::NormalPriority );
// we're modified, so let this change
emit m_widget->enableOk(true);
}
}
void KEditToolBarWidgetPrivate::slotProcessExited()
{
m_activeList->setEnabled( true );
m_toolbarCombo->setEnabled( true );
QString icon;
if (!m_kdialogProcess) {
kError() << "Something is wrong here! m_kdialogProcess is zero!";
return;
2014-11-13 01:04:59 +02:00
}
icon = QString::fromLocal8Bit( m_kdialogProcess->readLine() );
icon = icon.left( icon.indexOf( '\n' ) );
kDebug() << "icon=" << icon;
2014-11-13 01:04:59 +02:00
if ( m_kdialogProcess->exitStatus() != QProcess::NormalExit ||
icon.isEmpty() ) {
delete m_kdialogProcess;
m_kdialogProcess = 0;
return;
}
ToolBarItem *item = m_activeList->currentItem();
kDebug() << item;
if(item){
item->setIcon(KIcon(icon));
Q_ASSERT( m_currentXmlData->type() != XmlData::Merged );
m_currentXmlData->m_isModified = true;
// Get hold of ActionProperties tag
QDomElement elem = KXMLGUIFactory::actionPropertiesElement( m_currentXmlData->domDocument() );
// Find or create an element for this action
QDomElement act_elem = KXMLGUIFactory::findActionByName( elem, item->internalName(), true /*create*/ );
Q_ASSERT( !act_elem.isNull() );
act_elem.setAttribute( "icon", icon );
// we're modified, so let this change
emit m_widget->enableOk(true);
}
delete m_kdialogProcess;
m_kdialogProcess = 0;
}
void KEditToolBarWidgetPrivate::slotDropped(ToolBarListWidget* list, int index, ToolBarItem* item, bool sourceIsActiveList)
{
//kDebug() << "slotDropped list=" << (list==m_activeList?"activeList":"inactiveList")
// << "index=" << index << "sourceIsActiveList=" << sourceIsActiveList;
if (list == m_activeList) {
ToolBarItem* after = index > 0 ? static_cast<ToolBarItem *>(list->item(index-1)) : 0;
//kDebug() << "after" << after->text() << after->internalTag();
if (sourceIsActiveList) {
// has been dragged within the active list (moved).
moveActive(item, after);
} else {
// dragged from the inactive list to the active list
insertActive(item, after, true);
}
} else if (list == m_inactiveList) {
// has been dragged to the inactive list -> remove from the active list.
removeActive(item);
}
delete item; // not needed anymore. must be deleted before slotToolBarSelected clears the lists
// we're modified, so let this change
emit m_widget->enableOk(true);
slotToolBarSelected( m_toolbarCombo->currentIndex() );
}
void KEditToolBar::showEvent( QShowEvent * event )
{
if (!event->spontaneous()) {
// The dialog has been shown, enable toolbar editing
if ( d->m_factory ) {
// call the xmlgui-factory version
d->m_widget->load( d->m_factory, d->m_defaultToolBar );
} else {
// call the action collection version
d->m_widget->load( d->m_file, d->m_global, d->m_defaultToolBar );
}
KToolBar::setToolBarsEditable(true);
}
KDialog::showEvent(event);
}
void KEditToolBar::hideEvent(QHideEvent* event)
{
// The dialog has been hidden, disable toolbar editing
KToolBar::setToolBarsEditable(false);
KDialog::hideEvent(event);
}
#include "moc_kedittoolbar.cpp"
#include "moc_kedittoolbar_p.cpp"