diff --git a/src/core/kexipart.cpp b/src/core/kexipart.cpp index 9e901379c..a3a9d6196 100644 --- a/src/core/kexipart.cpp +++ b/src/core/kexipart.cpp @@ -1,441 +1,456 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2014 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 "kexipart.h" #include "kexipartinfo.h" #include "kexipartitem.h" //! @todo KEXI3 #include "kexistaticpart.h" #include "KexiWindow.h" #include "KexiWindowData.h" #include "KexiView.h" #include "kexipartguiclient.h" #include "KexiMainWindowIface.h" #include "kexi.h" #include +#include #include #include #include #include namespace KexiPart { KEXICORE_EXPORT QString version() { return QString::fromLatin1("%1.%2").arg(KEXI_STABLE_VERSION_MAJOR).arg(KEXI_STABLE_VERSION_MINOR); } //! @internal class Q_DECL_HIDDEN Part::Private { public: Private() : guiClient(0) , newObjectsAreDirty(false) , instanceActionsInitialized(false) { } //! Helper, used in Part::openInstance() tristate askForOpeningInTextMode(KexiWindow *window, KexiPart::Item *item, Kexi::ViewModes supportedViewModes, Kexi::ViewMode viewMode) { if (viewMode != Kexi::TextViewMode && supportedViewModes & Kexi::TextViewMode && window->data()->proposeOpeningInTextViewModeBecauseOfProblems) { //ask KexiUtils::WaitCursorRemover remover; //! @todo use message handler for this to enable non-gui apps QString singleStatusString(window->singleStatusString()); if (!singleStatusString.isEmpty()) singleStatusString.prepend(QString("\n\n") + xi18n("Details:") + " "); if (KMessageBox::No == KMessageBox::questionYesNo(0, ((viewMode == Kexi::DesignViewMode) ? xi18nc("@info", "Object %1 could not be opened in Design View.", item->name()) : xi18n("Object could not be opened in Data View.")) + "\n" + xi18n("Do you want to open it in Text View?") + singleStatusString, 0, KStandardGuiItem::open(), KStandardGuiItem::cancel())) { return false; } return true; } return cancelled; } QString toolTip; QString whatsThis; QString instanceName; GUIClient *guiClient; QMap instanceGuiClients; Kexi::ObjectStatus status; bool newObjectsAreDirty; bool instanceActionsInitialized; }; } //---------------------------------------------------------------- using namespace KexiPart; Part::Part(QObject *parent, const QString& instanceName, const QString& toolTip, const QString& whatsThis, const QVariantList& list) : PartBase(parent, list) , d(new Private()) { d->instanceName = KDb::stringToIdentifier( instanceName.isEmpty() ? xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " "Use '_' character instead of spaces. First character should be a..z character. " "If you cannot use latin characters in your language, use english word.", "object").toLower() : instanceName); d->toolTip = toolTip; d->whatsThis = whatsThis; } /*! @todo KEXI3 Part::Part(QObject* parent, StaticPartInfo *info) : PartBase(parent, QVariantList()) , d(new Private()) { setObjectName("StaticPart"); setInfo(info); }*/ Part::~Part() { delete d; } void Part::createGUIClients()//KexiMainWindow *win) { if (!d->guiClient) { //create part's gui client d->guiClient = new GUIClient(this, false, "part"); //default actions for part's gui client: QAction* act = info()->newObjectAction(); // - update action's tooltip and "what's this" QString tip(toolTip()); if (!tip.isEmpty()) { act->setToolTip(tip); } QString what(whatsThis()); if (!what.isEmpty()) { act->setWhatsThis(what); } //default actions for part instance's gui client: //NONE //let init specific actions for part instances for (int mode = 1; mode <= 0x01000; mode <<= 1) { if (info()->supportedViewModes() & (Kexi::ViewMode)mode) { GUIClient *instanceGuiClient = new GUIClient( this, true, Kexi::nameForViewMode((Kexi::ViewMode)mode).toLatin1()); d->instanceGuiClients.insert((Kexi::ViewMode)mode, instanceGuiClient); } } // also add an instance common for all modes (mode==0) GUIClient *instanceGuiClient = new GUIClient(this, true, "allViews"); d->instanceGuiClients.insert(Kexi::AllViewModes, instanceGuiClient); initPartActions(); } } KActionCollection* Part::actionCollectionForMode(Kexi::ViewMode viewMode) const { GUIClient *cli = d->instanceGuiClients.value((int)viewMode); return cli ? cli->actionCollection() : 0; } QAction * Part::createSharedAction(Kexi::ViewMode mode, const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name, const char *subclassName) { GUIClient *instanceGuiClient = d->instanceGuiClients.value((int)mode); if (!instanceGuiClient) { qWarning() << "no gui client for mode" << mode << "!"; return 0; } return KexiMainWindowIface::global()->createSharedAction(text, pix_name, cut, name, instanceGuiClient->actionCollection(), subclassName); } QAction * Part::createSharedPartAction(const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name, const char *subclassName) { if (!d->guiClient) return 0; return KexiMainWindowIface::global()->createSharedAction(text, pix_name, cut, name, d->guiClient->actionCollection(), subclassName); } QAction * Part::createSharedToggleAction(Kexi::ViewMode mode, const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name) { return createSharedAction(mode, text, pix_name, cut, name, "KToggleAction"); } QAction * Part::createSharedPartToggleAction(const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name) { return createSharedPartAction(text, pix_name, cut, name, "KToggleAction"); } void Part::setActionAvailable(const char *action_name, bool avail) { for (QMap::Iterator it = d->instanceGuiClients.begin(); it != d->instanceGuiClients.end(); ++it) { QAction *act = it.value()->actionCollection()->action(action_name); if (act) { act->setEnabled(avail); return; } } KexiMainWindowIface::global()->setActionAvailable(action_name, avail); } KexiWindow* Part::openInstance(QWidget* parent, KexiPart::Item *item, Kexi::ViewMode viewMode, QMap* staticObjectArgs) { Q_ASSERT(item); //now it's the time for creating instance actions if (!d->instanceActionsInitialized) { initInstanceActions(); d->instanceActionsInitialized = true; } d->status.clearStatus(); KexiWindow *window = new KexiWindow(parent, info()->supportedViewModes(), this, item); KexiProject *project = KexiMainWindowIface::global()->project(); KDbObject object(project->typeIdForPluginId(info()->pluginId())); object.setName(item->name()); object.setCaption(item->caption()); object.setDescription(item->description()); /*! @todo js: apply settings for caption displaying method; there can be option for - displaying item.caption() as caption, if not empty, without instanceName - displaying the same as above in tabCaption (or not) */ window->setId(item->identifier()); //not needed, but we did it window->setWindowIcon(QIcon::fromTheme(window->iconName())); KexiWindowData *windowData = createWindowData(window); if (!windowData) { d->status = Kexi::ObjectStatus(KexiMainWindowIface::global()->project()->dbConnection(), xi18n("Could not create object's window."), xi18n("The plugin or object definition may be corrupted.")); delete window; return 0; } window->setData(windowData); if (!item->neverSaved()) { //we have to load object data for this dialog loadAndSetSchemaObject(window, object, viewMode); if (!window->schemaObject()) { //last chance: if (false == d->askForOpeningInTextMode( window, item, window->supportedViewModes(), viewMode)) { delete window; return 0; } viewMode = Kexi::TextViewMode; loadAndSetSchemaObject(window, object, viewMode); } if (!window->schemaObject()) { if (!d->status.error()) d->status = Kexi::ObjectStatus(KexiMainWindowIface::global()->project()->dbConnection(), xi18n("Could not load object's definition."), xi18n("Object design may be corrupted.")); d->status.append( Kexi::ObjectStatus(xi18nc("@info", "You can delete %1 object and create it again.", item->name()), QString())); window->close(); delete window; return 0; } } bool switchingFailed = false; bool dummy; tristate res = window->switchToViewMode(viewMode, staticObjectArgs, &dummy); if (!res) { tristate askForOpeningInTextModeRes = d->askForOpeningInTextMode(window, item, window->supportedViewModes(), viewMode); if (true == askForOpeningInTextModeRes) { delete window->schemaObject(); //old one window->close(); delete window; //try in text mode return openInstance(parent, item, Kexi::TextViewMode, staticObjectArgs); } else if (false == askForOpeningInTextModeRes) { delete window->schemaObject(); //old one window->close(); delete window; qWarning() << "!window, cannot switch to a view mode" << Kexi::nameForViewMode(viewMode); return 0; } //the window has an error info switchingFailed = true; } if (~res) switchingFailed = true; if (switchingFailed) { d->status = window->status(); window->close(); delete window; qWarning() << "!window, switching to view mode failed," << Kexi::nameForViewMode(viewMode); return 0; } window->registerWindow(); //ok? window->show(); window->setMinimumSize(window->minimumSizeHint().width(), window->minimumSizeHint().height()); //dirty only if it's a new object if (window->selectedView()) { window->selectedView()->setDirty( internalPropertyValue("newObjectsAreDirty", false).toBool() ? item->neverSaved() : false); } return window; } KDbObject* Part::loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow) { Q_UNUSED(window); Q_UNUSED(viewMode); KDbObject *newObject = new KDbObject(); *newObject = object; if (ownedByWindow) *ownedByWindow = true; return newObject; } void Part::loadAndSetSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode) { bool schemaObjectOwned = true; KDbObject* sd = loadSchemaObject(window, object, viewMode, &schemaObjectOwned); window->setSchemaObject(sd); window->setSchemaObjectOwned(schemaObjectOwned); } bool Part::loadDataBlock(KexiWindow *window, QString *dataString, const QString& dataID) { if (true != KexiMainWindowIface::global()->project()->dbConnection()->loadDataBlock( window->id(), dataString, dataID)) { d->status = Kexi::ObjectStatus(KexiMainWindowIface::global()->project()->dbConnection(), xi18n("Could not load object's data."), xi18nc("@info", "Data identifier: %1.", dataID)); d->status.append(*window); return false; } return true; } void Part::initPartActions() { } void Part::initInstanceActions() { } tristate Part::remove(KexiPart::Item *item) { Q_ASSERT(item); KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); if (!conn) return false; return conn->removeObject(item->identifier()); } KexiWindowData* Part::createWindowData(KexiWindow* window) { return new KexiWindowData(window); } QString Part::instanceName() const { return d->instanceName; } QString Part::toolTip() const { return d->toolTip; } QString Part::whatsThis() const { return d->whatsThis; } tristate Part::rename(KexiPart::Item *item, const QString& newName) { Q_UNUSED(item); Q_UNUSED(newName); return true; } GUIClient* Part::instanceGuiClient(Kexi::ViewMode mode) const { return d->instanceGuiClients.value((int)mode); } GUIClient* Part::guiClient() const { return d->guiClient; } const Kexi::ObjectStatus& Part::lastOperationStatus() const { return d->status; } KDbQuerySchema* Part::currentQuery(KexiView* view) { Q_UNUSED(view); return 0; } KEXICORE_EXPORT QString KexiPart::fullCaptionForItem(KexiPart::Item *item, KexiPart::Part *part) { Q_ASSERT(item); Q_ASSERT(part); if (part) return item->name() + " : " + part->info()->name(); return item->name(); } + +KEXICORE_EXPORT void KexiPart::getTextViewAction(const QString& pluginId, QString *actionText, + QString *iconName) +{ + Q_ASSERT(actionText); + Q_ASSERT(iconName); + if (pluginId == QLatin1String("org.kexi-project.query")) { + *actionText = xi18n("Design in SQL View"); + *iconName = KexiIconName("mode-selector-sql"); + } else { + *actionText = xi18n("Design in Text View"); + iconName->clear(); + } +} diff --git a/src/core/kexipart.h b/src/core/kexipart.h index 8c5e88d09..5a0621073 100644 --- a/src/core/kexipart.h +++ b/src/core/kexipart.h @@ -1,284 +1,289 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2014 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. */ #ifndef KEXIPART_H #define KEXIPART_H #include #include #include #include "kexipartbase.h" #include class KActionCollection; class KexiWindow; class KexiWindowData; class KexiView; class KDbQuerySchema; class QAction; class QKeySequence; namespace KexiPart { class Item; class GUIClient; class StaticPartInfo; /*! Official (registered) type IDs for objects like table, query, form... */ enum ObjectType { UnknownObjectType = KDb::UnknownObjectType, //!< -1, helper AnyObjectType = KDb::AnyObjectType, //!< 0, helper TableObjectType = KDb::TableObjectType, //!< 1, like in KDb::ObjectType QueryObjectType = KDb::QueryObjectType, //!< 2, like in KDb::ObjectType FormObjectType = 3, ReportObjectType = 4, ScriptObjectType = 5, WebObjectType = 6, MacroObjectType = 7, LastObjectType = 7, //ALWAYS UPDATE THIS UserObjectType = 100 //!< external types }; //! @return Kexi Part API version: "major.minor" //! @since 3.1 KEXICORE_EXPORT QString version(); //! @short The main class for kexi frontend parts (plugins) like tables, queries, forms and reports /*! Plugins create windows (KexiWindow) for a given type of object. Notes for plugins implementors: This class supports InternalPropertyMap interface, so supported internal properties affecting its behaviour are: - newObjectsAreDirty: True if newly created, unsaved objects are dirty. False by default. - textViewModeCaption: custum i18n'd action text replacing standard "Text View" text. - textViewModeToolTip: custum i18n'd action tool tip replacing standard "Switch to text view" text. Used in for query's "SQL View". In general: a whole set of i18n'd action names, initialised on KexiPart::Part subclass ctor. The names are useful because the same action can have other name for each part, e.g. "New table" vs "New query" can have different forms for some languages. So this is a flexible way for customizing translatable strings. */ class KEXICORE_EXPORT Part : public PartBase { Q_OBJECT public: virtual ~Part(); //! @todo make it protected, outside world should use KexiProject /*! Try to execute the part. Implementations of this \a Part are able to overwrite this method to offer execution. \param item The \a KexiPart::Item that should be executed. \param sender The sender QObject which likes to execute this \a Part or NULL if there is no sender. The KFormDesigner uses this to pass the actual widget (e.g. the button that was pressed). \return true if execution was successfully else false. */ virtual bool execute(KexiPart::Item* item, QObject* sender = 0) { Q_UNUSED(item); Q_UNUSED(sender); return false; } //! @todo make it protected, outside world should use KexiProject /*! "Opens" an instance that the part provides, pointed by \a item in a mode \a viewMode. \a viewMode is one of Kexi::ViewMode enum. \a staticObjectArgs can be passed for static Kexi Parts. The new widget will be a child of \a parent. */ KexiWindow* openInstance(QWidget* parent, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0); //! @todo make it protected, outside world should use KexiProject /*! Removes any stored data pointed by \a item (example: table is dropped for table part). From now this data is inaccesible, and \a item disappear. You do not need to remove \a item, or remove object's schema stored in the database, beacuse this will be done automatically by KexiProject after successful call of this method. All object's data blocks are also automatically removed from database (from "kexi__objectdata" table). For this, a database connection associated with kexi project owned by \a win can be used. Database transaction is started by KexiProject before calling this method, and it will be rolled back if you return false here. You shouldn't use by hand transactions here. Default implementation just removes object from kexi__* system structures at the database backend using KDbConnection::removeObject(). */ virtual tristate remove(KexiPart::Item *item); /*! Renames stored data pointed by \a item to \a newName (example: table name is altered in the database). For this, a database connection associated with kexi project owned by \a win can be used. You do not need to change \a item, and change object's schema stored in the database, beacuse this is automatically handled by KexiProject. Database transaction is started by KexiProject before calling this method, and it will be rolled back if you return false here. You shouldn't use by hand transactions here. Default implementation does nothing and returns true. */ virtual tristate rename(KexiPart::Item *item, const QString& newName); /*! Creates and returns a new temporary data for a window \a window. This method is called on openInstance() once per dialog. Reimplement this to return KexiWindowData subclass instance. Default implemention just returns empty KexiWindowData object. */ virtual KexiWindowData* createWindowData(KexiWindow *window); /*! Creates a new view for mode \a viewMode, \a item and \a parent. The view will be used inside \a dialog. */ virtual KexiView* createView(QWidget *parent, KexiWindow *window, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0) = 0; //virtual void initTabs(); /*! @return i18n'd instance name usable for displaying in gui as object's name, e.g. "table". The name is valid identifier - contains latin-1 lowercase characters only. */ QString instanceName() const; /*! @return i18n'd tooltip that can also act as descriptive name of the action. Example: "Create new table". */ QString toolTip() const; /*! @return i18n'd "what's this" string. Example: "Creates new table." */ QString whatsThis() const; /*! \return part's GUI Client, so you can create part-wide actions using this client. */ GUIClient *guiClient() const; /*! \return part's GUI Client, so you can create instance-wide actions using this client. */ GUIClient *instanceGuiClient(Kexi::ViewMode mode = Kexi::AllViewModes) const; /*! \return action collection for mode \a viewMode. */ KActionCollection* actionCollectionForMode(Kexi::ViewMode viewMode) const; const Kexi::ObjectStatus& lastOperationStatus() const; /*! \return query schema currently edited in the \a view. * It may be the original/saved query if user has no unsaved changes so far * or a temporary unsaved query if there are unsaved modifications. * The query can be used for example by data exporting routines so user can * export result of a running unsaved query without prior saving it. For implementation in plugins. */ virtual KDbQuerySchema *currentQuery(KexiView* view); /*! @internal Creates GUIClients for this part, attached to the main window. This method is called by KexiMainWindow. */ void createGUIClients(); Q_SIGNALS: void newObjectRequest(KexiPart::Info *info); protected: /*! Creates new Plugin @param parent parent of this plugin @param instanceName i18n'd instance name written using only lowercase alphanumeric characters (a..z, 0..9). Use '_' character instead of spaces. First character should be a..z character. If you cannot use latin characters in your language, use english word. Example: "table". @param toolTip i18n'd tooltip that can also act as descriptive name of the action. Example: "Create new table". @param whatsThis i18n'd "what's this" string. Example: "Creates new table." @param list extra arguments passed to the plugin */ Part(QObject *parent, const QString& instanceName, const QString& toolTip, const QString& whatsThis, const QVariantList& list); //! Used by StaticPart Part(QObject* parent, StaticPartInfo *info); virtual void initPartActions(); virtual void initInstanceActions(); /*! Can be reimplemented if object data is extended behind the default set of properties. This is the case for table and query schema objects, where object of KDbObject subclass is returned. In this case value pointed by @a ownedByWindow is set to false. Default implemenatation owned (value pointed by @a ownedByWindow is set to true). */ virtual KDbObject* loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow); bool loadDataBlock(KexiWindow *window, QString *dataString, const QString& dataID = QString()); /*! Creates shared action for action collection declared for 'instance actions' of this part. See KexiSharedActionHost::createSharedAction() for details. Pass desired QAction subclass with \a subclassName (e.g. "KToggleAction") to have that subclass allocated instead just QAction (what is the default). */ QAction * createSharedAction(Kexi::ViewMode mode, const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name, const char *subclassName = 0); /*! Convenience version of above method - creates shared toggle action. */ QAction * createSharedToggleAction(Kexi::ViewMode mode, const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name); /*! Creates shared action for action collection declared for 'part actions' of this part. See KexiSharedActionHost::createSharedAction() for details. Pass desired QAction subclass with \a subclassName (e.g. "KToggleAction") to have that subclass allocated instead just QAction (what is the default). */ QAction * createSharedPartAction(const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name, const char *subclassName = 0); /*! Convenience version of above method - creates shared toggle action for 'part actions' of this part. */ QAction * createSharedPartToggleAction(const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name); void setActionAvailable(const char *action_name, bool avail); private: //! Calls loadSchemaObject() (virtual), updates ownership of object data for @a window //! and assigns the created data to @a window. void loadAndSetSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode); Q_DISABLE_COPY(Part) class Private; Private * const d; friend class Manager; friend class ::KexiWindow; friend class GUIClient; }; /*! \return full caption for item \a item and part \a part. If \a part is provided, the captions will be in a form of "name : inctancetype", e.g. "Employees : Table", otherwise it will be in a form of "name", e.g. "Employees". */ KEXICORE_EXPORT QString fullCaptionForItem(KexiPart::Item *item, KexiPart::Part *part); +/*! \return i18n'd actionText and iconName for "Open in text view" action specific for @a pluginId. + Currently it the only special is for "org.kexi-project.query". + The default is "Design in Text View" and no icon. */ +KEXICORE_EXPORT void getTextViewAction(const QString& pluginId, QString *actionText, QString *iconName); + } // namespace KexiPart #endif diff --git a/src/formeditor/kexiactionselectiondialog.cpp b/src/formeditor/kexiactionselectiondialog.cpp index 68a91b952..d46f0ead9 100644 --- a/src/formeditor/kexiactionselectiondialog.cpp +++ b/src/formeditor/kexiactionselectiondialog.cpp @@ -1,772 +1,775 @@ /* This file is part of the KDE project Copyright (C) 2005-2006 Jarosław Staniek Copyright (C) 2012 Adam Pigg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 "kexiactionselectiondialog.h" #include "kexiactionselectiondialog_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class ActionSelectorDialogTreeItem : public QTreeWidgetItem { public: enum ActionRole{ ActionCategoryRole = Qt::UserRole + 1, ActionDataRole, ActionPluginIdRole }; ActionSelectorDialogTreeItem(QString label, QTreeWidget *parent) : QTreeWidgetItem(parent) { setText(0, label); } ActionSelectorDialogTreeItem(QString label, QTreeWidgetItem *parent) : QTreeWidgetItem(parent) { setText(0, label); } using QTreeWidgetItem::data; QVariant data(ActionRole role) const { return QTreeWidgetItem::data(0, role); }; using QTreeWidgetItem::setData; void setData(ActionRole role, QVariant value) { QTreeWidgetItem::setData(0, role, value); } QIcon icon() const { return QTreeWidgetItem::icon(0); } void setIcon(const QIcon& icon) { QTreeWidgetItem::setIcon(0, icon); } }; //--------------------------------------- ActionsListViewBase::ActionsListViewBase(QWidget* parent) : QTreeWidget(parent) { setColumnCount(1); setHeaderHidden(true); setRootIsDecorated(false); } ActionsListViewBase::~ActionsListViewBase() { } QTreeWidgetItem *ActionsListViewBase::itemForAction(const QString& actionName, QTreeWidgetItem* parent) { Q_UNUSED(parent); QTreeWidgetItemIterator it(this); while (*it) { ActionSelectorDialogTreeItem* itm = dynamic_cast(*it); if (itm && itm->data(ActionSelectorDialogTreeItem::ActionDataRole).toString() == actionName) return itm; ++it; } return 0; } void ActionsListViewBase::selectAction(const QString& actionName) { //qDebug() << "Selecting action:" << actionName; QTreeWidgetItem *itm = itemForAction(actionName); if (itm) { setCurrentItem(itm); itm->setSelected(true); } } //--------------------------------------- KActionsListViewBase::KActionsListViewBase(QWidget* parent) : ActionsListViewBase(parent) { } KActionsListViewBase::~KActionsListViewBase() {} void KActionsListViewBase::init() { const QPixmap noIcon(KexiUtils::emptyIcon(KIconLoader::Small)); QList sharedActions(KexiMainWindowIface::global()->allActions()); const Kexi::ActionCategories *acat = Kexi::actionCategories(); foreach(QAction *action, sharedActions) { // qDebug() << (*it)->name() << (*it)->text(); //! @todo group actions //! @todo: store QAction * here? const int actionCategories = acat->actionCategories(action->objectName().toLatin1()); if (actionCategories == -1) { qWarning() << "no category declared for action \"" << action->objectName() << "\"! Fix this!"; continue; } if (!isActionVisible(action->objectName().toLatin1(), actionCategories)) continue; QString actionName; if (!action->toolTip().isEmpty()) { actionName = action->toolTip().remove("").remove(""); } else { actionName = action->text().remove('&'); } ActionSelectorDialogTreeItem *pitem = new ActionSelectorDialogTreeItem( actionName, this); pitem->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "kaction"); pitem->setData(ActionSelectorDialogTreeItem::ActionDataRole, action->objectName()); pitem->setIcon(action->icon()); if (pitem->icon().isNull()) pitem->setIcon(noIcon); } setSortingEnabled(true); } //--------------------------------------- //! @internal Used to display KActions (in column 2) class KActionsListView : public KActionsListViewBase { Q_OBJECT public: explicit KActionsListView(QWidget* parent) : KActionsListViewBase(parent) { } virtual ~KActionsListView() {} virtual bool isActionVisible(const char* actionName, int actionCategories) const { Q_UNUSED(actionName); return actionCategories & Kexi::GlobalActionCategory; } }; //! @internal Used to display KActions (in column 2) class CurrentFormActionsListView : public KActionsListViewBase { Q_OBJECT public: explicit CurrentFormActionsListView(QWidget* parent) : KActionsListViewBase(parent) { } virtual ~CurrentFormActionsListView() {} virtual bool isActionVisible(const char* actionName, int actionCategories) const { return actionCategories & Kexi::WindowActionCategory && Kexi::actionCategories()->actionSupportsObjectType(actionName, KexiPart::FormObjectType); } }; //! @internal a list view displaying action categories user can select from (column 1) class ActionCategoriesListView : public ActionsListViewBase { Q_OBJECT public: explicit ActionCategoriesListView(QWidget* parent) : ActionsListViewBase(parent) { ActionSelectorDialogTreeItem *itm = new ActionSelectorDialogTreeItem(xi18n("No action"), this ); itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "noaction"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, "noaction"); const QPixmap noIcon(KexiUtils::emptyIcon(KIconLoader::Small)); itm->setIcon(noIcon); itm = new ActionSelectorDialogTreeItem(xi18n("Application actions"), this ); itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "kaction"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, "kaction"); itm->setIcon(koIcon("kexi")); KexiPart::PartInfoList *pl = Kexi::partManager().infoList(); if (pl) { foreach(KexiPart::Info *info, *pl) { KexiPart::Part *part = Kexi::partManager().part(info); if (!info->isVisibleInNavigator() || !part) continue; itm = new ActionSelectorDialogTreeItem(part->info()->name(), this ); itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "navObject"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, info->typeName()); itm->setData(ActionSelectorDialogTreeItem::ActionPluginIdRole, info->pluginId()); itm->setIcon(QIcon::fromTheme(part->info()->iconName())); } } QTreeWidgetItem *fitm = itemForAction("form"); if (fitm) { itm = new ActionSelectorDialogTreeItem(xi18nc("Current form's actions", "Current"), fitm); } else { itm = new ActionSelectorDialogTreeItem(xi18nc("Current form's actions", "Current"), this); } itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "currentForm"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, "currentForm"); itm->setIcon(KexiIcon("form")); expandAll(); setSortingEnabled(false); } ~ActionCategoriesListView() { } }; //! @internal Used to display list of actions available to executing (column 3) class ActionToExecuteListView : public ActionsListViewBase { Q_OBJECT public: explicit ActionToExecuteListView(QWidget* parent) : ActionsListViewBase(parent) { } ~ActionToExecuteListView() { } //! Updates actions void showActionsForPluginId(const QString& pluginId) { if (m_currentPluginId == pluginId) return; m_currentPluginId = pluginId; clear(); KexiPart::Part *part = Kexi::partManager().partForPluginId(m_currentPluginId); if (!part) return; Kexi::ViewModes supportedViewModes = part->info()->supportedViewModes(); ActionSelectorDialogTreeItem *itm; const QPixmap noIcon(KexiUtils::emptyIcon(KIconLoader::Small)); if (supportedViewModes & Kexi::DataViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Data View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "open"); itm->setIcon(koIcon("document-open")); } if (part->info()->isExecuteSupported()) { itm = new ActionSelectorDialogTreeItem(xi18n("Execute"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "execute"); itm->setIcon(koIcon("media-playback-start")); } #ifdef KEXI_QUICK_PRINTING_SUPPORT if (part->info()->isPrintingSupported()) { ActionSelectorDialogListItem *printItem = new ActionSelectorDialogListItem( "print", this, futureI18n("Print")); printItem->setPixmap(0, koIcon("document-print")); QAction *a = KStandardAction::printPreview(0, 0, 0); item = new ActionSelectorDialogListItem("printPreview", printItem, a->text().remove('&').remove("...")); item->setPixmap(0, a->icon().pixmap(16)); delete a; item = new ActionSelectorDialogListItem( "pageSetup", printItem, futureI18n("Show Page Setup")); item->setPixmap(0, noIcon); setOpen(printItem, true); printItem->setExpandable(false); } #endif if (part->info()->isDataExportSupported()) { itm = new ActionSelectorDialogTreeItem( xi18nc("Note: use multiple rows if needed", "Export to File\nAs Data Table"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "exportToCSV"); itm->setIcon(KexiIcon("table")); QTreeWidgetItem *eitem = itm; itm = new ActionSelectorDialogTreeItem(xi18nc("Note: use multiple rows if needed", "Copy to Clipboard\nAs Data Table"), eitem); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "copyToClipboardAsCSV"); itm->setIcon(KexiIcon("table")); } itm = new ActionSelectorDialogTreeItem(xi18n("Create New Object (%1)", part->info()->name().toLower()), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "new"); itm->setIcon(koIcon("document-new")); if (supportedViewModes & Kexi::DesignViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Design View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "design"); itm->setIcon(koIcon("document-properties")); } if (supportedViewModes & Kexi::TextViewMode) { - itm = new ActionSelectorDialogTreeItem(xi18n("Open in Text View"), this); + QString actionText; + QString iconName; + KexiPart::getTextViewAction(pluginId, &actionText, &iconName); + itm = new ActionSelectorDialogTreeItem(actionText, this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "editText"); - itm->setIcon(noIcon); + itm->setIcon(iconName.isEmpty() ? noIcon : QIcon::fromTheme(iconName)); } itm = new ActionSelectorDialogTreeItem( xi18n("Close View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "close"); itm->setIcon(koIcon("window-close")); expandAll(); setSortingEnabled(true); } QString m_currentPluginId; }; //------------------------------------- //! @internal class Q_DECL_HIDDEN KexiActionSelectionDialog::Private { public: Private() : kactionPageWidget(0), kactionListView(0), objectsListView(0) , currentFormActionsPageWidget(0) , currentFormActionsListView(0) , secondAnd3rdColumnMainWidget(0) , hideActionToExecuteListView(false) { } void raiseWidget(QWidget *w) { secondAnd3rdColumnStack->setCurrentWidget(w); } QString selectActionToBeExecutedMessage(const QString& actionType) const { if (actionType == "noaction") return QString(); if (actionType == "kaction" || actionType == "currentForm") return xi18n("&Select action to be executed after clicking %1 button:", actionWidgetName); // hardcoded, but it's not that bad if (actionType == "org.kexi-project.macro") return xi18n("&Select macro to be executed after clicking %1 button:", actionWidgetName); if (actionType == "org.kexi-project.script") return xi18n("&Select script to be executed after clicking %1 button:", actionWidgetName); //default: org.kexi-project.table/query/form/report... return xi18n("&Select object to be opened after clicking %1 button:", actionWidgetName); } // changes 3rd column visibility void setActionToExecuteSectionVisible(bool visible) { actionToExecuteListView->setVisible(visible); actionToExecuteLbl->setVisible(visible); } QString actionWidgetName; ActionCategoriesListView* actionCategoriesListView; //!< for column #1 QWidget *kactionPageWidget; KActionsListView* kactionListView; //!< for column #2 KexiProjectNavigator* objectsListView; //!< for column #2 QWidget *currentFormActionsPageWidget; //!< for column #2 CurrentFormActionsListView* currentFormActionsListView; //!< for column #2 QWidget *emptyWidget; QLabel *selectActionToBeExecutedLabel; QLabel *kactionPageLabel; QLabel *currentFormActionsPageLabel; ActionToExecuteListView* actionToExecuteListView; QLabel *actionToExecuteLbl; QWidget *secondAnd3rdColumnMainWidget; QGridLayout *glyr; QGridLayout *secondAnd3rdColumnGrLyr; QStackedWidget *secondAnd3rdColumnStack; //, *secondColumnStack; bool hideActionToExecuteListView; QDialogButtonBox *buttonBox; }; //------------------------------------- static QLabel *createSelectActionLabel(QWidget *parent, QWidget *buddy) { QLabel *lbl = new QLabel(parent); lbl->setBuddy(buddy); lbl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); lbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); lbl->setWordWrap(true); lbl->setMinimumHeight(lbl->fontMetrics().height()*2); return lbl; } //------------------------------------- KexiActionSelectionDialog::KexiActionSelectionDialog( QWidget *parent, const KexiFormEventAction::ActionData& action, const QString& actionWidgetName) : QDialog(parent) , d(new Private()) { setModal(true); setObjectName("actionSelectorDialog"); setWindowTitle(xi18nc("@title:window", "Assigning Action to Button")); // layout QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget *mainWidget = new QWidget(this); mainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); mainLayout->addWidget(mainWidget); /* lbl 1 +------------+ +-------------------------------+ | | | [a] | | 1st column | | +----------- + +------------+ | | | | | 2nd column | | 3rd column | | | | | + + + + | | | | +------------+ +------------+ | +------------+ +-------------------------------+ \______________________________________________/ glyr [a]- QStackedWidget *secondAnd3rdColumnStack, - for displaying KActions, the stack contains d->kactionPageWidget QWidget - for displaying objects, the stack contains secondAnd3rdColumnMainWidget QWidget and QGridLayout *secondAnd3rdColumnGrLyr - kactionPageWidget contains only a QVBoxLayout and label+kactionListView */ d->glyr = new QGridLayout(mainWidget); // 2x2 KexiUtils::setStandardMarginsAndSpacing(d->glyr); d->glyr->setRowStretch(1, 1); // 1st column: action types d->actionCategoriesListView = new ActionCategoriesListView(mainWidget); d->actionCategoriesListView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); d->glyr->addWidget(d->actionCategoriesListView, 1, 0); connect(d->actionCategoriesListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotActionCategorySelected(QTreeWidgetItem*))); QLabel *lbl = new QLabel(xi18n("Action category:"), mainWidget); lbl->setBuddy(d->actionCategoriesListView); lbl->setMinimumHeight(lbl->fontMetrics().height()*2); lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); lbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); lbl->setWordWrap(true); d->glyr->addWidget(lbl, 0, 0, Qt::AlignTop | Qt::AlignLeft); // widget stack for 2nd and 3rd column d->secondAnd3rdColumnStack = new QStackedWidget(mainWidget); d->secondAnd3rdColumnStack->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->glyr->addWidget(d->secondAnd3rdColumnStack, 0, 1, 2, 1); d->secondAnd3rdColumnMainWidget = new QWidget(d->secondAnd3rdColumnStack); d->secondAnd3rdColumnMainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->secondAnd3rdColumnGrLyr = new QGridLayout(d->secondAnd3rdColumnMainWidget); //! @todo KEXI3 QDialog::resizeLayout(d->secondAnd3rdColumnGrLyr, 0, KexiUtils::spacingHint()); d->secondAnd3rdColumnGrLyr->setRowStretch(1, 2); d->secondAnd3rdColumnStack->addWidget(d->secondAnd3rdColumnMainWidget); // 2nd column: list of actions/objects d->objectsListView = new KexiProjectNavigator(d->secondAnd3rdColumnMainWidget, KexiProjectNavigator::Borders); d->secondAnd3rdColumnGrLyr->addWidget(d->objectsListView, 1, 0); d->secondAnd3rdColumnGrLyr->setColumnStretch(0,1); d->secondAnd3rdColumnGrLyr->setColumnStretch(1,1); connect(d->objectsListView, SIGNAL(selectionChanged(KexiPart::Item*)), this, SLOT(slotItemForOpeningOrExecutingSelected(KexiPart::Item*))); d->selectActionToBeExecutedLabel = createSelectActionLabel(d->secondAnd3rdColumnMainWidget, 0); d->secondAnd3rdColumnGrLyr->addWidget( d->selectActionToBeExecutedLabel, 0, 0, Qt::AlignTop | Qt::AlignLeft); d->emptyWidget = new QWidget(d->secondAnd3rdColumnStack); d->secondAnd3rdColumnStack->addWidget(d->emptyWidget); // 3rd column: actions to execute d->actionToExecuteListView = new ActionToExecuteListView(d->secondAnd3rdColumnMainWidget); d->actionToExecuteListView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); connect(d->actionToExecuteListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotActionToExecuteItemExecuted(QTreeWidgetItem*))); connect(d->actionToExecuteListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotActionToExecuteItemSelected(QTreeWidgetItem*))); d->secondAnd3rdColumnGrLyr->addWidget(d->actionToExecuteListView, 1, 1); d->actionToExecuteLbl = createSelectActionLabel(d->secondAnd3rdColumnMainWidget, d->actionToExecuteListView); d->actionToExecuteLbl->setText(xi18n("Action to execute:")); d->secondAnd3rdColumnGrLyr->addWidget(d->actionToExecuteLbl, 0, 1, Qt::AlignTop | Qt::AlignLeft); // buttons d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = d->buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(d->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); d->actionWidgetName = actionWidgetName; d->buttonBox->button(QDialogButtonBox::Ok)->setText(xi18nc("Assign action", "&Assign")); //buttonBox->button(QDialogButtonBox::Ok)->setIcon(koIconName("dialog-ok")); d->buttonBox->button(QDialogButtonBox::Ok)->setToolTip(xi18n("Assign action")); mainLayout->addWidget(d->buttonBox); // temporary show all sections to avoid resizing the dialog in the future d->actionCategoriesListView->selectAction("table"); d->setActionToExecuteSectionVisible(true); adjustSize(); resize(qMax(700, width()), qMax(450, height())); bool ok; QString actionType, actionArg; KexiPart::Info* partInfo = action.decodeString(actionType, actionArg, &ok); if (ok) { d->actionCategoriesListView->selectAction(actionType); if (actionType == "kaction") { d->kactionListView->selectAction(actionArg); d->kactionListView->setFocus(); } else if (actionType == "currentForm") { d->currentFormActionsListView->selectAction(actionArg); d->currentFormActionsListView->setFocus(); } else if (partInfo && Kexi::partManager().part(partInfo)) // We use the Part Manager // to determine whether the Kexi-plugin is installed and whether we like to show // it in our list of actions. { KexiPart::Item *item = KexiMainWindowIface::global()->project()->item( partInfo, actionArg); if (d->objectsListView && item) { d->objectsListView->selectItem(*item); slotItemForOpeningOrExecutingSelected(item); QString actionOption(action.option); if (actionOption.isEmpty()) { actionOption = "open"; // for backward compatibility } d->actionToExecuteListView->selectAction(actionOption); d->objectsListView->setFocus(); } } } else {//invalid assignment or 'noaction' d->actionCategoriesListView->selectAction("noaction"); d->actionCategoriesListView->setFocus(); } } KexiActionSelectionDialog::~KexiActionSelectionDialog() { delete d; } void KexiActionSelectionDialog::slotKActionItemExecuted(QTreeWidgetItem*) { accept(); } void KexiActionSelectionDialog::slotKActionItemSelected(QTreeWidgetItem*) { d->setActionToExecuteSectionVisible(false); updateOKButtonStatus(); } void KexiActionSelectionDialog::slotCurrentFormActionItemExecuted(QTreeWidgetItem*) { accept(); } void KexiActionSelectionDialog::slotCurrentFormActionItemSelected(QTreeWidgetItem*) { d->setActionToExecuteSectionVisible(false); updateOKButtonStatus(); } void KexiActionSelectionDialog::slotItemForOpeningOrExecutingSelected(KexiPart::Item* item) { d->setActionToExecuteSectionVisible(item); } void KexiActionSelectionDialog::slotActionToExecuteItemExecuted(QTreeWidgetItem* item) { if (!item) return; ActionSelectorDialogTreeItem *listItem = dynamic_cast(item); if (listItem && listItem->data(ActionSelectorDialogTreeItem::ActionDataRole).isValid()) accept(); } void KexiActionSelectionDialog::slotActionToExecuteItemSelected(QTreeWidgetItem*) { //qDebug(); updateOKButtonStatus(); } void KexiActionSelectionDialog::slotActionCategorySelected(QTreeWidgetItem* item) { ActionSelectorDialogTreeItem *categoryItm = dynamic_cast(item); // simple case: part-less item, e.g. kaction: if (categoryItm) { if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "kaction") { if (!d->kactionPageWidget) { //create lbl+list view with a vlayout d->kactionPageWidget = new QWidget(); d->kactionPageWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QVBoxLayout *vlyr = new QVBoxLayout(d->kactionPageWidget); vlyr->setSpacing(KexiUtils::spacingHint()); d->kactionListView = new KActionsListView(d->kactionPageWidget); d->kactionListView->init(); d->kactionPageLabel = createSelectActionLabel(d->kactionPageWidget, d->kactionListView); vlyr->addWidget(d->kactionPageLabel); vlyr->addWidget(d->kactionListView); KexiUtils::setMargins(vlyr, 0); d->secondAnd3rdColumnStack->addWidget(d->kactionPageWidget); connect(d->kactionListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotKActionItemExecuted(QTreeWidgetItem*))); connect(d->kactionListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotKActionItemSelected(QTreeWidgetItem*))); } d->kactionPageLabel->setText( d->selectActionToBeExecutedMessage(categoryItm->data(ActionSelectorDialogTreeItem::ActionDataRole).toString())); d->setActionToExecuteSectionVisible(false); d->raiseWidget(d->kactionPageWidget); slotKActionItemSelected(d->kactionListView->currentItem()); //to refresh column #3 } else if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "currentForm") { if (!d->currentFormActionsPageWidget) { //create lbl+list view with a vlayout d->currentFormActionsPageWidget = new QWidget(); d->currentFormActionsPageWidget->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum); QVBoxLayout *vlyr = new QVBoxLayout(d->currentFormActionsPageWidget); vlyr->setSpacing(KexiUtils::spacingHint()); d->currentFormActionsListView = new CurrentFormActionsListView( d->currentFormActionsPageWidget); d->currentFormActionsListView->init(); d->currentFormActionsPageLabel = createSelectActionLabel( d->currentFormActionsPageWidget, d->currentFormActionsListView); vlyr->addWidget(d->currentFormActionsPageLabel); vlyr->addWidget(d->currentFormActionsListView); d->secondAnd3rdColumnStack->addWidget(d->currentFormActionsPageWidget); KexiUtils::setMargins(vlyr, 0); connect(d->currentFormActionsListView, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(slotCurrentFormActionItemExecuted(QTreeWidgetItem*))); connect(d->currentFormActionsListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotCurrentFormActionItemSelected(QTreeWidgetItem*))); } d->currentFormActionsPageLabel->setText( d->selectActionToBeExecutedMessage(categoryItm->data(ActionSelectorDialogTreeItem::ActionDataRole).toString())); d->setActionToExecuteSectionVisible(false); d->raiseWidget(d->currentFormActionsPageWidget); slotCurrentFormActionItemSelected(d->currentFormActionsListView->currentItem()); //to refresh column #3 } else if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "noaction") { d->raiseWidget(d->emptyWidget); d->objectsListView->clearSelection(); //hide column #3 d->setActionToExecuteSectionVisible(false); } else if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "navObject") { QString pluginId = categoryItm->data(ActionSelectorDialogTreeItem::ActionPluginIdRole).toString(); d->selectActionToBeExecutedLabel->setText(d->selectActionToBeExecutedMessage(pluginId)); if (d->objectsListView->itemsPluginId() != pluginId) { QString errorString; d->objectsListView->setProject(KexiMainWindowIface::global()->project(), pluginId, &errorString, false); d->actionToExecuteListView->showActionsForPluginId(pluginId); d->setActionToExecuteSectionVisible(false); } if (d->secondAnd3rdColumnStack->currentWidget() != d->secondAnd3rdColumnMainWidget) { d->raiseWidget(d->secondAnd3rdColumnMainWidget); d->objectsListView->clearSelection(); d->setActionToExecuteSectionVisible(false); } else { d->raiseWidget(d->secondAnd3rdColumnMainWidget); } d->selectActionToBeExecutedLabel->setBuddy(d->secondAnd3rdColumnMainWidget); } d->actionCategoriesListView->update(); updateOKButtonStatus(); return; } d->actionCategoriesListView->update(); d->actionToExecuteListView->update(); updateOKButtonStatus(); } KexiFormEventAction::ActionData KexiActionSelectionDialog::currentAction() const { KexiFormEventAction::ActionData data; ActionSelectorDialogTreeItem *categoryItm = dynamic_cast(d->actionCategoriesListView->currentItem()); if (categoryItm) { const QString actionCategory = categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString(); if (actionCategory == "kaction") { const ActionSelectorDialogTreeItem* actionToExecute = dynamic_cast( d->kactionListView->currentItem()); if (actionToExecute) { data.string = QString("kaction:") + actionToExecute->data(ActionSelectorDialogTreeItem::ActionDataRole).toString(); return data; } } else if (actionCategory == "currentForm") { const ActionSelectorDialogTreeItem *actionToExecute = dynamic_cast( d->currentFormActionsListView->currentItem()); if (actionToExecute) { data.string = QString("currentForm:") + actionToExecute->data(ActionSelectorDialogTreeItem::ActionDataRole).toString(); return data; } } else if (actionCategory == "noaction") { return data; } else if (actionCategory == "navObject") { const ActionSelectorDialogTreeItem *actionToExecute = dynamic_cast( d->actionToExecuteListView->currentItem()); if (d->objectsListView && actionToExecute && !actionToExecute->data(ActionSelectorDialogTreeItem::ActionDataRole).toString().isEmpty()) { KexiPart::Item* partItem = d->objectsListView->selectedPartItem(); KexiPart::Info* partInfo = partItem ? Kexi::partManager().infoForPluginId(partItem->pluginId()) : 0; if (partInfo) { // opening or executing: table:name, query:name, form:name, macro:name, script:name, etc. data.string = QString("%1:%2").arg(partInfo->typeName()).arg(partItem->name()); data.option = actionToExecute->data(ActionSelectorDialogTreeItem::ActionDataRole).toString(); return data; } } } else { qWarning() << "No current category item"; } } return data; // No Action } void KexiActionSelectionDialog::updateOKButtonStatus() { ActionSelectorDialogTreeItem *itm = dynamic_cast(d->actionCategoriesListView->currentItem()); //qDebug() << "Current Action:" << currentAction().string << ":" << currentAction().option; QPushButton *btn = d->buttonBox->button(QDialogButtonBox::Ok); btn->setEnabled((itm && itm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "noaction") || !currentAction().isEmpty()); } #include "kexiactionselectiondialog.moc" diff --git a/src/pics/icons/breeze/actions/16/mode-selector-sql.svg b/src/pics/icons/breeze/actions/16/mode-selector-sql.svg new file mode 100644 index 000000000..004141a01 --- /dev/null +++ b/src/pics/icons/breeze/actions/16/mode-selector-sql.svg @@ -0,0 +1,94 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/22/mode-selector-sql.svg b/src/pics/icons/breeze/actions/22/mode-selector-sql.svg new file mode 100644 index 000000000..7c4d4b6f7 --- /dev/null +++ b/src/pics/icons/breeze/actions/22/mode-selector-sql.svg @@ -0,0 +1,90 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-sql.svg b/src/pics/icons/breeze/actions/32/mode-selector-sql.svg new file mode 100644 index 000000000..7cf50aeea --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-sql.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/pics/kexi_breeze_files.cmake b/src/pics/kexi_breeze_files.cmake index 4abc9f10e..3388c8000 100644 --- a/src/pics/kexi_breeze_files.cmake +++ b/src/pics/kexi_breeze_files.cmake @@ -1,139 +1,142 @@ # List of project's own icon files # This file is generated by update_kexi_breeze_list.sh # WARNING! All changes made in this file will be lost! set(_PNG_FILES calligra-logo-black-glow.png calligra-logo-white-glow.png icons/breeze/actions/16/add-field.png icons/breeze/actions/16/autofield.png icons/breeze/actions/16/database-relations.png icons/breeze/actions/16/data-view.png icons/breeze/actions/16/design-view.png icons/breeze/actions/16/form-action.png icons/breeze/actions/16/lineedit.png icons/breeze/actions/16/multiple-objects.png icons/breeze/actions/16/radiobutton.png icons/breeze/actions/16/sql-view.png icons/breeze/actions/16/textedit.png icons/breeze/actions/16/unknown-widget.png icons/breeze/actions/16/widgets.png icons/breeze/actions/22/autofield.png icons/breeze/actions/22/database-relations.png icons/breeze/actions/22/data-view.png icons/breeze/actions/22/dateedit.png icons/breeze/actions/22/datetimeedit.png icons/breeze/actions/22/design-view.png icons/breeze/actions/22/form-action.png icons/breeze/actions/22/label.png icons/breeze/actions/22/lineedit.png icons/breeze/actions/22/multiple-objects.png icons/breeze/actions/22/progressbar.png icons/breeze/actions/22/radiobutton.png icons/breeze/actions/22/slider.png icons/breeze/actions/22/spinbox.png icons/breeze/actions/22/sql-view.png icons/breeze/actions/22/textedit.png icons/breeze/actions/22/timeedit.png icons/breeze/actions/22/unknown-widget.png icons/breeze/actions/22/widgets.png icons/breeze/actions/32/data-view.png icons/breeze/actions/32/form-action.png icons/breeze/actions/32/sql-view.png kexi-autonumber.png kexi-tableview-pen.png kexi-tableview-plus.png kexi-tableview-pointer.png ) set(_SVG_OBJECT_FILES icons/breeze/actions/16/form.svg icons/breeze/actions/16/macro.svg icons/breeze/actions/16/query.svg icons/breeze/actions/16/report.svg icons/breeze/actions/16/script.svg icons/breeze/actions/16/table.svg icons/breeze/actions/22/form.svg icons/breeze/actions/22/macro.svg icons/breeze/actions/22/query.svg icons/breeze/actions/22/report.svg icons/breeze/actions/22/script.svg icons/breeze/actions/22/table.svg icons/breeze/actions/32/form.svg icons/breeze/actions/32/macro.svg icons/breeze/actions/32/query.svg icons/breeze/actions/32/report.svg icons/breeze/actions/32/script.svg icons/breeze/actions/32/table.svg ) set(_SVG_FILES icons/breeze/actions/16/button.svg icons/breeze/actions/16/checkbox.svg icons/breeze/actions/16/combobox.svg icons/breeze/actions/16/database-key.svg icons/breeze/actions/16/data-source-tag.svg icons/breeze/actions/16/edit-clear-small.svg icons/breeze/actions/16/edit-table-clear.svg icons/breeze/actions/16/edit-table-delete-row.svg icons/breeze/actions/16/edit-table-insert-row.svg icons/breeze/actions/16/file-database.svg icons/breeze/actions/16/frame.svg icons/breeze/actions/16/groupbox.svg icons/breeze/actions/16/imagebox.svg icons/breeze/actions/16/line-horizontal.svg icons/breeze/actions/16/line-vertical.svg +icons/breeze/actions/16/mode-selector-sql.svg icons/breeze/actions/16/network-server-database.svg icons/breeze/actions/16/tabwidget-page.svg icons/breeze/actions/16/tabwidget.svg icons/breeze/actions/16/validate.svg icons/breeze/actions/22/button.svg icons/breeze/actions/22/checkbox.svg icons/breeze/actions/22/combobox.svg icons/breeze/actions/22/database-import.svg icons/breeze/actions/22/database-key.svg icons/breeze/actions/22/data-source-tag.svg icons/breeze/actions/22/document-empty.svg icons/breeze/actions/22/edit-table-clear.svg icons/breeze/actions/22/edit-table-delete-row.svg icons/breeze/actions/22/edit-table-insert-row.svg icons/breeze/actions/22/file-database.svg icons/breeze/actions/22/frame.svg icons/breeze/actions/22/groupbox.svg icons/breeze/actions/22/imagebox.svg icons/breeze/actions/22/line-horizontal.svg icons/breeze/actions/22/line-vertical.svg +icons/breeze/actions/22/mode-selector-sql.svg icons/breeze/actions/22/network-server-database.svg icons/breeze/actions/22/tabwidget-page.svg icons/breeze/actions/22/tabwidget.svg icons/breeze/actions/22/validate.svg icons/breeze/actions/32/button.svg icons/breeze/actions/32/checkbox.svg icons/breeze/actions/32/combobox.svg icons/breeze/actions/32/database-key.svg icons/breeze/actions/32/data-source-tag.svg icons/breeze/actions/32/document-empty.svg icons/breeze/actions/32/edit-table-clear.svg icons/breeze/actions/32/edit-table-delete-row.svg icons/breeze/actions/32/edit-table-insert-row.svg icons/breeze/actions/32/file-database.svg icons/breeze/actions/32/frame.svg icons/breeze/actions/32/groupbox.svg icons/breeze/actions/32/imagebox.svg icons/breeze/actions/32/line-horizontal.svg icons/breeze/actions/32/line-vertical.svg icons/breeze/actions/32/mode-selector-design.svg icons/breeze/actions/32/mode-selector-edit.svg icons/breeze/actions/32/mode-selector-help.svg icons/breeze/actions/32/mode-selector-project.svg +icons/breeze/actions/32/mode-selector-sql.svg icons/breeze/actions/32/mode-selector-welcome.svg icons/breeze/actions/32/network-server-database.svg icons/breeze/actions/32/tabwidget-page.svg icons/breeze/actions/32/tabwidget.svg icons/breeze/actions/32/validate.svg icons/breeze/apps/16/kexi.svg icons/breeze/apps/32/kexi.svg icons/breeze/apps/48/kexi.svg ) set(_FILES ${_PNG_FILES} ${_SVG_OBJECT_FILES} ${_SVG_FILES}) diff --git a/src/widget/navigator/KexiProjectNavigator.cpp b/src/widget/navigator/KexiProjectNavigator.cpp index bab986d59..29f054743 100644 --- a/src/widget/navigator/KexiProjectNavigator.cpp +++ b/src/widget/navigator/KexiProjectNavigator.cpp @@ -1,767 +1,773 @@ /* This file is part of the KDE project Copyright (C) 2002, 2003 Lucijan Busch Copyright (C) 2003-2016 Jarosław Staniek Copyright (C) 2010 Adam Pigg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 "KexiProjectNavigator.h" #include "KexiProjectTreeView.h" #include "KexiProjectModel.h" #include "KexiProjectModelItem.h" #include "KexiProjectItemDelegate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KexiProjectNavigator::Private { public: Private(Features features_, KexiProjectNavigator *qq) : features(features_) , q(qq) , emptyStateLabel(0) , prevSelectedPartInfo(0) , readOnly(false) { } ~Private() { delete model; } void clearSelectionIfNeeded() { if (features & ClearSelectionAfterAction) { list->selectionModel()->clear(); } } Features features; KexiProjectNavigator *q; QVBoxLayout *lyr; KexiProjectTreeView *list; QLabel *emptyStateLabel; KActionCollection *actions; KexiItemMenu *itemMenu; KexiGroupMenu *partMenu; QAction *deleteAction, *renameAction, *newObjectAction, *openAction, *designAction, *editTextAction, *executeAction, *dataExportToClipboardAction, *dataExportToFileAction; #ifdef KEXI_QUICK_PRINTING_SUPPORT QAction *printAction, *pageSetupAction; #endif KActionMenu* exportActionMenu; QAction *itemMenuTitle, *partMenuTitle, *exportActionMenu_sep, *pageSetupAction_sep; KexiPart::Info *prevSelectedPartInfo; bool readOnly; KexiProjectModel *model; QString itemsPluginId; }; KexiProjectNavigator::KexiProjectNavigator(QWidget* parent, Features features) : QWidget(parent) , d(new Private(features, this)) { d->actions = new KActionCollection(this); setObjectName("KexiProjectNavigator"); setWindowTitle(xi18nc("@title:window", "Project Navigator")); setWindowIcon(KexiMainWindowIface::global()->thisWidget()->windowIcon()); d->lyr = new QVBoxLayout(this); d->lyr->setContentsMargins(0, 0, 0, 0); d->list = new KexiProjectTreeView(this); if (d->features & Borders) { d->list->setAlternatingRowColors(true); } else { d->list->setFrameStyle(QFrame::NoFrame); QPalette pal(d->list->palette()); pal.setColor(QPalette::Base, Qt::transparent); d->list->setPalette(pal); d->list->setIndentation(0); } d->model = new KexiProjectModel(); connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(slotUpdateEmptyStateLabel())); connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(slotUpdateEmptyStateLabel())); d->list->setModel(d->model); KexiProjectItemDelegate *delegate = new KexiProjectItemDelegate(d->list); d->list->setItemDelegate(delegate); d->lyr->addWidget(d->list); //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange: // connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), SLOT(slotSettingsChanged(int))); // slotSettingsChanged(0); connect(d->list->selectionModel(), &QItemSelectionModel::currentChanged, this, &KexiProjectNavigator::slotSelectionChanged); if ((d->features & AllowSingleClickForOpeningItems) && KexiUtils::activateItemsOnSingleClick(d->list)) { connect(d->list, SIGNAL(clicked(QModelIndex)), this, SLOT(slotExecuteItem(QModelIndex))); } else { connect(d->list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotExecuteItem(QModelIndex))); } // actions d->openAction = addAction("open_object", koIcon("document-open"), xi18n("&Open"), xi18n("Open object"), xi18n("Opens object selected in the list."), SLOT(slotOpenObject())); if (KexiMainWindowIface::global() && KexiMainWindowIface::global()->userMode()) { //! @todo some of these actions can be supported once we deliver ACLs... d->deleteAction = 0; d->renameAction = 0; d->designAction = 0; d->editTextAction = 0; d->newObjectAction = 0; } else { d->deleteAction = addAction("edit_delete", koIcon("edit-delete"), xi18n("&Delete..."), xi18n("Delete object"), xi18n("Deletes the object selected in the list."), SLOT(slotRemove())); d->renameAction = addAction("edit_rename", koIcon("edit-rename"), xi18n("&Rename..."), xi18n("Rename object"), xi18n("Renames the object selected in the list."), SLOT(slotRename())); //! @todo enable, doesn't work now: d->renameAction->setShortcut(QKeySequence(Qt::Key_F2)); #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo plugSharedAction("edit_cut",SLOT(slotCut())); //! @todo plugSharedAction("edit_copy",SLOT(slotCopy())); //! @todo plugSharedAction("edit_paste",SLOT(slotPaste())); #endif d->designAction = addAction("design_object", koIcon("document-properties"), xi18n("&Design"), xi18n("Design object"), xi18n("Starts designing of the object selected in the list."), SLOT(slotDesignObject())); - d->editTextAction = addAction("editText_object", QIcon(), xi18n("Design in &Text View"), + d->editTextAction = addAction("editText_object", QIcon(), "Design in Text View", // <- no icon, no i18n, will be updated before use xi18n("Design object in text view"), xi18n("Starts designing of the object in the list in text view."), SLOT(slotEditTextObject())); d->newObjectAction = addAction("new_object", koIcon("document-new"), QString(),QString(), QString(), SLOT(slotNewObject())); } d->executeAction = addAction("data_execute", koIcon("system-run"), xi18n("Execute"), //! @todo tooltip, what's this QString(), QString(), SLOT(slotExecuteObject())); d->actions->addAction("export_object", d->exportActionMenu = new KActionMenu(xi18n("Export"), this)); d->dataExportToClipboardAction = addAction("exportToClipboardAsDataTable", koIcon("edit-copy"), xi18nc("Export->To Clipboard as Data... ", "To &Clipboard..."), xi18n("Export data to clipboard"), xi18n("Exports data from the currently selected table or query to clipboard."), SLOT(slotExportToClipboardAsDataTable())); d->exportActionMenu->addAction(d->dataExportToClipboardAction); d->dataExportToFileAction = addAction("exportToFileAsDataTable", KexiIcon("table"), xi18nc("Export->To File As Data &Table... ", "To &File As Data Table..."), xi18n("Export data to a file"), xi18n("Exports data from the currently selected table or query to a file."), SLOT(slotExportToFileAsDataTable())); d->exportActionMenu->addAction(d->dataExportToFileAction); #ifdef KEXI_QUICK_PRINTING_SUPPORT d->printAction = addAction("print_object", koIcon("document-print"), futureI18n("&Print..."), futureI18n("Print data"), futureI18n("Prints data from the currently selected table or query."), SLOT(slotPrintObject())); //! @todo document-page-setup could be a better icon d->pageSetupAction = addAction("pageSetupForObject", koIcon("configure"), futureI18n("Page Setup..."), futureI18n("Page setup for data"), futureI18n("Shows page setup for printing the active table or query."), SLOT(slotPageSetupForObject())); #endif if (KexiMainWindowIface::global() && KexiMainWindowIface::global()->userMode()) { //! @todo some of these actions can be supported once we deliver ACLs... d->partMenu = 0; } else { d->partMenu = new KexiGroupMenu(this, d->actions); } if (d->features & ContextMenus) { d->itemMenu = new KexiItemMenu(this, d->actions); } else { d->itemMenu = 0; } if (!(d->features & Writable)) { setReadOnly(true); } slotSelectionChanged(QModelIndex()); } void KexiProjectNavigator::setProject(KexiProject* prj, const QString& itemsPartClass, QString* partManagerErrorMessages, bool addAsSearchableModel) { d->itemsPluginId = itemsPartClass; d->model->setProject(prj, itemsPartClass, partManagerErrorMessages); if (addAsSearchableModel) { KexiMainWindowIface::global()->addSearchableModel(d->model); } d->list->expandAll(); d->list->setRootIsDecorated(false); slotUpdateEmptyStateLabel(); // Select and set current to first item d->list->setCurrentIndex(d->model->firstPartItem()); d->list->selectionModel()->select(d->list->currentIndex(), QItemSelectionModel::Rows); } QString KexiProjectNavigator::itemsPluginId() const { return d->itemsPluginId; } KexiProjectNavigator::~KexiProjectNavigator() { delete d; } QAction * KexiProjectNavigator::addAction(const QString& name, const QIcon& icon, const QString& text, const QString& toolTip, const QString& whatsThis, const char* slot) { QAction *action = new QAction(icon, text, this); d->actions->addAction(name, action); action->setToolTip(toolTip); action->setWhatsThis(whatsThis); connect(action, SIGNAL(triggered()), this, slot); return action; } void KexiProjectNavigator::contextMenuEvent(QContextMenuEvent* event) { if (!d->list->currentIndex().isValid() || !(d->features & ContextMenus)) return; QModelIndex pointedIndex = d->list->indexAt(d->list->mapFromGlobal(event->globalPos())); KexiProjectModelItem *bit = static_cast(pointedIndex.internalPointer()); if (!bit || !bit->partItem() /*no menu for group*/) { return; } QMenu *pm = 0; if (bit->partItem()) { pm = d->itemMenu; KexiProjectModelItem *par_it = static_cast(bit->parent()); if (par_it->partInfo() && bit->partItem()) { d->itemMenu->update(*par_it->partInfo(), *bit->partItem()); } } if (pm) { pm->exec(event->globalPos()); } event->setAccepted(true); d->clearSelectionIfNeeded(); } void KexiProjectNavigator::slotExecuteItem(const QModelIndex& vitem) { KexiProjectModelItem *it = static_cast(vitem.internalPointer()); if (!it) { qWarning() << "No internal pointer"; return; } if (it->partInfo()->isExecuteSupported()) emit executeItem(it->partItem()); else emit openOrActivateItem(it->partItem(), Kexi::DataViewMode); d->clearSelectionIfNeeded(); } void KexiProjectNavigator::slotSelectionChanged(const QModelIndex& i) { KexiProjectModelItem *it = static_cast(i.internalPointer()); if (!it) { if (KexiMainWindowIface::global() && !KexiMainWindowIface::global()->userMode()) { d->openAction->setEnabled(false); d->designAction->setEnabled(false); d->deleteAction->setEnabled(false); } return; } const bool gotitem = it->partItem(); //! @todo also check if the item is not read only if (d->deleteAction) { d->deleteAction->setEnabled(gotitem && !d->readOnly); } #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo setAvailable("edit_cut",gotitem); //! @todo setAvailable("edit_copy",gotitem); //! @todo setAvailable("edit_edititem",gotitem); #endif if ( KexiMainWindowIface::global() && !KexiMainWindowIface::global()->userMode() ) { d->openAction->setEnabled(gotitem && (it->partInfo()->supportedViewModes() & Kexi::DataViewMode)); if (d->designAction) { d->designAction->setEnabled(gotitem && (it->partInfo()->supportedViewModes() & Kexi::DesignViewMode)); } if (d->editTextAction) d->editTextAction->setEnabled(gotitem && (it->partInfo()->supportedViewModes() & Kexi::TextViewMode)); if (d->prevSelectedPartInfo != it->partInfo()) { d->prevSelectedPartInfo = it->partInfo(); if (d->newObjectAction) { d->newObjectAction->setText( xi18n("&Create Object: %1...", it->partInfo()->name() )); d->newObjectAction->setIcon(QIcon::fromTheme(it->partInfo()->iconName())); } #if 0 } else { if (d->newObjectAction) { d->newObjectAction->setText(xi18n("&Create Object...")); } #endif } } emit selectionChanged(it->partItem()); } void KexiProjectNavigator::slotRemove() { if (!d->deleteAction || !d->deleteAction->isEnabled() || !(d->features & Writable)) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit removeItem(it->partItem()); } void KexiProjectNavigator::slotNewObject() { if (!d->newObjectAction || !(d->features & Writable)) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partInfo()) return; emit newItem(it->partInfo()); } void KexiProjectNavigator::slotOpenObject() { KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit openItem(it->partItem(), Kexi::DataViewMode); } void KexiProjectNavigator::slotDesignObject() { if (!d->designAction) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit openItem(it->partItem(), Kexi::DesignViewMode); } void KexiProjectNavigator::slotEditTextObject() { if (!d->editTextAction) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit openItem(it->partItem(), Kexi::TextViewMode); } void KexiProjectNavigator::slotCut() { if (!(d->features & Writable)) return; //! @todo } void KexiProjectNavigator::slotCopy() { //! @todo } void KexiProjectNavigator::slotPaste() { if (!(d->features & Writable)) return; //! @todo } void KexiProjectNavigator::slotRename() { if (!d->renameAction || !(d->features & Writable)) return; KexiPart::Item* partItem = selectedPartItem(); if (!partItem) { return; } KexiProjectModelItem *partModelItem = d->model->modelItemFromItem(*partItem); if (!partModelItem) { return; } KexiPart::Info *info = partModelItem->partInfo(); KexiPart::Part *part = Kexi::partManager().partForPluginId(partItem->pluginId()); if (!info || !part) { return; } KexiNameDialog dialog( xi18nc("@info Rename object %1:", "Rename %1:", partItem->name()), this); dialog.buttonBox()->button(QDialogButtonBox::Ok)->setText(xi18nc("@action:button Rename object", "Rename")); if (!d->model->project()) { qWarning() << "No KexiProject assigned!"; return; } dialog.widget()->addNameSubvalidator( //check if new name is allowed new KDbObjectNameValidator(d->model->project()->dbConnection()->driver())); dialog.widget()->setCaptionText(partItem->caption()); dialog.widget()->setNameText(partItem->name()); dialog.setWindowTitle( xi18nc("@title:window Rename Object %1.", "Rename %1", partItem->name())); dialog.setDialogIcon(info->iconName()); dialog.setAllowOverwriting(true); bool overwriteNeeded; if (dialog.execAndCheckIfObjectExists(*d->model->project(), *part, &overwriteNeeded) != QDialog::Accepted) { return; } if (dialog.widget()->nameText() != dialog.widget()->originalNameText() && !d->model->renameItem(partItem, dialog.widget()->nameText())) { return; } d->model->setItemCaption(partItem, dialog.widget()->captionText()); } void KexiProjectNavigator::setFocus() { if (!d->list->currentIndex().isValid()) { // select first QModelIndex first = d->model->firstPartItem(); d->list->setCurrentIndex(first); } d->list->setFocus(); } void KexiProjectNavigator::updateItemName(KexiPart::Item& item, bool dirty) { if (!(d->features & Writable)) return; d->model->updateItemName(item, dirty); } void KexiProjectNavigator::selectItem(KexiPart::Item& item) { KexiProjectModelItem *bitem = d->model->modelItemFromItem(item); if (!bitem) return; QModelIndex idx = d->model->indexFromItem(bitem); d->list->setCurrentIndex(idx); d->list->scrollTo(idx); } void KexiProjectNavigator::clearSelection() { d->list->clearSelection(); d->list->scrollToTop(); } void KexiProjectNavigator::slotExecuteObject() { if (!d->executeAction) return; KexiPart::Item* item = selectedPartItem(); if (item) { emit executeItem(item); d->clearSelectionIfNeeded(); } } void KexiProjectNavigator::slotExportToClipboardAsDataTable() { if (!d->dataExportToClipboardAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit exportItemToClipboardAsDataTable(item); } void KexiProjectNavigator::slotExportToFileAsDataTable() { if (!d->dataExportToFileAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit exportItemToFileAsDataTable(item); } KexiPart::Item* KexiProjectNavigator::selectedPartItem() const { KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); return it ? it->partItem() : 0; } KexiPart::Item* KexiProjectNavigator::partItemWithSearchHighlight() const { KexiProjectModelItem *it = static_cast(d->model->itemWithSearchHighlight().internalPointer()); return it ? it->partItem() : 0; } bool KexiProjectNavigator::actionEnabled(const QString& actionName) const { if (actionName == "project_export_data_table" && (d->features & ContextMenus)) return d->exportActionMenu->isVisible(); qWarning() << "no such action:" << actionName; return false; } void KexiProjectNavigator::slotPrintObject() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (!d->printAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit printItem(item); #endif } void KexiProjectNavigator::slotPageSetupForObject() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (!d->pageSetupAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit pageSetupForItem(item); #endif } void KexiProjectNavigator::setReadOnly(bool set) { d->readOnly = set; if (d->deleteAction) d->deleteAction->setEnabled(!d->readOnly); if (d->renameAction) d->renameAction->setEnabled(!d->readOnly); if (d->newObjectAction) { d->newObjectAction->setEnabled(!d->readOnly); } } bool KexiProjectNavigator::isReadOnly() const { return d->readOnly; } void KexiProjectNavigator::clear() { d->model->clear(); } KexiProjectModel* KexiProjectNavigator::model() const { return d->model; } void KexiProjectNavigator::slotUpdateEmptyStateLabel() { if (d->model->objectsCount() == 0) { // handle the empty state with care... http://www.pinterest.com/romanyakimovich/ui-empty-states/ if (!d->emptyStateLabel) { QString imgPath = KIconLoader::global()->iconPath(KexiIconName("document-empty"), - KIconLoader::SizeLarge); //qDebug() << imgPath; d->emptyStateLabel = new QLabel( xi18nc("@info Message for empty state in project navigator", "" "" "" "Your project is empty..." "" "Why not create something?", imgPath), this); d->emptyStateLabel->setPalette( KexiUtils::paletteWithDimmedColor(d->emptyStateLabel->palette(), QPalette::WindowText)); d->emptyStateLabel->setAlignment(Qt::AlignCenter); d->emptyStateLabel->setTextFormat(Qt::RichText); d->emptyStateLabel->setWordWrap(true); QFont f(d->emptyStateLabel->font()); f.setItalic(true); f.setFamily("Times"); f.setPointSize(f.pointSize() * 4 / 3); //d->emptyStateLabel->setFont(f); d->lyr->insertWidget(0, d->emptyStateLabel); } d->emptyStateLabel->show(); } else { delete d->emptyStateLabel; d->emptyStateLabel = 0; } } //-------------------------------------------- KexiMenuBase::KexiMenuBase(QWidget* parent, KActionCollection *col) : QMenu(parent) , m_actionCollection(col) { } KexiMenuBase::~KexiMenuBase() { } QAction* KexiMenuBase::addAction(const QString& actionName) { QAction* action = m_actionCollection->action(actionName); if (action) QMenu::addAction(action); return action; } //-------------------------------------------- KexiItemMenu::KexiItemMenu(QWidget* parent, KActionCollection *col) : KexiMenuBase(parent, col) { } KexiItemMenu::~KexiItemMenu() { } void KexiItemMenu::update(const KexiPart::Info& partInfo, const KexiPart::Item& partItem) { clear(); addSection(QString()); KexiContextMenuUtils::updateTitle(this, partItem.name(), partInfo.name(), partInfo.iconName()); if (m_actionCollection->action("open_object") && m_actionCollection->action("open_object")->isEnabled() && (partInfo.supportedViewModes() & Kexi::DataViewMode)) { addAction("open_object"); } if (m_actionCollection->action("design_object") && m_actionCollection->action("design_object")->isEnabled() && (partInfo.supportedViewModes() & Kexi::DesignViewMode)) { addAction("design_object"); } - if (m_actionCollection->action("editText_object") - && m_actionCollection->action("editText_object")->isEnabled() - && (partInfo.supportedViewModes() & Kexi::TextViewMode)) { - addAction("editText_object"); + QAction *a = m_actionCollection->action("editText_object"); + if (a && a->isEnabled() + && (partInfo.supportedViewModes() & Kexi::TextViewMode)) + { + QString actionText; + QString iconName; + KexiPart::getTextViewAction(partInfo.id(), &actionText, &iconName); + a->setText(actionText); + a->setIcon(QIcon::fromTheme(iconName)); + QMenu::addAction(a); } addSeparator(); #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo plugSharedAction("edit_cut", m_itemMenu); //! @todo plugSharedAction("edit_copy", m_itemMenu); //! @todo addSeparator(); #endif bool addSep = false; if (partInfo.isExecuteSupported()) { addAction("data_execute"); addSep = true; } if (partInfo.isDataExportSupported()) { addAction("export_object"); addSep = true; } if (addSep) addSeparator(); #ifdef KEXI_QUICK_PRINTING_SUPPORT if (partInfo.isPrintingSupported()) addAction("print_object"); if (partInfo.isPrintingSupported()) addAction("pageSetupForObject"); if (m_actionCollection->action("edit_rename") || m_actionCollection->action("edit_delete")) addSeparator(); #endif addAction("edit_rename"); addAction("edit_delete"); } //-------------------------------------------- KexiGroupMenu::KexiGroupMenu(QWidget* parent, KActionCollection *col) : KexiMenuBase(parent, col) { } KexiGroupMenu::~KexiGroupMenu() { } void KexiGroupMenu::update(KexiPart::Info* partInfo) { Q_UNUSED(partInfo); clear(); addAction("new_object"); }