File indexing completed on 2024-05-12 16:39:38
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003 Lucijan Busch <lucijan@kde.org> 0003 Copyright (C) 2003-2014 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 #include "kexipart.h" 0022 #include "kexipartinfo.h" 0023 #include "kexipartitem.h" 0024 //! @todo KEXI3 #include "kexistaticpart.h" 0025 #include "KexiWindow.h" 0026 #include "KexiWindowData.h" 0027 #include "KexiView.h" 0028 #include "kexipartguiclient.h" 0029 #include "KexiMainWindowIface.h" 0030 #include "kexi.h" 0031 #include <kexiutils/utils.h> 0032 0033 #include <KDbConnection> 0034 0035 #include <KActionCollection> 0036 #include <KMessageBox> 0037 0038 #include <QDebug> 0039 0040 namespace KexiPart 0041 { 0042 0043 KEXICORE_EXPORT QString version() 0044 { 0045 return QString::fromLatin1("%1.%2").arg(KEXI_STABLE_VERSION_MAJOR).arg(KEXI_STABLE_VERSION_MINOR); 0046 } 0047 0048 //! @internal 0049 class Q_DECL_HIDDEN Part::Private 0050 { 0051 public: 0052 Private() 0053 : guiClient(0) 0054 , newObjectsAreDirty(false) 0055 , instanceActionsInitialized(false) 0056 { 0057 } 0058 0059 //! Helper, used in Part::openInstance() 0060 tristate askForOpeningInTextMode(KexiWindow *window, KexiPart::Item *item, 0061 Kexi::ViewModes supportedViewModes, Kexi::ViewMode viewMode) { 0062 if (viewMode != Kexi::TextViewMode 0063 && supportedViewModes & Kexi::TextViewMode 0064 && window->data()->proposeOpeningInTextViewModeBecauseOfProblems) { 0065 //ask 0066 KexiUtils::WaitCursorRemover remover; 0067 //! @todo use message handler for this to enable non-gui apps 0068 QString singleStatusString(window->singleStatusString()); 0069 if (!singleStatusString.isEmpty()) 0070 singleStatusString.prepend(QString("\n\n") + xi18n("Details:") + " "); 0071 if (KMessageBox::No == KMessageBox::questionYesNo(0, 0072 ((viewMode == Kexi::DesignViewMode) 0073 ? xi18nc("@info", 0074 "Object <resource>%1</resource> could not be opened in Design View.", item->name()) 0075 : xi18n("Object could not be opened in Data View.")) + "\n" 0076 + xi18n("Do you want to open it in Text View?") + singleStatusString, 0, 0077 KStandardGuiItem::open(), KStandardGuiItem::cancel())) { 0078 return false; 0079 } 0080 return true; 0081 } 0082 return cancelled; 0083 } 0084 0085 QString toolTip; 0086 QString whatsThis; 0087 QString instanceName; 0088 0089 GUIClient *guiClient; 0090 QMap<int, GUIClient*> instanceGuiClients; 0091 Kexi::ObjectStatus status; 0092 0093 bool newObjectsAreDirty; 0094 bool instanceActionsInitialized; 0095 }; 0096 } 0097 0098 //---------------------------------------------------------------- 0099 0100 using namespace KexiPart; 0101 0102 Part::Part(QObject *parent, 0103 const QString& instanceName, 0104 const QString& toolTip, 0105 const QString& whatsThis, 0106 const QVariantList& list) 0107 : PartBase(parent, list) 0108 , d(new Private()) 0109 { 0110 d->instanceName = KDb::stringToIdentifier( 0111 instanceName.isEmpty() 0112 ? xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " 0113 "Use '_' character instead of spaces. First character should be a..z character. " 0114 "If you cannot use latin characters in your language, use english word.", 0115 "object").toLower() 0116 : instanceName); 0117 d->toolTip = toolTip; 0118 d->whatsThis = whatsThis; 0119 } 0120 0121 /*! @todo KEXI3 0122 Part::Part(QObject* parent, StaticPartInfo *info) 0123 : PartBase(parent, QVariantList()) 0124 , d(new Private()) 0125 { 0126 setObjectName("StaticPart"); 0127 setInfo(info); 0128 }*/ 0129 0130 Part::~Part() 0131 { 0132 delete d; 0133 } 0134 0135 void Part::createGUIClients()//KexiMainWindow *win) 0136 { 0137 if (!d->guiClient) { 0138 //create part's gui client 0139 d->guiClient = new GUIClient(this, false, "part"); 0140 0141 //default actions for part's gui client: 0142 QAction* act = info()->newObjectAction(); 0143 // - update action's tooltip and "what's this" 0144 QString tip(toolTip()); 0145 if (!tip.isEmpty()) { 0146 act->setToolTip(tip); 0147 } 0148 QString what(whatsThis()); 0149 if (!what.isEmpty()) { 0150 act->setWhatsThis(what); 0151 } 0152 0153 //default actions for part instance's gui client: 0154 //NONE 0155 //let init specific actions for part instances 0156 for (int mode = 1; mode <= 0x01000; mode <<= 1) { 0157 if (info()->supportedViewModes() & (Kexi::ViewMode)mode) { 0158 GUIClient *instanceGuiClient = new GUIClient( 0159 this, true, Kexi::nameForViewMode((Kexi::ViewMode)mode).toLatin1()); 0160 d->instanceGuiClients.insert((Kexi::ViewMode)mode, instanceGuiClient); 0161 } 0162 } 0163 // also add an instance common for all modes (mode==0) 0164 GUIClient *instanceGuiClient = new GUIClient(this, true, "allViews"); 0165 d->instanceGuiClients.insert(Kexi::AllViewModes, instanceGuiClient); 0166 0167 initPartActions(); 0168 } 0169 } 0170 0171 KActionCollection* Part::actionCollectionForMode(Kexi::ViewMode viewMode) const 0172 { 0173 GUIClient *cli = d->instanceGuiClients.value((int)viewMode); 0174 return cli ? cli->actionCollection() : 0; 0175 } 0176 0177 QAction * Part::createSharedAction(Kexi::ViewMode mode, const QString &text, 0178 const QString &pix_name, const QKeySequence &cut, const char *name, 0179 const char *subclassName) 0180 { 0181 GUIClient *instanceGuiClient = d->instanceGuiClients.value((int)mode); 0182 if (!instanceGuiClient) { 0183 qWarning() << "no gui client for mode " << mode << "!"; 0184 return 0; 0185 } 0186 return KexiMainWindowIface::global()->createSharedAction(text, pix_name, cut, name, 0187 instanceGuiClient->actionCollection(), subclassName); 0188 } 0189 0190 QAction * Part::createSharedPartAction(const QString &text, 0191 const QString &pix_name, const QKeySequence &cut, const char *name, 0192 const char *subclassName) 0193 { 0194 if (!d->guiClient) 0195 return 0; 0196 return KexiMainWindowIface::global()->createSharedAction(text, pix_name, cut, name, 0197 d->guiClient->actionCollection(), subclassName); 0198 } 0199 0200 QAction * Part::createSharedToggleAction(Kexi::ViewMode mode, const QString &text, 0201 const QString &pix_name, const QKeySequence &cut, const char *name) 0202 { 0203 return createSharedAction(mode, text, pix_name, cut, name, "KToggleAction"); 0204 } 0205 0206 QAction * Part::createSharedPartToggleAction(const QString &text, 0207 const QString &pix_name, const QKeySequence &cut, const char *name) 0208 { 0209 return createSharedPartAction(text, pix_name, cut, name, "KToggleAction"); 0210 } 0211 0212 void Part::setActionAvailable(const char *action_name, bool avail) 0213 { 0214 for (QMap<int, GUIClient*>::Iterator it = d->instanceGuiClients.begin(); it != d->instanceGuiClients.end(); ++it) { 0215 QAction *act = it.value()->actionCollection()->action(action_name); 0216 if (act) { 0217 act->setEnabled(avail); 0218 return; 0219 } 0220 } 0221 KexiMainWindowIface::global()->setActionAvailable(action_name, avail); 0222 } 0223 0224 KexiWindow* Part::openInstance(QWidget* parent, KexiPart::Item *item, Kexi::ViewMode viewMode, 0225 QMap<QString, QVariant>* staticObjectArgs) 0226 { 0227 Q_ASSERT(item); 0228 //now it's the time for creating instance actions 0229 if (!d->instanceActionsInitialized) { 0230 initInstanceActions(); 0231 d->instanceActionsInitialized = true; 0232 } 0233 0234 d->status.clearStatus(); 0235 KexiWindow *window = new KexiWindow(parent, 0236 info()->supportedViewModes(), this, item); 0237 0238 KexiProject *project = KexiMainWindowIface::global()->project(); 0239 KDbObject object(project->typeIdForPluginId(info()->pluginId())); 0240 object.setName(item->name()); 0241 object.setCaption(item->caption()); 0242 object.setDescription(item->description()); 0243 0244 /*! @todo js: apply settings for caption displaying method; there can be option for 0245 - displaying item.caption() as caption, if not empty, without instanceName 0246 - displaying the same as above in tabCaption (or not) */ 0247 window->setId(item->identifier()); //not needed, but we did it 0248 window->setWindowIcon(QIcon::fromTheme(window->iconName())); 0249 KexiWindowData *windowData = createWindowData(window); 0250 if (!windowData) { 0251 d->status = Kexi::ObjectStatus(KexiMainWindowIface::global()->project()->dbConnection(), 0252 xi18n("Could not create object's window."), xi18n("The plugin or object definition may be corrupted.")); 0253 delete window; 0254 return 0; 0255 } 0256 window->setData(windowData); 0257 0258 if (!item->neverSaved()) { 0259 //we have to load object data for this dialog 0260 loadAndSetSchemaObject(window, object, viewMode); 0261 if (!window->schemaObject()) { 0262 //last chance: 0263 if (false == d->askForOpeningInTextMode( 0264 window, item, window->supportedViewModes(), viewMode)) { 0265 delete window; 0266 return 0; 0267 } 0268 viewMode = Kexi::TextViewMode; 0269 loadAndSetSchemaObject(window, object, viewMode); 0270 } 0271 if (!window->schemaObject()) { 0272 if (!d->status.error()) 0273 d->status = Kexi::ObjectStatus(KexiMainWindowIface::global()->project()->dbConnection(), 0274 xi18n("Could not load object's definition."), xi18n("Object design may be corrupted.")); 0275 d->status.append( 0276 Kexi::ObjectStatus(xi18nc("@info", 0277 "You can delete <resource>%1</resource> object and create it again.", 0278 item->name()), QString())); 0279 0280 window->close(); 0281 delete window; 0282 return 0; 0283 } 0284 } 0285 0286 bool switchingFailed = false; 0287 bool dummy; 0288 tristate res = window->switchToViewMode(viewMode, staticObjectArgs, &dummy); 0289 if (!res) { 0290 tristate askForOpeningInTextModeRes 0291 = d->askForOpeningInTextMode(window, item, window->supportedViewModes(), viewMode); 0292 if (true == askForOpeningInTextModeRes) { 0293 window->close(); 0294 delete window; 0295 //try in text mode 0296 return openInstance(parent, item, Kexi::TextViewMode, staticObjectArgs); 0297 } else if (false == askForOpeningInTextModeRes) { 0298 window->close(); 0299 delete window; 0300 qWarning() << "!window, cannot switch to a view mode" << 0301 Kexi::nameForViewMode(viewMode); 0302 return 0; 0303 } 0304 //the window has an error info 0305 switchingFailed = true; 0306 } 0307 if (~res) 0308 switchingFailed = true; 0309 0310 if (switchingFailed) { 0311 d->status = window->status(); 0312 window->close(); 0313 delete window; 0314 qWarning() << "!window, switching to view mode failed, " << 0315 Kexi::nameForViewMode(viewMode); 0316 return 0; 0317 } 0318 window->registerWindow(); //ok? 0319 window->show(); 0320 0321 window->setMinimumSize(window->minimumSizeHint().width(), window->minimumSizeHint().height()); 0322 0323 //dirty only if it's a new object 0324 if (window->selectedView()) { 0325 window->selectedView()->setDirty( 0326 internalPropertyValue("newObjectsAreDirty", false).toBool() ? item->neverSaved() : false); 0327 } 0328 return window; 0329 } 0330 0331 KDbObject* Part::loadSchemaObject(KexiWindow *window, const KDbObject& object, 0332 Kexi::ViewMode viewMode, bool *ownedByWindow) 0333 { 0334 Q_UNUSED(window); 0335 Q_UNUSED(viewMode); 0336 Q_ASSERT(ownedByWindow); 0337 KDbObject *newObject = new KDbObject(); 0338 *newObject = object; 0339 *ownedByWindow = true; 0340 return newObject; 0341 } 0342 0343 void Part::loadAndSetSchemaObject(KexiWindow *window, const KDbObject& object, 0344 Kexi::ViewMode viewMode) 0345 { 0346 bool schemaObjectOwned = true; 0347 KDbObject* sd = loadSchemaObject(window, object, viewMode, &schemaObjectOwned); 0348 window->setSchemaObject(sd); 0349 window->setSchemaObjectOwned(schemaObjectOwned); 0350 } 0351 0352 bool Part::loadDataBlock(KexiWindow *window, QString *dataString, const QString& dataID) 0353 { 0354 if (true != KexiMainWindowIface::global()->project()->dbConnection()->loadDataBlock( 0355 window->id(), dataString, dataID)) 0356 { 0357 d->status = Kexi::ObjectStatus(KexiMainWindowIface::global()->project()->dbConnection(), 0358 xi18n("Could not load object's data."), 0359 xi18nc("@info", 0360 "Data identifier: <resource>%1</resource>.", dataID)); 0361 d->status.append(*window); 0362 return false; 0363 } 0364 return true; 0365 } 0366 0367 void Part::initPartActions() 0368 { 0369 } 0370 0371 void Part::initInstanceActions() 0372 { 0373 } 0374 0375 tristate Part::remove(KexiPart::Item *item) 0376 { 0377 Q_ASSERT(item); 0378 KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); 0379 if (!conn) 0380 return false; 0381 return conn->removeObject(item->identifier()); 0382 } 0383 0384 KexiWindowData* Part::createWindowData(KexiWindow* window) 0385 { 0386 return new KexiWindowData(window); 0387 } 0388 0389 QString Part::instanceName() const 0390 { 0391 return d->instanceName; 0392 } 0393 0394 QString Part::toolTip() const 0395 { 0396 return d->toolTip; 0397 } 0398 0399 QString Part::whatsThis() const 0400 { 0401 return d->whatsThis; 0402 } 0403 0404 tristate Part::rename(KexiPart::Item *item, const QString& newName) 0405 { 0406 Q_UNUSED(item); 0407 Q_UNUSED(newName); 0408 return true; 0409 } 0410 0411 GUIClient* Part::instanceGuiClient(Kexi::ViewMode mode) const 0412 { 0413 return d->instanceGuiClients.value((int)mode); 0414 } 0415 0416 GUIClient* Part::guiClient() const 0417 { 0418 return d->guiClient; 0419 } 0420 0421 const Kexi::ObjectStatus& Part::lastOperationStatus() const 0422 { 0423 return d->status; 0424 } 0425 0426 KDbQuerySchema* Part::currentQuery(KexiView* view) 0427 { 0428 Q_UNUSED(view); 0429 return 0; 0430 } 0431 0432 KEXICORE_EXPORT QString KexiPart::fullCaptionForItem(KexiPart::Item *item, KexiPart::Part *part) 0433 { 0434 Q_ASSERT(item); 0435 Q_ASSERT(part); 0436 if (part) 0437 return item->name() + " : " + part->info()->name(); 0438 return item->name(); 0439 }