File indexing completed on 2024-05-12 16:39:39

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
0003    Copyright (C) 2003-2019 Jarosław Staniek <staniek@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #ifndef KEXIPROJECT_H
0022 #define KEXIPROJECT_H
0023 
0024 #include <QObject>
0025 
0026 #include <KDbTristate>
0027 #include <KDbObject>
0028 #include <KDbResult>
0029 
0030 #include "kexiprojectdata.h"
0031 #include "kexipartitem.h"
0032 #include "kexi.h"
0033 
0034 #include <KDbTableOrQuerySchema>
0035 
0036 /*! KexiProject implementation version.
0037  It is altered after every change:
0038  - major number is increased after KexiProject storage format change,
0039  - minor is increased after adding binary-incompatible change.
0040  Use KexiProject::versionMajor() and KexiProject::versionMinor() to get real project's version.
0041 */
0042 
0043 #define KEXIPROJECT_VERSION_MAJOR 1
0044 #define KEXIPROJECT_VERSION_MINOR 0
0045 
0046 class QFileInfo;
0047 class KDbConnection;
0048 class KDbParser;
0049 class KexiMainWindow;
0050 class KexiWindow;
0051 
0052 namespace KexiPart
0053 {
0054 class Part;
0055 class Info;
0056 
0057 struct MissingPart {
0058     QString name;
0059     QString id;
0060 };
0061 typedef QList<MissingPart> MissingPartsList;
0062 }
0063 
0064 /**
0065  * @brief A single project's controller and data structure.
0066  * It contains data connection, state, etc.
0067  */
0068 class KEXICORE_EXPORT KexiProject : public QObject, public KDbObject, public KDbResultable
0069 {
0070     Q_OBJECT
0071 
0072 public:
0073     /*! Constructor 1. Creates a new object using \a pdata.
0074      \a handler can be provided to receive error messages during
0075      entire KexiProject object's lifetime. */
0076     explicit KexiProject(const KexiProjectData& pdata, KDbMessageHandler* handler = 0);
0077 
0078     /*! Constructor 2. Like above but sets predefined connections \a conn.
0079      The connection should be created using the same connection data
0080      as pdata->connectionData(). The connection will become owned by created KexiProject
0081      object, so do not destroy it. */
0082     KexiProject(const KexiProjectData& pdata, KDbMessageHandler* handler,
0083                 KDbConnection* conn);
0084 
0085     ~KexiProject();
0086 
0087     /*! \return major version of KexiProject object.
0088      This information is retrieved from database when existing project is opened. */
0089     int versionMajor() const;
0090 
0091     /*! \return minor version of KexiProject object.
0092      @see versionMajor() */
0093     int versionMinor() const;
0094 
0095     /*! Opens existing project using project data.
0096      \return true on success */
0097     tristate open();
0098 
0099     /*! Like open().
0100      \return true on success.
0101      Additional \a incompatibleWithKexi, is set to false on failure when
0102      connection for the project was successfully started bu the project
0103      is probably not compatible with Kexi - no valid "kexidb_major_ver"
0104      value in "kexi__db" table.
0105      This is often the case for native server-based databases.
0106      If so, Kexi application can propose importing the database
0107      or linking it to parent project (the latter isn't yet implemented).
0108      For other types of errors the variable is set to true. */
0109     tristate open(bool *incompatibleWithKexi);
0110 
0111     /*! Creates new, empty project using project data.
0112      If \a forceOverwrite is true, existing database project is silently overwritten.
0113      KDbConnection is created (accessible then with KexiProject::dbConnection()).
0114 
0115      Since KexiProject inherits KDbObject, it is possible to get error message
0116      and other information on error.
0117 
0118      \return true on success, false on failure, and cancelled when database exists
0119      but \a forceOverwrite is false. */
0120     tristate create(bool forceOverwrite = false);
0121 
0122     /**
0123      * @return true if a we are connected to a database
0124      */
0125     bool isConnected();
0126 
0127     /**
0128      * @return internal numeric type identifier for plugin ID @a pluginId.
0129      * -1 is returned if the ID is unknown.
0130      * While the plugin IDs are unique strings like "org.kexi-project.table",
0131      * the type identifiers are specific to the given physically stored project
0132      * because sets of plugins can differ from between various Kexi installations
0133      * and configurations.
0134      * @see pluginIdForTypeId()
0135      */
0136     int typeIdForPluginId(const QString &pluginId) const;
0137 
0138     /**
0139      * @return plugin ID for a numeric type ID @a typeId.
0140      * Empty string is returned if the plugin ID is unknown.
0141      * @see typeIdForPluginId()
0142      */
0143     QString pluginIdForTypeId(int typeId) const;
0144 
0145     /**
0146      * Returns table or query type for given plugin ID
0147      *
0148      * - KDbTableOrQuerySchema::Type::Table for "org.kexi-project.table"
0149      * - KDbTableOrQuerySchema::Type::Query for "org.kexi-project.query"
0150      *
0151      * @a ok must not be @c nullptr. For "org.kexi-project.table" or "org.kexi-project.query" plugin
0152      * ID *ok is set to @c true, for other IDs it is set to @c false and
0153      * KDbTableOrQuerySchema::Type::Table is returned.
0154      */
0155     static KDbTableOrQuerySchema::Type pluginIdToTableOrQueryType(const QString &pluginId,
0156                                                                   bool *ok);
0157 
0158     /**
0159      * @return all items of a type \a i in this project
0160      */
0161     KexiPart::ItemDict* items(KexiPart::Info *i);
0162 
0163     /**
0164      * @return all items of a plugin ID \a pluginId in this project
0165      * It is a convenience function.
0166      */
0167     KexiPart::ItemDict* itemsForPluginId(const QString &pluginId);
0168 
0169     /**
0170      * Puts a list of items of a type \a i in this project into \a list.
0171      * You can then sort this list using ItemList::sort().
0172      */
0173     void getSortedItems(KexiPart::ItemList  *list, KexiPart::Info *i);
0174 
0175     /**
0176      * Puts a sorted list of items that use a plugin ID \a pluginId into \a list.
0177      * You can then sort this list using KexiPart::ItemList::sort().
0178      */
0179     void getSortedItemsForPluginId(KexiPart::ItemList *list, const QString &pluginId);
0180 
0181     /**
0182      * @return item corresponding with plugin ID \a pluginId and name \a name
0183      */
0184     KexiPart::Item* itemForPluginId(const QString &pluginId, const QString &name);
0185 
0186     /**
0187      * @return item of type \a i and name \a name
0188      */
0189     KexiPart::Item* item(KexiPart::Info *i, const QString &name);
0190 
0191     /**
0192      * @return item for \a identifier
0193      */
0194     KexiPart::Item* item(int identifier);
0195 
0196     /**
0197      * @return the database connection associated with this project
0198      */
0199     KDbConnection *dbConnection() const;
0200 
0201     /**
0202      * @return the project's data
0203      */
0204     KexiProjectData *data() const;
0205 
0206     /*! Opens object pointed by \a item in a view \a viewMode.
0207      \a staticObjectArgs can be passed for static object
0208      (only works when part for this item is of type KexiPart::StaticPart).
0209      The new widget will be a child of \a parent. */
0210     KexiWindow* openObject(QWidget* parent, KexiPart::Item *item,
0211                            Kexi::ViewMode viewMode = Kexi::DataViewMode,
0212                            QMap<QString, QVariant>* staticObjectArgs = 0);
0213 
0214     //! For convenience
0215     KexiWindow* openObject(QWidget* parent, const QString &pluginId,
0216                            const QString& name, Kexi::ViewMode viewMode = Kexi::DataViewMode);
0217 
0218     /*! Remove a part instance pointed by \a item.
0219      \return true on success. */
0220     bool removeObject(KexiPart::Item* item);
0221 
0222     /*! Renames a part instance pointed by \a item to a new name \a newName.
0223      \return true on success. */
0224     bool renameObject(KexiPart::Item* item, const QString& newName);
0225 
0226     /*! Renames a part instance pointed by \a item to a new name \a newName.
0227      \return true on success. */
0228     bool setObjectCaption(KexiPart::Item* item, const QString& newCaption);
0229 
0230     /*! Creates part item for given part \a info.
0231      Newly item will not be saved to the backend but stored in memory only
0232      (owned by project), and marked as "neverSaved" (see KexiPart::Item::neverSaved()).
0233      The item will have assigned a new unique caption like e.g. "Table15",
0234      and unique name like "table15", but no specific identifier
0235      (because id will be assigned on creation at the backend side).
0236 
0237      If \a suggestedCaption is not empty, it will be set as a caption
0238      (with number suffix, to avoid duplicated, e.g. "employees7"
0239      for "employees" sugested name). Name will be then built based
0240      on this caption using KDb::stringToIdentifier().
0241 
0242      This method is used before creating new object.
0243      \return newly created part item or NULL on any error. */
0244     KexiPart::Item* createPartItem(KexiPart::Info *info,
0245                                    const QString& suggestedCaption = QString());
0246 
0247     //! Added for convenience.
0248     KexiPart::Item* createPartItem(KexiPart::Part *part,
0249                                    const QString& suggestedCaption = QString());
0250 
0251     /*! Adds item \a item after it is successfully stored as an instance of part
0252      pointed by \a info. Also clears 'neverSaved' flag if \a item.
0253      Used by KexiWindow::storeNewData().
0254      @internal */
0255     void addStoredItem(KexiPart::Info *info, KexiPart::Item *item);
0256 
0257     /*! removes \a item from internal dictionaries. The item is destroyed
0258      after successful removal.
0259      Used to delete an unstored part item previously created with createPartItem(). */
0260     void deleteUnstoredItem(KexiPart::Item *item);
0261 
0262     /**
0263      * @returns parts metioned in the project meta tables but not available locally
0264      */
0265     KexiPart::MissingPartsList missingParts() const;
0266 
0267     KDbParser* sqlParser();
0268 
0269     /*! Shows dialog for creating new blank project,
0270      ans creates one. Dialog is not shown if option for automatic creation
0271      is checked or KexiStartupHandler::global()->projectData() was provided from command line.
0272      \a cancelled is set to true if creation has been cancelled (e.g. user answered
0273      no when asked for database overwriting, etc.
0274      \return true if database was created, false on error or when cancel was pressed */
0275     static KexiProject* createBlankProject(bool *cancelled, const KexiProjectData& data,
0276                                            KDbMessageHandler* handler = 0);
0277 
0278     /*! Drops project described by \a data. \return true on success.
0279      Use with care: Any KexiProject objects allocated for this project will become invalid! */
0280     static tristate dropProject(const KexiProjectData& data,
0281                                 KDbMessageHandler* handler, bool dontAsk = false);
0282 
0283     //! Helper method to ask user "Could not  open file for reading and writing. Do you want to
0284     //! open the file as read only?". @return true if user agrees, false if user cancels opening.
0285     static bool askForOpeningNonWritableFileAsReadOnly(QWidget *parent, const QFileInfo &finfo);
0286 
0287     /*! Generates ID for private "document" like Relations window.
0288      Private IDs are negative numbers (while ID regular part instance's IDs are >0)
0289      Private means that the object is not stored as-is in the project but is somewhat
0290      generated and in most cases there is at most one unique instance document of such type (part).
0291      To generate this ID, just app-wide internal counter is used. */
0292     virtual int generatePrivateID();
0293 
0294     //! Closes connection. @return true on success.
0295     bool closeConnection();
0296 
0297     /*! Loads current user's data block, referenced by \a objectID and \a dataID
0298      and puts it to \a dataString.
0299      \return true on success, false on failure and cancelled when there is no such data block
0300      \sa storeUserDataBlock() removeUserDataBlock() copyUserDataBlock() KDbConnection::loadDataBlock(). */
0301     tristate loadUserDataBlock(int objectID, const QString& dataID, QString *dataString);
0302 
0303     /*! Stores current user's data block \a dataString, referenced by \a objectID and \a dataID.
0304      The block will be stored in "kexi__userdata" table
0305      If there is already such record in the table, it's simply overwritten.
0306      \return true on success
0307      \sa loadUserDataBlock() removeUserDataBlock() copyUserDataBlock() KDbConnection::storeDataBlock(). */
0308     bool storeUserDataBlock(int objectID, const QString& dataID, const QString &dataString);
0309 
0310     /*! Copies urrent user's data blocks referenced by \a sourceObjectID and pointed
0311      by optional \a dataID.
0312      \return true on success. Does not fail if blocks do not exist.
0313      Prior to copying, existing user data blocks are removed even if there is nothing to copy.
0314      Copied data blocks will have \a destObjectID object identifier assigned.
0315      Note that if \a dataID is not specified, all user data blocks found for the \a sourceObjectID
0316      will be copied.
0317      \sa loadUserDataBlock() storeUserDataBlock() removeUserDataBlock() KDbConnection::copyDataBlock(). */
0318     bool copyUserDataBlock(int sourceObjectID, int destObjectID, const QString &dataID = QString());
0319 
0320     /*! Removes current user's data block referenced by \a objectID and \a dataID.
0321      \return true on success. Does not fail if the block does not exist.
0322      Note that if \a dataID is not specified, all data blocks for this user and object will be removed.
0323      \sa loadUserDataBlock() storeUserDataBlock() copyUserDataBlock() KDbConnection::removeDataBlock(). */
0324     bool removeUserDataBlock(int objectID, const QString& dataID = QString());
0325 
0326 protected:
0327     /*! Creates connection using project data.
0328      The connection will be readonly if data()->isReadOnly().
0329      \return true on success, otherwise false and appropriate error is set. */
0330     bool createConnection();
0331 
0332     bool initProject();
0333 
0334     //! Used in open() and open(bool*).
0335     tristate openInternal(bool *incompatibleWithKexi);
0336 
0337     /*! Kexi itself can define a number of internal database objects (mostly data structures),
0338      usually tables for it's own purposes.
0339      Even while at KDb library level, such "system" tables, like "kexi__objects", "kexi__objectdata"
0340      are created automatically on database project creation, this is not enough: there are objects
0341      needed specifically for Kexi but not for other applications utilizing the KDb library.
0342      Example table created here for now is "kexi__blobs".
0343 
0344      This method is called on create() and open(): creates necessary objects
0345      if they are not yet existing. This especially allows to create to create these objects
0346      (on open) within a project made with previous Kexi version not supporting
0347      all currently defined structurtes. We're trying to be here as much backward compatible as possible.
0348      For this purpose, here's the complete list of currently created objects:
0349      - "kexi__blobs" - a table containing BLOBs data that can be accessed globally at Kexi projects
0350        from within any database-aware view (table views, forms, reports, etc.)
0351 
0352      @param insideTransaction Embed entire creation process inside a transaction
0353 
0354      \return true on successful object's creation. Objects are created only once, they are not overwritten.
0355     */
0356     bool createInternalStructures(bool insideTransaction);
0357 
0358     /*! \return Kexi part for \a item. */
0359     KexiPart::Part *findPartFor(const KexiPart::Item& item);
0360 
0361     //! Closes connection without altering the m_result if is actually set. @return true on success.
0362     //! Used on failed operations such as useDatabase().
0363     bool closeConnectionInternal();
0364 
0365 Q_SIGNALS:
0366     /** signal emitted on error */
0367     void error(const QString &title, KDbObject *obj);
0368 
0369     /** signal emitted on error (not KDb-related) */
0370     void error(const QString &msg, const QString &desc);
0371 
0372     /** New \a item has been stored. */
0373     void newItemStored(KexiPart::Item *item);
0374 
0375     /** instance pointed by \a item is removed */
0376     void itemRemoved(const KexiPart::Item &item);
0377 
0378     /** instance pointed by \a item is renamed */
0379     void itemRenamed(const KexiPart::Item &item, const QString& oldName);
0380 
0381     /** caption for instance pointed by \a item is changed */
0382     void itemCaptionChanged(const KexiPart::Item &item, const QString& oldCaption);
0383 
0384 protected:
0385     bool createIdForPart(const KexiPart::Info& info);
0386 
0387 private:
0388     /*! Checks whether the project's connection is read-only.
0389      If so, error message is set and false is returned. */
0390     bool checkWritable();
0391 
0392     /*! Retrieves basic information (pluginId, typeId, name, caption)
0393      about all items of all types for this project.
0394      @return true on success. */
0395     bool retrieveItems();
0396 
0397     /**
0398      * Checks project's kexi__part table.
0399      * @a singlePluginId can be provided to only check specified part.
0400      * Internal identifiers of part(s) are remembered.
0401      *
0402      * Use @ref missingParts() to get a list of missing parts.
0403      * @see typeIdForPluginId()
0404      */
0405     bool checkProject(const QString& singlePluginId = QString());
0406 
0407     class Private;
0408     Private * const d;
0409 
0410     friend class KexiMainWindow;
0411     friend class KexiWindow;
0412     friend class Private;
0413 };
0414 
0415 #endif