diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/main | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/main')
56 files changed, 16312 insertions, 0 deletions
diff --git a/kexi/main/Makefile.am b/kexi/main/Makefile.am new file mode 100644 index 00000000..8786c7cf --- /dev/null +++ b/kexi/main/Makefile.am @@ -0,0 +1,35 @@ +include $(top_srcdir)/kexi/Makefile.global + +lib_LTLIBRARIES = libkeximain.la +libkeximain_la_SOURCES = \ + keximainwindowimpl.cpp \ + kexistatusbar.cpp \ + kexinamewidget.cpp kexinamedialog.cpp \ + kexinewstuff.cpp kexifinddialogbase.ui kexifinddialog.cpp + +libkeximain_la_LDFLAGS = -no-undefined $(KDE_RPATH) $(all_libraries) \ + $(VER_INFO) -Wnounresolved + +SUBDIRS = startup printing . + +libkeximain_la_LIBADD = $(top_builddir)/kexi/kexidb/libkexidb.la $(top_builddir)/kexi/core/libkexicore.la \ + $(top_builddir)/kexi/kexiutils/libkexiutils.la \ + $(top_builddir)/kexi/main/startup/libkeximainstartup.la \ + $(top_builddir)/kexi/main/printing/libkeximainprinting.la \ + $(top_builddir)/lib/koproperty/libkoproperty.la \ + $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \ + $(LIB_KFEEDBACK) $(LIB_KEXI_KMDI) $(LIB_KNEWSTUFF) $(LIB_KIO) $(LIB_KDEPRINT) + +#disabled ../migration/libkeximigrate.la + +INCLUDES = $(INC_KFEEDBACK) $(LIB_KEXI_KMDI_INCLUDES) \ + -I$(top_builddir)/lib/kofficeui -I$(top_srcdir)/lib/kofficeui \ + -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/core \ + -I$(top_srcdir)/kexi/main \ + -I$(top_srcdir)/kexi/main/startup -I$(top_srcdir)/kexi/widget \ + -I$(top_srcdir)/kexi/migration -I$(top_srcdir)/lib -I$(top_srcdir)/lib/kofficecore \ + $(all_includes) + +noinst_HEADERS = ksplitter.h keximainwindowimpl_p.h + +METASOURCES = AUTO diff --git a/kexi/main/configure.in.in b/kexi/main/configure.in.in new file mode 100644 index 00000000..00c25f38 --- /dev/null +++ b/kexi/main/configure.in.in @@ -0,0 +1,102 @@ + +dnl ====================================== +dnl KNewStuff Configuration +dnl ====================================== +dnl +dnl Copyright (C) 2004 Josef Spillner <spillner@kde.org> +dnl This file is to be used within KDE's build system. +dnl It defines $(LIB_KNEWSTUFF) if knewstuff has been found, +dnl and a HAVE_KNEWSTUFF #define statement is added. +dnl + +AC_MSG_CHECKING([for KDE library: knewstuff]) + +ac_knewstuff_includes=NO ac_knewstuff_libraries=NO +knewstuff_libraries="" +knewstuff_includes="" + +AC_CACHE_VAL(ac_cv_have_knewstuff, +[ +AC_FIND_FILE(knewstuff/downloaddialog.h, $kde_incdirs, knewstuff_incdir) +ac_knewstuff_includes="$knewstuff_incdir" + +AC_FIND_FILE(libknewstuff.so, $kde_libdirs, knewstuff_libdir) +ac_knewstuff_libraries="$knewstuff_libdir" + +if test "$ac_knewstuff_includes" = NO || test "$ac_knewstuff_libraries" = NO; then + ac_cv_have_knewstuff="have_knewstuff=no" + ac_knewstuff_notfound="" +else + have_knewstuff="yes" +fi +]) + +eval "$ac_cv_have_knewstuff" + +if test "$have_knewstuff" != yes; then + AC_MSG_RESULT([$have_knewstuff]) +else + AC_MSG_RESULT([$have_knewstuff (libraries $ac_knewstuff_libraries, headers $ac_knewstuff_includes)]) + +dnl AC_DEFINE_UNQUOTED(HAVE_KNEWSTUFF, 1, [Add KNewStuff functionality.]) + CXXFLAGS="$CXXFLAGS -DHAVE_KNEWSTUFF" + + LIB_KNEWSTUFF='-lknewstuff' + AC_SUBST(LIB_KNEWSTUFF) +fi + +AC_CHECK_FILE([kexi/3rdparty/kexifeedbackwizard/lib/kexifeedbackwizard.cpp], + have_internal_feedback="yes" +, + have_internal_feedback="no" +) + +AC_MSG_CHECKING([for KDE library: kfeedbackwizard]) + +ac_kfeedback_includes=NO ac_kfeedback_libraries=NO +kfeedback_libraries="" +kfeedback_includes="" + +AC_CACHE_VAL(ac_cv_have_kfeedback, +[ +AC_FIND_FILE(kfeedbackwizard.h, $kde_incdirs, kfeedback_incdir) +ac_kfeedback_includes="$kfeedback_incdir" + +AC_FIND_FILE(libkfeedbackwizard.so, $kde_libdirs, kfeedback_libdir) +ac_kfeedback_libraries="$kfeedback_libdir" + +if test "$ac_kfeedback_includes" = NO || test "$ac_kfeedback_libraries" = NO; then + ac_cv_have_kfeedback="have_kfeedback=no" + ac_kfeedback_notfound="" +else + have_kfeedback="yes" +fi +]) + +eval "$ac_cv_have_kfeedback" + +INC_KFEEDBACK='' +LIB_KFEEDBACK='' +if test "$have_kfeedback" != yes; then + if test "$have_internal_feedback" = yes; then + CXXFLAGS="$CXXFLAGS -DFEEDBACK_CLASS=KexiFeedbackWizard -DFEEDBACK_INCLUDE=\"<kexifeedbackwizard.h>\"" + use_kexifb="yes" + AC_MSG_RESULT([using internal]) + INC_KFEEDBACK='-I../3rdparty/kexifeedbackwizard/lib' + LIB_KFEEDBACK='../3rdparty/kexifeedbackwizard/lib/libkexifeedbackwizard.la' + else + use_kexifb="no" + AC_MSG_RESULT([dont use]) + fi +else + use_kexifb="no" + AC_MSG_RESULT([$have_kfeedback (libraries $ac_kfeedback_libraries, headers $ac_kfeedback_includes)]) + +dnl AC_DEFINE_UNQUOTED(HAVE_KFEEDBACK, 1, [Add KNewStuff functionality.]) + CXXFLAGS="$CXXFLAGS -DFEEDBACK_CLASS=KFeedbackWizard -DFEEDBACK_INCLUDE=\"<kfeedbackwizard.h>\"" + + LIB_KFEEDBACK='-lkfeedbackwizard' +fi +AC_SUBST(LIB_KFEEDBACK) +AC_SUBST(INC_KFEEDBACK) +AM_CONDITIONAL(use_kexifeedback, test "$use_kexifb" = "yes") diff --git a/kexi/main/kde2_closebutton.xpm b/kexi/main/kde2_closebutton.xpm new file mode 100644 index 00000000..5c05e714 --- /dev/null +++ b/kexi/main/kde2_closebutton.xpm @@ -0,0 +1,22 @@ +/* XPM */ +#ifndef _KDE2_CLOSEBUTTON_XPM_ +#define _KDE2_CLOSEBUTTON_XPM_ + +static const char* kde2_closebutton[]={ +"12 12 2 1", +". s None c None", +"# c #000000", +"............", +"............", +"...#....#...", +"..###..###..", +"...######...", +"....####....", +"....####....", +"...######...", +"..###..###..", +"...#....#...", +"............", +"............"}; + +#endif diff --git a/kexi/main/kexifinddialog.cpp b/kexi/main/kexifinddialog.cpp new file mode 100644 index 00000000..58f693c0 --- /dev/null +++ b/kexi/main/kexifinddialog.cpp @@ -0,0 +1,279 @@ +/* This file is part of the KDE project + Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 "kexifinddialog.h" + +#include <kstdguiitem.h> +#include <kstdaction.h> +#include <kpushbutton.h> +#include <kcombobox.h> +#include <klocale.h> +#include <kdebug.h> +#include <kdialog.h> +#include <kaction.h> +#include <kiconloader.h> + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qguardedptr.h> +#include <qlayout.h> +#include <qaccel.h> + +//! @internal +class KexiFindDialog::Private +{ + public: + Private() + { + accels.setAutoDelete(true); + } + ~Private() + { + } + //! Connects action \a action with appropriate signal \a member + //! and optionally adds accel that will receive shortcut for \a action + //! at global scope of the dialog \a parent. + void setActionAndAccel(KAction *action, QWidget* parent, const char* member) + { + if (!action) + return; + QObject::connect(parent, member, action, SLOT(activate())); + if (action->shortcut().isNull()) + return; + QAccel *accel = new QAccel(parent); // we want to handle dialog-wide shortcut as well + accels.append( accel ); + accel->connectItem( + accel->insertItem( action->shortcut() ), parent, member ); + } + + QStringList lookInColumnNames; + QStringList lookInColumnCaptions; + QString objectName; //!< for caption + QGuardedPtr<KAction> findnextAction; + QGuardedPtr<KAction> findprevAction; + QGuardedPtr<KAction> replaceAction; + QGuardedPtr<KAction> replaceallAction; + QPtrList<QAccel> accels; + bool replaceMode : 1; +}; + +//------------------------------------------ + +KexiFindDialog::KexiFindDialog( QWidget* parent ) + : KexiFindDialogBase(parent, "KexiFindDialog", false/*!modal*/, + Qt::WType_Dialog|Qt::WStyle_NormalBorder|Qt::WStyle_Title + |Qt::WStyle_SysMenu|Qt::WStyle_Customize|Qt::WStyle_Tool) + , d( new Private() ) +{ + m_search->setCurrentItem((int)KexiSearchAndReplaceViewInterface::Options::SearchDown); + layout()->setMargin( KDialog::marginHint() ); + layout()->setSpacing( KDialog::spacingHint() ); + KAction *a = KStdAction::findNext(0, 0, 0); + m_btnFind->setText(a->text()); + m_btnFind->setIconSet(a->iconSet()); + delete a; + m_btnClose->setText(KStdGuiItem::close().text()); + m_btnClose->setIconSet(KStdGuiItem::close().iconSet()); + connect(m_btnFind, SIGNAL(clicked()), this, SIGNAL(findNext())); + connect(m_btnClose, SIGNAL(clicked()), this, SLOT(slotCloseClicked())); + connect(m_btnReplace, SIGNAL(clicked()), this, SIGNAL(replaceNext())); + connect(m_btnReplaceAll, SIGNAL(clicked()), this, SIGNAL(replaceAll())); + // clear message after the text is changed + connect(m_textToFind, SIGNAL(textChanged()), this, SIGNAL(updateMessage())); + connect(m_textToReplace, SIGNAL(textChanged()), this, SIGNAL(updateMessage())); + + d->replaceMode = true; //to force updating by setReplaceMode() + setReplaceMode(false); + + setLookInColumnList(QStringList(), QStringList()); +} + +KexiFindDialog::~KexiFindDialog() +{ + delete d; +} + +void KexiFindDialog::setActions( KAction *findnext, KAction *findprev, + KAction *replace, KAction *replaceall ) +{ + d->findnextAction = findnext; + d->findprevAction = findprev; + d->replaceAction = replace; + d->replaceallAction = replaceall; + d->accels.clear(); + d->setActionAndAccel(d->findnextAction, this, SIGNAL(findNext())); + d->setActionAndAccel(d->findprevAction, this, SIGNAL(findPrevious())); + d->setActionAndAccel(d->replaceAction, this, SIGNAL(replaceNext())); + d->setActionAndAccel(d->replaceallAction, this, SIGNAL(replaceAll())); +} + +QStringList KexiFindDialog::lookInColumnNames() const +{ + return d->lookInColumnNames; +} + +QStringList KexiFindDialog::lookInColumnCaptions() const +{ + return d->lookInColumnCaptions; +} + +QString KexiFindDialog::currentLookInColumnName() const +{ + int index = m_lookIn->currentItem(); + if (index <= 0 || index >= (int)d->lookInColumnNames.count()) + return QString::null; + else if (index == 1) + return "(field)"; + return d->lookInColumnNames[index - 1/*"(All fields)"*/ - 1/*"(Current field)"*/]; +} + +QVariant KexiFindDialog::valueToFind() const +{ + return m_textToFind->currentText(); +} + +QVariant KexiFindDialog::valueToReplaceWith() const +{ + return m_textToReplace->currentText(); +} + +void KexiFindDialog::setLookInColumnList(const QStringList& columnNames, + const QStringList& columnCaptions) +{ + d->lookInColumnNames = columnNames; + d->lookInColumnCaptions = columnCaptions; + m_lookIn->clear(); + m_lookIn->insertItem(i18n("(All fields)")); + m_lookIn->insertItem(i18n("(Current field)")); + m_lookIn->insertStringList(d->lookInColumnCaptions); +} + +void KexiFindDialog::setCurrentLookInColumnName(const QString& columnName) +{ + int index; + if (columnName.isEmpty()) + index = 0; + else if (columnName == "(field)") + index = 1; + else { + index = d->lookInColumnNames.findIndex( columnName ); + if (index == -1) { + kdWarning() << QString("KexiFindDialog::setCurrentLookInColumn(%1) column name not found on the list") + .arg(columnName) << endl; + return; + } + index = index + 1/*"(All fields)"*/ + 1/*"(Current field)"*/; + } + m_lookIn->setCurrentItem(index); +} + +void KexiFindDialog::setReplaceMode(bool set) +{ + if (d->replaceMode == set) + return; + d->replaceMode = set; + if (d->replaceMode) { + m_promptOnReplace->show(); + m_replaceLbl->show(); + m_textToReplace->show(); + m_btnReplace->show(); + m_btnReplaceAll->show(); + } + else { + m_promptOnReplace->hide(); + m_replaceLbl->hide(); + m_textToReplace->hide(); + m_btnReplace->hide(); + m_btnReplaceAll->hide(); + resize(width(),height()-30); + } + setObjectNameForCaption(d->objectName); + updateGeometry(); +} + +void KexiFindDialog::setObjectNameForCaption(const QString& name) +{ + d->objectName = name; + if (d->replaceMode) { + if (name.isEmpty()) + setCaption(i18n("Replace")); + else + setCaption(i18n("Replace in \"%1\"").arg(name)); + } + else { + if (name.isEmpty()) + setCaption(i18n("Find")); + else + setCaption(i18n("Find in \"%1\"").arg(name)); + } +} + +void KexiFindDialog::setButtonsEnabled(bool enable) +{ + m_btnFind->setEnabled(enable); + m_btnReplace->setEnabled(enable); + m_btnReplaceAll->setEnabled(enable); + if (!enable) + setObjectNameForCaption(QString::null); +} + +void KexiFindDialog::setMessage(const QString& message) +{ + m_messageLabel->setText(message); +} + +void KexiFindDialog::updateMessage( bool found ) +{ + if (found) + setMessage(QString::null); + else + setMessage(i18n("The search item was not found")); +} + +void KexiFindDialog::slotCloseClicked() +{ + reject(); +} + +void KexiFindDialog::show() +{ + m_textToFind->setFocus(); + QDialog::show(); +} + +KexiSearchAndReplaceViewInterface::Options KexiFindDialog::options() const +{ + KexiSearchAndReplaceViewInterface::Options options; + if (m_lookIn->currentItem() <= 0) //"(All fields)" + options.columnNumber = KexiSearchAndReplaceViewInterface::Options::AllColumns; + else if (m_lookIn->currentItem() == 1) //"(Current field)" + options.columnNumber = KexiSearchAndReplaceViewInterface::Options::CurrentColumn; + else + options.columnNumber = m_lookIn->currentItem() - 1/*"(All fields)"*/ - 1/*"(Current field)"*/; + options.textMatching + = (KexiSearchAndReplaceViewInterface::Options::TextMatching)m_match->currentItem(); + options.searchDirection + = (KexiSearchAndReplaceViewInterface::Options::SearchDirection)m_search->currentItem(); + options.caseSensitive = m_caseSensitive->isChecked(); + options.wholeWordsOnly = m_wholeWords->isChecked(); + options.promptOnReplace = m_promptOnReplace->isChecked(); + return options; +} + +#include "kexifinddialog.moc" diff --git a/kexi/main/kexifinddialog.h b/kexi/main/kexifinddialog.h new file mode 100644 index 00000000..ea7777e0 --- /dev/null +++ b/kexi/main/kexifinddialog.h @@ -0,0 +1,130 @@ +/* This file is part of the KDE project + Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 KEXIFINDDIALOG_H +#define KEXIFINDDIALOG_H + +#include "kexifinddialogbase.h" +#include <core/kexisearchandreplaceiface.h> + +class KAction; + +//! @short A Kexi-specific "Find text" dialog. +/*! Also used for as replace dialog. + + @todo replace m_textToFind and m_textToReplace KComboBoxes with Kexi's db-aware comboboxes, + so we ca adapt to datatype being searched, e.g. date, time and numbers +*/ +class KexiFindDialog : public KexiFindDialogBase +{ + Q_OBJECT + public: + //! Creates a new find dialog. Replace mode is off by default. + KexiFindDialog(QWidget* parent); + virtual ~KexiFindDialog(); + + //! Sets actions that receive button clicks and shortcuts within the dialog. Should be called once. + void setActions( KAction *findnext, KAction *findprev, + KAction *replace, KAction *replaceall ); + + //! Shows the dialog as a modal dialog. + virtual void show(); + + //! \return current find and replace options set within the dialog +//! @todo should we have setOptions() too? + KexiSearchAndReplaceViewInterface::Options options() const; + + /*! \return a list of column names for 'look in column' combo box. + Neither "(All fields)" nor "(Current field)" items are prepended. */ + QStringList lookInColumnNames() const; + + /*! \return a list of column captions (i.e. visible values) for 'look in column' combo box. + Neither "(All fields)" nor "(Current field)" items are prepended. */ + QStringList lookInColumnCaptions() const; + + /*! \return column name selected in "look in column" combo box. + If "(All fields)" item is selected, empty string is returned. + If "(Current field)" item is selected, "(field)" string is returned. */ + QString currentLookInColumnName() const; + + //! \return value that to be used for searching + QVariant valueToFind() const; + + //! \return value that to be used as a replacement + QVariant valueToReplaceWith() const; + + public slots: + /*! Sets \a columnNames list and \a columnCaptions for 'look in column' combo box. + \a columnCaptions are visible values, while \a columnNames are used for returning + in currentLookInColumn(). + "(All fields)" and "(Current field)" items are also prepended. */ + void setLookInColumnList(const QStringList& columnNames, + const QStringList& columnCaptions); + + /*! Selects \a columnName to be selected 'look in column'. + By default "(All fields)" item is selected. To select this item, + pass empty string as \a columnName. + To select "(Current field)" item, "(field)" string should be passed + as \a columnName. */ + void setCurrentLookInColumnName(const QString& columnName); + + /*! Sets or clears replace mode. + For replace mode 'prompt or replace' option is visible. */ + void setReplaceMode(bool set); + + /*! Sets object name for caption, so for example it will be set + to i18n("Find \"Persons\"")). */ + void setObjectNameForCaption(const QString& name); + + /*! Enables of disables the find/replace/replace all buttons. + This is used if for the current context the dialog could not be used. + If \a enable is false, object name for caption is cleared + using setObjectNameForCaption() too. */ + void setButtonsEnabled(bool enable); + + /*! Sets message at the bottom to \a message. */ + void setMessage(const QString& message); + + /*! Updates message at the bottom; "The search item was not found" is set if \a found is true, + else the message is cleared. */ +//! @todo add "Search again" hyperlink + void updateMessage( bool found = true ); + + signals: + //! Emitted after clicking "Find next" button or pressing appropriate shortcut set by setActions() + void findNext(); + + //! Emitted after pressing appropriate shortcut set by setActions() + void findPrevious(); + + //! Emitted after clicking "Replace" button or pressing appropriate shortcut set by setActions() + void replaceNext(); + + //! Emitted after clicking "Replace All" button or pressing appropriate shortcut set by setActions() + void replaceAll(); + + protected slots: + void slotCloseClicked(); + + protected: + class Private; + Private * const d; +}; + +#endif diff --git a/kexi/main/kexifinddialogbase.ui b/kexi/main/kexifinddialogbase.ui new file mode 100644 index 00000000..3ba82bb5 --- /dev/null +++ b/kexi/main/kexifinddialogbase.ui @@ -0,0 +1,357 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiFindDialogBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>KexiFindDialogBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>472</width> + <height>247</height> + </rect> + </property> + <property name="caption"> + <string>Find</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Fi&nd:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_textToFind</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>m_replaceLbl</cstring> + </property> + <property name="text"> + <string>Re&place with:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_textToReplace</cstring> + </property> + </widget> + <widget class="KComboBox" row="2" column="1"> + <property name="name"> + <cstring>m_lookIn</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="insertionPolicy"> + <enum>NoInsertion</enum> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>&Look in:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_lookIn</cstring> + </property> + </widget> + <widget class="QCheckBox" row="5" column="2"> + <property name="name"> + <cstring>m_wholeWords</cstring> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <property name="text"> + <string>&Whole words only</string> + </property> + </widget> + <widget class="QCheckBox" row="6" column="2"> + <property name="name"> + <cstring>m_promptOnReplace</cstring> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <property name="text"> + <string>Prompt on replace</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="4" rowspan="7" colspan="1"> + <property name="name"> + <cstring>layout_btn</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>m_btnFind</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>m_btnClose</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>m_btnReplace</cstring> + </property> + <property name="text"> + <string>&Replace</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>m_btnReplaceAll</cstring> + </property> + <property name="text"> + <string>Replace All</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel2_2_3</cstring> + </property> + <property name="text"> + <string>&Match:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_match</cstring> + </property> + </widget> + <widget class="KComboBox" row="4" column="1"> + <item> + <property name="text"> + <string>Any Part of Field</string> + </property> + </item> + <item> + <property name="text"> + <string>Whole Field</string> + </property> + </item> + <item> + <property name="text"> + <string>Start of Field</string> + </property> + </item> + <property name="name"> + <cstring>m_match</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="insertionPolicy"> + <enum>NoInsertion</enum> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel2_2_2</cstring> + </property> + <property name="text"> + <string>&Search:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_search</cstring> + </property> + </widget> + <widget class="KComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>Up</string> + </property> + </item> + <item> + <property name="text"> + <string>Down</string> + </property> + </item> + <item> + <property name="text"> + <string>All Rows</string> + </property> + </item> + <property name="name"> + <cstring>m_search</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="insertionPolicy"> + <enum>NoInsertion</enum> + </property> + </widget> + <spacer row="7" column="2"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>2</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="4" column="2"> + <property name="name"> + <cstring>m_caseSensitive</cstring> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <property name="text"> + <string>C&ase sensitive</string> + </property> + </widget> + <widget class="QLabel" row="8" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>m_messageLabel</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer row="4" column="3"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>70</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KHistoryCombo" row="0" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>m_textToFind</cstring> + </property> + <property name="insertionPolicy"> + <enum>AtTop</enum> + </property> + <property name="autoCompletion"> + <bool>true</bool> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + </widget> + <widget class="KHistoryCombo" row="1" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>m_textToReplace</cstring> + </property> + <property name="insertionPolicy"> + <enum>AtTop</enum> + </property> + <property name="autoCompletion"> + <bool>true</bool> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_btnClose</sender> + <signal>clicked()</signal> + <receiver>KexiFindDialogBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_textToFind</tabstop> + <tabstop>m_textToReplace</tabstop> + <tabstop>m_btnFind</tabstop> + <tabstop>m_btnClose</tabstop> + <tabstop>m_btnReplace</tabstop> + <tabstop>m_btnReplaceAll</tabstop> + <tabstop>m_lookIn</tabstop> + <tabstop>m_search</tabstop> + <tabstop>m_match</tabstop> + <tabstop>m_caseSensitive</tabstop> + <tabstop>m_wholeWords</tabstop> + <tabstop>m_promptOnReplace</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/kexi/main/keximainwindowimpl.cpp b/kexi/main/keximainwindowimpl.cpp new file mode 100644 index 00000000..d5ce9939 --- /dev/null +++ b/kexi/main/keximainwindowimpl.cpp @@ -0,0 +1,4641 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Lucijan Busch <lucijan@kde.org> + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 "keximainwindowimpl.h" + +#include <unistd.h> + +#include <qapplication.h> +#include <qeventloop.h> +#include <qfile.h> +#include <qtimer.h> +#include <qobjectlist.h> +#include <qprocess.h> +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <qmutex.h> +#include <qwaitcondition.h> +#include <qfiledialog.h> +#include <qdockwindow.h> +#include <qdockarea.h> + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kaction.h> +#include <klocale.h> +#include <kstdaccel.h> +#include <kconfig.h> +#include <kglobal.h> +#include <kdebug.h> +#include <kkeydialog.h> +#include <kedittoolbar.h> +#include <kdeversion.h> +#include <kglobalsettings.h> +#include <kparts/componentfactory.h> +#include <ktip.h> +#include <kstandarddirs.h> +#include <kpushbutton.h> +#include <ktextbrowser.h> +#include <kiconloader.h> +#include <ktabwidget.h> +#include <kimageio.h> +#include <khelpmenu.h> +#include <kfiledialog.h> +#include <krecentdocument.h> + +#include <kexidb/connection.h> +#include <kexidb/utils.h> +#include <kexidb/cursor.h> +#include <kexidb/dbobjectnamevalidator.h> +#include <kexidb/admin.h> +#include <kexiutils/utils.h> + +//#include "projectsettingsui.h" +#include "kexiactionproxy.h" +#include "kexidialogbase.h" +#include "kexipartmanager.h" +#include "kexipart.h" +#include "kexipartinfo.h" +#include "kexipartguiclient.h" +#include "kexiproject.h" +#include "kexiprojectdata.h" +#include "kexiprojectset.h" +#include "kexi.h" +#include "kexistatusbar.h" +#include "kexiinternalpart.h" +#include "kexiactioncategories.h" +#include "kexifinddialog.h" +#include "kexisearchandreplaceiface.h" + +#include "kde2_closebutton.xpm" + +#include <widget/kexibrowser.h> +#include <widget/kexipropertyeditorview.h> +#include <widget/utils/kexirecordnavigator.h> +#include <koproperty/editor.h> +#include <koproperty/set.h> + +#include "startup/KexiStartup.h" +#include "startup/KexiNewProjectWizard.h" +#include "startup/KexiStartupDialog.h" +#include "startup/KexiStartupFileDialog.h" +#include "kexinamedialog.h" +#include "printing/kexisimpleprintingpart.h" +#include "printing/kexisimpleprintingpagesetup.h" + +//Extreme verbose debug +#if defined(Q_WS_WIN) +# include <krecentdirs.h> +# include <win32_utils.h> +//# define KexiVDebug kdDebug() +#endif + +#if !defined(KexiVDebug) +# define KexiVDebug if (0) kdDebug() +#endif + +//first fix the geometry +//#define KEXI_NO_CTXT_HELP 1 + +#ifndef KEXI_NO_CTXT_HELP +#include <kexicontexthelp.h> +#endif + +#ifdef HAVE_KNEWSTUFF +#include <knewstuff/downloaddialog.h> +#include "kexinewstuff.h" +#endif + +//! @todo REENABLE when blinking and dock +//! width changes will be removed in KMDI +//#define PROPEDITOR_VISIBILITY_CHANGES + +//temporary fix to manage layout +#include "ksplitter.h" +#define KDOCKWIDGET_P 1 + +#ifndef KEXI_NO_FEEDBACK_AGENT +#ifdef FEEDBACK_INCLUDE +#include FEEDBACK_INCLUDE +#endif +#include <kapplication.h> +#include <kaboutdata.h> +#endif + +#include "keximainwindowimpl_p.h" + +//------------------------------------------------- + +//static +int KexiMainWindowImpl::create(int argc, char *argv[], KAboutData* aboutdata) +{ + Kexi::initCmdLineArgs( argc, argv, aboutdata ); + + bool GUIenabled = true; + QWidget *dummyWidget = 0; //needed to have icon for dialogs before KexiMainWindowImpl is created +//! @todo switch GUIenabled off when needed + KApplication* app = new KApplication(true, GUIenabled); + +#ifdef KEXI_STANDALONE + KGlobal::locale()->removeCatalogue("kexi"); + KGlobal::locale()->insertCatalogue("standalone_kexi"); +#endif + KGlobal::locale()->insertCatalogue("koffice"); + KGlobal::locale()->insertCatalogue("koproperty"); + +#ifdef CUSTOM_VERSION +# include "custom_exec.h" +#endif + +#ifdef KEXI_DEBUG_GUI + QWidget* debugWindow = 0; +#endif + if (GUIenabled) { + dummyWidget = new QWidget(); + dummyWidget->setIcon( DesktopIcon( "kexi" ) ); + app->setMainWidget(dummyWidget); +#ifdef KEXI_DEBUG_GUI + app->config()->setGroup("General"); + if (app->config()->readBoolEntry("showInternalDebugger", false)) { + debugWindow = KexiUtils::createDebugWindow(0); + } +#endif + } + + tristate res = Kexi::startupHandler().init(argc, argv); + if (!res || ~res) { +#ifdef KEXI_DEBUG_GUI + delete debugWindow; +#endif + delete app; + return (~res) ? 0 : 1; + } + + kdDebug() << "startupActions OK" <<endl; + + /* Exit requested, e.g. after database removing. */ + if (Kexi::startupHandler().action() == KexiStartupData::Exit) { +#ifdef KEXI_DEBUG_GUI + delete debugWindow; +#endif + delete app; + return 0; + } + + KexiMainWindowImpl *win = new KexiMainWindowImpl(); + app->setMainWidget(win); +#ifdef KEXI_DEBUG_GUI + //if (debugWindow) + //debugWindow->reparent(win, QPoint(1,1)); +#endif + delete dummyWidget; + + if (true != win->startup()) { + delete win; + delete app; + return 1; + } + + win->show(); + app->processEvents();//allow refresh our app + +//#ifdef KEXI_DEBUG_GUI +// delete debugWindow; +//#endif + return 0; +} + +//------------------------------------------------- + +KexiMainWindowImpl::KexiMainWindowImpl() + : KexiMainWindow() + , KexiGUIMessageHandler(this) + , d(new KexiMainWindowImpl::Private(this) ) +{ + KImageIO::registerFormats(); + KexiProjectData *pdata = Kexi::startupHandler().projectData(); + d->userMode = Kexi::startupHandler().forcedUserMode() /* <-- simply forced the user mode */ + /* project has 'user mode' set as default and not 'design mode' override is found: */ + || (pdata && pdata->userMode() && !Kexi::startupHandler().forcedDesignMode()); + d->isProjectNavigatorVisible = Kexi::startupHandler().isProjectNavigatorVisible(); + + if(userMode()) + kdDebug() << "KexiMainWindowImpl::KexiMainWindowImpl(): starting up in the User Mode" << endl; + + d->config = kapp->config(); + + if ( !initialGeometrySet() ) { + int scnum = QApplication::desktop()->screenNumber(parentWidget()); + QRect desk = QApplication::desktop()->screenGeometry(scnum); + d->config->setGroup("MainWindow"); + QSize s ( d->config->readNumEntry( QString::fromLatin1("Width %1").arg(desk.width()), 700 ), + d->config->readNumEntry( QString::fromLatin1("Height %1").arg(desk.height()), 480 ) ); + resize (kMin (s.width(), desk.width()), kMin(s.height(), desk.height())); + } + + setManagedDockPositionModeEnabled(true);//TODO(js): remove this if will be default in kmdi :) + manager()->setSplitterHighResolution(true); + manager()->setSplitterKeepSize(true); + setStandardMDIMenuEnabled(false); + setAsDefaultHost(); //this is default host now. + KGlobal::iconLoader()->addAppDir("kexi"); + KGlobal::iconLoader()->addAppDir("koffice"); + + //get informed + connect(&Kexi::partManager(),SIGNAL(partLoaded(KexiPart::Part*)),this,SLOT(slotPartLoaded(KexiPart::Part*))); + connect( m_pMdi, SIGNAL(nowMaximized(bool)), this, SLOT(slotCaptionForCurrentMDIChild(bool)) ); + connect( m_pMdi, SIGNAL(noMaximizedChildFrmLeft(KMdiChildFrm*)), this, SLOT(slotNoMaximizedChildFrmLeft(KMdiChildFrm*))); +// connect( this, SIGNAL(lastChildFrmClosed()), this, SLOT(slotLastChildFrmClosed())); + connect( this, SIGNAL(lastChildViewClosed()), this, SLOT(slotLastChildViewClosed())); + + connect( this, SIGNAL(childViewIsDetachedNow(QWidget*)), this, SLOT(slotChildViewIsDetachedNow(QWidget*))); + connect( this, SIGNAL(mdiModeHasBeenChangedTo(KMdi::MdiMode)), + this, SLOT(slotMdiModeHasBeenChangedTo(KMdi::MdiMode))); + + + //if (!userMode()) { + setXMLFile("kexiui.rc"); + setAcceptDrops(true); + initActions(); + createShellGUI(true); + //} + + d->statusBar = new KexiStatusBar(this, "status_bar"); + + d->origAppCaption = caption(); + + restoreSettings(); + (void)Kexi::smallFont(this/*init*/); + + if (!userMode()) { + initContextHelp(); + initPropertyEditor(); + } + + {//store menu popups list + QObjectList *l = queryList( "QPopupMenu" ); + for (QObjectListIt it( *l ); it.current(); ++it ) { + //kdDebug() << "name=" <<it.current()->name() << " cname="<<it.current()->className()<<endl; + //KexiMainWindowImpl::eventFilter() will filter our popups: + it.current()->installEventFilter(this); + d->popups.insert(it.current()->name(), static_cast<QPopupMenu*>(it.current())); + } + delete l; + d->createMenu = d->popups["create"]; + +#ifdef KEXI_NO_REPORTBUG_COMMAND + //remove "bug report" action to avoid confusion for supported with commercial technical support + QPopupMenu *helpMenu = d->popups["help"]; + if (helpMenu) { + //const int idx = helpMenu->indexOf( (int)KHelpMenu::menuReportBug ); + helpMenu->removeItemAt(int(KHelpMenu::menuReportBug)-1); + helpMenu->removeItemAt(int(KHelpMenu::menuReportBug)-1); //separator + } +#endif + } + + //fix menus a bit more: +#ifndef KEXI_SHOW_UNIMPLEMENTED +//disabled (possible crash) d->hideMenuItem("file", i18n("&Import"), true); +//disabled (possible crash) d->hideMenuItem("help", i18n( "&Report Bug..." ), true); +#endif + KAction *kmdi_tooldock_menu_action = childClients()->getFirst() ? childClients()->getFirst()->actionCollection()->action("kmdi_tooldock_menu") : 0; + if (kmdi_tooldock_menu_action) { + kmdi_tooldock_menu_action->setEnabled(false); + } + + if (!isFakingSDIApplication()/* && !userMode()*/) { +// QPopupMenu *menu = (QPopupMenu*) child( "window", "KPopupMenu" ); + QPopupMenu *menu = d->popups["window"]; + unsigned int count = menuBar()->count(); + if (menu) + setWindowMenu(menu); + else + menuBar()->insertItem( i18n("&Window"), windowMenu(), -1, count-2); // standard position is left to the last ('Help') + } + if (userMode()) { + //hide "insert" menu and disable "project_import", "edit_paste_special" menus + QPopupMenu *menu = d->popups["insert"]; + if (menu) { + for (uint i=0; i < menuBar()->count(); i++) { + if (menuBar()->text( menuBar()->idAt(i) ) == i18n("&Insert")) { + menuBar()->setItemVisible( menuBar()->idAt(i), false ); + break; + } + } + } + d->disableMenuItem("file", i18n("&Import")); + d->disableMenuItem("edit", i18n("Paste &Special")); + } + + m_pTaskBar->setCaption(i18n("Task Bar")); //js TODO: move this to KMDIlib + +// if (!userMode()) { + invalidateActions(); + d->timer.singleShot(0,this,SLOT(slotLastActions())); +// } + + setTabWidgetVisibility(KMdi::AlwaysShowTabs); + if (mdiMode()==KMdi::IDEAlMode) { + d->config->setGroup("MainWindow"); + tabWidget()->setHoverCloseButton(d->config->readBoolEntry("HoverCloseButtonForTabs", false)); + //create special close button as corner widget for IDEAl mode + QToolButton *closeButton = new QToolButton( tabWidget() ); + closeButton->setAutoRaise( true ); + closeButton->setPixmap( QPixmap( kde2_closebutton ) ); + closeButton->setPaletteBackgroundColor(closeButton->palette().active().background()); +// closeButton->setIconSet(SmallIconSet("tab_remove")); + tabWidget()->setCornerWidget( closeButton, Qt::TopRight ); + closeButton->hide(); // hide until it's needed to avoid problems in "user mode" + // when initially the main window is empty + QToolTip::add(closeButton, + i18n("Close the current tab page in Kexi tab interface", "Close the current tab")); + QObject::connect( closeButton, SIGNAL( clicked() ), this, SLOT( closeActiveView() ) ); + } + +#ifdef KEXI_ADD_CUSTOM_KEXIMAINWINDOWIMPL +# include "keximainwindowimpl_ctor.h" +#endif +} + +KexiMainWindowImpl::~KexiMainWindowImpl() +{ + d->forceDialogClosing=true; + closeProject(); + delete d; +} + +KexiProject *KexiMainWindowImpl::project() +{ + return d->prj; +} + +void KexiMainWindowImpl::setWindowMenu(QPopupMenu *menu) +{ + delete m_pWindowMenu; + m_pWindowMenu = menu; + int count = menuBar()->count(); + //try to move "window" menu just before "Settings" menu (count-3) + const QString txt = i18n("&Window"); + int i; + for (i=0; i<count; i++) { + //kdDebug() << menuBar()->text( menuBar()->idAt(i) ) << endl; + if (txt==menuBar()->text( menuBar()->idAt(i) )) + break; + } + if (i<count) { + const int id = menuBar()->idAt(i); + menuBar()->removeItemAt(i); + menuBar()->insertItem(txt, m_pWindowMenu, id, count-3); + } + m_pWindowMenu->setCheckable(true); + QObject::connect( m_pWindowMenu, SIGNAL(aboutToShow()), this, SLOT(fillWindowMenu()) ); +} + +void KexiMainWindowImpl::fillWindowMenu() +{ + KexiMainWindow::fillWindowMenu(); + +/* int i; + for (i=0; i < (int)m_pWindowMenu->count(); i++) { + if (m_pWindowMenu->text( m_pWindowMenu->idAt( i ) ) == i18n( "&MDI Mode" )) { +// kdDebug() << m_pWindowMenu->text( m_pWindowMenu->idAt( i ) ) << endl; + m_pWindowMenu->removeItem( m_pWindowMenu->idAt( i ) ); + break; + } + }*/ + + m_pMdiModeMenu->removeItem( m_pMdiModeMenu->idAt( 0 ) ); //hide toplevel mode + m_pMdiModeMenu->removeItem( m_pMdiModeMenu->idAt( 1 ) ); //hide tabbed mode + //update + if (d->mdiModeToSwitchAfterRestart != (KMdi::MdiMode)0) { + m_pMdiModeMenu->setItemChecked( m_pMdiModeMenu->idAt( 0 ), + d->mdiModeToSwitchAfterRestart == KMdi::ChildframeMode ); + m_pMdiModeMenu->setItemChecked( m_pMdiModeMenu->idAt( 1 ), + d->mdiModeToSwitchAfterRestart == KMdi::IDEAlMode ); + } + + //insert window_next, window_previous actions: +// const QString t = i18n("&Dock/Undock..."); + int i = m_pWindowMenu->count()-1; + for (int index;; i--) { + index = m_pWindowMenu->idAt(i); + if (index==-1 || m_pWindowMenu->text(index).isNull()) + break; + } + i++; + d->action_window_next->plug( m_pWindowMenu, i++ ); + d->action_window_previous->plug( m_pWindowMenu, i++ ); + if (!m_pDocumentViews->isEmpty()) + m_pWindowMenu->insertSeparator( i++ ); +} + +void KexiMainWindowImpl::switchToIDEAlMode() +{ + switchToIDEAlMode(true); +} + +void KexiMainWindowImpl::switchToIDEAlMode(bool showMessage) +{ + if (showMessage) { + if ((int)d->mdiModeToSwitchAfterRestart == 0 && mdiMode()==KMdi::IDEAlMode) + return; + if (d->mdiModeToSwitchAfterRestart == KMdi::IDEAlMode) + return; + if (mdiMode()==KMdi::IDEAlMode) {//current mode + d->mdiModeToSwitchAfterRestart = (KMdi::MdiMode)0; + } + else { + KMessageBox::information(this, + i18n("User interface mode will be switched to IDEAl at next %1 application startup.") + .arg(KEXI_APP_NAME)); + //delayed + d->mdiModeToSwitchAfterRestart = KMdi::IDEAlMode; + } + } + else + KexiMainWindow::switchToIDEAlMode(); +} + +void KexiMainWindowImpl::switchToChildframeMode() +{ + switchToChildframeMode(true); +} + +void KexiMainWindowImpl::switchToChildframeMode(bool showMessage) +{ + if (showMessage) { + if ((int)d->mdiModeToSwitchAfterRestart == 0 && mdiMode()==KMdi::ChildframeMode) + return; + if (d->mdiModeToSwitchAfterRestart == KMdi::ChildframeMode) + return; + if (mdiMode()==KMdi::ChildframeMode) {//current mode + d->mdiModeToSwitchAfterRestart = (KMdi::MdiMode)0; + } + else { + KMessageBox::information(this, + i18n("User interface mode will be switched to Childframe at next %1 application startup.") + .arg(KEXI_APP_NAME)); + //delayed + d->mdiModeToSwitchAfterRestart = KMdi::ChildframeMode; + } + } + else + KexiMainWindow::switchToChildframeMode(); +} + +QPopupMenu* KexiMainWindowImpl::findPopupMenu(const char *popupName) +{ + return d->popups[popupName]; +} + +KActionPtrList KexiMainWindowImpl::allActions() const +{ + return actionCollection()->actions(); +} + +KexiDialogBase* KexiMainWindowImpl::currentDialog() const +{ + return d->curDialog; +} + +void KexiMainWindowImpl::initActions() +{ +// setupGUI(KMainWindow::Keys|KMainWindow::StatusBar|KMainWindow::Save|KMainWindow::Create); + +// d->actionMapper = new QSignalMapper(this, "act_map"); +// connect(d->actionMapper, SIGNAL(mapped(const QString &)), this, SLOT(slotAction(const QString &))); + + // PROJECT MENU + KAction *action = new KAction(i18n("&New..."), "filenew", KStdAccel::shortcut(KStdAccel::New), + this, SLOT(slotProjectNew()), actionCollection(), "project_new"); + action->setToolTip(i18n("Create a new project")); + action->setWhatsThis(i18n("Creates a new project. Currently opened project is not affected.")); + + action = KStdAction::open( this, SLOT( slotProjectOpen() ), actionCollection(), "project_open" ); + action->setToolTip(i18n("Open an existing project")); + action->setWhatsThis(i18n("Opens an existing project. Currently opened project is not affected.")); + +#ifdef HAVE_KNEWSTUFF + action = new KAction(i18n("&Download Example Databases..."), "kget", KShortcut(0), + this, SLOT(slotGetNewStuff()), actionCollection(), "project_download_examples"); + action->setToolTip(i18n("Download example databases from the Internet")); + action->setWhatsThis(i18n("Downloads example databases from the Internet.")); +#endif + +// d->action_open_recent = KStdAction::openRecent( this, SLOT(slotProjectOpenRecent(const KURL&)), actionCollection(), "project_open_recent" ); + +//#ifdef KEXI_SHOW_UNIMPLEMENTED +#ifndef KEXI_NO_UNFINISHED + d->action_open_recent = new KActionMenu(i18n("Open Recent"), + actionCollection(), "project_open_recent"); + connect(d->action_open_recent->popupMenu(),SIGNAL(activated(int)), + this,SLOT(slotProjectOpenRecent(int))); + connect(d->action_open_recent->popupMenu(), SIGNAL(aboutToShow()), + this,SLOT(slotProjectOpenRecentAboutToShow())); +//moved down d->action_open_recent_projects_title_id = +// d->action_open_recent->popupMenu()->insertTitle(i18n("Recently Opened Databases")); +//moved down d->action_open_recent_connections_title_id = +// d->action_open_recent->popupMenu()->insertTitle(i18n("Recently Connected Database Servers")); +// d->action_open_recent->popupMenu()->insertSeparator(); +// d->action_open_recent_more_id = d->action_open_recent->popupMenu() +// ->insertItem(i18n("&More Projects..."), this, SLOT(slotProjectOpenRecentMore()), 0, 1000); +#else + d->action_open_recent = d->dummy_action; +#endif + + d->action_save = KStdAction::save( + this, SLOT( slotProjectSave() ), actionCollection(), "project_save" ); +// d->action_save = new KAction(i18n("&Save"), "filesave", KStdAccel::shortcut(KStdAccel::Save), +// this, SLOT(slotProjectSave()), actionCollection(), "project_save"); + d->action_save->setToolTip(i18n("Save object changes")); + d->action_save->setWhatsThis(i18n("Saves object changes from currently selected window.")); + +#ifdef KEXI_SHOW_UNIMPLEMENTED + d->action_save_as = new KAction(i18n("Save &As..."), "filesaveas", 0, + this, SLOT(slotProjectSaveAs()), actionCollection(), "project_saveas"); + d->action_save_as->setToolTip(i18n("Save object as")); + d->action_save_as->setWhatsThis( + i18n("Saves object changes from currently selected window under a new name (within the same project).")); + + d->action_project_properties = new KAction(i18n("Project Properties"), "info", 0, + this, SLOT(slotProjectProperties()), actionCollection(), "project_properties"); +#else + d->action_save_as = d->dummy_action; + d->action_project_properties = d->dummy_action; +#endif + + d->action_close = new KAction(i18n("&Close Project"), "fileclose", 0, + this, SLOT(slotProjectClose()), actionCollection(), "project_close" ); + d->action_close->setToolTip(i18n("Close the current project")); + d->action_close->setWhatsThis(i18n("Closes the current project.")); + + KStdAction::quit( this, SLOT(slotProjectQuit()), actionCollection(), "quit"); + +#ifdef KEXI_SHOW_UNIMPLEMENTED + d->action_project_relations = new KAction(i18n("&Relationships..."), "relation", Qt::CTRL + Qt::Key_R, + this, SLOT(slotProjectRelations()), actionCollection(), "project_relations"); + d->action_project_relations->setToolTip(i18n("Project relationships")); + d->action_project_relations->setWhatsThis(i18n("Shows project relationships.")); + +#else + d->action_project_relations = d->dummy_action; +#endif + d->action_tools_data_migration = new KAction( + i18n("&Import Database..."), "database_import", 0, + this, SLOT(slotToolsProjectMigration()), actionCollection(), "tools_import_project"); + d->action_tools_data_migration->setToolTip(i18n("Import entire database as a Kexi project")); + d->action_tools_data_migration->setWhatsThis(i18n("Imports entire database as a Kexi project.")); + + d->action_tools_compact_database = new KAction( + i18n("&Compact Database..."), "", 0, + this, SLOT(slotToolsCompactDatabase()), actionCollection(), "tools_compact_database"); + d->action_tools_compact_database->setToolTip(i18n("Compact the current database project")); + d->action_tools_compact_database->setWhatsThis( + i18n("Compacts the current database project, so it will take less space and work faster.")); + + if (userMode()) + d->action_project_import_data_table = 0; + else { + d->action_project_import_data_table = new KAction( + i18n("Import->Table Data From File...", "Table Data From &File..."), + "table"/*! @todo: change to "file_import" or so*/, + 0, this, SLOT(slotProjectImportDataTable()), actionCollection(), + "project_import_data_table"); + d->action_project_import_data_table->setToolTip(i18n("Import table data from a file")); + d->action_project_import_data_table->setWhatsThis(i18n("Imports table data from a file.")); + } + + d->action_project_export_data_table = new KAction(i18n("Export->Table or Query Data to File...", + "Table or Query Data to &File..."), + "table"/*! @todo: change to "file_export" or so*/, + 0, this, SLOT(slotProjectExportDataTable()), actionCollection(), + "project_export_data_table"); + d->action_project_export_data_table->setToolTip( + i18n("Export data from the active table or query data to a file")); + d->action_project_export_data_table->setWhatsThis( + i18n("Exports data from the active table or query data to a file.")); + +//TODO new KAction(i18n("From File..."), "fileopen", 0, +//TODO this, SLOT(slotImportFile()), actionCollection(), "project_import_file"); +//TODO new KAction(i18n("From Server..."), "server", 0, +//TODO this, SLOT(slotImportServer()), actionCollection(), "project_import_server"); + + d->action_project_print = KStdAction::print(this, SLOT(slotProjectPrint()), + actionCollection(), "project_print" ); + d->action_project_print->setToolTip(i18n("Print data from the active table or query")); + d->action_project_print->setWhatsThis(i18n("Prints data from the active table or query.")); + + d->action_project_print_preview = KStdAction::printPreview( + this, SLOT(slotProjectPrintPreview()), + actionCollection(), "project_print_preview" ); + d->action_project_print_preview->setToolTip( + i18n("Show print preview for the active table or query")); + d->action_project_print_preview->setWhatsThis( + i18n("Shows print preview for the active table or query.")); + + d->action_project_print_setup = new KAction(i18n("Page Set&up..."), + "", 0, this, SLOT(slotProjectPageSetup()), actionCollection(), + "project_print_setup"); + d->action_project_print_setup->setToolTip( + i18n("Show page setup for printing the active table or query")); + d->action_project_print_setup->setWhatsThis( + i18n("Shows page setup for printing the active table or query.")); + + //EDIT MENU + d->action_edit_cut = createSharedAction( KStdAction::Cut, "edit_cut"); + d->action_edit_copy = createSharedAction( KStdAction::Copy, "edit_copy"); + d->action_edit_paste = createSharedAction( KStdAction::Paste, "edit_paste"); + + if (userMode()) + d->action_edit_paste_special_data_table = 0; + else { + d->action_edit_paste_special_data_table = + new KAction(i18n("Paste Special->As Data &Table...", "As Data &Table..."), + "table", 0, this, SLOT(slotEditPasteSpecialDataTable()), + actionCollection(), "edit_paste_special_data_table"); + d->action_edit_paste_special_data_table->setToolTip( + i18n("Paste clipboard data as a table")); + d->action_edit_paste_special_data_table->setWhatsThis( + i18n("Pastes clipboard data to a table.")); + } + + d->action_edit_copy_special_data_table = + new KAction(i18n("Copy Special->Table or Query Data...", + "Table or Query as Data Table..."), + "table", 0, this, SLOT(slotEditCopySpecialDataTable()), + actionCollection(), "edit_copy_special_data_table"); + d->action_edit_copy_special_data_table->setToolTip( + i18n("Copy selected table or query data to clipboard")); + d->action_edit_copy_special_data_table->setWhatsThis( + i18n("Copies selected table or query data to clipboard.")); + + d->action_edit_undo = createSharedAction( KStdAction::Undo, "edit_undo"); + d->action_edit_undo->setWhatsThis(i18n("Reverts the most recent editing action.")); + d->action_edit_redo = createSharedAction( KStdAction::Redo, "edit_redo"); + d->action_edit_redo->setWhatsThis(i18n("Reverts the most recent undo action.")); + +#if 0 //old + d->action_edit_find = createSharedAction( KStdAction::Find, "edit_find"); + d->action_edit_findnext = createSharedAction( KStdAction::FindNext, "edit_findnext"); + d->action_edit_findprev = createSharedAction( KStdAction::FindPrev, "edit_findprevious"); +//! @todo d->action_edit_paste = createSharedAction( KStdAction::Replace, "edit_replace"); +#endif + + d->action_edit_find = KStdAction::find( + this, SLOT(slotEditFind()), actionCollection(), "edit_find" ); +// d->action_edit_find = createSharedAction( KStdAction::Find, "edit_find"); + d->action_edit_findnext = KStdAction::findNext( + this, SLOT(slotEditFindNext()), actionCollection(), "edit_findnext"); + d->action_edit_findprev = KStdAction::findPrev( + this, SLOT(slotEditFindPrevious()), actionCollection(), "edit_findprevious"); + d->action_edit_replace = 0; +//! @todo d->action_edit_replace = KStdAction::replace( +//! this, SLOT(slotEditReplace()), actionCollection(), "project_print_preview" ); + d->action_edit_replace_all = 0; +//! @todo d->action_edit_replace_all = new KAction( i18n("Replace All"), "", 0, +//! this, SLOT(slotEditReplaceAll()), actionCollection(), "edit_replaceall"); + + d->action_edit_select_all = createSharedAction( KStdAction::SelectAll, "edit_select_all"); + + d->action_edit_delete = createSharedAction(i18n("&Delete"), "editdelete", + 0/*Qt::Key_Delete*/, "edit_delete"); + d->action_edit_delete->setToolTip(i18n("Delete selected object")); + d->action_edit_delete->setWhatsThis(i18n("Deletes currently selected object.")); + + d->action_edit_delete_row = createSharedAction(i18n("Delete Row"), "delete_table_row", + Qt::CTRL+Qt::Key_Delete, "edit_delete_row"); + d->action_edit_delete_row->setToolTip(i18n("Delete currently selected row")); + d->action_edit_delete_row->setWhatsThis(i18n("Deletes currently selected row.")); + + d->action_edit_clear_table = createSharedAction(i18n("Clear Table Contents"), "clear_table_contents", + 0, "edit_clear_table"); + d->action_edit_clear_table->setToolTip(i18n("Clear table contents")); + d->action_edit_clear_table->setWhatsThis(i18n("Clears table contents.")); + setActionVolatile( d->action_edit_clear_table, true ); + + d->action_edit_edititem = createSharedAction(i18n("Edit Item"), 0, 0, /* CONFLICT in TV: Qt::Key_F2, */ + "edit_edititem"); + d->action_edit_edititem->setToolTip(i18n("Edit currently selected item")); + d->action_edit_edititem->setWhatsThis(i18n("Edits currently selected item.")); + + d->action_edit_insert_empty_row = createSharedAction(i18n("&Insert Empty Row"), "insert_table_row", + Qt::SHIFT | Qt::CTRL | Qt::Key_Insert, "edit_insert_empty_row"); + setActionVolatile( d->action_edit_insert_empty_row, true ); + d->action_edit_insert_empty_row->setToolTip(i18n("Insert one empty row above")); + d->action_edit_insert_empty_row->setWhatsThis(i18n("Inserts one empty row above currently selected table row.")); + + //VIEW MENU + if (!userMode()) { + d->action_view_data_mode = new KRadioAction(i18n("&Data View"), "state_data", Qt::Key_F6, + this, SLOT(slotViewDataMode()), actionCollection(), "view_data_mode"); + d->actions_for_view_modes.insert( Kexi::DataViewMode, d->action_view_data_mode ); + d->action_view_data_mode->setExclusiveGroup("view_mode"); + d->action_view_data_mode->setToolTip(i18n("Switch to data view")); + d->action_view_data_mode->setWhatsThis(i18n("Switches to data view.")); + } + else + d->action_view_data_mode = 0; + + if (!userMode()) { + d->action_view_design_mode = new KRadioAction(i18n("D&esign View"), "state_edit", Qt::Key_F7, + this, SLOT(slotViewDesignMode()), actionCollection(), "view_design_mode"); + d->actions_for_view_modes.insert( Kexi::DesignViewMode, d->action_view_design_mode ); + d->action_view_design_mode->setExclusiveGroup("view_mode"); + d->action_view_design_mode->setToolTip(i18n("Switch to design view")); + d->action_view_design_mode->setWhatsThis(i18n("Switches to design view.")); + } + else + d->action_view_design_mode = 0; + + if (!userMode()) { + d->action_view_text_mode = new KRadioAction(i18n("&Text View"), "state_sql", Qt::Key_F8, + this, SLOT(slotViewTextMode()), actionCollection(), "view_text_mode"); + d->actions_for_view_modes.insert( Kexi::TextViewMode, d->action_view_text_mode ); + d->action_view_text_mode->setExclusiveGroup("view_mode"); + d->action_view_text_mode->setToolTip(i18n("Switch to text view")); + d->action_view_text_mode->setWhatsThis(i18n("Switches to text view.")); + } + else + d->action_view_text_mode = 0; + + if (d->isProjectNavigatorVisible) { + d->action_view_nav = new KAction(i18n("Project Navigator"), "", Qt::ALT + Qt::Key_1, + this, SLOT(slotViewNavigator()), actionCollection(), "view_navigator"); + d->action_view_nav->setToolTip(i18n("Go to project navigator panel")); + d->action_view_nav->setWhatsThis(i18n("Goes to project navigator panel.")); + } + else + d->action_view_nav = 0; + + d->action_view_mainarea = new KAction(i18n("Main Area"), "", Qt::ALT + Qt::Key_2, + this, SLOT(slotViewMainArea()), actionCollection(), "view_mainarea"); + d->action_view_mainarea->setToolTip(i18n("Go to main area")); + d->action_view_mainarea->setWhatsThis(i18n("Goes to main area.")); + + if (!userMode()) { + d->action_view_propeditor = new KAction(i18n("Property Editor"), "", Qt::ALT + Qt::Key_3, + this, SLOT(slotViewPropertyEditor()), actionCollection(), "view_propeditor"); + d->action_view_propeditor->setToolTip(i18n("Go to property editor panel")); + d->action_view_propeditor->setWhatsThis(i18n("Goes to property editor panel.")); + } + else + d->action_view_propeditor = 0; + + //DATA MENU + d->action_data_save_row = createSharedAction(i18n("&Save Row"), "button_ok", + Qt::SHIFT | Qt::Key_Return, "data_save_row"); + d->action_data_save_row->setToolTip(i18n("Save changes made to the current row")); + d->action_data_save_row->setWhatsThis(i18n("Saves changes made to the current row.")); +//temp. disable because of problems with volatile actions setActionVolatile( d->action_data_save_row, true ); + + d->action_data_cancel_row_changes = createSharedAction(i18n("&Cancel Row Changes"), + "button_cancel", 0 , "data_cancel_row_changes"); + d->action_data_cancel_row_changes->setToolTip(i18n("Cancel changes made to the current row")); + d->action_data_cancel_row_changes->setWhatsThis(i18n("Cancels changes made to the current row.")); +//temp. disable because of problems with volatile actions setActionVolatile( d->action_data_cancel_row_changes, true ); + + d->action_data_execute = createSharedAction(i18n("&Execute"), "player_play", 0 , "data_execute"); + //d->action_data_execute->setToolTip(i18n("")); //TODO + //d->action_data_execute->setWhatsThis(i18n("")); //TODO + +#ifndef KEXI_NO_UNFINISHED + action = createSharedAction(i18n("&Filter"), "filter", 0, "data_filter"); + setActionVolatile( action, true ); +#endif +// action->setToolTip(i18n("")); //todo +// action->setWhatsThis(i18n("")); //todo + +// setSharedMenu("data_sort"); + action = createSharedAction(i18n("&Ascending"), "sort_az", 0, "data_sort_az"); +//temp. disable because of problems with volatile actions setActionVolatile( action, true ); + action->setToolTip(i18n("Sort data in ascending order")); + action->setWhatsThis(i18n("Sorts data in ascending order (from A to Z and from 0 to 9). Data from selected column is used for sorting.")); + + action = createSharedAction(i18n("&Descending"), "sort_za", 0, "data_sort_za"); +//temp. disable because of problems with volatile actions setActionVolatile( action, true ); + action->setToolTip(i18n("Sort data in descending order")); + action->setWhatsThis(i18n("Sorts data in descending (from Z to A and from 9 to 0). Data from selected column is used for sorting.")); + + // - record-navigation related actions + createSharedAction( KexiRecordNavigator::Actions::moveToFirstRecord(), 0, "data_go_to_first_record"); + createSharedAction( KexiRecordNavigator::Actions::moveToPreviousRecord(), 0, "data_go_to_previous_record"); + createSharedAction( KexiRecordNavigator::Actions::moveToNextRecord(), 0, "data_go_to_next_record"); + createSharedAction( KexiRecordNavigator::Actions::moveToLastRecord(), 0, "data_go_to_last_record"); + createSharedAction( KexiRecordNavigator::Actions::moveToNewRecord(), 0, "data_go_to_new_record"); + + //FORMAT MENU + d->action_format_font = createSharedAction(i18n("&Font..."), "fonts", 0, "format_font"); + d->action_format_font->setToolTip(i18n("Change font for selected object")); + d->action_format_font->setWhatsThis(i18n("Changes font for selected object.")); + + //TOOLS MENU + + //WINDOW MENU +#ifndef Q_WS_WIN + //KMDI <= 3.5.1 has no shortcut here: + KAction *closeWindowAction = actionCollection()->action("window_close"); + if (closeWindowAction) + closeWindowAction->setShortcut(KStdAccel::close()); +#endif + + //additional 'Window' menu items + d->action_window_next = new KAction( i18n("&Next Window"), "", +#ifdef Q_WS_WIN + Qt::CTRL+Qt::Key_Tab, +#else + Qt::ALT+Qt::Key_Right, +#endif + this, SLOT(activateNextWin()), actionCollection(), "window_next"); + d->action_window_next->setToolTip( i18n("Next window") ); + d->action_window_next->setWhatsThis(i18n("Switches to the next window.")); + + d->action_window_previous = new KAction( i18n("&Previous Window"), "", +#ifdef Q_WS_WIN + Qt::CTRL+Qt::SHIFT+Qt::Key_Tab, +#else + Qt::ALT+Qt::Key_Left, +#endif + this, SLOT(activatePrevWin()), actionCollection(), "window_previous"); + d->action_window_previous->setToolTip( i18n("Previous window") ); + d->action_window_previous->setWhatsThis(i18n("Switches to the previous window.")); + + //SETTINGS MENU + setStandardToolBarMenuEnabled( true ); + action = KStdAction::keyBindings(this, SLOT( slotConfigureKeys() ), actionCollection() ); + action->setWhatsThis(i18n("Lets you configure shortcut keys.")); + +#ifdef KEXI_SHOW_UNIMPLEMENTED + action = KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars() ), actionCollection() ); + action->setWhatsThis(i18n("Lets you configure toolbars.")); + + d->action_show_other = new KActionMenu(i18n("Other"), + actionCollection(), "options_show_other"); +#endif + +#ifndef KEXI_NO_CTXT_HELP + d->action_show_helper = new KToggleAction(i18n("Show Context Help"), "", Qt::CTRL + Qt::Key_H, + actionCollection(), "options_show_contexthelp"); +#if KDE_IS_VERSION(3,2,90) + d->action_show_helper->setCheckedState(i18n("Hide Context Help")); +#endif +#endif + +#ifdef KEXI_FORMS_SUPPORT + slotOptionsEnableForms(true, true); +#else + slotOptionsEnableForms(false, true); +#endif + +#ifdef KEXI_REPORTS_SUPPORT + Kexi::tempShowReports() = true; +#else + Kexi::tempShowReports() = false; +#endif + +#ifdef KEXI_MACROS_SUPPORT + Kexi::tempShowMacros() = true; +#else + Kexi::tempShowMacros() = false; +#endif + +#ifdef KEXI_SCRIPTS_SUPPORT + Kexi::tempShowScripts() = true; +#else + Kexi::tempShowScripts() = false; +#endif + +#ifdef KEXI_SHOW_UNIMPLEMENTED + d->action_configure = KStdAction::preferences(this, SLOT(slotShowSettings()), actionCollection()); + action->setWhatsThis(i18n("Lets you configure Kexi.")); +#endif + + //HELP MENU +#if 0//js: todo reenable later + KStdAction::tipOfDay( this, SLOT( slotTipOfTheDayAction() ), actionCollection() ) + ->setWhatsThis(i18n("This shows useful tips on the use of this application.")); +#endif +#if 0 //we don't have a time for updating info text for each new version + new KAction(i18n("Important Information"), "messagebox_info", 0, + this, SLOT(slotImportantInfo()), actionCollection(), "help_show_important_info"); +#endif +//TODO: UNCOMMENT TO REMOVE MDI MODES SETTING m_pMdiModeMenu->hide(); + +#ifndef KEXI_NO_FEEDBACK_AGENT +#ifdef FEEDBACK_CLASS + new KAction(i18n("Give Feedback..."), "messagebox_info", 0, + this, SLOT(slotStartFeedbackAgent()), actionCollection(), "help_start_feedback_agent"); +#endif +#endif +// KAction *actionSettings = new KAction(i18n("Configure Kexi..."), "configure", 0, +// actionCollection(), "kexi_settings"); +// actionSettings->setWhatsThis(i18n("Lets you configure Kexi.")); +// connect(actionSettings, SIGNAL(activated()), this, SLOT(slotShowSettings())); + + // -- add a few missing tooltips (usable especially in Form's "Assign action" dialog) + if ((action = actionCollection()->action("window_close"))) + action->setToolTip(i18n("Close the current window")); + + // ----- declare action categories, so form's "assign action to button" + // (and macros in the future) will be able to recognize category + // of actions and filter them ----------------------------------- +//! @todo shouldn't we move this to core? + Kexi::ActionCategories *acat = Kexi::actionCategories(); + acat->addAction("data_execute", Kexi::PartItemActionCategory); + + //! @todo unused for now + acat->addWindowAction("data_filter", + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addWindowAction("data_save_row", + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addWindowAction("data_cancel_row_changes", + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addWindowAction("delete_table_row", + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + //! @todo support this in KexiPart::FormObjectType as well + acat->addWindowAction("data_sort_az", + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + //! @todo support this in KexiPart::FormObjectType as well + acat->addWindowAction("data_sort_za", + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + //! @todo support this in KexiPart::FormObjectType as well + acat->addWindowAction("edit_clear_table", + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + //! @todo support this in KexiPart::FormObjectType as well + acat->addWindowAction("edit_copy_special_data_table", + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + // GlobalActions, etc. + acat->addAction("edit_copy", Kexi::GlobalActionCategory|Kexi::PartItemActionCategory); + + acat->addAction("edit_cut", Kexi::GlobalActionCategory|Kexi::PartItemActionCategory); + + acat->addAction("edit_paste", Kexi::GlobalActionCategory|Kexi::PartItemActionCategory); + + acat->addAction("edit_delete", Kexi::GlobalActionCategory|Kexi::PartItemActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addAction("edit_delete_row", Kexi::GlobalActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addAction("edit_edititem", Kexi::PartItemActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + acat->addAction("edit_find", Kexi::GlobalActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addAction("edit_findnext", Kexi::GlobalActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addAction("edit_findprevious", Kexi::GlobalActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addAction("edit_replace", Kexi::GlobalActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + acat->addAction("edit_paste_special_data_table", Kexi::GlobalActionCategory); + + acat->addAction("help_about_app", Kexi::GlobalActionCategory); + + acat->addAction("help_about_kde", Kexi::GlobalActionCategory); + + acat->addAction("help_contents", Kexi::GlobalActionCategory); + + acat->addAction("help_report_bug", Kexi::GlobalActionCategory); + + acat->addAction("help_whats_this", Kexi::GlobalActionCategory); + + acat->addAction("options_configure_keybinding", Kexi::GlobalActionCategory); + + acat->addAction("project_close", Kexi::GlobalActionCategory); + + //! @todo support this in FormObjectType as well + acat->addAction("project_export_data_table", Kexi::GlobalActionCategory|Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + acat->addAction("project_import_data_table", Kexi::GlobalActionCategory); + + acat->addAction("project_new", Kexi::GlobalActionCategory); + + acat->addAction("project_open", Kexi::GlobalActionCategory); + + //! @todo support this in FormObjectType, ReportObjectType as well as others + acat->addAction("project_print", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + //! @todo support this in FormObjectType, ReportObjectType as well as others + acat->addAction("project_print_preview", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + //! @todo support this in FormObjectType, ReportObjectType as well as others + acat->addAction("project_print_setup", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType); + + acat->addAction("quit", Kexi::GlobalActionCategory); + + acat->addAction("tools_compact_database", Kexi::GlobalActionCategory); + + acat->addAction("tools_import_project", Kexi::GlobalActionCategory); + + acat->addAction("view_data_mode", Kexi::GlobalActionCategory); + + acat->addAction("view_design_mode", Kexi::GlobalActionCategory); + + acat->addAction("view_text_mode", Kexi::GlobalActionCategory); + + acat->addAction("view_mainarea", Kexi::GlobalActionCategory); + + acat->addAction("view_navigator", Kexi::GlobalActionCategory); + + acat->addAction("view_propeditor", Kexi::GlobalActionCategory); + + acat->addAction("window_close", Kexi::GlobalActionCategory | Kexi::WindowActionCategory); + acat->setAllObjectTypesSupported("window_close", true); + + acat->addAction("window_next", Kexi::GlobalActionCategory); + + acat->addAction("window_previous", Kexi::GlobalActionCategory); + + //skipped - design view only + acat->addAction("format_font", Kexi::NoActionCategory); + acat->addAction("project_save", Kexi::NoActionCategory); + acat->addAction("edit_insert_empty_row", Kexi::NoActionCategory); + //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType later + acat->addAction("edit_select_all", Kexi::NoActionCategory); + //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType later + acat->addAction("edit_redo", Kexi::NoActionCategory); + //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType later + acat->addAction("edit_undo", Kexi::NoActionCategory); + + //record-navigation related actions + acat->addAction("data_go_to_first_record", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + acat->addAction("data_go_to_previous_record", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + acat->addAction("data_go_to_next_record", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + acat->addAction("data_go_to_last_record", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + acat->addAction("data_go_to_new_record", Kexi::WindowActionCategory, + KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); + + //skipped - internal: + acat->addAction("tablepart_create", Kexi::NoActionCategory); + acat->addAction("querypart_create", Kexi::NoActionCategory); + acat->addAction("formpart_create", Kexi::NoActionCategory); + acat->addAction("reportpart_create", Kexi::NoActionCategory); + acat->addAction("macropart_create", Kexi::NoActionCategory); + acat->addAction("scriptpart_create", Kexi::NoActionCategory); +} + +void KexiMainWindowImpl::invalidateActions() +{ + invalidateProjectWideActions(); + invalidateSharedActions(); +} + +void KexiMainWindowImpl::invalidateSharedActions(QObject *o) +{ + //TODO: enabling is more complex... +/* d->action_edit_cut->setEnabled(true); + d->action_edit_copy->setEnabled(true); + d->action_edit_paste->setEnabled(true);*/ + + if (!o) + o = focusWindow(); + KexiSharedActionHost::invalidateSharedActions(o); +} + +void KexiMainWindowImpl::invalidateSharedActions() +{ + invalidateSharedActions(0); +} + +// unused, I think +void KexiMainWindowImpl::invalidateSharedActionsLater() +{ + QTimer::singleShot(1, this, SLOT(invalidateSharedActions())); +} + +void KexiMainWindowImpl::invalidateProjectWideActions() +{ +// stateChanged("project_opened",d->prj ? StateNoReverse : StateReverse); + + const bool have_dialog = d->curDialog; + const bool dialog_dirty = d->curDialog && d->curDialog->dirty(); + const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->isReadOnly(); + + //PROJECT MENU + d->action_save->setEnabled(have_dialog && dialog_dirty && !readOnly); + d->action_save_as->setEnabled(have_dialog && !readOnly); + d->action_project_properties->setEnabled(d->prj); + d->action_close->setEnabled(d->prj); + d->action_project_relations->setEnabled(d->prj); + if (d->action_project_import_data_table) + d->action_project_import_data_table->setEnabled(d->prj && !readOnly); + d->action_project_export_data_table->setEnabled( + d->curDialog && d->curDialog->part()->info()->isDataExportSupported() + && !d->curDialog->neverSaved() ); + + const bool printingActionsEnabled = + d->curDialog && d->curDialog->part()->info()->isPrintingSupported() + && !d->curDialog->neverSaved(); + d->action_project_print->setEnabled( printingActionsEnabled ); + d->action_project_print_preview->setEnabled( printingActionsEnabled ); + d->action_project_print_setup->setEnabled( printingActionsEnabled ); + + //EDIT MENU + + if (d->action_edit_paste_special_data_table) + d->action_edit_paste_special_data_table->setEnabled(d->prj && !readOnly); + +//! @todo "copy special" is currently enabled only for data view mode; +//! what about allowing it to enable in design view for "kexi/table" ? + if (d->curDialog && d->curDialog->currentViewMode()==Kexi::DataViewMode) { + KexiPart::Info *activePartInfo = d->curDialog->part()->info(); + d->action_edit_copy_special_data_table->setEnabled( + activePartInfo ? activePartInfo->isDataExportSupported() : false ); + } + else + d->action_edit_copy_special_data_table->setEnabled( false ); + + //VIEW MENU + if (d->action_view_nav) + d->action_view_nav->setEnabled(d->prj); + d->action_view_mainarea->setEnabled(d->prj); + if (d->action_view_propeditor) + d->action_view_propeditor->setEnabled(d->prj); + if (d->action_view_data_mode) { + d->action_view_data_mode->setEnabled( have_dialog && d->curDialog->supportsViewMode(Kexi::DataViewMode) ); + if (!d->action_view_data_mode->isEnabled()) + d->action_view_data_mode->setChecked(false); + } + if (d->action_view_design_mode) { + d->action_view_design_mode->setEnabled( have_dialog && d->curDialog->supportsViewMode(Kexi::DesignViewMode) ); + if (!d->action_view_design_mode->isEnabled()) + d->action_view_design_mode->setChecked(false); + } + if (d->action_view_text_mode) { + d->action_view_text_mode->setEnabled( have_dialog && d->curDialog->supportsViewMode(Kexi::TextViewMode) ); + if (!d->action_view_text_mode->isEnabled()) + d->action_view_text_mode->setChecked(false); + } +#ifndef KEXI_NO_CTXT_HELP + d->action_show_helper->setEnabled(d->prj); +#endif + + //CREATE MENU + if (d->createMenu) + d->createMenu->setEnabled(d->prj); + + // DATA MENU + //d->action_data_execute->setEnabled( d->curDialog && d->curDialog->part()->info()->isExecuteSupported() ); + + //TOOLS MENU + // "compact db" supported if there's no db or the current db supports compacting and is opened r/w: + d->action_tools_compact_database->setEnabled( + !d->prj || !readOnly && d->prj && d->prj->dbConnection() + && (d->prj->dbConnection()->driver()->features() & KexiDB::Driver::CompactingDatabaseSupported) ); + + //WINDOW MENU + if (d->action_window_next) { + d->action_window_next->setEnabled(!m_pDocumentViews->isEmpty()); + d->action_window_previous->setEnabled(!m_pDocumentViews->isEmpty()); + } + + //DOCKS + if (d->nav) + d->nav->setEnabled(d->prj); + if (d->propEditor) + d->propEditorTabWidget->setEnabled(d->prj); +} + +void KexiMainWindowImpl::invalidateViewModeActions() +{ + if (d->curDialog) { + //update toggle action + if (d->curDialog->currentViewMode()==Kexi::DataViewMode) { + if (d->action_view_data_mode) + d->action_view_data_mode->setChecked( true ); + } + else if (d->curDialog->currentViewMode()==Kexi::DesignViewMode) { + if (d->action_view_design_mode) + d->action_view_design_mode->setChecked( true ); + } + else if (d->curDialog->currentViewMode()==Kexi::TextViewMode) { + if (d->action_view_text_mode) + d->action_view_text_mode->setChecked( true ); + } + } +} + +tristate KexiMainWindowImpl::startup() +{ + switch (Kexi::startupHandler().action()) { + case KexiStartupHandler::CreateBlankProject: + if (d->propEditor) + makeDockInvisible( manager()->findWidgetParentDock(d->propEditorTabWidget) ); + return createBlankProject(); + case KexiStartupHandler::CreateFromTemplate: + return createProjectFromTemplate(*Kexi::startupHandler().projectData()); + case KexiStartupHandler::OpenProject: + return openProject(*Kexi::startupHandler().projectData()); + case KexiStartupHandler::ImportProject: + return showProjectMigrationWizard( + Kexi::startupHandler().importActionData().mimeType, + Kexi::startupHandler().importActionData().fileName + ); + default:; + if (d->propEditor) + makeDockInvisible( manager()->findWidgetParentDock(d->propEditorTabWidget) ); + } + return true; +} + +static QString internalReason(KexiDB::Object *obj) +{ + const QString &s = obj->errorMsg(); + if (s.isEmpty()) + return s; + return QString("<br>(%1) ").arg(i18n("reason:")+" <i>"+s+"</i>"); +} + +tristate KexiMainWindowImpl::openProject(const KexiProjectData& projectData) +{ + KexiProjectData *newProjectData = new KexiProjectData(projectData); +// if (userMode()) { + //TODO: maybe also auto allow to open objects... +// return initUserModeMode(newProjectData); +// } + createKexiProject( newProjectData ); + if (!newProjectData->connectionData()->savePassword + && newProjectData->connectionData()->password.isEmpty() + && newProjectData->connectionData()->fileName().isEmpty() //! @todo temp.: change this if there are file-based drivers requiring a password + ) + { + //ask for password + KexiDBPasswordDialog pwdDlg(this, *newProjectData->connectionData(), + false /*!showDetailsButton*/); + if (QDialog::Accepted!=pwdDlg.exec()) { + delete d->prj; + d->prj = 0; + return cancelled; + } + } + bool incompatibleWithKexi; + tristate res = d->prj->open(incompatibleWithKexi); + if (~res) { + delete d->prj; + d->prj = 0; + return cancelled; + } + else if (!res) { + delete d->prj; + d->prj = 0; + if (incompatibleWithKexi) { + if (KMessageBox::Yes == KMessageBox::questionYesNo(this, + i18n("<qt>Database project %1 does not appear to have been created using Kexi.<br><br>" + "Do you want to import it as a new Kexi project?</qt>").arg(projectData.infoString()), + 0, KGuiItem(i18n("Import Database", "&Import..."), "database_import"), + KStdGuiItem::quit())) + { + const bool anotherProjectAlreadyOpened = d->prj; + tristate res = showProjectMigrationWizard("application/x-kexi-connectiondata", + projectData.databaseName(), projectData.constConnectionData()); + + if (!anotherProjectAlreadyOpened) //the project could have been opened within this instance + return res; + + //always return cancelled because even if migration succeeded, new Kexi instance + //will be started if user wanted to open the imported db + return cancelled; + } + return cancelled; + } + return false; + } + initNavigator(); + Kexi::recentProjects().addProjectData( newProjectData ); + updateReadOnlyState(); + invalidateActions(); +// d->disableErrorMessages = true; + enableMessages( false ); + + QTimer::singleShot(1, this, SLOT(slotAutoOpenObjectsLater())); + return true; +} + +tristate KexiMainWindowImpl::createProjectFromTemplate(const KexiProjectData& projectData) +{ + QStringList mimetypes; + mimetypes.append( KexiDB::Driver::defaultFileBasedDriverMimeType() ); + QString fname; + const QString startDir(":OpenExistingOrCreateNewProject"/*as in KexiNewProjectWizard*/); + const QString caption( i18n("Select New Project's Location") ); + + while (true) { +#ifdef Q_WS_WIN + //! @todo remove + QString recentDir = KGlobalSettings::documentPath(); + if (fname.isEmpty() && !projectData.constConnectionData()->dbFileName().isEmpty()) //propose filename from db template name + fname = KFileDialog::getStartURL(startDir, recentDir).path() + + '/' + projectData.constConnectionData()->dbFileName(); + fname = QFileDialog::getSaveFileName( + KFileDialog::getStartURL(fname.isEmpty() ? startDir : fname, recentDir).path(), + KexiUtils::fileDialogFilterStrings(mimetypes, false), + this, "CreateProjectFromTemplate", caption); + if ( !fname.isEmpty() ) { + //save last visited path + KURL url; + url.setPath( fname ); + if (url.isLocalFile()) + KRecentDirs::add(startDir, url.directory()); + } +#else + Q_UNUSED(projectData); + if (fname.isEmpty() && + !projectData.constConnectionData()->dbFileName().isEmpty()) + { + //propose filename from db template name + fname = projectData.constConnectionData()->dbFileName(); + } + const bool specialDir = fname.isEmpty(); + kdDebug() << fname << "............." << endl; + KFileDialog dlg( specialDir ? startDir : QString::null, + mimetypes.join(" "), this, "filedialog", true); + if ( !specialDir ) + dlg.setSelection( fname ); // may also be a filename + dlg.setOperationMode( KFileDialog::Saving ); + dlg.setCaption( caption ); + dlg.exec(); + fname = dlg.selectedFile(); + if (!fname.isEmpty()) + KRecentDocument::add(fname); +// fname = KFileDialog::getSaveFileName(fname.isEmpty() ? startDir : fname, + // mimetypes.join(" "), this, caption); +#endif + if ( fname.isEmpty() ) + return cancelled; + if (KexiStartupFileDialog::askForOverwriting(fname, this)) + break; + } + + if (KexiUtils::CopySuccess != KexiUtils::copyFile( + projectData.constConnectionData()->fileName(), fname )) + { + return false; + } + + return openProject(fname, 0, QString::null, projectData.autoopenObjects/*copy*/); +} + +void KexiMainWindowImpl::updateReadOnlyState() +{ + const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->isReadOnly(); + d->statusBar->setReadOnlyFlag( readOnly ); + if (d->nav) + d->nav->setReadOnly(readOnly); + // update "insert ....." actions for every part + KActionCollection *ac = actionCollection(); + for (KexiPart::PartInfoListIterator it(*Kexi::partManager().partInfoList()); it.current(); ++it) { + KAction *a = ac->action( KexiPart::nameForCreateAction( *it.current() ) ); + if (a) + a->setEnabled(!readOnly); + } +} + +void KexiMainWindowImpl::slotAutoOpenObjectsLater() +{ + QString not_found_msg; + bool openingCancelled; + //ok, now open "autoopen: objects + if (d->prj) { + for (QValueList<KexiProjectData::ObjectInfo>::ConstIterator it = + d->prj->data()->autoopenObjects.constBegin(); + it != d->prj->data()->autoopenObjects.constEnd(); ++it ) + { + KexiProjectData::ObjectInfo info = *it; + KexiPart::Info *i = Kexi::partManager().infoForMimeType( + QCString("kexi/")+info["type"].lower().latin1() ); + if (!i) { + not_found_msg += "<li>"; + if (!info["name"].isEmpty()) + not_found_msg += (QString("\"") + info["name"] + "\" - "); + if (info["action"]=="new") + not_found_msg += i18n("cannot create object - unknown object type \"%1\"") + .arg(info["type"]); + else + not_found_msg += i18n("unknown object type \"%1\"").arg(info["type"]); + not_found_msg += internalReason(&Kexi::partManager())+"<br></li>"; + continue; + } + // * NEW + if (info["action"]=="new") { + if (!newObject( i, openingCancelled) && !openingCancelled) { + not_found_msg += "<li>"; + not_found_msg += (i18n("cannot create object of type \"%1\"").arg(info["type"])+ + internalReason(d->prj)+"<br></li>"); + } + else + d->wasAutoOpen = true; + continue; + } + + KexiPart::Item *item = d->prj->item(i, info["name"]); + + if (!item) { + QString taskName; + if (info["action"]=="print-preview") + taskName = i18n("making print preview for"); + else if (info["action"]=="print") + taskName = i18n("printing"); + else if (info["action"]=="execute") + taskName = i18n("\"executing object\" action", "executing"); + else + taskName = i18n("opening"); + + not_found_msg += (QString("<li>")+ taskName + " \"" + info["name"] + "\" - "); + if ("table"==info["type"].lower()) + not_found_msg += i18n("table not found"); + else if ("query"==info["type"].lower()) + not_found_msg += i18n("query not found"); + else if ("macro"==info["type"].lower()) + not_found_msg += i18n("macro not found"); + else if ("script"==info["type"].lower()) + not_found_msg += i18n("script not found"); + else + not_found_msg += i18n("object not found"); + not_found_msg += (internalReason(d->prj)+"<br></li>"); + continue; + } + // * EXECUTE, PRINT, PRINT PREVIEW + if (info["action"]=="execute") { + tristate res = executeItem(item); + if (false == res) { + not_found_msg += ( QString("<li>\"")+ info["name"] + "\" - " + i18n("cannot execute object")+ + internalReason(d->prj)+"<br></li>" ); + } + continue; + } + else if (info["action"]=="print") { + tristate res = printItem(item); + if (false == res) { + not_found_msg += ( QString("<li>\"")+ info["name"] + "\" - " + i18n("cannot print object")+ + internalReason(d->prj)+"<br></li>" ); + } + continue; + } + else if (info["action"]=="print-preview") { + tristate res = printPreviewForItem(item); + if (false == res) { + not_found_msg += ( QString("<li>\"")+ info["name"] + "\" - " + i18n("cannot make print preview of object")+ + internalReason(d->prj)+"<br></li>" ); + } + continue; + } + + int viewMode; + if (info["action"]=="open") + viewMode = Kexi::DataViewMode; + else if (info["action"]=="design") + viewMode = Kexi::DesignViewMode; + else if (info["action"]=="edittext") + viewMode = Kexi::TextViewMode; + else + continue; //sanity + + QString openObjectMessage; + if (!openObject(item, viewMode, openingCancelled, 0, &openObjectMessage) + && (!openingCancelled || !openObjectMessage.isEmpty())) + { + not_found_msg += (QString("<li>\"")+ info["name"] + "\" - "); + if (openObjectMessage.isEmpty()) + not_found_msg += i18n("cannot open object"); + else + not_found_msg += openObjectMessage; + not_found_msg += internalReason(d->prj) + "<br></li>"; + continue; + } + else { + d->wasAutoOpen = true; + } + } + } + enableMessages( true ); +// d->disableErrorMessages = false; + + if (!not_found_msg.isEmpty()) + showErrorMessage(i18n("You have requested selected objects to be automatically opened " + "or processed on startup. Several objects cannot be opened or processed."), + QString("<ul>%1</ul>").arg(not_found_msg) ); + + d->updatePropEditorVisibility(d->curDialog ? d->curDialog->currentViewMode() : 0); +#if defined(KDOCKWIDGET_P) + if (d->propEditor) { + KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + if(ds) + ds->setSeparatorPosInPercent(d->config->readNumEntry("RightDockPosition", 80/* % */)); + } +#endif + + updateAppCaption(); + +// d->navToolWindow->wrapperWidget()->setFixedWidth(200); +//js TODO: make visible FOR OTHER MODES if needed + if (mdiMode()==KMdi::ChildframeMode || mdiMode()==KMdi::TabPageMode) { + //make docks visible again + if (!d->navToolWindow->wrapperWidget()->isVisible()) + static_cast<KDockWidget*>(d->navToolWindow->wrapperWidget())->makeDockVisible(); +// if (!d->propEditorToolWindow->wrapperWidget()->isVisible()) +// static_cast<KDockWidget*>(d->propEditorToolWindow->wrapperWidget())->makeDockVisible(); + } + + // if (!d->prj->data()->autoopenObjects.isEmpty()) + d->restoreNavigatorWidth(); + +#ifndef PROPEDITOR_VISIBILITY_CHANGES +// KDockWidget *dw = (KDockWidget *)d->nav->parentWidget(); +// KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); +// const int pos = ds->separatorPos(); + + //if (!d->curDialog || d->curDialog->currentViewMode()==Kexi::DataViewMode) +// d->propEditorToolWindow->hide(); + +// ds->setSeparatorPos( pos, true ); +#endif + if (d->nav) { + d->nav->updateGeometry(); + } + qApp->processEvents(); + emit projectOpened(); +} + +tristate KexiMainWindowImpl::closeProject() +{ +#ifndef KEXI_NO_PENDING_DIALOGS + if (d->pendingDialogsExist()) { + kdDebug() << "KexiMainWindowImpl::closeProject() pendingDialogsExist..." << endl; + d->actionToExecuteWhenPendingJobsAreFinished = Private::CloseProjectAction; + return cancelled; + } +#endif + + //only save nav. visibility setting is project is opened + d->saveSettingsForShowProjectNavigator = d->prj && d->isProjectNavigatorVisible; + + if (!d->prj) + return true; + + { + // make sure the project can be closed + bool cancel = false; + emit acceptProjectClosingRequested(cancel); + if (cancel) + return cancelled; + } + + d->dialogExistedBeforeCloseProject = !d->curDialog.isNull(); + +#if defined(KDOCKWIDGET_P) + //remember docks position - will be used on storeSettings() + if (d->propEditor) { + KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + if (ds) + d->propEditorDockSeparatorPos = ds->separatorPosInPercent(); + } + if (d->nav) { +// makeDockInvisible( manager()->findWidgetParentDock(d->propEditor) ); + + if (d->propEditor) { + if (d->openedDialogsCount() == 0) + makeWidgetDockVisible(d->propEditorTabWidget); + KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + if(ds) + ds->setSeparatorPosInPercent(80); + } + + KDockWidget *dw = (KDockWidget *)d->nav->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + int dwWidth = dw->width(); + if (ds) { + if (d->openedDialogsCount()!=0 && d->propEditorTabWidget && d->propEditorTabWidget->isVisible()) + d->navDockSeparatorPos = ds->separatorPosInPercent(); + else + d->navDockSeparatorPos = (100 * dwWidth) / width(); + +// int navDockSeparatorPosWithAutoOpen = (100 * dw->width()) / width() + 4; +// d->navDockSeparatorPos = (100 * dw->width()) / width() + 1; + } + } +#endif + + //close each window, optionally asking if user wants to close (if data changed) + while (!d->curDialog.isNull()) { + tristate res = closeDialog( d->curDialog ); + if (!res || ~res) + return res; + } + + // now we will close for sure + emit beforeProjectClosing(); + + if (!d->prj->closeConnection()) + return false; + + if(d->nav) + { + d->navWasVisibleBeforeProjectClosing = manager()->findWidgetParentDock(d->nav)->isVisible(); + d->nav->clear(); +#if 0 //do not confuse users + d->navToolWindow->hide(); +#endif + } + + if (d->propEditor) + makeDockInvisible( manager()->findWidgetParentDock(d->propEditorTabWidget) ); + +// if(d->propEditorToolWindow) + // d->propEditorToolWindow->hide(); + + d->clearDialogs(); //sanity! + delete d->prj; + d->prj=0; + +// Kexi::partManager().unloadAllParts(); + + updateReadOnlyState(); + invalidateActions(); +// if (!userMode()) + updateAppCaption(); + + emit projectClosed(); + return true; +} + +void KexiMainWindowImpl::initContextHelp() { +#ifndef KEXI_NO_CTXT_HELP + d->ctxHelp=new KexiContextHelp(this,this); +/*todo + d->ctxHelp->setContextHelp(i18n("Welcome"),i18n("The <B>KEXI team</B> wishes you a lot of productive work, " + "with this product. <BR><HR><BR>If you have found a <B>bug</B> or have a <B>feature</B> request, please don't " + "hesitate to report it at our <A href=\"http://www.kexi-project.org/cgi-bin/bug.pl\"> issue " + "tracking system </A>.<BR><HR><BR>If you would like to <B>join</B> our effort, the <B>development</B> documentation " + "at <A href=\"http://www.kexi-project.org\">www.kexi-project.org</A> is a good starting point."),0); +*/ + addToolWindow(d->ctxHelp,KDockWidget::DockBottom | KDockWidget::DockLeft,getMainDockWidget(),20); +#endif +} + +void KexiMainWindowImpl::initNavigator() +{ + if (!d->isProjectNavigatorVisible) + return; + + if(!d->nav) + { + d->nav = new KexiBrowser(this, this); + d->nav->installEventFilter(this); + d->navToolWindow = addToolWindow(d->nav, KDockWidget::DockLeft, getMainDockWidget(), 20/*, lv, 35, "2"*/); +// d->navToolWindow->hide(); + + connect(d->nav,SIGNAL(openItem(KexiPart::Item*,int)),this,SLOT(openObject(KexiPart::Item*,int))); + connect(d->nav,SIGNAL(openOrActivateItem(KexiPart::Item*,int)), + this,SLOT(openObjectFromNavigator(KexiPart::Item*,int))); + connect(d->nav,SIGNAL(newItem( KexiPart::Info* )), + this,SLOT(newObject(KexiPart::Info*))); + connect(d->nav,SIGNAL(removeItem(KexiPart::Item*)), + this,SLOT(removeObject(KexiPart::Item*))); + connect(d->nav,SIGNAL(renameItem(KexiPart::Item*,const QString&, bool&)), + this,SLOT(renameObject(KexiPart::Item*,const QString&, bool&))); + connect(d->nav,SIGNAL(executeItem(KexiPart::Item*)), + this,SLOT(executeItem(KexiPart::Item*))); + connect(d->nav,SIGNAL(exportItemAsDataTable(KexiPart::Item*)), + this,SLOT(exportItemAsDataTable(KexiPart::Item*))); + connect(d->nav,SIGNAL(printItem( KexiPart::Item* )), + this,SLOT(printItem(KexiPart::Item*))); + connect(d->nav,SIGNAL(pageSetupForItem( KexiPart::Item*)), + this,SLOT(showPageSetupForItem(KexiPart::Item*))); + if (d->prj) {//connect to the project + connect(d->prj, SIGNAL(itemRemoved(const KexiPart::Item&)), + d->nav, SLOT(slotRemoveItem(const KexiPart::Item&))); + } + connect(d->nav,SIGNAL(selectionChanged(KexiPart::Item*)), + this,SLOT(slotPartItemSelectedInNavigator(KexiPart::Item*))); + +// d->restoreNavigatorWidth(); + } + if(d->prj->isConnected()) { + QString partManagerErrorMessages; + d->nav->setProject( d->prj, QString::null/*all mimetypes*/, &partManagerErrorMessages ); + if (!partManagerErrorMessages.isEmpty()) { + showWarningContinueMessage(partManagerErrorMessages, QString::null, + "dontShowWarningsRelatedToPluginsLoading"); + } + } + connect(d->prj, SIGNAL(newItemStored(KexiPart::Item&)), d->nav, SLOT(addItem(KexiPart::Item&))); + d->nav->setFocus(); + + if (d->forceShowProjectNavigatorOnCreation) { + slotViewNavigator(); + d->forceShowProjectNavigatorOnCreation = false; + } + else if (d->forceHideProjectNavigatorOnCreation) { + d->navToolWindow->hide(); +// makeDockInvisible( manager()->findWidgetParentDock(d->nav) ); + d->forceHideProjectNavigatorOnCreation = false; + } + + invalidateActions(); +} + +void KexiMainWindowImpl::slotLastActions() +{ +#if defined(KDOCKWIDGET_P) + if (mdiMode()==KMdi::ChildframeMode || mdiMode()==KMdi::TabPageMode) { +// KDockWidget *dw = (KDockWidget *)d->propEditor->parentWidget(); + //KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); +// Q_UNUSED(ds); +//1 ds->resize(ds->width()*3, ds->height()); +//1 ds->setSeparatorPos(30, true); +//1 ds->setForcedFixedWidth( dw, 200 ); + } +#endif +#ifdef Q_WS_WIN + showMaximized();//js: workaround for not yet completed layout settings storage on win32 +#endif +} + +void KexiMainWindowImpl::initPropertyEditor() +{ + if (!d->propEditor) { +//TODO: FIX LAYOUT PROBLEMS + d->propEditorTabWidget = new KTabWidget(this); + d->propEditorTabWidget->hide(); + d->propEditor = new KexiPropertyEditorView(this, d->propEditorTabWidget); + d->propEditorTabWidget->setCaption(d->propEditor->caption()); + d->propEditorTabWidget->addTab(d->propEditor, i18n("Properties")); + d->propEditor->installEventFilter(this); + d->propEditorToolWindow = addToolWindow(d->propEditorTabWidget, + KDockWidget::DockRight, getMainDockWidget(), 20); + + d->config->setGroup("PropertyEditor"); + int size = d->config->readNumEntry("FontSize", -1); + QFont f( Kexi::smallFont() ); + if (size>0) + f.setPixelSize( size ); + d->propEditorTabWidget->setFont(f); + + if (mdiMode()==KMdi::ChildframeMode || mdiMode()==KMdi::TabPageMode) { + KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); + #if defined(KDOCKWIDGET_P) + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); +// ds->setKeepSize(true); + makeWidgetDockVisible(d->propEditorTabWidget); + // ds->show(); + // ds->resize(400, ds->height()); + // ds->setSeparatorPos(400, true); + // ds->setForcedFixedWidth( dw, 400 ); + // ds->setSeparatorPos(600, true); + + + d->config->setGroup("MainWindow"); + ds->setSeparatorPosInPercent(d->config->readNumEntry("RightDockPosition", 80/* % */)); +// makeDockInvisible( manager()->findWidgetParentDock(d->propEditor) ); + + // ds->setForcedFixedWidth( dw, d->config->readNumEntry("RightDockPosition", 80) ); + // ds->resize(400, ds->height()); + // dw->resize(400, dw->height()); + #endif + + //1 dw->setMinimumWidth(200); + + // ds->setSeparatorPos(d->propEditor->sizeHint().width(), true); + + //heh, this is for IDEAl only, I suppose? + //js if (m_rightContainer) { + //js m_rightContainer->setForcedFixedWidth( 400 ); + //js } + } + + // int w = d->propEditor->width(); + /* KMdiToolViewAccessor *tmp=createToolWindow(); + tmp->setWidgetToWrap(d->propEditor); + d->propEditor->show(); // I'm not sure, if this is a bug in kdockwidget, which I would better fix there + tmp->show(KDockWidget::DockRight,getMainDockWidget(),20); + */ + } +// makeDockInvisible(manager()->findWidgetParentDock(d->propEditorTabWidget)); +} + +void KexiMainWindowImpl::slotPartLoaded(KexiPart::Part* p) +{ + if (!p) + return; + connect(p, SIGNAL(newObjectRequest(KexiPart::Info*)), + this, SLOT(newObject(KexiPart::Info*))); + p->createGUIClients(this); +} + +//! internal +void KexiMainWindowImpl::slotCaptionForCurrentMDIChild(bool childrenMaximized) +{ + //js todo: allow to set custom "static" app caption + + KMdiChildView *view = 0L; + if (!d->curDialog) + view = 0; + else if (d->curDialog->isAttached()) { + view = d->curDialog; + } else { + //current dialog isn't attached! - find top level child + if (m_pMdi->topChild()) { + view = m_pMdi->topChild()->m_pClient; + childrenMaximized = view->mdiParent()->state()==KMdiChildFrm::Maximized; + } + else + view = 0; + } + + if (childrenMaximized && view) { + setCaption( d->curDialog->caption() + + (d->appCaptionPrefix.isEmpty() ? QString::null : (QString::fromLatin1(" - ") + d->appCaptionPrefix)) ); + } + else { + setCaption( (d->appCaptionPrefix.isEmpty() ? QString::null : (d->appCaptionPrefix + QString::fromLatin1(" - "))) + + d->origAppCaption ); + } +} + +void KexiMainWindowImpl::updateAppCaption() +{ + //js todo: allow to set custom "static" app caption + + d->appCaptionPrefix = ""; + if (d->prj && d->prj->data()) {//add project name + d->appCaptionPrefix = d->prj->data()->caption(); + if (d->appCaptionPrefix.isEmpty()) + d->appCaptionPrefix = d->prj->data()->databaseName(); + } +// if (!d->appCaptionPrefix.isEmpty()) +// d->appCaptionPrefix = d->appCaptionPrefix; + + bool max = false; + if (d->curDialog && d->curDialog->mdiParent()) + max = d->curDialog->mdiParent()->state()==KMdiChildFrm::Maximized; + + slotCaptionForCurrentMDIChild(max); +/* + KMdiChildView *view; + if (!d->curDialog) + view = 0; + else if (d->curDialog->isAttached()) { + view = d->curDialog; + } else { + //current dialog isn't attached! - find top level child + if (m_pMdi->topChild()) { + view = m_pMdi->topChild()->m_pClient; + } + else + view = 0; + } + + kApp->setCaption( d->appCaption ); + if (view && view->mdiParent()->state()==KMdiChildFrm::Maximized) { + setCaption( view->caption() ); + } + else { + setCaption( d->appCaption ); + }*/ +} + +void KexiMainWindowImpl::slotNoMaximizedChildFrmLeft(KMdiChildFrm*) +{ + slotCaptionForCurrentMDIChild(false); +} + +void KexiMainWindowImpl::slotLastChildViewClosed() //slotLastChildFrmClosed() +{ + if (m_pDocumentViews->count()>0) //a fix for KMDI bug (will be fixed in KDE 3.4) + return; + + slotCaptionForCurrentMDIChild(false); + activeWindowChanged(0); + +//js: too WEIRD if (d->propEditor) +//js: too WEIRD makeDockInvisible( manager()->findWidgetParentDock(d->propEditorTabWidget) ); +// if (d->propEditorToolWindow) + // d->propEditorToolWindow->hide(); +} + +void KexiMainWindowImpl::slotChildViewIsDetachedNow(QWidget*) +{ + slotCaptionForCurrentMDIChild(false); +} + +/*void +KexiMainWindowImpl::closeEvent(QCloseEvent *ev) +{ + storeSettings(); + + bool cancelled = false; + if (!closeProject(cancelled)) { + //todo: error message + return; + } + if (cancelled) { + ev->ignore(); + return; + } + + ev->accept(); +}*/ + +bool +KexiMainWindowImpl::queryClose() +{ +#ifndef KEXI_NO_PENDING_DIALOGS + if (d->pendingDialogsExist()) { + kdDebug() << "KexiMainWindowImpl::queryClose() pendingDialogsExist..." << endl; + d->actionToExecuteWhenPendingJobsAreFinished = Private::QuitAction; + return false; + } +#endif +// storeSettings(); + const tristate res = closeProject(); + if (~res) + return false; + + if (res==true) + storeSettings(); + + return ! ~res; +} + +bool +KexiMainWindowImpl::queryExit() +{ +// storeSettings(); + return true; +} + +void +KexiMainWindowImpl::restoreSettings() +{ + d->config->setGroup("MainWindow"); + + // Saved settings + applyMainWindowSettings( d->config, "MainWindow" ); + + //small hack - set the default -- bottom +// d->config->setGroup(QString(name()) + " KMdiTaskBar Toolbar style"); + d->config->setGroup("MainWindow Toolbar KMdiTaskBar"); + const bool tbe = d->config->readEntry("Position").isEmpty(); + if (tbe || d->config->readEntry("Position")=="Bottom") { + if (tbe) + d->config->writeEntry("Position","Bottom"); + moveDockWindow(m_pTaskBar, DockBottom); + } + + d->config->setGroup("MainWindow"); + int mdimode = d->config->readNumEntry("MDIMode", -1);//KMdi::TabPageMode); + + const bool showProjectNavigator = d->config->readBoolEntry("ShowProjectNavigator", true); + + switch(mdimode) + { +/* case KMdi::ToplevelMode: + switchToToplevelMode(); + m_pTaskBar->switchOn(true); + break;*/ + case KMdi::ChildframeMode: + switchToChildframeMode(false); + m_pTaskBar->switchOn(true); + + // restore a possible maximized Childframe mode, + // will be used in KexiMainWindowImpl::addWindow() + d->maximizeFirstOpenedChildFrm = d->config->readBoolEntry("maximized childframes", true); + setEnableMaximizedChildFrmMode(d->maximizeFirstOpenedChildFrm); + + if (!showProjectNavigator) { + //it's visible by default but we want to hide it on navigator creation + d->forceHideProjectNavigatorOnCreation = true; + } + + break; + +#define DEFAULT_MDI_MODE KMdi::IDEAlMode + + case DEFAULT_MDI_MODE: + default: + switchToIDEAlMode(false); + if (showProjectNavigator) { + //it's invisible by default but we want to show it on navigator creation + d->forceShowProjectNavigatorOnCreation = true; + } + break; +/* case KMdi::TabPageMode: + switchToTabPageMode(); + break; +*/ + } + +#if 0 + if ( !initialGeometrySet() ) { + // Default size +// int restoredWidth, restoredHeight; + int scnum = QApplication::desktop()->screenNumber(parentWidget()); + QRect desk = QApplication::desktop()->screenGeometry(scnum); +//#if KDE_IS_VERSION(3,1,90) +// restoredWidth = KGlobalSettings::screenGeometry(scnum).width(); + // restoredHeight = KGlobalSettings::screenGeometry(scnum).height(); +//#else +// restoredWidth = QApplication::desktop()->width(); +// restoredHeight = QApplication::desktop()->height(); +//#endif +/* if (restoredWidth > 1100) {// very big desktop ? + restoredWidth = 1000; + restoredHeight = 800; + } + if (restoredWidth > 850) {// big desktop ? + restoredWidth = 800; + restoredHeight = 600; + } + else {// small (800x600, 640x480) desktop + restoredWidth = QMIN( restoredWidth, 600 ); + restoredHeight = QMIN( restoredHeight, 400 ); + }*/ + + config->setGroup("MainWindow"); + QSize s ( config->readNumEntry( QString::fromLatin1("Width %1").arg(desk.width()), 700 ), + config->readNumEntry( QString::fromLatin1("Height %1").arg(desk.height()), 480 ) ); + resize (kMin (s.width(), desk.width()), kMin(s.height(), desk.height())); + } +#endif +} + +void +KexiMainWindowImpl::storeSettings() +{ + kdDebug() << "KexiMainWindowImpl::storeSettings()" << endl; + +// saveWindowSize( d->config ); //instance()->config() ); + saveMainWindowSettings( d->config, "MainWindow" ); + d->config->setGroup("MainWindow"); + KMdi::MdiMode modeToSave = mdiMode(); + if (d->mdiModeToSwitchAfterRestart!=(KMdi::MdiMode)0) + modeToSave = d->mdiModeToSwitchAfterRestart; + if (modeToSave == DEFAULT_MDI_MODE) + d->config->deleteEntry("MDIMode"); + else + d->config->writeEntry("MDIMode", modeToSave); + d->config->writeEntry("maximized childframes", isInMaximizedChildFrmMode()); + +// if (manager()->findWidgetParentDock(d->nav)->isVisible()) + if (d->saveSettingsForShowProjectNavigator) { + if (d->navWasVisibleBeforeProjectClosing) + d->config->deleteEntry("ShowProjectNavigator"); + else + d->config->writeEntry("ShowProjectNavigator", false); + } + + if (modeToSave==KMdi::ChildframeMode || modeToSave==KMdi::TabPageMode) { + if (d->propEditor && d->propEditorDockSeparatorPos >= 0 && d->propEditorDockSeparatorPos <= 100) { + d->config->setGroup("MainWindow"); + d->config->writeEntry("RightDockPosition", d->propEditorDockSeparatorPos); + } + else + d->propEditorDockSeparatorPos = 80; + if (d->nav && d->navDockSeparatorPos >= 0 && d->navDockSeparatorPos <= 100) { + d->config->setGroup("MainWindow"); + //KDockWidget *dw = (KDockWidget *)d->nav->parentWidget(); + //int w = dw->width(); + //int ww = width(); + //int d1 = (100 * dw->width()) / width() + 1; + //KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + //int d2 = ds->separatorPosInPercent(); + if (d->wasAutoOpen && d->dialogExistedBeforeCloseProject) { +#ifdef Q_WS_WIN + d->config->writeEntry("LeftDockPositionWithAutoOpen", + d->navDockSeparatorPos); +#endif +// d->config->writeEntry("LeftDockPosition", dw->width()); +// d->config->writeEntry("LeftDockPosition", d->nav->width()); + } else { +#ifdef Q_WS_WIN + if (d->dialogExistedBeforeCloseProject) + d->config->writeEntry("LeftDockPosition", d->navDockSeparatorPos); + else + d->config->writeEntry("LeftDockPosition", qRound(double(d->navDockSeparatorPos) / 0.77 + / (double(d->propEditorDockSeparatorPos) / 80) )); +#endif + } + } + } + + if (d->propEditor) { + d->config->setGroup("PropertyEditor"); + d->config->writeEntry("FontSize", d->propEditorTabWidget->font().pixelSize()); + } +} + +void +KexiMainWindowImpl::restoreWindowConfiguration(KConfig *config) +{ + kdDebug()<<"preparing session restoring"<<endl; + + config->setGroup("MainWindow"); + + QString dockGrp; + + if (kapp->isRestored()) + dockGrp=config->group()+"-Docking"; + else + dockGrp="MainWindow0-Docking"; + + if (config->hasGroup(dockGrp)) + readDockConfig(config,dockGrp); +} + +void +KexiMainWindowImpl::storeWindowConfiguration(KConfig *config) +{ + kdDebug()<<"preparing session saving"<<endl; + config->setGroup("MainWindow"); + QString dockGrp; + +#if KDE_IS_VERSION(3,1,9) && !defined(Q_WS_WIN) + if (kapp->sessionSaving()) + dockGrp=config->group()+"-Docking"; + else +#endif + dockGrp="MainWindow0-Docking"; + + kdDebug()<<"Before write dock config"<<endl; + writeDockConfig(config,dockGrp); + kdDebug()<<"After write dock config"<<endl; +} + +void +KexiMainWindowImpl::readProperties(KConfig *config) { + restoreWindowConfiguration(config); +} + +void +KexiMainWindowImpl::saveProperties(KConfig *config) +{ + storeWindowConfiguration(config); +// m_docManager->saveDocumentList (config); + // m_projectManager->saveProjectList (config); +} + +void +KexiMainWindowImpl::saveGlobalProperties( KConfig* sessionConfig ) { + storeWindowConfiguration(sessionConfig); +} + +void +KexiMainWindowImpl::registerChild(KexiDialogBase *dlg) +{ + kdDebug() << "KexiMainWindowImpl::registerChild()" << endl; + connect(dlg, SIGNAL(activated(KMdiChildView *)), + this, SLOT(activeWindowChanged(KMdiChildView *))); + connect(dlg, SIGNAL(dirtyChanged(KexiDialogBase*)), + this, SLOT(slotDirtyFlagChanged(KexiDialogBase*))); + +// connect(dlg, SIGNAL(childWindowCloseRequest(KMdiChildView *)), this, SLOT(childClosed(KMdiChildView *))); + if(dlg->id() != -1) { + d->insertDialog(dlg); + } + kdDebug() << "KexiMainWindowImpl::registerChild() ID = " << dlg->id() << endl; + + if (m_mdiMode==KMdi::ToplevelMode || m_mdiMode==KMdi::ChildframeMode) {//kmdi fix + //js TODO: check if taskbar is switched in menu + if (m_pTaskBar && !m_pTaskBar->isSwitchedOn()) + m_pTaskBar->switchOn(true); + } + //KMdiChildFrm *frm = dlg->mdiParent(); + //if (frm) { +// dlg->setMargin(20); + //dlg->setLineWidth(20); + //} +} + +void +KexiMainWindowImpl::updateDialogViewGUIClient(KXMLGUIClient *viewClient) +{ + if (viewClient!=d->curDialogViewGUIClient) { + //view clients differ + kdDebug()<<"KexiMainWindowImpl::activeWindowChanged(): old view gui client:" + <<(d->curDialogViewGUIClient ? d->curDialogViewGUIClient->xmlFile() : "") + <<" new view gui client: "<<( viewClient ? viewClient->xmlFile() : "") <<endl; + if (d->curDialogViewGUIClient) { + guiFactory()->removeClient(d->curDialogViewGUIClient); + } + if (viewClient) { + if (d->closedDialogViewGUIClient) { + //ooh, there is a client which dialog is already closed -- BUT it is the same client as our + //so: give up + } + else { + guiFactory()->addClient(viewClient); + } + } + } +} + +void KexiMainWindowImpl::updateCustomPropertyPanelTabs(KexiDialogBase *prevDialog, int prevViewMode) +{ + updateCustomPropertyPanelTabs( + prevDialog ? prevDialog->part() : 0, + prevDialog ? prevDialog->currentViewMode() : prevViewMode, + d->curDialog ? d->curDialog->part() : 0, + d->curDialog ? d->curDialog->currentViewMode() : Kexi::NoViewMode + ); +} + +void KexiMainWindowImpl::updateCustomPropertyPanelTabs( + KexiPart::Part *prevDialogPart, int prevViewMode, KexiPart::Part *curDialogPart, int curViewMode ) +{ + if (!d->propEditorTabWidget) + return; + + if (!curDialogPart + || (/*prevDialogPart &&*/ curDialogPart + && (prevDialogPart!=curDialogPart || prevViewMode!=curViewMode) + )) + { + if (d->partForPreviouslySetupPropertyPanelTabs) { + //remember current page number for this part + if (prevViewMode==Kexi::DesignViewMode && + ((KexiPart::Part*)d->partForPreviouslySetupPropertyPanelTabs != curDialogPart) //part changed + || curViewMode!=Kexi::DesignViewMode) //..or switching to other view mode + { + d->recentlySelectedPropertyPanelPages.insert( d->partForPreviouslySetupPropertyPanelTabs, + d->propEditorTabWidget->currentPageIndex() ); + } + } + + //delete old custom tabs (other than 'property' tab) + const uint count = d->propEditorTabWidget->count(); + for (uint i=1; i < count; i++) + d->propEditorTabWidget->removePage( d->propEditorTabWidget->page(1) ); + } + + //don't change anything if part is not switched nor view mode changed + if ((!prevDialogPart && !curDialogPart) + || (prevDialogPart == curDialogPart && prevViewMode==curViewMode) + || (curDialogPart && curViewMode!=Kexi::DesignViewMode)) + { + //new part for 'previously setup tabs' + d->partForPreviouslySetupPropertyPanelTabs = curDialogPart; + return; + } + + if (curDialogPart) { + //recreate custom tabs + curDialogPart->setupCustomPropertyPanelTabs(d->propEditorTabWidget, this); + + //restore current page number for this part + if (d->recentlySelectedPropertyPanelPages.contains( curDialogPart )) { + d->propEditorTabWidget->setCurrentPage( + d->recentlySelectedPropertyPanelPages[ curDialogPart ] + ); + } + } + + //new part for 'previously setup tabs' + d->partForPreviouslySetupPropertyPanelTabs = curDialogPart; +} + +void KexiMainWindowImpl::activeWindowChanged(KMdiChildView *v) +{ + KexiDialogBase *dlg = static_cast<KexiDialogBase *>(v); + kdDebug() << "KexiMainWindowImpl::activeWindowChanged() to = " << (dlg ? dlg->caption() : "<none>") << endl; + + KXMLGUIClient *client=0; //common for all views + KXMLGUIClient *viewClient=0; //specific for current dialog's view + KexiDialogBase* prevDialog = d->curDialog; + + if (!dlg) + client=0; + else if ( dlg->isRegistered()) { +// client=dlg->guiClient(); + client=dlg->commonGUIClient(); + viewClient=dlg->guiClient(); + if (d->closedDialogGUIClient) { + if (client!=d->closedDialogGUIClient) { + //ooh, there is a client which dialog is already closed -- and we don't want it + guiFactory()->removeClient(d->closedDialogGUIClient); + d->closedDialogGUIClient=0; + } + } + if (d->closedDialogViewGUIClient) { + if (viewClient!=d->closedDialogViewGUIClient) { + //ooh, there is a client which dialog is already closed -- and we don't want it + guiFactory()->removeClient(d->closedDialogViewGUIClient); + d->closedDialogViewGUIClient=0; + } + } + if (client!=d->curDialogGUIClient) { + //clients differ + kdDebug()<<"KexiMainWindowImpl::activeWindowChanged(): old gui client:" + <<(d->curDialogGUIClient ? d->curDialogGUIClient->xmlFile() : "") + <<" new gui client: "<<( client ? client->xmlFile() : "") <<endl; + if (d->curDialogGUIClient) { + guiFactory()->removeClient(d->curDialogGUIClient); + d->curDialog->detachFromGUIClient(); + } + if (client) { + if (d->closedDialogGUIClient) { + //ooh, there is a client which dialog is already closed -- BUT it is the same client as our + //so: give up + } + else { + guiFactory()->addClient(client); + } + dlg->attachToGUIClient(); + } + } else { + //clients are the same + if ((KexiDialogBase*)d->curDialog!=dlg) { + if (d->curDialog) + d->curDialog->detachFromGUIClient(); + if (dlg) + dlg->attachToGUIClient(); + } + } + updateDialogViewGUIClient(viewClient); +/* if (viewClient!=d->curDialogViewGUIClient) { + //view clients differ + kdDebug()<<"KexiMainWindowImpl::activeWindowChanged(): old view gui client:" + <<d->curDialogViewGUIClient<<" new view gui client: "<<viewClient<<endl; + if (d->curDialogViewGUIClient) { + guiFactory()->removeClient(d->curDialogViewGUIClient); + } + if (viewClient) { + if (d->closedDialogViewGUIClient) { + //ooh, there is a client which dialog is already closed -- BUT it is the same client as our + //so: give up + } + else { + guiFactory()->addClient(viewClient); + } + } + }*/ + } + bool update_dlg_caption = dlg && dlg!=(KexiDialogBase*)d->curDialog && dlg->mdiParent(); + + if (d->curDialogGUIClient && !client) + guiFactory()->removeClient(d->curDialogGUIClient); + d->curDialogGUIClient=client; + + if (d->curDialogViewGUIClient && !viewClient) + guiFactory()->removeClient(d->curDialogViewGUIClient); + d->curDialogViewGUIClient=viewClient; + + bool dialogChanged = ((KexiDialogBase*)d->curDialog)!=dlg; + + if (dialogChanged) { + if (d->curDialog) { + //inform previously activated dialog about deactivation + d->curDialog->deactivate(); + } + } + d->curDialog=dlg; + +//moved below: propertySetSwitched(d->curDialog); + + updateCustomPropertyPanelTabs(prevDialog, prevDialog ? prevDialog->currentViewMode() : Kexi::NoViewMode); + + // inform the current view of the new dialog about property switching + // (this will also call KexiMainWindowImpl::propertySetSwitched() to update the current property editor's set + if (dialogChanged && d->curDialog) + d->curDialog->selectedView()->propertySetSwitched(); + + if (dialogChanged) { +// invalidateSharedActions(); + //update property editor's contents... +// if ((KexiPropertyBuffer*)d->propBuffer!=d->curDialog->propertyBuffer()) { +// propertyBufferSwitched();//d->curDialog); +// d->propBuffer = d->curDialog->propertyBuffer(); +// d->propEditor->editor()->setBuffer( d->propBuffer ); +// } + if (d->curDialog && d->curDialog->currentViewMode()!=0) //on opening new dialog it can be 0; we don't want this + d->updatePropEditorVisibility(d->curDialog->currentViewMode()); + } + + //update caption... + if (update_dlg_caption) {//d->curDialog is != null for sure + slotCaptionForCurrentMDIChild(d->curDialog->mdiParent()->state()==KMdiChildFrm::Maximized); + } +// if (!d->curDialog.isNull()) +// d->last_checked_mode = d->actions_for_view_modes[ d->curDialog->currentViewMode() ]; + invalidateViewModeActions(); + invalidateActions(); + d->updateFindDialogContents(); + if (dlg) + dlg->setFocus(); +} + +bool +KexiMainWindowImpl::activateWindow(int id) +{ + kdDebug() << "KexiMainWindowImpl::activateWindow()" << endl; +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + return activateWindow( d->openedDialogFor( id, pendingType ) ); +#else + return activateWindow( d->openedDialogFor( id ) ); +#endif +} + +bool +KexiMainWindowImpl::activateWindow(KexiDialogBase *dlg) +{ + kdDebug() << "KexiMainWindowImpl::activateWindow(KexiDialogBase *)" << endl; + if(!dlg) + return false; + + d->focus_before_popup = dlg; + dlg->activate(); + return true; +} + +void +KexiMainWindowImpl::childClosed(KMdiChildView *v) +{ + KexiDialogBase *dlg = static_cast<KexiDialogBase *>(v); + d->removeDialog(dlg->id()); +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog(dlg->id()); +#endif + + //focus navigator if nothing else available + if (d->openedDialogsCount() == 0) + d->nav->setFocus(); +} + +void +KexiMainWindowImpl::slotShowSettings() +{ + KEXI_UNFINISHED(d->action_configure->text()); +//TODO KexiSettings s(this); +// s.exec(); +} + +void +KexiMainWindowImpl::slotConfigureKeys() +{ +/* KKeyDialog dlg; + dlg.insert( actionCollection() ); + dlg.configure();*/ + KKeyDialog::configure( actionCollection(), false/*bAllowLetterShortcuts*/, this ); +} + +void +KexiMainWindowImpl::slotConfigureToolbars() +{ + KEditToolbar edit(factory()); +// connect(&edit,SIGNAL(newToolbarConfig()),this,SLOT(slotNewToolbarConfig())); + (void) edit.exec(); +} + +void +KexiMainWindowImpl::slotProjectNew() +{ + if (!d->prj) { + //create within this instance + createBlankProject(); + return; + } +//TODO use KexiStartupDialog(KexiStartupDialog::Templates...) + + bool cancel; + QString fileName; + KexiProjectData *new_data = createBlankProjectData( + cancel, + false, /* do not confirm prj overwrites: user will be asked on process startup */ + &fileName //shortcut fname + ); + if (!new_data) + return; + + QStringList args; + args << qApp->applicationFilePath() << "-create-opendb"; + if (new_data->connectionData()->fileName().isEmpty()) { + //server based - pass .kexic file + if (fileName.isEmpty()) + return; + args << new_data->databaseName() << fileName; + //args << "--skip-conn-dialog"; //user does not expect conn. dialog to be shown here + } + else { + //file based + fileName = new_data->connectionData()->fileName(); + args << fileName; + } +//todo: pass new_data->caption() + //start new instance +//! @todo use KProcess? + QProcess proc(args, this, "process"); + proc.setCommunication((QProcess::Communication)0); +// proc.setWorkingDirectory( QFileInfo(new_data->connectionData()->fileName()).dir(true) ); + proc.setWorkingDirectory( QFileInfo(fileName).dir(true) ); + if (!proc.start()) { + d->showStartProcessMsg(args); + } + delete new_data; +} + +void +KexiMainWindowImpl::createKexiProject(KexiProjectData* new_data) +{ + d->prj = new KexiProject( new_data, this ); +// d->prj = ::createKexiProject(new_data); +//provided by KexiMessageHandler connect(d->prj, SIGNAL(error(const QString&,KexiDB::Object*)), this, SLOT(showErrorMessage(const QString&,KexiDB::Object*))); +//provided by KexiMessageHandler connect(d->prj, SIGNAL(error(const QString&,const QString&)), this, SLOT(showErrorMessage(const QString&,const QString&))); + connect(d->prj, SIGNAL(itemRenamed(const KexiPart::Item&, const QCString&)), this, SLOT(slotObjectRenamed(const KexiPart::Item&, const QCString&))); + + if (d->nav) + connect(d->prj, SIGNAL(itemRemoved(const KexiPart::Item&)), d->nav, SLOT(slotRemoveItem(const KexiPart::Item&))); +} + +KexiProjectData* +KexiMainWindowImpl::createBlankProjectData(bool &cancelled, bool confirmOverwrites, + QString* shortcutFileName) +{ + cancelled = false; + KexiNewProjectWizard wiz(Kexi::connset(), 0, "KexiNewProjectWizard", true); + wiz.setConfirmOverwrites(confirmOverwrites); + if (wiz.exec() != QDialog::Accepted) { + cancelled=true; + return 0; + } + + KexiProjectData *new_data; + + if (shortcutFileName) + *shortcutFileName = QString::null; + if (wiz.projectConnectionData()) { + //server-based project + KexiDB::ConnectionData *cdata = wiz.projectConnectionData(); + kdDebug() << "DBNAME: " << wiz.projectDBName() << " SERVER: " << cdata->serverInfoString() << endl; + new_data = new KexiProjectData( *cdata, wiz.projectDBName(), wiz.projectCaption() ); + if (shortcutFileName) + *shortcutFileName = Kexi::connset().fileNameForConnectionData(cdata); + } + else if (!wiz.projectDBName().isEmpty()) { + //file-based project + KexiDB::ConnectionData cdata; + cdata.caption = wiz.projectCaption(); + cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName(); + cdata.setFileName( wiz.projectDBName() ); + new_data = new KexiProjectData( cdata, wiz.projectDBName(), wiz.projectCaption() ); + } + else { + cancelled = true; + return 0; + } + return new_data; +} + +tristate +KexiMainWindowImpl::createBlankProject() +{ + bool cancel; + KexiProjectData *new_data = createBlankProjectData(cancel); + if (cancel) + return cancelled; + if (!new_data) + return false; + + createKexiProject( new_data ); + + tristate res = d->prj->create(true /*overwrite*/ ); + if (res != true) { + delete d->prj; + d->prj = 0; + return res; + } + kdDebug() << "KexiMainWindowImpl::slotProjectNew(): new project created --- " << endl; + initNavigator(); + Kexi::recentProjects().addProjectData( new_data ); + + invalidateActions(); + updateAppCaption(); + return true; +} + +void +KexiMainWindowImpl::slotProjectOpen() +{ + KexiStartupDialog dlg( + KexiStartupDialog::OpenExisting, 0, Kexi::connset(), Kexi::recentProjects(), + this, "KexiOpenDialog"); + + if (dlg.exec()!=QDialog::Accepted) + return; + + openProject(dlg.selectedFileName(), dlg.selectedExistingConnection()); +} + +tristate KexiMainWindowImpl::openProject(const QString& aFileName, + const QString& fileNameForConnectionData, const QString& dbName) +{ + if (d->prj) + return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName); + + KexiDB::ConnectionData *cdata = 0; + if (!fileNameForConnectionData.isEmpty()) { + cdata = Kexi::connset().connectionDataForFileName( fileNameForConnectionData ); + if (!cdata) { + kdWarning() << "KexiMainWindowImpl::openProject() cdata?" << endl; + return false; + } + } + return openProject(aFileName, cdata, dbName); +} + +tristate KexiMainWindowImpl::openProject(const QString& aFileName, + KexiDB::ConnectionData *cdata, const QString& dbName, + const QValueList<KexiProjectData::ObjectInfo>& autoopenObjects) +{ + if (d->prj) { + return openProjectInExternalKexiInstance(aFileName, cdata, dbName); + } + + KexiProjectData* projectData = 0; + bool deleteAfterOpen = false; + if (cdata) { + //server-based project + if (dbName.isEmpty()) {//no database name given, ask user + bool cancel; + projectData = Kexi::startupHandler().selectProject( cdata, cancel, this ); + if (cancel) + return cancelled; + } + else { +//! @todo caption arg? + projectData = new KexiProjectData( *cdata, dbName ); + deleteAfterOpen = true; + } + } + else { +// QString selFile = dlg.selectedExistingFile(); + if (aFileName.isEmpty()) { + kdWarning() << "KexiMainWindowImpl::openProject(): aFileName.isEmpty()" << endl; + return false; + } + //file-based project + kdDebug() << "Project File: " << aFileName << endl; + KexiDB::ConnectionData cdata; + cdata.setFileName( aFileName ); +// cdata.driverName = KexiStartupHandler::detectDriverForFile( cdata.driverName, fileName, this ); + QString detectedDriverName; + KexiStartupData::Import importActionData; + const tristate res = KexiStartupHandler::detectActionForFile( + importActionData, detectedDriverName, cdata.driverName, aFileName, this ); + if (true != res) + return res; + + if (importActionData) { //importing requested + return showProjectMigrationWizard( importActionData.mimeType, importActionData.fileName ); + } + cdata.driverName = detectedDriverName; + + if (cdata.driverName.isEmpty()) + return false; + + //opening requested + projectData = new KexiProjectData(cdata, aFileName); + deleteAfterOpen = true; + } + if (!projectData) + return false; + projectData->autoopenObjects = autoopenObjects; + const tristate res = openProject(*projectData); + if (deleteAfterOpen) //projectData object has been copied + delete projectData; + return res; +} + +tristate KexiMainWindowImpl::openProjectInExternalKexiInstance(const QString& aFileName, + KexiDB::ConnectionData *cdata, const QString& dbName) +{ + QString fileNameForConnectionData; + if (aFileName.isEmpty()) { //try .kexic file + if (cdata) + fileNameForConnectionData = Kexi::connset().fileNameForConnectionData(cdata); + } + return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName); +} + +tristate KexiMainWindowImpl::openProjectInExternalKexiInstance(const QString& aFileName, + const QString& fileNameForConnectionData, const QString& dbName) +{ + QString fileName(aFileName); + QStringList args; + args << qApp->applicationFilePath(); + // open a file-based project or a server connection provided as a .kexic file + // (we have no other simple way to provide the startup data to a new process) + if (fileName.isEmpty()) { //try .kexic file + if (!fileNameForConnectionData.isEmpty()) + args << "--skip-conn-dialog"; //user does not expect conn. dialog to be shown here + + if (dbName.isEmpty()) { //use 'kexi --skip-conn-dialog file.kexic' + fileName = fileNameForConnectionData; + } + else { //use 'kexi --skip-conn-dialog --connection file.kexic dbName' + args << "--connection" << fileNameForConnectionData; + fileName = dbName; + } + } + if (fileName.isEmpty()) { + kdWarning() << "KexiMainWindowImpl::openProjectInExternalKexiInstance() fileName?" << endl; + return false; + } +//! @todo use KRun + args << fileName; + QProcess proc(args, this, "process"); + proc.setWorkingDirectory( QFileInfo(fileName).dir(true) ); + const bool ok = proc.start(); + if (!ok) { + d->showStartProcessMsg(args); + } + return ok; +} + +void +KexiMainWindowImpl::slotProjectOpenRecentAboutToShow() +{ + /* + //setup + KPopupMenu *popup = d->action_open_recent->popupMenu(); + const int cnt = popup->count(); + //remove older + for (int i = 0; i<cnt; i++) { + int id = popup->idAt(0); + if (id==d->action_open_recent_more_id) + break; + if (id>=0) { + popup->removeItem(id); + } + } + //insert current items + int cur_id = 0, cur_idx = 0; + //TODO: + cur_id = popup->insertItem("My example project 1", ++cur_id, cur_idx++); + cur_id = popup->insertItem("My example project 2", ++cur_id, cur_idx++); + cur_id = popup->insertItem("My example project 3", ++cur_id, cur_idx++); + */ + + //show recent databases + KPopupMenu *popup = d->action_open_recent->popupMenu(); + popup->clear(); +#if 0 + d->action_open_recent_projects_title_id = popup->insertTitle(i18n("Recently Opened Databases")); +#endif +// int action_open_recent_projects_title_index = popup->indexOf(d->action_open_recent_projects_title_id); +// int count = popup->count(); +// int action_open_recent_connections_title_index = popup->indexOf(d->action_open_recent_connections_title_id); +// for (int i=action_open_recent_projects_title_index+1; +// i<action_open_recent_connections_title_index; i++) +// { +// popup->removeItemAt(action_open_recent_projects_title_index+1); +// } + +// int cur_idx = action_open_recent_projects_title_index+1; + popup->insertItem(SmallIconSet("kexiproject_sqlite"), "My project 1"); + popup->insertItem(SmallIconSet("kexiproject_sqlite"), "My project 2"); + popup->insertItem(SmallIconSet("kexiproject_sqlite"), "My project 3"); + +#if 0 + //show recent connections + d->action_open_recent_connections_title_id = + d->action_open_recent->popupMenu()->insertTitle(i18n("Recently Connected Database Servers")); + +// cur_idx = popup->indexOf(d->action_open_recent_connections_title_id) + 1; +// for (int i=cur_idx; i<count; i++) { +// popup->removeItemAt(cur_idx); +// } + popup->insertItem(SmallIconSet("socket"), "My connection 1"); + popup->insertItem(SmallIconSet("socket"), "My connection 2"); + popup->insertItem(SmallIconSet("socket"), "My connection 3"); + popup->insertItem(SmallIconSet("socket"), "My connection 4"); +#endif +} + +void +KexiMainWindowImpl::slotProjectOpenRecent(int id) +{ + if (id<0) // || id==d->action_open_recent_more_id) + return; + kdDebug() << "KexiMainWindowImpl::slotProjectOpenRecent("<<id<<")"<<endl; +} + +void +KexiMainWindowImpl::slotProjectOpenRecentMore() +{ + KEXI_UNFINISHED(i18n("Open Recent")); +} + +void +KexiMainWindowImpl::slotProjectSave() +{ + if (!d->curDialog) + return; + saveObject( d->curDialog ); + updateAppCaption(); + invalidateActions(); +} + +void +KexiMainWindowImpl::slotProjectSaveAs() +{ + KEXI_UNFINISHED(i18n("Save object as")); +} + +void +KexiMainWindowImpl::slotProjectPrint() +{ + if (d->curDialog && d->curDialog->partItem()) + printItem(d->curDialog->partItem()); +} + +void +KexiMainWindowImpl::slotProjectPrintPreview() +{ + if (d->curDialog && d->curDialog->partItem()) + printPreviewForItem(d->curDialog->partItem()); +} + +void +KexiMainWindowImpl::slotProjectPageSetup() +{ + if (d->curDialog && d->curDialog->partItem()) + showPageSetupForItem(d->curDialog->partItem()); +} + +void KexiMainWindowImpl::slotProjectExportDataTable() +{ + if (d->curDialog && d->curDialog->partItem()) + exportItemAsDataTable(d->curDialog->partItem()); +} + +void +KexiMainWindowImpl::slotProjectProperties() +{ + //TODO: load the implementation not the ui :) +// ProjectSettingsUI u(this); +// u.exec(); +} + +void +KexiMainWindowImpl::slotProjectClose() +{ + closeProject(); +} + +void KexiMainWindowImpl::slotProjectRelations() +{ + if (!d->prj) + return; + KexiDialogBase *d = KexiInternalPart::createKexiDialogInstance("relation", this, this); + activateWindow(d); +} + +void KexiMainWindowImpl::slotImportFile() +{ + KEXI_UNFINISHED("Import: " + i18n("From File...")); +} + +void KexiMainWindowImpl::slotImportServer() +{ + KEXI_UNFINISHED("Import: " + i18n("From Server...")); +} + +void +KexiMainWindowImpl::slotProjectQuit() +{ + if (~ closeProject()) + return; + close(); +} + +void KexiMainWindowImpl::slotViewNavigator() +{ + if (!d->nav || !d->navToolWindow) + return; + if (!d->nav->isVisible()) + makeWidgetDockVisible(d->nav); +// makeDockVisible(dynamic_cast<KDockWidget*>(d->navToolWindow->wrapperWidget())); +// d->navToolWindow->wrapperWidget()->show(); +// d->navToolWindow->show(KDockWidget::DockLeft, getMainDockWidget()); + + d->navToolWindow->wrapperWidget()->raise(); +// + d->block_KMdiMainFrm_eventFilter=true; + d->nav->setFocus(); + d->block_KMdiMainFrm_eventFilter=false; +} + +void KexiMainWindowImpl::slotViewMainArea() +{ + if (d->curDialog) + d->curDialog->setFocus(); +} + +void KexiMainWindowImpl::slotViewPropertyEditor() +{ + if (!d->propEditor || !d->propEditorToolWindow) + return; + +//js d->config->setGroup("MainWindow"); +//js ds->setSeparatorPos(d->config->readNumEntry("RightDockPosition", 80/* % */), true); + + if (!d->propEditorTabWidget->isVisible()) + makeWidgetDockVisible(d->propEditorTabWidget); + + + d->propEditorToolWindow->wrapperWidget()->raise(); + + d->block_KMdiMainFrm_eventFilter=true; + if (d->propEditorTabWidget->currentPage()) + d->propEditorTabWidget->currentPage()->setFocus(); + d->block_KMdiMainFrm_eventFilter=false; + +/*#if defined(KDOCKWIDGET_P) + KDockWidget *dw = (KDockWidget *)d->propEditor->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + ds->setSeparatorPos(80,true);//d->config->readNumEntry("RightDockPosition", 80), true); +#endif*/ +} + +bool KexiMainWindowImpl::switchToViewMode(int viewMode) +{ + if (!d->curDialog) { + d->toggleLastCheckedMode(); + return false; + } + if (!d->curDialog->supportsViewMode( viewMode )) { + showErrorMessage(i18n("Selected view is not supported for \"%1\" object.") + .arg(d->curDialog->partItem()->name()), + i18n("Selected view (%1) is not supported by this object type (%2).") + .arg(Kexi::nameForViewMode(viewMode)) + .arg(d->curDialog->part()->instanceCaption()) ); + d->toggleLastCheckedMode(); + return false; + } + int prevViewMode = d->curDialog->currentViewMode(); + updateCustomPropertyPanelTabs(d->curDialog->part(), prevViewMode, + d->curDialog->part(), viewMode ); + tristate res = d->curDialog->switchToViewMode( viewMode ); + if (!res) { + updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert + showErrorMessage(i18n("Switching to other view failed (%1).").arg(Kexi::nameForViewMode(viewMode)), + d->curDialog); + d->toggleLastCheckedMode(); + return false; + } + if (~res) { + updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert + d->toggleLastCheckedMode(); + return false; + } + + //view changed: switch to this view's gui client + KXMLGUIClient *viewClient=d->curDialog->guiClient(); + updateDialogViewGUIClient(viewClient); + if (d->curDialogViewGUIClient && !viewClient) + guiFactory()->removeClient(d->curDialogViewGUIClient); + d->curDialogViewGUIClient=viewClient; //remember + + d->updatePropEditorVisibility(viewMode); + invalidateProjectWideActions(); + invalidateSharedActions(); + d->updateFindDialogContents(); + return true; +} + + +void KexiMainWindowImpl::slotViewDataMode() +{ + switchToViewMode(Kexi::DataViewMode); +} + +void KexiMainWindowImpl::slotViewDesignMode() +{ + switchToViewMode(Kexi::DesignViewMode); +} + +void KexiMainWindowImpl::slotViewTextMode() +{ + switchToViewMode(Kexi::TextViewMode); +} + +void KexiMainWindowImpl::closeWindow(KMdiChildView *pWnd, bool layoutTaskBar) +{ + if (d->insideCloseDialog && dynamic_cast<KexiDialogBase *>(pWnd)) { + d->windowsToClose.append(dynamic_cast<KexiDialogBase *>(pWnd)); + return; + } + /*moved to closeDialog() + if (pWnd == d->curDialog && !pWnd->isAttached()) { + if (d->propEditor) { + // ah, closing detached window - better switch off property buffer right now... + d->propBuffer = 0; + d->propEditor->editor()->setBuffer( 0, false ); + } + } + */ + closeDialog(dynamic_cast<KexiDialogBase *>(pWnd), layoutTaskBar); +} + +tristate KexiMainWindowImpl::getNewObjectInfo( + KexiPart::Item *partItem, KexiPart::Part *part, + bool& allowOverwriting, const QString& messageWhenAskingForName ) +{ + //data was never saved in the past -we need to create a new object at the backend + KexiPart::Info *info = part->info(); +#ifdef KEXI_ADD_CUSTOM_OBJECT_CREATION +# include "keximainwindowimpl_customobjcreation.h" +#endif + if (!d->nameDialog) { + d->nameDialog = new KexiNameDialog( + messageWhenAskingForName, this, "nameDialog"); + //check if that name is allowed + d->nameDialog->widget()->addNameSubvalidator( + new KexiDB::ObjectNameValidator(project()->dbConnection()->driver(), 0, "sub")); + } + else { + d->nameDialog->widget()->setMessageText( messageWhenAskingForName ); + } + d->nameDialog->widget()->setCaptionText(partItem->caption()); + d->nameDialog->widget()->setNameText(partItem->name()); + d->nameDialog->setCaption(i18n("Save Object As")); + d->nameDialog->setDialogIcon( DesktopIcon( info->itemIcon(), KIcon::SizeMedium ) ); + allowOverwriting = false; + bool found; + do { + if (d->nameDialog->exec()!=QDialog::Accepted) + return cancelled; + //check if that name already exists + KexiDB::SchemaData tmp_sdata; + tristate result = project()->dbConnection()->loadObjectSchemaData( + info->projectPartID(), + d->nameDialog->widget()->nameText(), tmp_sdata ); + if (!result) + return false; + found = result==true; + if (found) { + if (allowOverwriting) { + int res = KMessageBox::warningYesNoCancel(this, + "<p>"+part->i18nMessage("Object \"%1\" already exists.", 0) + .arg(d->nameDialog->widget()->nameText()) + +"</p><p>"+i18n("Do you want to replace it?")+"</p>", 0, + KGuiItem(i18n("&Replace"), "button_yes"), + KGuiItem(i18n("&Choose Other Name...")), + QString::null, KMessageBox::Notify|KMessageBox::Dangerous); + if (res == KMessageBox::No) + continue; + else if (res == KMessageBox::Cancel) + return cancelled; + else {//yes + allowOverwriting = true; + break; + } + } + else { + KMessageBox::information(this, + "<p>"+part->i18nMessage("Object \"%1\" already exists.", 0) + .arg(d->nameDialog->widget()->nameText()) + +"</p><p>"+i18n("Please choose other name.")+"</p>"); +// " For example: Table \"my_table\" already exists" , +// "%1 \"%2\" already exists.\nPlease choose other name.") +// .arg(dlg->part()->instanceName()).arg(d->nameDialog->widget()->nameText())); + continue; + } + } + } + while (found); + + //update name and caption + partItem->setName( d->nameDialog->widget()->nameText() ); + partItem->setCaption( d->nameDialog->widget()->captionText() ); + return true; +} + +tristate KexiMainWindowImpl::saveObject( KexiDialogBase *dlg, const QString& messageWhenAskingForName, + bool dontAsk) +{ + tristate res; + if (!dlg->neverSaved()) { + //data was saved in the past -just save again + res = dlg->storeData(dontAsk); + if (!res) + showErrorMessage(i18n("Saving \"%1\" object failed.").arg(dlg->partItem()->name()), + d->curDialog); + return res; + } + + const int oldItemID = dlg->partItem()->identifier(); + + bool allowOverwriting = false; + res = getNewObjectInfo( dlg->partItem(), dlg->part(), allowOverwriting, + messageWhenAskingForName ); + if (res != true) + return res; + + res = dlg->storeNewData(); + if (~res) + return cancelled; + if (!res) { + showErrorMessage(i18n("Saving new \"%1\" object failed.").arg(dlg->partItem()->name()), + d->curDialog); + return false; + } + + //update navigator +//this is alreday done in KexiProject::addStoredItem(): d->nav->addItem(dlg->partItem()); + //item id changed to final one: update association in dialogs' dictionary +// d->dialogs.take(oldItemID); + d->updateDialogId(dlg, oldItemID); + invalidateProjectWideActions(); + return true; +} + +tristate KexiMainWindowImpl::closeDialog(KexiDialogBase *dlg) +{ + return closeDialog(dlg, true); +} + +tristate KexiMainWindowImpl::closeDialog(KexiDialogBase *dlg, bool layoutTaskBar, bool doNotSaveChanges) +{ + if (!dlg) + return true; + if (d->insideCloseDialog) + return true; + +#ifndef KEXI_NO_PENDING_DIALOGS + d->addItemToPendingDialogs(dlg->partItem(), Private::DialogClosingJob); +#endif + + d->insideCloseDialog = true; + + if (dlg == d->curDialog && !dlg->isAttached()) { + if (d->propEditor) { + // ah, closing detached window - better switch off property buffer right now... + d->propBuffer = 0; + d->propEditor->editor()->changeSet( 0, false ); + } + } + + bool remove_on_closing = dlg->partItem() ? dlg->partItem()->neverSaved() : false; + if (dlg->dirty() && !d->forceDialogClosing && !doNotSaveChanges) { + //more accurate tool tips and what's this + KGuiItem saveChanges( KStdGuiItem::save() ); + saveChanges.setToolTip(i18n("Save changes")); + saveChanges.setWhatsThis( + i18n( "Pressing this button will save all recent changes made in \"%1\" object." ) + .arg(dlg->partItem()->name()) ); + KGuiItem discardChanges( KStdGuiItem::discard() ); + discardChanges.setWhatsThis( + i18n( "Pressing this button will discard all recent changes made in \"%1\" object." ) + .arg(dlg->partItem()->name()) ); + + //dialog's data is dirty: + //--adidional message, e.g. table designer will return + // "Note: This table is already filled with data which will be removed." + // if the dlg is in design view mode. + QString additionalMessage = dlg->part()->i18nMessage( + ":additional message before saving design", dlg); + if (additionalMessage.startsWith(":")) + additionalMessage = QString::null; + if (!additionalMessage.isEmpty()) + additionalMessage = "<p>"+additionalMessage+"</p>"; + + const int questionRes = KMessageBox::warningYesNoCancel( this, + "<p>"+dlg->part()->i18nMessage("Design of object \"%1\" has been modified.", dlg) + .arg(dlg->partItem()->name())+"</p><p>"+i18n("Do you want to save changes?")+"</p>" + + additionalMessage /*may be empty*/, + QString::null, + saveChanges, + discardChanges); + if (questionRes==KMessageBox::Cancel) { +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog(dlg->id()); +#endif + d->insideCloseDialog = false; + d->windowsToClose.clear(); //give up with 'close all' + return cancelled; + } + if (questionRes==KMessageBox::Yes) { + //save it +// if (!dlg->storeData()) + tristate res = saveObject( dlg, QString::null, true /*dontAsk*/ ); + if (!res || ~res) { +//js:TODO show error info; (retry/ignore/cancel) +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog(dlg->id()); +#endif + d->insideCloseDialog = false; + d->windowsToClose.clear(); //give up with 'close all' + return res; + } + remove_on_closing = false; + } + } + + const int dlg_id = dlg->id(); //remember now, because removeObject() can destruct partitem object + + if (remove_on_closing) { + //we won't save this object, and it was never saved -remove it + if (!removeObject( dlg->partItem(), true )) { +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog(dlg->id()); +#endif + //msg? + //TODO: ask if we'd continue and return true/false + d->insideCloseDialog = false; + d->windowsToClose.clear(); //give up with 'close all' + return false; + } + } + else { + //not dirty now + if(d->nav) + d->nav->updateItemName( *dlg->partItem(), false ); + } + + d->removeDialog(dlg_id); //don't remove -KMDI will do that + //also remove from 'print setup dialogs' cache, if needed + int printedObjectID = 0; + if (d->pageSetupDialogItemID2dataItemID_map.contains(dlg_id)) + printedObjectID = d->pageSetupDialogItemID2dataItemID_map[ dlg_id ]; + d->pageSetupDialogs.take(printedObjectID); + + KXMLGUIClient *client = dlg->commonGUIClient(); + KXMLGUIClient *viewClient = dlg->guiClient(); + if (d->curDialogGUIClient==client) { + d->curDialogGUIClient=0; + } + if (d->curDialogViewGUIClient==viewClient) { + d->curDialogViewGUIClient=0; + } + if (client) { + //sanity: ouch, it is not removed yet? - do it now + if (d->closedDialogGUIClient && d->closedDialogGUIClient!=client) + guiFactory()->removeClient(d->closedDialogGUIClient); + if (d->openedDialogsCount()==0) {//now there is no dialogs - remove client RIGHT NOW! + d->closedDialogGUIClient=0; + guiFactory()->removeClient(client); + } + else { + //remember this - and MAYBE remove later, if needed + d->closedDialogGUIClient=client; + } + } + if (viewClient) { + //sanity: ouch, it is not removed yet? - do it now + if (d->closedDialogViewGUIClient && d->closedDialogViewGUIClient!=viewClient) + guiFactory()->removeClient(d->closedDialogViewGUIClient); + if (d->openedDialogsCount()==0) {//now there is no dialogs - remove client RIGHT NOW! + d->closedDialogViewGUIClient=0; + guiFactory()->removeClient(viewClient); + } + else { + //remember this - and MAYBE remove later, if needed + d->closedDialogViewGUIClient=viewClient; + } + } + + const bool isInMaximizedChildFrmMode = this->isInMaximizedChildFrmMode(); + + KMdiMainFrm::closeWindow(dlg, layoutTaskBar); + + //focus navigator if nothing else available + if (d->openedDialogsCount()==0) { + d->maximizeFirstOpenedChildFrm = isInMaximizedChildFrmMode; + if (d->nav) + d->nav->setFocus(); + d->updatePropEditorVisibility(0); + } + + invalidateActions(); + d->insideCloseDialog = false; + if (!d->windowsToClose.isEmpty()) //continue 'close all' + closeDialog(d->windowsToClose.take(0), true); + +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog( dlg_id ); + + //perform pending global action that was suspended: + if (!d->pendingDialogsExist()) { + d->executeActionWhenPendingJobsAreFinished(); + } +#endif + return true; +} + +void KexiMainWindowImpl::detachWindow(KMdiChildView *pWnd,bool bShow) +{ + KMdiMainFrm::detachWindow(pWnd,bShow); + // update icon - from small to large + pWnd->setIcon( DesktopIcon( static_cast<KexiDialogBase *>(pWnd)->itemIcon() ) ); +// pWnd->setIcon( DesktopIcon( static_cast<KexiDialogBase *>(pWnd)->part()->info()->itemIcon() ) ); + if (dynamic_cast<KexiDialogBase*>(pWnd)) + dynamic_cast<KexiDialogBase*>(pWnd)->sendDetachedStateToCurrentView(); +} + +void KexiMainWindowImpl::attachWindow(KMdiChildView *pWnd, bool /*bShow*/, bool bAutomaticResize) +{ +// if (bAutomaticResize || w->size().isEmpty() || (w->size() == QSize(1,1))) { + KMdiMainFrm::attachWindow(pWnd,true,bAutomaticResize); + //for dialogs in normal state: decrease dialog's height if it exceeds area contents + if (pWnd->mdiParent()->state() == KMdiChildFrm::Normal + && pWnd->geometry().bottom() > pWnd->mdiParent()->mdiAreaContentsRect().bottom()) + { + QRect r = pWnd->geometry(); + r.setBottom( pWnd->mdiParent()->mdiAreaContentsRect().bottom() - 5 ); + pWnd->setGeometry( r ); + } + // update icon - from large to small + pWnd->mdiParent()->setIcon( SmallIcon( static_cast<KexiDialogBase *>(pWnd)->itemIcon() ) ); + if (dynamic_cast<KexiDialogBase*>(pWnd)) + dynamic_cast<KexiDialogBase*>(pWnd)->sendAttachedStateToCurrentView(); +} + +QWidget* KexiMainWindowImpl::findWindow(QWidget *w) +{ + while (w && !acceptsSharedActions(w)) + w = w->parentWidget(); + return w; +} + +bool KexiMainWindowImpl::acceptsSharedActions(QObject *w) +{ + return w->inherits("KexiDialogBase") || w->inherits("KexiViewBase"); +} + +bool KexiMainWindowImpl::eventFilter( QObject *obj, QEvent * e ) +{ + //KexiVDebug << "eventFilter: " <<e->type() << " " <<obj->name()<<endl; + if (e->type()==QEvent::KeyPress) { + KexiVDebug << "KEY EVENT " << QString::number(static_cast<QKeyEvent*>(e)->key(), 16) << endl; + KexiVDebug << endl; + } + if (e->type()==QEvent::AccelOverride) { + //KexiVDebug << "AccelOverride EVENT " << static_cast<QKeyEvent*>(e)->key() << " " << static_cast<QKeyEvent*>(e)->state() == ControlButton << endl; + + //avoid sending CTRL+Tab key twice for tabbed/ideal mode, epecially for win32 + if (static_cast<QKeyEvent*>(e)->key()==Qt::Key_Tab && static_cast<QKeyEvent*>(e)->state() == ControlButton) { + if (d->action_window_next->shortcut().keyCodeQt()==Qt::Key_Tab+Qt::CTRL && d->action_window_next->shortcut().count()==1 + && (mdiMode()==KMdi::TabPageMode || mdiMode()==KMdi::IDEAlMode)) + { + static_cast<QKeyEvent*>(e)->accept(); + } + } + } + if (e->type()==QEvent::Close) { + KexiVDebug << "Close EVENT" << endl; + } + if (e->type()==QEvent::Resize) { + KexiVDebug << "Resize EVENT" << endl; + } + if (e->type()==QEvent::ShowMaximized) { + KexiVDebug << "ShowMaximized EVENT" << endl; + } + +/* if (obj==d->propEditor) { + if (e->type()==QEvent::Resize) { + d->updatePropEditorDockWidthInfo(); + } + }*/ + + QWidget *focus_w = 0; + if (obj->inherits("QPopupMenu")) { + /* Fixes for popup menus behaviour: + For hiding/showing: focus previously (d->focus_before_popup) + focused window, if known, otherwise focus currently focused one. + And: just invalidate actions. + */ + if (e->type()==QEvent::Hide || e->type()==QEvent::Show) { + KexiVDebug << e->type() << endl; + focus_w = focusWindow(); + if (!d->focus_before_popup.isNull()) { + d->focus_before_popup->setFocus(); + d->focus_before_popup=0; + invalidateSharedActions(); + } else { + if (focus_w) { + focus_w->setFocus(); + invalidateSharedActions(); + } + } + } + return false; + } + + /*! On mouse click on the findow, make sure it's focused and actions are invalidated */ + if (e->type()==QEvent::MouseButtonPress) { + QWidget *w = findWindow(static_cast<QWidget*>(obj)); + KexiVDebug << "MouseButtonPress EVENT " << (w ? w->name() : 0) << endl; + if (w) { + w->setFocus(); + invalidateSharedActions(d->curDialog); + } + } + QWidget *w = findWindow(static_cast<QWidget*>(obj)); + if (e->type()==QEvent::FocusIn) { + focus_w = focusWindow(); + KexiVDebug << "Focus EVENT" << endl; + KexiVDebug << (focus_w ? focus_w->name() : "" ) << endl; + KexiVDebug << "eventFilter: " <<e->type() << " " <<obj->name() <<endl; +#ifdef KEXI_STATUSBAR_DEBUG + QWidget *focus_widget = focus_w ? focus_w->focusWidget() : 0; + d->statusBar->setStatus(QString("FOCUS VIEW: %1 %2, FOCUS WIDGET: %3 %4") + .arg(focus_w ? focus_w->className() : "").arg(focus_w ? focus_w->name() : "") + .arg(focus_widget ? focus_widget->className() : "").arg(focus_widget ? focus_widget->name() : "") + ); +#endif + } + else if (e->type()==QEvent::FocusOut) { + focus_w = focusWindow(); + KexiVDebug << "Focus OUT EVENT" << endl; + KexiVDebug << (focus_w ? focus_w->name() : "" ) << endl; + KexiVDebug << "eventFilter: " <<e->type() << " " <<obj->name() <<endl; +#ifdef KEXI_STATUSBAR_DEBUG + QWidget *focus_widget = focus_w ? focus_w->focusWidget() : 0; + d->statusBar->setStatus(QString("FOCUS VIEW: %1 %2, FOCUS WIDGET: %3 %4") + .arg(focus_w ? focus_w->className() : "").arg(focus_w ? focus_w->name() : "") + .arg(focus_widget ? focus_widget->className() : "").arg(focus_widget ? focus_widget->name() : "") + ); +#endif + } + if (e->type()==QEvent::WindowActivate) { + KexiVDebug << "WindowActivate EVENT" << endl; + KexiVDebug << "eventFilter: " <<e->type() << " " <<obj->name()<<endl; + } +#if 0 + if (e->type()==QEvent::FocusIn) { + if (focus_w) { +// if (d->actionProxies[ w ]) +// if (d->actionProxies[ focus_w ]) { + if (actionProxyFor( focus_w )) { +// invalidateSharedActions(); + } + else { +/* QObject* o = focusWidget(); + while (o && !o->inherits("KexiDialogBase") && !o->inherits("KexiDockBase")) + o = o->parent();*/ +//js invalidateSharedActions(focus_w); + } + } +// /*|| e->type()==QEvent::FocusOut*/) && /*(!obj->inherits("KexiDialogBase")) &&*/ d->actionProxies[ obj ]) { +// invalidateSharedActions(); + } + if (e->type()==QEvent::FocusOut && focus_w && focus_w==d->curDialog && actionProxyFor( obj )) { + invalidateSharedActions(d->curDialog); + } +#endif + + if (!d->focus_before_popup.isNull() && e->type()==QEvent::FocusOut && obj->inherits("KMenuBar")) { + //d->nav->setFocus(); + d->focus_before_popup->setFocus(); + d->focus_before_popup=0; + invalidateSharedActions(d->curDialog); + return true; + } + + //remember currently focued window invalidate act. + if (e->type()==QEvent::FocusOut) { + if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Popup) { + if (KexiUtils::hasParent(d->curDialog, focus_w)) { + invalidateSharedActions(d->curDialog); + d->focus_before_popup=d->curDialog; + } + else { +//not needed??? invalidateSharedActions(focus_w); + d->focus_before_popup=focus_w; + } + } + } + + //keep focus in main window: + if (w && w==d->nav) { +// kdDebug() << "NAV" << endl; + if (e->type()==QEvent::FocusIn) { + return true; + } else if (e->type()==QEvent::WindowActivate && w==d->focus_before_popup) { +// d->nav->setFocus(); + d->focus_before_popup=0; + return true; + } else if (e->type()==QEvent::FocusOut) { + if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Tab) { + //activate current child: + if (d->curDialog) { + d->curDialog->activate(); + return true; + } + } + else if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Popup) { + d->focus_before_popup=w; + } + //invalidateSharedActions(); + } else if (e->type()==QEvent::Hide) { + setFocus(); + return false; + } + } + if (d->block_KMdiMainFrm_eventFilter)//we don't want KMDI to eat our event! + return false; + return KMdiMainFrm::eventFilter(obj,e);//let KMDI do its work +} + +bool KexiMainWindowImpl::openingAllowed(KexiPart::Item* item, int viewMode) +{ + //! @todo this can be more complex once we deliver ACLs... + if (!userMode()) + return true; + KexiPart::Part * part = Kexi::partManager().partForMimeType(item->mimeType()); + return part && (part->supportedUserViewModes() & viewMode); +} + +KexiDialogBase * +KexiMainWindowImpl::openObject(const QCString& mimeType, const QString& name, + int viewMode, bool &openingCancelled, QMap<QString,QString>* staticObjectArgs) +{ + KexiPart::Item *item = d->prj->itemForMimeType(mimeType,name); + if (!item) + return 0; + return openObject(item, viewMode, openingCancelled, staticObjectArgs); +} + +KexiDialogBase * +KexiMainWindowImpl::openObject(KexiPart::Item* item, int viewMode, bool &openingCancelled, + QMap<QString,QString>* staticObjectArgs, QString* errorMessage) +{ + if (!openingAllowed(item, viewMode)) { + if (errorMessage) + *errorMessage = i18n("opening is not allowed in \"data view/design view/text view\" mode", + "opening is not allowed in \"%1\" mode").arg(Kexi::nameForViewMode(viewMode)); + openingCancelled = true; + return 0; + } + + if (!d->prj || !item) + return 0; + KexiUtils::WaitCursor wait; +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + KexiDialogBase *dlg = d->openedDialogFor( item, pendingType ); + if (pendingType != Private::NoJob) { + openingCancelled = true; + return 0; + } +#else + KexiDialogBase *dlg = d->openedDialogFor( item ); +#endif + openingCancelled = false; + + bool needsUpdateViewGUIClient = true; + if (dlg) { + dlg->activate(); + if (viewMode!=dlg->currentViewMode()) { + if (!switchToViewMode(viewMode)) + return 0; + } + needsUpdateViewGUIClient = false; + } + else { + d->updatePropEditorVisibility(viewMode); + KexiPart::Part *part = Kexi::partManager().partForMimeType(item->mimeType()); + //update tabs before opening + updateCustomPropertyPanelTabs(d->curDialog ? d->curDialog->part() : 0, + d->curDialog ? d->curDialog->currentViewMode() : Kexi::NoViewMode, + part, viewMode); + +#ifndef KEXI_NO_PENDING_DIALOGS + d->addItemToPendingDialogs(item, Private::DialogOpeningJob); +#endif + dlg = d->prj->openObject(this, *item, viewMode, staticObjectArgs); + } + + if (!dlg || !activateWindow(dlg)) { +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog(item->identifier()); +#endif + updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert + //js TODO: add error msg... + return 0; + } + + if (needsUpdateViewGUIClient /*&& !userMode()*/) { + //view changed: switch to this view's gui client + KXMLGUIClient *viewClient=dlg->guiClient(); + updateDialogViewGUIClient(viewClient); + if (d->curDialogViewGUIClient && !viewClient) + guiFactory()->removeClient(d->curDialogViewGUIClient); + d->curDialogViewGUIClient=viewClient; //remember + } + + invalidateViewModeActions(); + if (viewMode!=dlg->currentViewMode()) + invalidateSharedActions(); + +#ifndef KEXI_NO_PENDING_DIALOGS + d->removePendingDialog( dlg->id() ); + + //perform pending global action that was suspended: + if (!d->pendingDialogsExist()) { + d->executeActionWhenPendingJobsAreFinished(); + } +#endif + return dlg; +} + +KexiDialogBase * +KexiMainWindowImpl::openObjectFromNavigator(KexiPart::Item* item, int viewMode) +{ + bool openingCancelled; + return openObjectFromNavigator(item, viewMode, openingCancelled); +} + +KexiDialogBase * +KexiMainWindowImpl::openObjectFromNavigator(KexiPart::Item* item, int viewMode, + bool &openingCancelled) +{ + if (!openingAllowed(item, viewMode)) { + openingCancelled = true; + return 0; + } + if (!d->prj || !item) + return false; +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + KexiDialogBase *dlg = d->openedDialogFor( item, pendingType ); + if (pendingType!=Private::NoJob) { + openingCancelled = true; + return 0; + } +#else + KexiDialogBase *dlg = d->openedDialogFor( item ); +#endif + openingCancelled = false; + if (dlg) { + if (activateWindow(dlg)) {//item->identifier())) {//just activate + invalidateViewModeActions(); + return dlg; + } + } + //if DataViewMode is not supported, try Design, then Text mode (currently useful for script part) + KexiPart::Part *part = Kexi::partManager().partForMimeType(item->mimeType()); + if (!part) + return 0; + if (viewMode == Kexi::DataViewMode && !(part->supportedViewModes() & Kexi::DataViewMode)) { + if (part->supportedViewModes() & Kexi::DesignViewMode) + return openObjectFromNavigator( item, Kexi::DesignViewMode, openingCancelled ); + else if (part->supportedViewModes() & Kexi::TextViewMode) + return openObjectFromNavigator( item, Kexi::TextViewMode, openingCancelled ); + } + //do the same as in openObject() + return openObject(item, viewMode, openingCancelled); +} + +tristate KexiMainWindowImpl::closeObject(KexiPart::Item* item) +{ +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + KexiDialogBase *dlg = d->openedDialogFor( item, pendingType ); + if (pendingType == Private::DialogClosingJob) + return true; + else if (pendingType == Private::DialogOpeningJob) + return cancelled; +#else + KexiDialogBase *dlg = d->openedDialogFor( item ); +#endif + if (!dlg) + return cancelled; + return closeDialog(dlg); +} + +bool KexiMainWindowImpl::newObject( KexiPart::Info *info, bool& openingCancelled ) +{ + if (userMode()) { + openingCancelled = true; + return false; + } + openingCancelled = false; + if (!d->prj || !info) + return false; + KexiPart::Part *part = Kexi::partManager().partForMimeType(info->mimeType()); + if(!part) + return false; + +#ifdef KEXI_ADD_CUSTOM_OBJECT_CREATION +# include "keximainwindowimpl_customobjcreation.h" +#endif + + KexiPart::Item *it = d->prj->createPartItem(info); //this, *item, viewMode); + if (!it) { + //js: todo: err + return false; + } + + if (!it->neverSaved()) //only add stored objects to the browser + d->nav->addItem(*it); + return openObject(it, Kexi::DesignViewMode, openingCancelled); +} + +tristate KexiMainWindowImpl::removeObject( KexiPart::Item *item, bool dontAsk ) +{ + if (userMode()) + return cancelled; + if (!d->prj || !item) + return false; + + KexiPart::Part *part = Kexi::partManager().partForMimeType(item->mimeType()); + if (!part) + return false; + + if (!dontAsk) { + if (KMessageBox::No == KMessageBox::warningYesNo(this, + "<p>"+i18n("Do you want to permanently delete:\n" + "%1\n" + "If you click \"Delete\", you will not be able to undo the deletion.") + .arg( "</p><p>"+part->instanceCaption()+" \""+ item->name() + "\"?</p>" ), + 0, KGuiItem(i18n("Delete"), "editdelete"), KStdGuiItem::no())) + return cancelled; + } + + //also close 'print setup' dialog for this item, if any + tristate res; +// int printedObjectID = 0; +// if (d->pageSetupDialogItemID2dataItemID_map.contains(item->identifier())) +// printedObjectID = d->pageSetupDialogItemID2dataItemID_map[ item->identifier() ]; + KexiDialogBase * pageSetupDlg = d->pageSetupDialogs[ item->identifier() ]; + const bool oldInsideCloseDialog = d->insideCloseDialog; + d->insideCloseDialog = false; + res = closeDialog(pageSetupDlg); + d->insideCloseDialog = oldInsideCloseDialog; + if (!res || ~res) { + return res; + } + +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + KexiDialogBase *dlg = d->openedDialogFor( item, pendingType ); + if (pendingType!=Private::NoJob) { + return cancelled; + } +#else + KexiDialogBase *dlg = d->openedDialogFor( item ); +#endif + + if (dlg) {//close existing window +// if (!dlg->tryClose(true)) + const bool tmp = d->forceDialogClosing; + /*const bool remove_on_closing = */dlg->partItem()->neverSaved(); + d->forceDialogClosing = true; + res = closeDialog(dlg); + d->forceDialogClosing = tmp; //restore + if (!res || ~res) { + return res; + } +// if (remove_on_closing) //already removed + // return true; +// if (!dlg->close(true)) +// return true; //ok - close cancelled + } + + //in case the dialog is a 'print setup' dialog, also update d->pageSetupDialogs + int dataItemID = d->pageSetupDialogItemID2dataItemID_map[item->identifier()]; + d->pageSetupDialogItemID2dataItemID_map.remove(item->identifier()); + d->pageSetupDialogs.take( dataItemID ); + + if (!d->prj->removeObject(this, *item)) { + //TODO(js) better msg + showSorryMessage( i18n("Could not remove object.") ); + return false; + } + return true; +} + +void KexiMainWindowImpl::renameObject( KexiPart::Item *item, const QString& _newName, bool &success ) +{ + if (userMode()) { + success = false; + return; + } + d->pendingDialogsExist(); + QString newName = _newName.stripWhiteSpace(); + if (newName.isEmpty()) { + showSorryMessage( i18n("Could not set empty name for this object.") ); + success = false; + return; + } + enableMessages(false); //to avoid double messages + const bool res = d->prj->renameObject(this, *item, newName); + enableMessages(true); + if (!res) { + showErrorMessage( d->prj, i18n("Renaming object \"%1\" failed.").arg(newName) ); + success = false; + return; + } + d->pendingDialogsExist(); +} + +void KexiMainWindowImpl::slotObjectRenamed(const KexiPart::Item &item, const QCString& /*oldName*/) +{ +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + KexiDialogBase *dlg = d->openedDialogFor( &item, pendingType ); + if (pendingType!=Private::NoJob) + return; +#else + KexiDialogBase *dlg = d->openedDialogFor( &item ); +#endif + if (!dlg) + return; + + //change item + dlg->updateCaption(); + if (static_cast<KexiDialogBase*>(d->curDialog)==dlg)//optionally, update app. caption + updateAppCaption(); +} + +int KexiMainWindowImpl::generatePrivateID() +{ + return --d->privateIDCounter; +} + +void KexiMainWindowImpl::acceptPropertySetEditing() +{ + if (d->propEditor) + d->propEditor->editor()->acceptInput(); +} + +void KexiMainWindowImpl::propertySetSwitched(KexiDialogBase *dlg, bool force, + bool preservePrevSelection, const QCString& propertyToSelect) +{ + kdDebug() << "KexiMainWindowImpl::propertySetSwitched() d->curDialog: " + << (d->curDialog ? d->curDialog->caption() : QString("NULL")) << " dlg: " << (dlg ? dlg->caption() : QString("NULL"))<< endl; + if ((KexiDialogBase*)d->curDialog!=dlg) { + d->propBuffer = 0; //we'll need to move to another prop. set + return; + } + if (d->propEditor) { + KoProperty::Set *newBuf = d->curDialog ? d->curDialog->propertySet() : 0; + if (!newBuf || (force || static_cast<KoProperty::Set*>(d->propBuffer) != newBuf)) { + d->propBuffer = newBuf; + if (preservePrevSelection) { + if (propertyToSelect.isEmpty()) + d->propEditor->editor()->changeSet( d->propBuffer, preservePrevSelection ); + else + d->propEditor->editor()->changeSet( d->propBuffer, propertyToSelect ); + } + } + } +} + +void KexiMainWindowImpl::slotDirtyFlagChanged(KexiDialogBase* dlg) +{ + KexiPart::Item *item = dlg->partItem(); + //update text in navigator and app. caption + if(!userMode()) + d->nav->updateItemName( *item, dlg->dirty() ); + + invalidateActions(); + updateAppCaption(); +} + +void KexiMainWindowImpl::slotMdiModeHasBeenChangedTo(KMdi::MdiMode) +{ + //after switching to other MDI mode, pointer to current dialog needs to be updated + activateFirstWin(); + activeWindowChanged(activeWindow()); +} + +void KexiMainWindowImpl::slotTipOfTheDay() +{ + //todo +} + +void KexiMainWindowImpl::slotImportantInfo() +{ + importantInfo(false); +} + +void KexiMainWindowImpl::slotStartFeedbackAgent() +{ +#ifndef KEXI_NO_FEEDBACK_AGENT +#ifdef FEEDBACK_CLASS + const KAboutData* about = KApplication::kApplication()->aboutData(); + FEEDBACK_CLASS* wizard = new FEEDBACK_CLASS( about->programName(), + about->version(), 0, 0, 0, FEEDBACK_CLASS::AllPages ); + + if ( wizard->exec() ) + { + KApplication::kApplication()->invokeMailer( "kexi-reports-dummy@kexi.org", + QString::null, QString::null, + about->appName() + QCString( " [feedback]" ), + wizard->feedbackDocument().toString( 2 ).local8Bit() ); + } + + delete wizard; +#endif +#endif +} + +void KexiMainWindowImpl::importantInfo(bool /*onStartup*/) +{ +#if 0 + if (onStartup && !d->showImportantInfoOnStartup) + return; + + QString key = QString("showImportantInfo %1").arg(KEXI_VERSION_STRING); + d->config->setGroup("Startup"); + bool show = d->config->readBoolEntry(key,true); + + if (show || !onStartup) { //if !onStartup - dialog is always shown + d->config->setGroup("TipOfDay"); + if (!d->config->hasKey("RunOnStart")) + d->config->writeEntry("RunOnStart",true); + + QString lang = KGlobal::locale()->language(); + QString fname = locate("data", QString("kexi/readme_")+lang); + if (fname.isEmpty())//back to default + fname = locate("data", "kexi/readme_en"); + KTipDialog tipDialog(new KTipDatabase(QString::null), 0); + tipDialog.setCaption(i18n("Important Information")); + QObjectList *l = tipDialog.queryList( "KPushButton" );//hack: hide <- -> buttons + int i=0; + for (QObjectListIt it( *l ); it.current() && i<2; ++it, i++ ) + static_cast<KPushButton*>(it.current())->hide(); + QFile f(fname); + if ( f.open( IO_ReadOnly ) ) { + QTextStream ts(&f); + ts.setCodec( KGlobal::locale()->codecForEncoding() ); + QTextBrowser *tb = KexiUtils::findFirstChild<KTextBrowser>(&tipDialog,"KTextBrowser"); + if (tb) { + tb->setText( QString("<qt>%1</qt>").arg(ts.read()) ); + } + f.close(); + } + + tipDialog.adjustSize(); + QRect desk = QApplication::desktop()->screenGeometry( QApplication::desktop()->screenNumber(this) ); + tipDialog.resize( QMAX(tipDialog.width(),desk.width()*3/5), QMAX(tipDialog.height(),desk.height()*3/5) ); + KDialog::centerOnScreen(&tipDialog); + tipDialog.setModal ( true ); + tipDialog.exec(); + //a hack: get user's settings + d->config->setGroup("TipOfDay"); + show = d->config->readBoolEntry("RunOnStart", show); + } + + //write our settings back + d->config->setGroup("Startup"); + d->config->writeEntry(key,show); + d->showImportantInfoOnStartup = false; +#endif +} + +void KexiMainWindowImpl::slotOptionsEnableForms(bool show, bool noMessage) +{ + Q_UNUSED(noMessage); + Kexi::tempShowForms() = show; +} + +bool KexiMainWindowImpl::userMode() const +{ + return d->userMode; +} + +bool +KexiMainWindowImpl::initUserMode(KexiProjectData *projectData) +{ +// Kexi::tempShowForms() = true; +// Kexi::tempShowReports() = true; +// Kexi::tempShowMacros() = true; +// Kexi::tempShowScripts() = true; + if(!projectData) + return false; + + createKexiProject(projectData); //initialize project +// d->prj->setFinal(true); //announce that we are in fianl mode + + tristate res = d->prj->open(); //try to open database + if (!res || ~res) { + delete d->prj; + d->prj = 0; + return false; + } + +#if 0 //todo reenable; autoopen objects are handled elsewhere + KexiDB::TableSchema *sch = d->prj->dbConnection()->tableSchema("kexi__final"); + QString err_msg = i18n("Could not start project \"%1\" in Final Mode.") + .arg(static_cast<KexiDB::SchemaData*>(projectData)->name()); + if(!sch) + { + hide(); + showErrorMessage( err_msg, i18n("No Final Mode data found.") ); + return false; + } + + KexiDB::Cursor *c = d->prj->dbConnection()->executeQuery(*sch); + if(!c) + { + hide(); + showErrorMessage( err_msg, i18n("Error reading Final Mode data.") ); + return false; + } + + QString startupPart; + QString startupItem; + while(c->moveNext()) + { + kdDebug() << "KexiMainWinImpl::initFinalMode(): property: [" << c->value(1).toString() << "] " << c->value(2).toString() << endl; + if(c->value(1).toString() == "startup-part") + startupPart = c->value(2).toString(); + else if(c->value(1).toString() == "startup-item") + startupItem = c->value(2).toString(); + else if(c->value(1).toString() == "mainxmlui") + setXML(c->value(2).toString()); + } + d->prj->dbConnection()->deleteCursor(c); + + kdDebug() << "KexiMainWinImpl::initFinalMode(): part: " << startupPart << endl; + kdDebug() << "KexiMainWinImpl::initFinalMode(): item: " << startupItem << endl; + + initActions(); + initUserActions(); + guiFactory()->addClient(this); + setStandardToolBarMenuEnabled(false); + setHelpMenuEnabled(false); + + KexiPart::Info *i = Kexi::partManager().infoForMimeType(startupPart.latin1()); + if (!i) { + hide(); + showErrorMessage( err_msg, i18n("Specified plugin does not exist.") ); + return false; + } + + Kexi::partManager().part(i); + KexiPart::Item *item = d->prj->item(i, startupItem); + bool openingCancelled; + if(!openObject(item, Kexi::DataViewMode, openingCancelled) && !openingCancelled) { + hide(); + showErrorMessage( err_msg, i18n("Specified object could not be opened.") ); + return false; + } + + QWidget::setCaption("MyApp");//TODO +#endif + return true; +} + +void +KexiMainWindowImpl::initUserActions() +{ +#if 0 //unused for now + KexiDB::Cursor *c = d->prj->dbConnection()->executeQuery("SELECT p_id, name, text, icon, method, arguments FROM kexi__useractions WHERE scope = 0"); + if(!c) + return; + + while(c->moveNext()) + { + KexiUserAction::fromCurrentRecord(this, actionCollection(), c); + } + d->prj->dbConnection()->deleteCursor(c); +/* + KexiUserAction *a1 = new KexiUserAction(this, actionCollection(), "user_dataview", "Change to dataview", "table"); + Arguments args; + args.append(QVariant("kexi/table")); + args.append(QVariant("persons")); + a1->setMethod(KexiUserAction::OpenObject, args); +*/ +#endif +} + +void KexiMainWindowImpl::slotToolsProjectMigration() +{ + showProjectMigrationWizard(QString::null, QString::null); +} + +void KexiMainWindowImpl::slotToolsCompactDatabase() +{ + KexiProjectData *data = 0; + KexiDB::Driver *drv = 0; + const bool projectWasOpened = d->prj; + + if (!d->prj) { + KexiStartupDialog dlg( + KexiStartupDialog::OpenExisting, 0, Kexi::connset(), Kexi::recentProjects(), + this, "KexiOpenDialog"); + + if (dlg.exec()!=QDialog::Accepted) + return; + + if (dlg.selectedFileName().isEmpty()) { +//! @todo add support for server based if needed? + return; + } + KexiDB::ConnectionData cdata; + cdata.setFileName( dlg.selectedFileName() ); + + //detect driver name for the selected file + KexiStartupData::Import detectedImportAction; + tristate res = KexiStartupHandler::detectActionForFile( + detectedImportAction, cdata.driverName, + "" /*suggestedDriverName*/, cdata.fileName(), 0, + KexiStartupHandler::SkipMessages | KexiStartupHandler::ThisIsAProjectFile + | KexiStartupHandler::DontConvert); + + if (true==res && !detectedImportAction) + drv = Kexi::driverManager().driver( cdata.driverName ); + if (!drv || !(drv->features() & KexiDB::Driver::CompactingDatabaseSupported)) { + KMessageBox::information(this, "<qt>"+ + i18n("Compacting database file <nobr>\"%1\"</nobr> is not supported.") + .arg(QDir::convertSeparators(cdata.fileName()))); + return; + } + data = new KexiProjectData( cdata, cdata.fileName() ); + } + else { + //sanity + if ( !(d->prj && d->prj->dbConnection() + && (d->prj->dbConnection()->driver()->features() & KexiDB::Driver::CompactingDatabaseSupported) )) + return; + + if (KMessageBox::Continue != KMessageBox::warningContinueCancel(this, + i18n("The current project has to be closed before compacting the database. " + "It will be open again after compacting.\n\nDo you want to continue?"))) + return; + + data = new KexiProjectData(*d->prj->data()); // a copy + drv = d->prj->dbConnection()->driver(); + const tristate res = closeProject(); + if (~res || !res) + return; + } + + if (!drv->adminTools().vacuum(*data->connectionData(), data->databaseName())) { + //err msg + showErrorMessage( &drv->adminTools() ); + } + + if (data && projectWasOpened) { + openProject(*data); + delete data; + } +} + +tristate KexiMainWindowImpl::showProjectMigrationWizard( + const QString& mimeType, const QString& databaseName, const KexiDB::ConnectionData *cdata) +{ + //pass arguments + QMap<QString,QString> args; + args.insert("mimeType", mimeType); + args.insert("databaseName", databaseName); + if (cdata) { //pass ConnectionData serialized as a string... + QString str; + KexiUtils::serializeMap( KexiDB::toMap( *cdata ), str ); + args.insert("connectionData", str); + } + + QDialog *dlg = KexiInternalPart::createModalDialogInstance("migration", this, this, 0, &args); + if (!dlg) + return false; //error msg has been shown by KexiInternalPart + + const int result = dlg->exec(); + delete dlg; + //raise(); + if (result!=QDialog::Accepted) + return cancelled; + + //open imported project in a new Kexi instance + QString destinationDatabaseName( args["destinationDatabaseName"] ); + QString fileName, destinationConnectionShortcut, dbName; + if (!destinationDatabaseName.isEmpty()) { + if (args.contains("destinationConnectionShortcut")) { + // server-based + destinationConnectionShortcut = args["destinationConnectionShortcut"]; + } + else { + // file-based + fileName = destinationDatabaseName; + destinationDatabaseName = QString::null; + } + tristate res = openProject(fileName, destinationConnectionShortcut, + destinationDatabaseName); + raise(); + return res; +// KexiDB::ConnectionData *connData = new KexiDB::ConnectionData(); +// KexiDB::fromMap( KexiUtils::deserializeMap( args["destinationConnectionData"] ), *connData ); +// return openProject(destinationFileName, 0); + } + return true; +} + +tristate KexiMainWindowImpl::executeItem(KexiPart::Item* item) +{ + KexiPart::Info *info = item ? Kexi::partManager().infoForMimeType(item->mimeType()) : 0; + if ( (! info) || (! info->isExecuteSupported()) ) + return false; + KexiPart::Part *part = Kexi::partManager().part(info); + if (!part) + return false; + return part->execute(item); +} + +void KexiMainWindowImpl::slotProjectImportDataTable() +{ +//! @todo allow data appending (it is not possible now) + if (userMode()) + return; + QMap<QString,QString> args; + args.insert("sourceType", "file"); + QDialog *dlg = KexiInternalPart::createModalDialogInstance( + "csv_importexport", "KexiCSVImportDialog", this, this, 0, &args); + if (!dlg) + return; //error msg has been shown by KexiInternalPart + dlg->exec(); + delete dlg; +} + +tristate KexiMainWindowImpl::executeCustomActionForObject(KexiPart::Item* item, + const QString& actionName) +{ + if (actionName == "exportToCSV") + return exportItemAsDataTable(item); + else if (actionName == "copyToClipboardAsCSV") + return copyItemToClipboardAsDataTable(item); + + kexiwarn << "KexiMainWindowImpl::executeCustomActionForObject(): no such action: " + << actionName << endl; + return false; +} + +tristate KexiMainWindowImpl::exportItemAsDataTable(KexiPart::Item* item) +{ + if (!item) + return false; +//! @todo: check if changes to this are saved, if not: ask for saving +//! @todo: accept row changes... + + QMap<QString,QString> args; + args.insert("destinationType", "file"); + args.insert("itemId", QString::number(item->identifier())); + QDialog *dlg = KexiInternalPart::createModalDialogInstance( + "csv_importexport", "KexiCSVExportWizard", this, this, 0, &args); + if (!dlg) + return false; //error msg has been shown by KexiInternalPart + int result = dlg->exec(); + delete dlg; + return result == QDialog::Rejected ? cancelled : true; +} + +bool KexiMainWindowImpl::printItem(KexiPart::Item* item, const QString& titleText) +{ + return printItem(item, KexiSimplePrintingSettings::load(), titleText); +} + +tristate KexiMainWindowImpl::printItem(KexiPart::Item* item) +{ + return printItem(item, QString::null); +} + +bool KexiMainWindowImpl::printItem(KexiPart::Item* item, const KexiSimplePrintingSettings& settings, + const QString& titleText) +{ +//! @todo: check if changes to this object's design are saved, if not: ask for saving +//! @todo: accept row changes... + KexiSimplePrintingCommand cmd(this, item->identifier()); + //modal + return cmd.print(settings, titleText); +} + +bool KexiMainWindowImpl::printPreviewForItem(KexiPart::Item* item, const QString& titleText, bool reload) +{ + return printPreviewForItem(item, KexiSimplePrintingSettings::load(), titleText, reload); +} + +tristate KexiMainWindowImpl::printPreviewForItem(KexiPart::Item* item) +{ + return printPreviewForItem(item, QString::null, +//! @todo store cached row data? + true/*reload*/); +} + +bool KexiMainWindowImpl::printPreviewForItem(KexiPart::Item* item, + const KexiSimplePrintingSettings& settings, const QString& titleText, bool reload) +{ +//! @todo: check if changes to this object's design are saved, if not: ask for saving +//! @todo: accept row changes... + KexiSimplePrintingCommand* cmd = d->openedCustomObjectsForItem<KexiSimplePrintingCommand>( + item, "KexiSimplePrintingCommand"); + if (!cmd) { + d->addOpenedCustomObjectForItem( + item, + cmd = new KexiSimplePrintingCommand(this, item->identifier()), + "KexiSimplePrintingCommand" + ); + } + return cmd->showPrintPreview(settings, titleText, reload); +} + +tristate KexiMainWindowImpl::showPageSetupForItem(KexiPart::Item* item) +{ +//! @todo: check if changes to this object's design are saved, if not: ask for saving +//! @todo: accept row changes... + return printActionForItem(item, PageSetupForItem); +} + +tristate KexiMainWindowImpl::printActionForItem(KexiPart::Item* item, PrintActionType action) +{ + if (!item) + return false; + KexiPart::Info *info = Kexi::partManager().infoForMimeType( item->mimeType() ); + if (!info->isPrintingSupported()) + return false; + + KexiDialogBase *printingDialog = d->pageSetupDialogs[ item->identifier() ]; + if (printingDialog) { + if (!activateWindow(printingDialog)) + return false; + if (action == PreviewItem || action == PrintItem) { + QTimer::singleShot(0,printingDialog->selectedView(), + (action == PreviewItem) ? SLOT(printPreview()) : SLOT(print())); + } + return true; + } + +#ifndef KEXI_NO_PENDING_DIALOGS + Private::PendingJobType pendingType; + KexiDialogBase *dlg = d->openedDialogFor( item, pendingType ); + if (pendingType!=Private::NoJob) + return cancelled; +#else + KexiDialogBase *dlg = d->openedDialogFor( item ); +#endif + + if (dlg) { + // accept row changes + QWidget *prevFocusWidget = focusWidget(); + dlg->setFocus(); + d->action_data_save_row->activate(); + if (prevFocusWidget) + prevFocusWidget->setFocus(); + + // opened: check if changes made to this dialog are saved, if not: ask for saving + if (dlg->neverSaved()) //sanity check + return false; + if (dlg->dirty()) { + KGuiItem saveChanges( KStdGuiItem::save() ); + saveChanges.setToolTip(i18n("Save changes")); + saveChanges.setWhatsThis( + i18n( "Pressing this button will save all recent changes made in \"%1\" object." ) + .arg(item->name()) ); + KGuiItem doNotSave( KStdGuiItem::no() ); + doNotSave.setWhatsThis( + i18n( "Pressing this button will ignore all unsaved changes made in \"%1\" object." ) + .arg(dlg->partItem()->name()) ); + + QString question; + if (action == PrintItem) + question = i18n("Do you want to save changes before printing?"); + else if (action == PreviewItem) + question = i18n("Do you want to save changes before making print preview?"); + else if (action == PageSetupForItem) + question = i18n("Do you want to save changes before showing page setup?"); + else + return false; + + const int questionRes = KMessageBox::warningYesNoCancel( this, + "<p>"+dlg->part()->i18nMessage("Design of object \"%1\" has been modified.", dlg) + .arg(item->name()) + "</p><p>" + question + "</p>", + QString::null, + saveChanges, + doNotSave); + if (KMessageBox::Cancel == questionRes) + return cancelled; + if (KMessageBox::Yes == questionRes) { + tristate savingRes = saveObject( dlg, QString::null, true /*dontAsk*/ ); + if (true != savingRes) + return savingRes; + } + } + } + KexiPart::Part * printingPart = Kexi::partManager().partForMimeType("kexi/simpleprinting"); + if (!printingPart) + printingPart = new KexiSimplePrintingPart(); //hardcoded as there're no .desktop file + KexiPart::Item* printingPartItem = d->prj->createPartItem( + printingPart, item->name() //<-- this will look like "table1 : printing" on the window list + ); + QMap<QString,QString> staticObjectArgs; + staticObjectArgs["identifier"] = QString::number(item->identifier()); + if (action == PrintItem) + staticObjectArgs["action"] = "print"; + else if (action == PreviewItem) + staticObjectArgs["action"] = "printPreview"; + else if (action == PageSetupForItem) + staticObjectArgs["action"] = "pageSetup"; + else + return false; + bool openingCancelled; + printingDialog = openObject(printingPartItem, Kexi::DesignViewMode, + openingCancelled, &staticObjectArgs); + if (openingCancelled) + return cancelled; + if (!printingDialog) //sanity + return false; + d->pageSetupDialogs.insert(item->identifier(), printingDialog); + d->pageSetupDialogItemID2dataItemID_map.insert( + printingDialog->partItem()->identifier(), item->identifier()); + + return true; +} + +void KexiMainWindowImpl::slotEditCopySpecialDataTable() +{ + KexiPart::Item* item = d->nav->selectedPartItem(); + if (item) + exportItemAsDataTable(item); +} + +tristate KexiMainWindowImpl::copyItemToClipboardAsDataTable(KexiPart::Item* item) +{ + if (!item) + return false; + + QMap<QString,QString> args; + args.insert("destinationType", "clipboard"); + args.insert("itemId", QString::number(item->identifier())); + QDialog *dlg = KexiInternalPart::createModalDialogInstance( + "csv_importexport", "KexiCSVExportWizard", this, this, 0, &args); + if (!dlg) + return false; //error msg has been shown by KexiInternalPart + const int result = dlg->exec(); + delete dlg; + return result == QDialog::Rejected ? cancelled : true; +} + +void KexiMainWindowImpl::slotEditPasteSpecialDataTable() +{ +//! @todo allow data appending (it is not possible now) + if (userMode()) + return; + QMap<QString,QString> args; + args.insert("sourceType", "clipboard"); + QDialog *dlg = KexiInternalPart::createModalDialogInstance( + "csv_importexport", "KexiCSVImportDialog", this, this, 0, &args); + if (!dlg) + return; //error msg has been shown by KexiInternalPart + dlg->exec(); + delete dlg; +} + +void KexiMainWindowImpl::slotEditFind() +{ +// KexiViewBase *view = d->currentViewSupportingAction("edit_findnext"); + KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); + if (!iface) + return; + d->updateFindDialogContents(true/*create if does not exist*/); + d->findDialog()->setReplaceMode(false); + + d->findDialog()->show(); + d->findDialog()->setActiveWindow(); + d->findDialog()->raise(); +} + +void KexiMainWindowImpl::slotEditFind(bool next) +{ + KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); + if (!iface) + return; + tristate res = iface->find( + d->findDialog()->valueToFind(), d->findDialog()->options(), next); + if (~res) + return; + d->findDialog()->updateMessage( true == res ); +//! @todo result +} + +void KexiMainWindowImpl::slotEditFindNext() +{ + slotEditFind( true ); +} + +void KexiMainWindowImpl::slotEditFindPrevious() +{ + slotEditFind( false ); +} + +void KexiMainWindowImpl::slotEditReplace() +{ + KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); + if (!iface) + return; + d->updateFindDialogContents(true/*create if does not exist*/); + d->findDialog()->setReplaceMode(true); +//! @todo slotEditReplace() + d->findDialog()->show(); + d->findDialog()->setActiveWindow(); +} + +void KexiMainWindowImpl::slotEditReplaceNext() +{ + slotEditReplace( false ); +} + +void KexiMainWindowImpl::slotEditReplace(bool all) +{ + KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); + if (!iface) + return; +//! @todo add question: "Do you want to replace every occurence of \"%1\" with \"%2\"? +//! You won't be able to undo this." + "Do not ask again". + tristate res = iface->findNextAndReplace( + d->findDialog()->valueToFind(), d->findDialog()->valueToReplaceWith(), + d->findDialog()->options(), all); + d->findDialog()->updateMessage( true == res ); +//! @todo result +} + +void KexiMainWindowImpl::slotEditReplaceAll() +{ + slotEditReplace( true ); +} + +void KexiMainWindowImpl::addWindow( KMdiChildView* pView, int flags ) +{ + //maximize this window, if it's +//!@todo Certain windows' sizes, e.g. forms could have own size configation specified! +//! Query for this, and if so: give up. + if (d->maximizeFirstOpenedChildFrm) { + flags |= KMdi::Maximize; + d->maximizeFirstOpenedChildFrm = false; + } + KexiMainWindow::addWindow( pView, flags ); +} + +/// TMP (until there's true template support) +void KexiMainWindowImpl::slotGetNewStuff() +{ +#ifdef HAVE_KNEWSTUFF + if(!d->newStuff) + d->newStuff = new KexiNewStuff(this); + d->newStuff->download(); + + //KNS::DownloadDialog::open(newstuff->customEngine(), "kexi/template"); +#endif +} + +void KexiMainWindowImpl::highlightObject(const QCString& mime, const QCString& name) +{ + slotViewNavigator(); + if (!d->prj) + return; + KexiPart::Item *item = d->prj->itemForMimeType(mime, name); + if (!item) + return; + if (d->nav) { + d->nav->selectItem(*item); + } +} + +void KexiMainWindowImpl::slotPartItemSelectedInNavigator(KexiPart::Item* item) +{ + Q_UNUSED(item); +} + +#include "keximainwindowimpl.moc" diff --git a/kexi/main/keximainwindowimpl.h b/kexi/main/keximainwindowimpl.h new file mode 100644 index 00000000..93545439 --- /dev/null +++ b/kexi/main/keximainwindowimpl.h @@ -0,0 +1,538 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Lucijan Busch <lucijan@kde.org> + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 KEXIMAINWINDOWIMPL_H +#define KEXIMAINWINDOWIMPL_H + +#include <kmessagebox.h> +#include "core/keximainwindow.h" +#include "core/kexiguimsghandler.h" + +class KexiProjectData; +class KexiActionProxy; +class KMdiChildView; +class KexiSimplePrintingSettings; + +namespace KexiDB { + class Object; + class ConnectionData; +} +namespace KexiPart { + class Info; + class Part; +} + +/** + * @short Kexi's main window implementation + */ +class KEXIMAIN_EXPORT KexiMainWindowImpl : public KexiMainWindow, public KexiGUIMessageHandler +{ + Q_OBJECT + + public: + /*! Creates an empty mainwindow. */ + KexiMainWindowImpl(); + virtual ~KexiMainWindowImpl(); + + /*! Used by the main kexi routine. Creates a new Kexi main window and a new KApplication object. + kdemain() has to destroy the latter on exit. + \return result 1 on error and 0 on success (the result can be used as a result of kdemain()) */ + static int create(int argc, char *argv[], KAboutData* aboutdata = 0); + + //! \return KexiMainWindowImpl singleton (if it is instantiated) + static KexiMainWindowImpl* self() { return dynamic_cast<KexiMainWindowImpl*>(qApp->mainWidget()); } + + //! Project data of currently opened project or NULL if no project here yet. + virtual KexiProject *project(); + + /*! Registers dialog \a dlg for watching and adds it to the main window's stack. */ + virtual void registerChild(KexiDialogBase *dlg); + + /*! Activates a window by it's document identifier. + \return false if doc couldn't be raised or isn't opened. */ + bool activateWindow(int id); + + /*! Like above, using \a dlg passed explicitly. Above method just calls this one. */ + bool activateWindow(KexiDialogBase *dlg); + + /*! Performs startup actions. \return false if application should exit immediately + with an error status. */ + tristate startup(); + + /*! \return true if the application window is in the User Mode. */ + virtual bool userMode() const; + + /*! \return true if opening of item \a item in \a viewMode mode is allowed. + userMode() is taken into account as well + as KexiPart::Part::supportedUserViewModes() for \a item. */ + bool openingAllowed(KexiPart::Item* item, int viewMode); + + virtual bool eventFilter( QObject *obj, QEvent * e ); + + //! \return popup menu for \a popupName name. + virtual QPopupMenu* findPopupMenu(const char *popupName); + + /*! Implemented for KexiMainWindow. */ + virtual KActionPtrList allActions() const; + + /*! \return currently active dialog (window) od 0 if there is no active dialog. + Implemented for KexiMainWindow. */ + virtual KexiDialogBase* currentDialog() const; + +//! @todo move to kexiproject + /*! Generates ID for private "document" like Relations window. + Private IDs are negative numbers (while ID regular part instance's IDs are >0) + Private means that the object is not stored as-is in the project but is somewhat + generated and in most cases there is at most one unique instance document of such type (part). + To generate this ID, just app-wide internal counter is used. */ + virtual int generatePrivateID(); + + /*! Reimplemented */ + virtual void readProperties(KConfig *config); + virtual void saveProperties(KConfig *config); + virtual void saveGlobalProperties( KConfig* sessionConfig ); + + public slots: + /*! Inherited from KMdiMainFrm: we need to do some tasks before child is closed. + Just calls closeDialog(). Use closeDialog() if you need, not this one. */ + virtual void closeWindow(KMdiChildView *pWnd, bool layoutTaskBar = true); + + /*! Reimplemented for internal reasons. */ + virtual void addWindow( KMdiChildView* pView, int flags = KMdi::StandardAdd ); + + /*! Implemented for KexiMainWindow */ + virtual tristate closeDialog(KexiDialogBase *dlg); + + /*! Internal implementation. If \a doNotSaveChanges is true, + messages asking for saving the will be skipped and the changes will be dropped. + This should not be usually used, maybe except for test suites + (see kexi/tests/altertable/ directory). */ + tristate closeDialog(KexiDialogBase *dlg, bool layoutTaskBar, bool doNotSaveChanges = false); + + virtual void detachWindow(KMdiChildView *pWnd,bool bShow=true); + virtual void attachWindow(KMdiChildView *pWnd,bool bShow=true,bool bAutomaticResize=false); + +//! @todo move part of this to KexiProject, because currently KexiProject::openObject() allows multiple opens! + /*! Opens object pointed by \a item in a view \a viewMode. + \a staticObjectArgs can be passed for static object + (only works when part for this item is of type KexiPart::StaticPart). + \a openingCancelled is set to true is opening has been cancelled. + \a errorMessage, if not 0, points to a string that can be set to error message + if one encountered. */ + virtual KexiDialogBase* openObject(KexiPart::Item *item, int viewMode, + bool &openingCancelled, QMap<QString,QString>* staticObjectArgs = 0, + QString* errorMessage = 0); + + //! For convenience + virtual KexiDialogBase* openObject(const QCString& mime, const QString& name, + int viewMode, bool &openingCancelled, QMap<QString,QString>* staticObjectArgs = 0); + + /*! Closes the object for \a item. + \return true on success (closing can be dealyed though), false on failure and cancelled + if the object has "opening" job assigned. */ + virtual tristate closeObject(KexiPart::Item* item); + + /*! Implemented for KexiMainWindow */ + virtual tristate saveObject( KexiDialogBase *dlg, + const QString& messageWhenAskingForName = QString::null, bool dontAsk = false ); + + /*! Implemented for KexiMainWindow */ + virtual tristate getNewObjectInfo( KexiPart::Item *partItem, KexiPart::Part *part, + bool& allowOverwriting, const QString& messageWhenAskingForName = QString::null ); + + /*! Implemented for KexiMainWindow */ + virtual void highlightObject(const QCString& mime, const QCString& name); + + /*! Opens project pointed by \a projectData. + Application state (e.g. actions) is updated. + \a projectData is copied into a project structures. + \return true on success */ + tristate openProject(const KexiProjectData& projectData); + + /*! Helper. Opens project pointed by \a aFileName. + If \a aFileName is empty, a connection shortcut (.kexic file name) is obtained from + global connection set using \a cdata (if present). + In this case: + * If connection shortcut has been found and \a dbName (a server database name) is provided + 'kexi --skip-dialog --connection file.kexic dbName' is executed (or the project + is opened directly if there's no project opened in the current Kexi main window. + * If connection shortcut has been found and \a dbName is not provided, + 'kexi --skip-dialog file.kexic' is executed (or the connection is opened + directly if there's no porject opened in the current Kexi main window. */ + tristate openProject(const QString& aFileName, KexiDB::ConnectionData *cdata, + const QString& dbName = QString::null, + const QValueList<KexiProjectData::ObjectInfo>& autoopenObjects = QValueList<KexiProjectData::ObjectInfo>()); + + /*! Helper. Opens project pointed by \a aFileName. + Like above but \a fileNameForConnectionData can be passed instead of + a pointer to connection data itself. + \return false if \a fileNameForConnectionData is not empty but there is no such + connection in Kexi::connset() for this filename. + \a fileNameForConnectionData can be empty. */ + tristate openProject(const QString& aFileName, + const QString& fileNameForConnectionData, const QString& dbName = QString::null); + + /*! Creates a new project usign template pointed by \a projectData. + Application state (e.g. actions) is updated. + New project data is copied into a project structures. + \return true on success */ + tristate createProjectFromTemplate(const KexiProjectData& projectData); + + /*! Closes current project, \return true on success. + Application state (e.g. actions) is updated. + \return true on success. + If closing was cancelled by user, cancelled is returned. */ + tristate closeProject(); + + //! Shows "print" dialog for \a item. + //! \return true on success. + virtual tristate printItem(KexiPart::Item* item); + + //! Shows "print preview" dialog. + //! \return true on success. + virtual tristate printPreviewForItem(KexiPart::Item* item); + + //! Shows "page setup" dialog for \a item. + //! \return true on success and cancelled when the action was cancelled. + virtual tristate showPageSetupForItem(KexiPart::Item* item); + + /*! Executes custom action for the main window, usually provided by a plugin. + Also used by KexiFormEventAction. */ + virtual tristate executeCustomActionForObject(KexiPart::Item* item, const QString& actionName); + + signals: + //! Emitted after opening a project, even after slotAutoOpenObjectsLater(). + void projectOpened(); + + protected: + /*! Initialises the User Mode: constructs window according to kexi__final database + and loads the specified part. + \return true on success or false if e.g. kexi__final does not exist + or a fatal exception happened */ + bool initUserMode(KexiProjectData *projectData); + + /*! + Creates navigator (if it's not yet created), + lookups items for current project and fills the nav. with not-opened items + */ + void initNavigator(); + + void initContextHelp(); + + void initPropertyEditor(); + + //! reimplementation of events +// virtual void closeEvent(QCloseEvent *); + + /*! Creates standard actions like new, open, save ... */ + void initActions(); + + /*! Creates user project-wide actions */ + void initUserActions(); + + /*! Sets up the window from user settings (e.g. mdi mode). */ + void restoreSettings(); + + /*! Writes user settings back. */ + void storeSettings(); + + /*! Invalidates availability of all actions for current application state. */ + void invalidateActions(); + + /*! Invalidates action availability for current application state. + These actions are dependent on curently selected dialog. */ + virtual void invalidateSharedActions(QObject *o); + + /*! Invalidates action availability for current application state. + These actions only depend on project availability, not on curently selected dialog. */ + void invalidateProjectWideActions(); + + /*! Invalidates action availability for current application state. + These actions only depend on curently selected dialog and currently selected view + (KexiViewBase derived object) within this dialog. */ + void invalidateViewModeActions(); + + /*! Shows dialog for creating new blank project, + and creates one. Dialog is not shown if option for automatic creation + is checked or Kexi::startupHandler().projectData() was provided from command line. + \a cancelled is set to true if creation has been cancelled (e.g. user answered + no when asked for database overwriting, etc. + \return true if database was created, false on error or when cancel was pressed */ + tristate createBlankProject(); + + /*! Shows dialog for creating new blank project, + and return a data describing it. It the dialog was cancelled, + \a cancelled will be set to true (false otherwise). + \a shortcutFileName, if not 0, will be set to a shortcut filename + (in case when server database project was selected). */ + KexiProjectData* createBlankProjectData(bool &cancelled, bool confirmOverwrites = true, + QString *shortcutFileName = 0); + + void setWindowMenu(QPopupMenu *menu); + + /*! \return focused kexi window (KexiDialogBase or KexiDockBase subclass) */ +// QWidget* focusWindow() const; + + /*! Reimplemented from KexiSharedActionHost: + accepts only KexiDockBase and KexiDialogBase subclasses. */ + virtual bool acceptsSharedActions(QObject *w); + + /*! Performs lookup like in KexiSharedActionHost::focusWindow() + but starting from \a w instead of a widget returned by QWidget::focusWidget(). + \return NULL if no widget matches acceptsSharedActions() or if \a w is NULL. */ + QWidget* findWindow(QWidget *w); + + /*! Updates application's caption - also shows project's name. */ + void updateAppCaption(); + + void restoreWindowConfiguration(KConfig *config); + void storeWindowConfiguration(KConfig *config); + + virtual bool queryClose(); + virtual bool queryExit(); + + /*! Helper: switches to view \a mode. */ + bool switchToViewMode(int viewMode); + + /*! Helper. Removes and/or adds GUI client for current dialog's view; + on switching to other dialog (activeWindowChanged()) + or on switching to other view within the same dialog (switchToViewMode()). */ + void updateDialogViewGUIClient(KXMLGUIClient *viewClient); + + /*! Helper. Updates setup of property panel's tabs. Used when switching + from \a prevDialog dialog to a current dialog. */ + void updateCustomPropertyPanelTabs(KexiDialogBase *prevDialog, int prevViewMode); + + /*! @overload void updateCustomPropertyPanelTabs(KexiDialogBase *prevDialog, int prevViewMode) */ + void updateCustomPropertyPanelTabs( + KexiPart::Part *prevDialogPart, int prevViewMode, KexiPart::Part *curDialogPart, int curViewMode ); + + /*! Used in openProject when running another Kexi process is required. */ + tristate openProjectInExternalKexiInstance(const QString& aFileName, + KexiDB::ConnectionData *cdata, const QString& dbName); + + /*! Used in openProject when running another Kexi process is required. */ + tristate openProjectInExternalKexiInstance(const QString& aFileName, + const QString& fileNameForConnectionData, const QString& dbName); + + protected slots: + + /*! Called once after timeout (after ctors are executed). */ + void slotAutoOpenObjectsLater(); + + /*! This slot is called if a window changes */ + void activeWindowChanged(KMdiChildView *dlg); + + /*! Tthis slot is called if a window gets colsed and will unregister stuff */ + void childClosed(KMdiChildView *dlg); + + void slotPartLoaded(KexiPart::Part* p); + + void slotCaptionForCurrentMDIChild(bool childrenMaximized); + void slotNoMaximizedChildFrmLeft(KMdiChildFrm*); + void slotLastChildViewClosed(); + void slotChildViewIsDetachedNow(QWidget*); + + //! internal - creates and initializes kexi project + void createKexiProject(KexiProjectData* new_data); + + /*! Handles event when user double clicked (or single -depending on settings) + or pressed Return key on the part item in the navigator. + This differs from openObject() signal in that if the object is already opened + in view mode other than \a viewMode, the mode is not changed. + \sa KexiBrowser::openOrActivateItem() */ + KexiDialogBase* openObjectFromNavigator(KexiPart::Item* item, int viewMode, + bool &openingCancelled); + + //! For convenience + KexiDialogBase* openObjectFromNavigator(KexiPart::Item* item, int viewMode); + + /*! Creates new object of type defined by \a info part info. + \a openingCancelled is set to true is opening has been cancelled. + \return true on success. */ + virtual bool newObject( KexiPart::Info *info, bool& openingCancelled ); + + //! For convenience + bool newObject( KexiPart::Info *info ) { + bool openingCancelled; + return newObject(info, openingCancelled); + } + + //! For convenience + KexiDialogBase* openObject(KexiPart::Item *item, int viewMode, + QMap<QString,QString>* staticObjectArgs = 0) + { + bool openingCancelled; + return openObject(item, viewMode, openingCancelled, staticObjectArgs); + } + + /*! Removes object pointed by \a item from current project. + Asks for confirmation. \return true on success + or cancelled if removing was cancelled (only possible if \a dontAsk is false). */ + tristate removeObject( KexiPart::Item *item, bool dontAsk = false ); + + /*! Renames object pointed by \a item to a new name \a _newName. + Sets \a success to false on failure. Used as a slot connected + to KexiBrowser::renameItem() signal. */ + void renameObject( KexiPart::Item *item, const QString& _newName, bool &succes ); + + /*! Reaction for object rename (signalled by KexiProject). + If this item has opened dialog, it's caption is updated, + and also optionally application's caption. */ + virtual void slotObjectRenamed(const KexiPart::Item &item, const QCString& oldName); + + virtual void fillWindowMenu(); + + void invalidateSharedActions(); + void invalidateSharedActionsLater(); + + //! Updates the statusbar, navigator and "Insert->....." actions, dependent on read-only state. + //! Only called on project opening and closing. + void updateReadOnlyState(); + + void slotProjectNew(); + void slotProjectOpen(); + void slotProjectOpenRecentAboutToShow(); + void slotProjectOpenRecent(int id); + void slotProjectOpenRecentMore(); + void slotProjectSave(); + void slotProjectSaveAs(); + void slotProjectPrint(); + void slotProjectPrintPreview(); + void slotProjectPageSetup(); + void slotProjectProperties(); + void slotProjectClose(); + void slotProjectRelations(); + void slotProjectImportDataTable(); + void slotProjectExportDataTable(); + void slotProjectQuit(); + void slotEditPasteSpecialDataTable(); + void slotEditCopySpecialDataTable(); + void slotEditFind(); + void slotEditFind(bool next); //!< helper + void slotEditFindNext(); + void slotEditFindPrevious(); + void slotEditReplace(bool all); //!< helper + void slotEditReplace(); + void slotEditReplaceNext(); + void slotEditReplaceAll(); + void slotViewNavigator(); + void slotViewMainArea(); + void slotViewPropertyEditor(); + void slotViewDataMode(); + void slotViewDesignMode(); + void slotViewTextMode(); //!< sometimes called "SQL View" + void slotShowSettings(); + void slotConfigureKeys(); + void slotConfigureToolbars(); + void slotToolsProjectMigration(); + void slotToolsCompactDatabase(); + + /// TMP: Display a dialog to download db examples from internet + void slotGetNewStuff(); + + void slotTipOfTheDay(); + + //! Shows 'important info' dialog, is \a onStartup is false, it's always shown + void importantInfo(bool onStartup); + void slotImportantInfo(); //!< just importantInfo(false); + void slotStartFeedbackAgent(); + + void slotOptionsEnableForms(bool show, bool noMessage = false); //temp. + + void slotImportFile(); + void slotImportServer(); + + //! There are performed all actions that need to be done immediately after ctro (using timer) + void slotLastActions(); + + virtual void acceptPropertySetEditing(); + + virtual void propertySetSwitched(KexiDialogBase *dlg, bool force=false, + bool preservePrevSelection = true, const QCString& propertyToSelect = QCString()); + + /*! Handles changes in 'dirty' flag for dialogs. */ + void slotDirtyFlagChanged(KexiDialogBase*); + + void slotMdiModeHasBeenChangedTo(KMdi::MdiMode); + + //! reimplemented to add "restart is required" message box + virtual void switchToIDEAlMode(); + void switchToIDEAlMode(bool showMessage); + virtual void switchToChildframeMode(); + void switchToChildframeMode(bool showMessage); + + /*! Shows Project Migration Wizard. \return true on successful migration, + cancelled on cancellation, and false on failure. + If \a mimeType and \a databaseName are not empty, the wizard will only ask about + parameters of destination project and skip pages related to source project. + \a cdata connection data can be also provided to preselect server-based connections. */ + tristate showProjectMigrationWizard(const QString& mimeType, const QString& databaseName, + const KexiDB::ConnectionData *cdata = 0); + + //! Receives "selectionChanged()" signal from navigator to update some actions. + void slotPartItemSelectedInNavigator(KexiPart::Item* item); + + /*! Receives the "executeItem" signal from navigator to perform "execute" action + on \a item. \return true on success */ + tristate executeItem(KexiPart::Item* item); + + //! Shows "exports as data table" dialog for \a item. + tristate exportItemAsDataTable(KexiPart::Item* item); + + //! Shows "copy special as data table" dialog for \a item. + tristate copyItemToClipboardAsDataTable(KexiPart::Item* item); + + //! Shows "print" dialog for \a item. + //! \return true on success. + bool printItem(KexiPart::Item* item, const QString& titleText); + + //! Shows "print" dialog for \a item and \a settings. + //! \return true on success. + bool printItem(KexiPart::Item* item, const KexiSimplePrintingSettings& settings, + const QString& titleText = QString::null); + + /*! Shows "print preview" dialog for \a item. + The preview dialog is cached, so \a reload == true is sometimes needed + if data or print settings have changed in the meantime. + \return true on success. */ + bool printPreviewForItem(KexiPart::Item* item, const QString& titleText, + bool reload); + + //! Shows "print preview" dialog. + //! \return true on success. + bool printPreviewForItem(KexiPart::Item* item, const KexiSimplePrintingSettings& settings, + const QString& titleText = QString::null, bool reload = false); + + /*! Implemented for KexiMainWindow. Helper for printItem() and printPreviewForItem(). + Also used by KexiFormEventAction. + \return true on success and cancelled when the action was cancelled. */ + tristate printActionForItem(KexiPart::Item* item, PrintActionType action); + + private: + class MessageHandler; + class Private; + Private *d; + + friend class KexiDialogBase; +}; + +#endif + diff --git a/kexi/main/keximainwindowimpl_p.h b/kexi/main/keximainwindowimpl_p.h new file mode 100644 index 00000000..b48c7ca0 --- /dev/null +++ b/kexi/main/keximainwindowimpl_p.h @@ -0,0 +1,599 @@ +/* This file is part of the KDE projec + Copyright (C) 2003 Lucijan Busch <lucijan@kde.org> + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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. +*/ + +#ifdef KEXI_NO_PROCESS_EVENTS +# define KEXI_NO_PENDING_DIALOGS +#endif + +//! @internal safer dictionary +typedef QMap< int, QGuardedPtr<KexiDialogBase> > KexiDialogDict; + +//! @internal +class KexiMainWindowImpl::Private +{ +public: + Private(KexiMainWindowImpl* w) +// : dialogs(401) + : wnd(w) + , m_openedCustomObjectsForItem(1019, true) + { + propEditor=0; + propEditorToolWindow=0; + propEditorTabWidget=0; + userMode = false; + nav=0; + navToolWindow=0; + prj = 0; + curDialogGUIClient=0; + curDialogViewGUIClient=0; + closedDialogGUIClient=0; + closedDialogViewGUIClient=0; + nameDialog=0; + curDialog=0; + m_findDialog=0; + block_KMdiMainFrm_eventFilter=false; + focus_before_popup=0; +// relationPart=0; + privateIDCounter=0; + action_view_nav=0; + action_view_propeditor=0; + action_view_mainarea=0; + action_open_recent_projects_title_id = -1; + action_open_recent_connections_title_id = -1; + forceDialogClosing=false; + insideCloseDialog=false; +#ifndef KEXI_NO_PENDING_DIALOGS + actionToExecuteWhenPendingJobsAreFinished = NoAction; +#endif +// callSlotLastChildViewClosedAfterCloseDialog=false; + createMenu=0; + showImportantInfoOnStartup=true; +// disableErrorMessages=false; +// last_checked_mode=0; + propEditorDockSeparatorPos=-1; + navDockSeparatorPos=-1; +// navDockSeparatorPosWithAutoOpen=-1; + wasAutoOpen = false; + dialogExistedBeforeCloseProject = false; +#ifndef KEXI_SHOW_UNIMPLEMENTED + dummy_action = new KActionMenu("", wnd); +#endif + maximizeFirstOpenedChildFrm = false; +#ifdef HAVE_KNEWSTUFF + newStuff = 0; +#endif + mdiModeToSwitchAfterRestart = (KMdi::MdiMode)0; + forceShowProjectNavigatorOnCreation = false; + forceHideProjectNavigatorOnCreation = false; + navWasVisibleBeforeProjectClosing = false; + saveSettingsForShowProjectNavigator = true; + m_openedCustomObjectsForItem.setAutoDelete(true); + } + ~Private() { + } + +#ifndef KEXI_NO_PENDING_DIALOGS + //! Job type. Currently used for marking items as being opened or closed. + enum PendingJobType { + NoJob = 0, + DialogOpeningJob, + DialogClosingJob + }; + + KexiDialogBase *openedDialogFor( const KexiPart::Item* item, PendingJobType &pendingType ) + { + return openedDialogFor( item->identifier(), pendingType ); + } + + KexiDialogBase *openedDialogFor( int identifier, PendingJobType &pendingType ) + { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + QMap<int, PendingJobType>::ConstIterator it = pendingDialogs.find( identifier ); + if (it==pendingDialogs.constEnd()) + pendingType = NoJob; + else + pendingType = it.data(); + + if (pendingType == DialogOpeningJob) { + return 0; + } + return (KexiDialogBase*)dialogs[ identifier ]; + } +#else + KexiDialogBase *openedDialogFor( const KexiPart::Item* item ) + { + return openedDialogFor( item->identifier() ); + } + + KexiDialogBase *openedDialogFor( int identifier ) + { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + return (KexiDialogBase*)dialogs[ identifier ]; + } +#endif + + void insertDialog(KexiDialogBase *dlg) { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + dialogs.insert(dlg->id(), QGuardedPtr<KexiDialogBase>(dlg)); +#ifndef KEXI_NO_PENDING_DIALOGS + pendingDialogs.remove(dlg->id()); +#endif + } + +#ifndef KEXI_NO_PENDING_DIALOGS + void addItemToPendingDialogs(const KexiPart::Item* item, PendingJobType jobType) { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + pendingDialogs.replace( item->identifier(), jobType ); + } + + bool pendingDialogsExist() { + if (pendingDialogs.constBegin()!=pendingDialogs.constEnd()) + kdDebug() << pendingDialogs.constBegin().key() << " " << (int)pendingDialogs.constBegin().data() << endl; +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + return !pendingDialogs.isEmpty(); + } +#endif + + void updateDialogId(KexiDialogBase *dlg, int oldItemID) { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + dialogs.remove(oldItemID); +#ifndef KEXI_NO_PENDING_DIALOGS + pendingDialogs.remove(oldItemID); +#endif + dialogs.insert(dlg->id(), QGuardedPtr<KexiDialogBase>(dlg)); + } + + void removeDialog(int identifier) { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + dialogs.remove(identifier); + } + +#ifndef KEXI_NO_PENDING_DIALOGS + void removePendingDialog(int identifier) { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + pendingDialogs.remove(identifier); + } +#endif + + uint openedDialogsCount() { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + return dialogs.count(); + } + + //! Used in KexiMainWindowImple::closeProject() + void clearDialogs() { +//todo(threads) QMutexLocker dialogsLocker( &dialogsMutex ); + dialogs.clear(); +#ifndef KEXI_NO_PENDING_DIALOGS + pendingDialogs.clear(); +#endif + } + + /*! Toggles last checked view mode radio action, if available. */ + void toggleLastCheckedMode() + { + if (curDialog.isNull()) + return; + KRadioAction *ra = actions_for_view_modes[ curDialog->currentViewMode() ]; + if (ra) + ra->setChecked(true); +// if (!last_checked_mode) +// return; +// last_checked_mode->setChecked(true); + } + +/* +void updatePropEditorDockWidthInfo() { + if (propEditor) { + KDockWidget *dw = (KDockWidget *)propEditor->parentWidget(); +#if defined(KDOCKWIDGET_P) + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + if (ds) { + propEditorDockSeparatorPos = ds->separatorPosInPercent();*/ +/* if (propEditorDockSeparatorPos<=0) { + config->setGroup("MainWindow"); + propEditorDockSeparatorPos = config->readNumEntry("RightDockPosition", 80); + ds->setSeparatorPos(propEditorDockSeparatorPos, true); + }*/ + /*} +#endif + } + }*/ + + void showStartProcessMsg(const QStringList& args) + { + wnd->showErrorMessage(i18n("Could not start %1 application.").arg(KEXI_APP_NAME), + i18n("Command \"%1\" failed.").arg(args.join(" "))); + } + + void hideMenuItem(const QString& menuName, const QString& itemText, bool alsoSeparator) + { + QPopupMenu *pm = popups[menuName.ascii()]; + if (!pm) + return; + uint i=0; + const uint c = pm->count(); + for (;i<c;i++) { + kdDebug() << pm->text( pm->idAt(i) ) <<endl; + if (pm->text( pm->idAt(i) ).lower().stripWhiteSpace()==itemText.lower().stripWhiteSpace()) + break; + } + if (i<c) { + pm->setItemVisible( pm->idAt(i), false ); + if (alsoSeparator) + pm->setItemVisible( pm->idAt(i+1), false ); //also separator + } + } + + void disableMenuItem(const QString& menuName, const QString& itemText) + { + QPopupMenu *pm = popups[menuName.ascii()]; + if (!pm) + return; + uint i=0; + const uint c = pm->count(); + for (;i<c;i++) { + if (pm->text( pm->idAt(i) ).lower().stripWhiteSpace()==itemText.lower().stripWhiteSpace()) + break; + } + if (i<c) + pm->setItemEnabled( pm->idAt(i), false ); + } + + void updatePropEditorVisibility(int viewMode) + { + if (propEditorToolWindow) { + if (viewMode==0 || viewMode==Kexi::DataViewMode) { +#ifdef PROPEDITOR_VISIBILITY_CHANGES + wnd->makeDockInvisible( wnd->manager()->findWidgetParentDock(propEditor) ); +// propEditorToolWindow->hide(); +#endif + } else { + //propEditorToolWindow->show(); + QWidget *origFocusWidget = qApp->focusWidget(); + wnd->makeWidgetDockVisible(propEditorTabWidget); + if (origFocusWidget) + origFocusWidget->setFocus(); +/*moved +#if defined(KDOCKWIDGET_P) + KDockWidget *dw = (KDockWidget *)propEditor->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); + ds->setSeparatorPosInPercent(config->readNumEntry("RightDockPosition", 80));//% +#endif*/ + } + } + } + + void restoreNavigatorWidth() + { +#if defined(KDOCKWIDGET_P) + if (wnd->mdiMode()==KMdi::ChildframeMode || wnd->mdiMode()==KMdi::TabPageMode) { + KDockWidget *dw = (KDockWidget *)nav->parentWidget(); + KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); +// ds->setKeepSize(true); + + config->setGroup("MainWindow"); +# if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0) + + if (wasAutoOpen) //(dw2->isVisible()) +// ds->setSeparatorPosInPercent( 100 * nav->width() / wnd->width() ); + ds->setSeparatorPosInPercent( + QMAX(QMAX( config->readNumEntry("LeftDockPositionWithAutoOpen",20), + config->readNumEntry("LeftDockPosition",20)),20) + ); + else + ds->setSeparatorPosInPercent( + QMAX(20, config->readNumEntry("LeftDockPosition", 20/* % */))); + + // dw->resize( d->config->readNumEntry("LeftDockPosition", 115/* % */), dw->height() ); +# else + //there were problems on KDE < 3.4 + ds->setSeparatorPosInPercent( 20 ); +# endif + //if (!wasAutoOpen) //(dw2->isVisible()) +// ds->setSeparatorPos( ds->separatorPos(), true ); + } +#endif + } + + template<class type> + type *openedCustomObjectsForItem(KexiPart::Item* item, const char* name) + { + if (!item || !name) { + kdWarning() << + "KexiMainWindowImpl::Private::openedCustomObjectsForItem(): !item || !name" << endl; + return 0; + } + QString key( QString::number(item->identifier()) + name ); + return dynamic_cast<type*>( m_openedCustomObjectsForItem.find( key.latin1() ) ); + } + + void addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name) + { + QString key = QString::number(item->identifier()) + name; + m_openedCustomObjectsForItem.insert( key.latin1(), object ); + } + + KexiFindDialog *findDialog() { + if (!m_findDialog) { + m_findDialog = new KexiFindDialog(wnd); + m_findDialog->setActions( action_edit_findnext, action_edit_findprev, + action_edit_replace, action_edit_replace_all ); +/* connect(m_findDialog, SIGNAL(findNext()), action_edit_findnext, SLOT(activate())); + connect(m_findDialog, SIGNAL(find()), wnd, SLOT(slotEditFindNext())); + connect(m_findDialog, SIGNAL(replace()), wnd, SLOT(slotEditReplaceNext())); + connect(m_findDialog, SIGNAL(replaceAll()), wnd, SLOT(slotEditReplaceAll()));*/ + } + return m_findDialog; + } + + /*! Updates the find/replace dialog depending on the active view. + Nothing is performed if the dialog is not instantiated yet or is invisible. */ + void updateFindDialogContents(bool createIfDoesNotExist = false) { + if (!createIfDoesNotExist && (!m_findDialog || !m_findDialog->isVisible())) + return; + KexiSearchAndReplaceViewInterface* iface = currentViewSupportingSearchAndReplaceInterface(); + if (!iface) { + if (m_findDialog) { + m_findDialog->setButtonsEnabled(false); + m_findDialog->setLookInColumnList(QStringList(), QStringList()); + } + return; + } +//! @todo use ->caption() here, depending on global settings related to displaying captions + findDialog()->setObjectNameForCaption(curDialog->partItem()->name()); + + QStringList columnNames; + QStringList columnCaptions; + QString currentColumnName; // for 'look in' + if (!iface->setupFindAndReplace(columnNames, columnCaptions, currentColumnName)) { + m_findDialog->setButtonsEnabled(false); + m_findDialog->setLookInColumnList(QStringList(), QStringList()); + return; + } + m_findDialog->setButtonsEnabled(true); + + /* //update "look in" list + KexiTableViewColumn::List columns( dataAwareObject()->data()->columns ); + QStringList columnNames; + QStringList columnCaptions; + for (KexiTableViewColumn::ListIterator it(columns); it.current(); ++it) { + if (!it.current()->visible()) + continue; + columnNames.append( it.current()->field()->name() ); + columnCaptions.append( it.current()->captionAliasOrName() ); + }*/ + const QString prevColumnName( m_findDialog->currentLookInColumnName()); + m_findDialog->setLookInColumnList(columnNames, columnCaptions); + m_findDialog->setCurrentLookInColumnName( prevColumnName ); + } + + //! \return the current view if it supports \a actionName, otherwise returns 0. + KexiViewBase *currentViewSupportingAction(const char* actionName) const + { + if (!curDialog) + return 0; + KexiViewBase *view = curDialog->selectedView(); + if (!view) + return 0; + KAction *action = view->sharedAction(actionName); + if (!action || !action->isEnabled()) + return 0; + return view; + } + + //! \return the current view if it supports KexiSearchAndReplaceViewInterface. + KexiSearchAndReplaceViewInterface* currentViewSupportingSearchAndReplaceInterface() const + { + if (!curDialog) + return 0; + KexiViewBase *view = curDialog->selectedView(); + if (!view) + return 0; + return dynamic_cast<KexiSearchAndReplaceViewInterface*>(view); + } + + KexiMainWindowImpl *wnd; + KexiStatusBar *statusBar; + KexiProject *prj; + KConfig *config; +#ifndef KEXI_NO_CTXT_HELP + KexiContextHelp *ctxHelp; +#endif + KexiBrowser *nav; + KTabWidget *propEditorTabWidget; + //! poits to kexi part which has been previously used to setup proppanel's tabs using + //! KexiPart::setupCustomPropertyPanelTabs(), in updateCustomPropertyPanelTabs(). + QGuardedPtr<KexiPart::Part> partForPreviouslySetupPropertyPanelTabs; + QMap<KexiPart::Part*, int> recentlySelectedPropertyPanelPages; + QGuardedPtr<KexiPropertyEditorView> propEditor; + QGuardedPtr<KoProperty::Set> propBuffer; + + KXMLGUIClient *curDialogGUIClient, *curDialogViewGUIClient, + *closedDialogGUIClient, *closedDialogViewGUIClient; + QGuardedPtr<KexiDialogBase> curDialog; + + KexiNameDialog *nameDialog; + + QTimer timer; //helper timer +// QSignalMapper *actionMapper; + + QAsciiDict<QPopupMenu> popups; //list of menu popups + QPopupMenu *createMenu; + + QString origAppCaption; //<! original application's caption (without project name) + QString appCaptionPrefix; //<! application's caption prefix - prj name (if opened), else: null + +#ifndef KEXI_SHOW_UNIMPLEMENTED + KActionMenu *dummy_action; +#endif + + //! project menu + KAction *action_save, *action_save_as, *action_close, + *action_project_properties, *action_open_recent_more, + *action_project_relations, *action_project_import_data_table, + *action_project_export_data_table, + *action_project_print, *action_project_print_preview, + *action_project_print_setup; +// KRecentFilesAction *action_open_recent; + KActionMenu *action_open_recent, *action_show_other; +// int action_open_recent_more_id; + int action_open_recent_projects_title_id, + action_open_recent_connections_title_id; + + //! edit menu + KAction *action_edit_delete, *action_edit_delete_row, + *action_edit_cut, *action_edit_copy, *action_edit_paste, + *action_edit_find, *action_edit_findnext, *action_edit_findprev, + *action_edit_replace, *action_edit_replace_all, + *action_edit_select_all, + *action_edit_undo, *action_edit_redo, + *action_edit_insert_empty_row, + *action_edit_edititem, *action_edit_clear_table, + *action_edit_paste_special_data_table, + *action_edit_copy_special_data_table; + + //! view menu + KAction *action_view_nav, *action_view_propeditor, *action_view_mainarea; + KRadioAction *action_view_data_mode, *action_view_design_mode, *action_view_text_mode; + QIntDict<KRadioAction> actions_for_view_modes; +// KRadioAction *last_checked_mode; +#ifndef KEXI_NO_CTXT_HELP + KToggleAction *action_show_helper; +#endif + //! data menu + KAction *action_data_save_row; + KAction *action_data_cancel_row_changes; + KAction *action_data_execute; + + //! format menu + KAction *action_format_font; + + //! tools menu + KAction *action_tools_data_migration, *action_tools_compact_database; + KActionMenu *action_tools_scripts; + + //! window menu + KAction *action_window_next, *action_window_previous; + + //! settings menu + KAction *action_configure; + + //! for dock windows + KMdiToolViewAccessor* navToolWindow; + KMdiToolViewAccessor* propEditorToolWindow; + + QGuardedPtr<QWidget> focus_before_popup; +// KexiRelationPart *relationPart; + + int privateIDCounter; //!< counter: ID for private "document" like Relations window + + bool block_KMdiMainFrm_eventFilter : 1; + + //! Set to true only in destructor, used by closeDialog() to know if + //! user can cancel dialog closing. If true user even doesn't see any messages + //! before closing a dialog. This is for extremely sanity... and shouldn't be even needed. + bool forceDialogClosing : 1; + + //! Indicates that we're inside closeDialog() method - to avoid inf. recursion + //! on dialog removing + bool insideCloseDialog : 1; + +#ifndef KEXI_NO_PENDING_DIALOGS + //! Used in executeActionWhenPendingJobsAreFinished(). + enum ActionToExecuteWhenPendingJobsAreFinished { + NoAction, + QuitAction, + CloseProjectAction + }; + ActionToExecuteWhenPendingJobsAreFinished actionToExecuteWhenPendingJobsAreFinished; + + void executeActionWhenPendingJobsAreFinished() { + ActionToExecuteWhenPendingJobsAreFinished a = actionToExecuteWhenPendingJobsAreFinished; + actionToExecuteWhenPendingJobsAreFinished = NoAction; + switch (a) { + case QuitAction: + qApp->quit(); + break; + case CloseProjectAction: + wnd->closeProject(); + break; + default:; + } + } +#endif + + //! Used for delayed dialogs closing for 'close all' + QPtrList<KexiDialogBase> windowsToClose; + + //! Opened page setup dialogs, used by printOrPrintPreviewForItem(). + QIntDict<KexiDialogBase> pageSetupDialogs; + + /*! A map from Kexi dialog to "print setup" part item's ID of the data item + used by closeDialog() to find an ID of the data item, so the entry + can be removed from pageSetupDialogs dictionary. */ + QMap<int, int> pageSetupDialogItemID2dataItemID_map; + + //! Used in several places to show info dialog at startup (only once per session) + //! before displaying other stuff + bool showImportantInfoOnStartup : 1; + +// //! Used sometimes to block showErrorMessage() +// bool disableErrorMessages : 1; + + //! Indicates if project is started in User Mode + bool userMode : 1; + + //! Indicates if project navigator should be visible + bool isProjectNavigatorVisible : 1; + + //! Used on opening 1st child window + bool maximizeFirstOpenedChildFrm : 1; + + //! Set in restoreSettings() and used in initNavigator() + //! to customize navigator visibility on startup + bool forceShowProjectNavigatorOnCreation : 1; + bool forceHideProjectNavigatorOnCreation : 1; + + bool navWasVisibleBeforeProjectClosing : 1; + bool saveSettingsForShowProjectNavigator : 1; +#ifdef HAVE_KNEWSTUFF + KexiNewStuff *newStuff; +#endif + + //! Used by openedCustomObjectsForItem() and addOpenedCustomObjectForItem() + QAsciiDict<QObject> m_openedCustomObjectsForItem; + + int propEditorDockSeparatorPos, navDockSeparatorPos; +// int navDockSeparatorPosWithAutoOpen; + bool wasAutoOpen; + bool dialogExistedBeforeCloseProject; + + KMdi::MdiMode mdiModeToSwitchAfterRestart; + + private: + //! @todo move to KexiProject + KexiDialogDict dialogs; +#ifndef KEXI_NO_PROCESS_EVENTS + QMap<int, PendingJobType> pendingDialogs; //!< part item identifiers for dialogs whoose opening has been started + //todo(threads) QMutex dialogsMutex; //!< used for locking dialogs and pendingDialogs dicts +#endif + KexiFindDialog *m_findDialog; +}; diff --git a/kexi/main/kexinamedialog.cpp b/kexi/main/kexinamedialog.cpp new file mode 100644 index 00000000..85f7f04a --- /dev/null +++ b/kexi/main/kexinamedialog.cpp @@ -0,0 +1,111 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + 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 "kexinamedialog.h" + +KexiNameDialog::KexiNameDialog(const QString& message, + QWidget * parent, const char * name) + : KDialogBase(KDialogBase::Plain, QString::null, + KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::Help, + KDialogBase::Ok, + parent, name) +{ +// QHBox ( QWidget * parent = 0, const char * name = 0, WFlags f = 0 ) + m_widget= new KexiNameWidget(message, plainPage(), "KexiNameWidget"); + init(); +} + +KexiNameDialog::KexiNameDialog(const QString& message, + const QString& nameLabel, const QString& nameText, + const QString& captionLabel, const QString& captionText, + QWidget * parent, const char * name) + : KDialogBase(KDialogBase::Plain, QString::null, + KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, + parent, name) +{ + m_widget= new KexiNameWidget(message, nameLabel, nameText, + captionLabel, captionText, plainPage(), "KexiNameWidget"); + init(); +} + +KexiNameDialog::~KexiNameDialog() +{ +} + +void KexiNameDialog::init() +{ + QGridLayout *lyr = new QGridLayout(plainPage(), 2, 3); + m_icon = new QLabel( plainPage(), "icon" ); + m_icon->setAlignment( int( AlignTop | AlignLeft ) ); + m_icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred,1,0)); + m_icon->setFixedWidth(50); + lyr->addWidget(m_icon,0,0); + + m_widget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred,1,0)); + lyr->addWidget(m_widget,0,1); + lyr->addItem(new QSpacerItem( 25, 10, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, 2); + lyr->addItem(new QSpacerItem( 5, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ), 1, 1); +// m_widget->captionLineEdit()->selectAll(); +// m_widget->captionLineEdit()->setFocus(); + connect(m_widget,SIGNAL(messageChanged()),this, SLOT(updateSize())); + updateSize(); + enableButtonOK( true ); + slotTextChanged(); + connect(m_widget, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); +} + +void KexiNameDialog::updateSize() +{ +// resize( QSize(400, 140 + (m_widget->lbl_message->isVisible()?m_widget->lbl_message->height():0) ) + resize( QSize(400, 140 + (!m_widget->lbl_message->text().isEmpty()?m_widget->lbl_message->height():0) ) + .expandedTo(minimumSizeHint()) ); +// updateGeometry(); +} + +void KexiNameDialog::slotTextChanged() +{ + bool enable = true; + if (m_widget->isNameRequired() && m_widget->nameText().isEmpty() + || m_widget->isCaptionRequired() && m_widget->captionText().isEmpty()) + enable = false; + enableButtonOK( enable ); +} + +void KexiNameDialog::accept() +{ + if (!m_widget->checkValidity()) + return; + KDialogBase::accept(); +} + +void KexiNameDialog::setDialogIcon(const QPixmap& icon) +{ + m_icon->setPixmap(icon); +} + +void KexiNameDialog::show() +{ + m_widget->captionLineEdit()->selectAll(); + m_widget->captionLineEdit()->setFocus(); + KDialogBase::show(); +} + +#include "kexinamedialog.moc" + diff --git a/kexi/main/kexinamedialog.h b/kexi/main/kexinamedialog.h new file mode 100644 index 00000000..27707c0d --- /dev/null +++ b/kexi/main/kexinamedialog.h @@ -0,0 +1,61 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + 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 KEXINAMEDIALOG_H +#define KEXINAMEDIALOG_H + +#include <kdialogbase.h> + +#include "kexinamewidget.h" + +class KEXIMAIN_EXPORT KexiNameDialog : public KDialogBase +{ + Q_OBJECT + + public: + KexiNameDialog(const QString& message, + QWidget * parent = 0, const char * name = 0); + + KexiNameDialog(const QString& message, + const QString& nameLabel, const QString& nameText, + const QString& captionLabel, const QString& captionText, + QWidget * parent = 0, const char * name = 0); + + virtual ~KexiNameDialog(); + + KexiNameWidget* widget() const { return m_widget; } + + virtual void show(); + + public slots: + virtual void setDialogIcon(const QPixmap& icon); + + protected slots: + void slotTextChanged(); + virtual void accept(); + void updateSize(); + + protected: + void init(); + + QLabel *m_icon; + KexiNameWidget* m_widget; +}; + +#endif diff --git a/kexi/main/kexinamewidget.cpp b/kexi/main/kexinamewidget.cpp new file mode 100644 index 00000000..39cb084a --- /dev/null +++ b/kexi/main/kexinamewidget.cpp @@ -0,0 +1,236 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + 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 "kexinamewidget.h" + +#include <qlabel.h> +#include <qlayout.h> + +#include <klineedit.h> +#include <kmessagebox.h> +#include <klocale.h> + +#include <kexiutils/validator.h> +#include <kexiutils/identifier.h> +#include <core/kexi.h> + +using namespace KexiUtils; + +KexiNameWidget::KexiNameWidget( const QString& message, + QWidget* parent, const char* name, WFlags fl ) + : QWidget(parent, name, fl) +{ + init(message, QString::null, QString::null, QString::null, QString::null); +} + +KexiNameWidget::KexiNameWidget(const QString& message, + const QString& nameLabel, const QString& nameText, + const QString& captionLabel, const QString& captionText, + QWidget * parent, const char * name, WFlags fl) +{ + Q_UNUSED( parent ); + Q_UNUSED( name ); + Q_UNUSED( fl ); + + init(message, nameLabel, nameText, captionLabel, captionText); +} + +void KexiNameWidget::init( + const QString& message, + const QString& nameLabel, const QString& nameText, + const QString& captionLabel, const QString& captionText) +{ + Q_UNUSED( captionText ); + + m_le_name_txtchanged_disable = false; + m_le_name_autofill = true; + m_caption_required = false; + + lyr = new QGridLayout( this, 1, 1, 0, 6, "lyr"); + + lbl_message = new QLabel( this, "message" ); + setMessageText( message ); + lbl_message->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + lbl_message->setAlignment( QLabel::AlignTop | QLabel::WordBreak ); + lyr->addMultiCellWidget( lbl_message, 0, 0, 0, 1 ); + + lbl_caption = new QLabel( captionLabel.isEmpty() ? i18n( "Caption:" ) : captionLabel, + this, "lbl_caption" ); + lyr->addWidget( lbl_caption, 1, 0 ); + + lbl_name = new QLabel( nameLabel.isEmpty() ? tr( "Name:" ) : nameLabel, + this, "lbl_name" ); + lyr->addWidget( lbl_name, 2, 0 ); + + le_caption = new KLineEdit( nameText, this, "le_caption" ); + le_caption->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 1, 0)); + lyr->addWidget( le_caption, 1, 1 ); + + le_name = new KLineEdit( nameText, this, "le_name" ); + le_name->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed,1,0)); + Validator *idValidator = new IdentifierValidator(0, "id_val"); + le_name->setValidator( m_validator = new MultiValidator(idValidator, this, "val") ); + lyr->addWidget( le_name, 2, 1 ); + + setFocusProxy(le_caption); + resize( QSize(342, 123).expandedTo(minimumSizeHint()) ); + + m_nameWarning = i18n("Please enter the name."); + m_captionWarning = i18n("Please enter the caption."); + + connect(le_caption, SIGNAL(textChanged(const QString&)), + this,SLOT(slotCaptionTxtChanged(const QString&))); + connect(le_name, SIGNAL(textChanged(const QString&)), + this,SLOT(slotNameTxtChanged(const QString&))); + connect(le_caption, SIGNAL(returnPressed()), + this,SIGNAL(returnPressed())); + connect(le_name, SIGNAL(returnPressed()), + this,SIGNAL(returnPressed())); +} + +KexiNameWidget::~KexiNameWidget() +{ +} + +void KexiNameWidget::slotCaptionTxtChanged(const QString &capt) +{ + emit textChanged(); + if (le_name->text().isEmpty()) + m_le_name_autofill=true; + if (m_le_name_autofill) { + m_le_name_txtchanged_disable = true; + le_name->setText( string2Identifier(capt).lower() ); + m_le_name_txtchanged_disable = false; + } +} + +void KexiNameWidget::slotNameTxtChanged(const QString &) +{ + emit textChanged(); + if (m_le_name_txtchanged_disable) + return; + m_le_name_autofill = false; +} + +void KexiNameWidget::clear() +{ + le_name->clear(); + le_caption->clear(); +} + +bool KexiNameWidget::empty() const +{ + return le_name->text().isEmpty() || le_caption->text().stripWhiteSpace().isEmpty(); +} + +void KexiNameWidget::setNameRequired( bool set ) +{ m_validator->setAcceptsEmptyValue(!set); } + +bool KexiNameWidget::isNameRequired() const +{ return !m_validator->acceptsEmptyValue(); } + +void KexiNameWidget::setCaptionText(const QString& capt) +{ + le_caption->setText(capt); + m_le_name_autofill = true; +} + +void KexiNameWidget::setNameText(const QString& name) +{ + le_name->setText(name); + m_le_name_autofill = true; +} + +void KexiNameWidget::setMessageText(const QString& msg) +{ + if (msg.stripWhiteSpace().isEmpty()) { + lbl_message->setText(""); + lbl_message->hide(); + } else { + lbl_message->setText(msg.stripWhiteSpace()+"<br>"); + lbl_message->show(); + } + messageChanged(); +} + +QString KexiNameWidget::captionText() const +{ + return le_caption->text(); +} + +QString KexiNameWidget::nameText() const +{ + return le_name->text().lower(); +} + +bool KexiNameWidget::checkValidity() +{ + if (isNameRequired() && le_name->text().stripWhiteSpace().isEmpty()) { + KMessageBox::sorry(0, m_nameWarning); + le_name->setFocus(); + return false; + } + if (isCaptionRequired() && le_caption->text().stripWhiteSpace().isEmpty()) { + KMessageBox::sorry(0, m_captionWarning); + le_caption->setFocus(); + return false; + } + QString dummy, message, details; + if (m_validator->check(dummy, le_name->text(), message, details) + ==Validator::Error) { + KMessageBox::detailedSorry(0, message, details); + le_name->setFocus(); + return false; + } + return true; +} + +Validator *KexiNameWidget::nameValidator() const +{ + return m_validator; +} + +void KexiNameWidget::addNameSubvalidator( Validator* validator, bool owned ) +{ + m_validator->addSubvalidator( validator, owned ); +} + +/*bool KexiNameWidget::eventFilter( QObject *obj, QEvent *ev ) +{ + if (ev->type()==QEvent::FocusOut && !acceptsEmptyValue()) { + if (obj==le_name) { + if (le_name->text().isEmpty()) { + KMessageBox::information(0, m_nameWarning); + le_name->setFocus(); + return true; + } + } + else if (obj==le_caption) { + if (le_caption->text().isEmpty()) { + KMessageBox::information(0, m_captionWarning); + le_caption->setFocus(); + return true; + } + } + } + return false; +}*/ + +#include "kexinamewidget.moc" + diff --git a/kexi/main/kexinamewidget.h b/kexi/main/kexinamewidget.h new file mode 100644 index 00000000..07962b6c --- /dev/null +++ b/kexi/main/kexinamewidget.h @@ -0,0 +1,142 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + 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 KEXINAMEWIDGET_H +#define KEXINAMEWIDGET_H + +#include <qlabel.h> +#include <qlayout.h> +#include <klineedit.h> + +namespace KexiUtils { +class Validator; +class MultiValidator; +} + +class KEXIMAIN_EXPORT KexiNameWidget : public QWidget +{ + Q_OBJECT + + public: + KexiNameWidget(const QString& message, + QWidget * parent = 0, const char * name = 0, WFlags fl = 0); + + KexiNameWidget(const QString& message, + const QString& nameLabel, const QString& nameText, + const QString& captionLabel, const QString& captionText, + QWidget * parent = 0, const char * name = 0, WFlags fl = 0); + + virtual ~KexiNameWidget(); + + QLabel* captionLabel() const { return lbl_caption; } + QLabel* nameLabel() const { return lbl_name; } + KLineEdit* captionLineEdit() const { return le_caption; } + KLineEdit* nameLineEdit() const { return le_name; } + + QString messageText() const { return lbl_message->text(); } + + void setMessageText(const QString& msg); + + //! \return entered caption text + QString captionText() const; + + void setCaptionText(const QString& capt); + //! \return entered name text, always in lower case + + QString nameText() const; + + void setNameText(const QString& name); + + /*! Sets i18n'ed warning message displayed when user leaves 'name' field + without filling it (if acceptsEmptyValue() is false). + By default the message is equal "Please enter the name.". */ + void setWarningForName( const QString& txt ) { m_nameWarning = txt; } + + /*! Sets i18n'ed warning message displayed when user leaves 'name' field + without filling it (if acceptsEmptyValue() is false). + By default the message is equal "Please enter the caption." */ + void setWarningForCaption( const QString& txt ) { m_captionWarning = txt; } + + /*! \return true if name or caption is empty. */ + bool empty() const; + + KexiUtils::Validator *nameValidator() const; + + /*! Adds subvalidator for name field. In fact it's is added to internal + multivalidator. If \a owned is true, \a validator will be owned by the object. + \sa MultiValidator::addSubvalidator(). */ + void addNameSubvalidator( KexiUtils::Validator* validator, bool owned = true ); + + /*! \return true if name text cannot be empty (true by default). */ + bool isNameRequired() const; + + void setNameRequired( bool set ); + + /*! \return true if caption text cannot be empty (false by default). */ + bool isCaptionRequired() const { return m_caption_required; } + + void setCaptionRequired(bool set) { m_caption_required = set; } + + public slots: + /*! Clears both name and caption. */ + virtual void clear(); + + /*! Checks if both fields have valid values + (i.e. not empty if acceptsEmptyValue() is false). + If not, warning message is shown and false is returned. */ + bool checkValidity(); + + signals: + /*! Emitted whenever return key is pressed on name or caption label. */ + void returnPressed(); + + /*! Emitted whenever the caption or the name text changes */ + void textChanged(); + + /*! Emitted whenever the message changes */ + void messageChanged(); + + protected slots: + void slotNameTxtChanged(const QString&); + void slotCaptionTxtChanged(const QString&); +// bool eventFilter( QObject *obj, QEvent *ev ); + + protected: + void init( + const QString& message, + const QString& nameLabel, const QString& nameText, + const QString& captionLabel, const QString& captionText); + + QLabel* lbl_message; + QLabel* lbl_caption; + QLabel* lbl_name; + KLineEdit* le_caption; + KLineEdit* le_name; + QGridLayout* lyr; + KexiUtils::MultiValidator *m_validator; + QString m_nameWarning, m_captionWarning; + + bool m_le_name_txtchanged_disable : 1; + bool m_le_name_autofill : 1; + bool m_caption_required : 1; + + friend class KexiNameDialog; +}; + +#endif diff --git a/kexi/main/kexinewstuff.cpp b/kexi/main/kexinewstuff.cpp new file mode 100644 index 00000000..adc0fc83 --- /dev/null +++ b/kexi/main/kexinewstuff.cpp @@ -0,0 +1,81 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> + + 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. +*/ + +#ifdef HAVE_KNEWSTUFF + +#include <kdebug.h> +#include <ktar.h> +#include <qdir.h> +#include <kaction.h> +#include <kapplication.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <kdeversion.h> + +#include "kexinewstuff.h" + +KexiNewStuff::KexiNewStuff(QWidget *parent) + : KNewStuff( "kexi/template" +#if KDE_IS_VERSION(3,3,0) + , "http://download.kde.org/khotnewstuff/kexi-providers.xml" +#endif + , parent) +{ + // Prevent GHNS to deny downloading a second time. If GHNS + // fails to download something, it still marks the thing as + // successfully downloaded and therefore we arn't able to + // download it again :-/ + KGlobal::config()->deleteGroup("KNewStuffStatus"); +} + +KexiNewStuff::~KexiNewStuff() +{ +} + +bool +KexiNewStuff::install(const QString &fileName) +{ + kdDebug() << "KexiNewStuff::install(): " << fileName << endl; + + KTar archive( fileName ); + if ( !archive.open( IO_ReadOnly ) ) { + kdDebug() << QString("KexiNewStuff::install: Failed to open archivefile \"%1\"").arg(fileName) << endl; + return false; + } + const KArchiveDirectory *archiveDir = archive.directory(); + const QString destDir = KFileDialog::getExistingDirectory( + ":DownloadExampleDatabases", parentWidget(), + i18n("Choose Directory Where to Install Example Database")); + if (destDir.isEmpty()) { + kdDebug() << QString("KexiNewStuff::install: Destination-directory is empty.") << endl; + return false; + } + archiveDir->copyTo(destDir); + archive.close(); + + return true; +} + +bool +KexiNewStuff::createUploadFile(const QString &) +{ + return true; +} + +#endif diff --git a/kexi/main/kexinewstuff.h b/kexi/main/kexinewstuff.h new file mode 100644 index 00000000..0af25276 --- /dev/null +++ b/kexi/main/kexinewstuff.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> + + 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. +*/ + +#ifdef HAVE_KNEWSTUFF + +#ifndef KEXINEWSTUFF_H +#define KEXINEWSTUFF_H + +#include "knewstuff/knewstuff.h" + +class KexiNewStuff : public KNewStuff +{ + public: + KexiNewStuff(QWidget *parent); + virtual ~KexiNewStuff(); + + virtual bool install( const QString &fileName ); + virtual bool createUploadFile( const QString &fileName ); + + //KNS::Engine* customEngine() { return KNewStuff::engine(); } +}; + +#endif + +#endif //HAVE_KNEWSTUFF diff --git a/kexi/main/kexistatusbar.cpp b/kexi/main/kexistatusbar.cpp new file mode 100644 index 00000000..c05f0eeb --- /dev/null +++ b/kexi/main/kexistatusbar.cpp @@ -0,0 +1,145 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + + Loosely based on kdevelop/src/statusbar.cpp + Copyright (C) 2001 by Bernd Gehrmann <bernd@kdevelop.org> +*/ + +#include "kexistatusbar.h" + +#include <qlayout.h> +#include <qlineedit.h> +#include <qpainter.h> +#include <qtimer.h> +#include <qfontmetrics.h> + +#include <kdebug.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kparts/part.h> + +#if KexiStatusBar_KTEXTEDITOR_USED +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/viewstatusmsginterface.h> +#endif + +KexiStatusBar::KexiStatusBar(QWidget *parent, const char *name) + : KStatusBar(parent, name) +#if KexiStatusBar_KTEXTEDITOR_USED + , m_cursorIface(0) +#endif + , m_activePart(0) +{ + int id = 0; + m_msgID = id++; + insertItem("", m_msgID, 1, true); + + m_readOnlyID = id++; + insertFixedItem(i18n("Read only"), m_readOnlyID, true); + setReadOnlyFlag(false); + +// @todo +// connect(PartController::getInstance(), SIGNAL(activePartChanged(KParts::Part*)), +// this, SLOT(activePartChanged(KParts::Part*))); + + /// @todo remove parts from the map on PartRemoved() ? +} + + +KexiStatusBar::~KexiStatusBar() +{ +} + +void KexiStatusBar::activePartChanged(KParts::Part *part) +{ + if ( m_activePart && m_activePart->widget() ) + disconnect( m_activePart->widget(), 0, this, 0 ); + + m_activePart = part; +#if KexiStatusBar_KTEXTEDITOR_USED + m_cursorIface = 0; + m_viewmsgIface = 0; +// @todo + if (part && part->widget()) { + if ((m_viewmsgIface = dynamic_cast<KTextEditor::ViewStatusMsgInterface*>(part->widget()))) { + connect( part->widget(), SIGNAL( viewStatusMsg( const QString & ) ), + this, SLOT( setStatus( const QString & ) ) ); + +# if KDE_VERSION < KDE_MAKE_VERSION(3,1,90) + changeItem(m_map[ m_activePart ], m_msgID); +// m_status->setText( m_map[ m_activePart ] ); +# endif + } + else if ((m_cursorIface = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()))) { + connect(part->widget(), SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged())); + cursorPositionChanged(); + } + else { + // we can't produce any status data, hide the status box + changeItem("", m_msgID); + } + } +#endif +} + + +void KexiStatusBar::cursorPositionChanged() +{ +#if KexiStatusBar_KTEXTEDITOR_USED + if (m_cursorIface) + { + uint line, col; + m_cursorIface->cursorPosition(&line, &col); + setCursorPosition(line, col); + } +#endif +} + +void KexiStatusBar::setStatus(const QString &str) +{ + kdDebug() << "KexiStatusBar::setStatus(" << str << ")" << endl; +// m_status->setText(str); + changeItem(str, m_msgID); + +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION < KDE_MAKE_VERSION(3,1,90) + m_map[m_activePart] = str; +# endif +#endif +} + +void KexiStatusBar::setCursorPosition(int line, int col) +{ +// m_status->setText(i18n(" Line: %1 Col: %2 ").arg(line+1).arg(col)); + changeItem(i18n(" Line: %1 Col: %2 ").arg(line+1).arg(col), m_msgID); +} + +/*void KexiStatusBar::addWidget ( QWidget *widget, int stretch, bool permanent) +{ + KStatusBar::addWidget(widget,stretch,permanent); + + if(widget->sizeHint().height() + 4 > height()) + setFixedHeight(widget->sizeHint().height() + 4); +}*/ + +void KexiStatusBar::setReadOnlyFlag(bool readOnly) +{ + changeItem(readOnly ? i18n("Read only") : QString::null, m_readOnlyID); +} + +#include "kexistatusbar.moc" diff --git a/kexi/main/kexistatusbar.h b/kexi/main/kexistatusbar.h new file mode 100644 index 00000000..eec24932 --- /dev/null +++ b/kexi/main/kexistatusbar.h @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + + Loosely based on kdevelop/src/statusbar.h + Copyright (C) 2001 by Bernd Gehrmann <bernd@kdevelop.org> +*/ + +#ifndef KEXISTATUSBAR_H +#define KEXISTATUSBAR_H + +//temporary +#define KexiStatusBar_KTEXTEDITOR_USED 0 + +#include <kdeversion.h> +#include <kstatusbar.h> +#include <qmap.h> + +class QLabel; + +#if KexiStatusBar_KTEXTEDITOR_USED +namespace KTextEditor { class ViewStatusMsgInterface; } +namespace KTextEditor { class ViewCursorInterface; } +#endif +namespace KParts { class Part; } + +class KexiStatusBar : public KStatusBar +{ + Q_OBJECT + public: + KexiStatusBar( QWidget *parent=0, const char *name=0 ); + virtual ~KexiStatusBar(); +// virtual void addWidget( QWidget *widget, int stretch = 0, bool permanent = false); + + public slots: + virtual void setStatus(const QString &str); + virtual void setReadOnlyFlag(bool readOnly); + + protected slots: + virtual void cursorPositionChanged(); + virtual void activePartChanged(KParts::Part *part); + virtual void setCursorPosition(int line, int col); + + protected: + int m_msgID, m_readOnlyID; +// QLabel *m_status, *m_readOnlyStatus; + +#if KexiStatusBar_KTEXTEDITOR_USED + KTextEditor::ViewCursorInterface * m_cursorIface; + KTextEditor::ViewStatusMsgInterface * m_viewmsgIface; +#endif + KParts::Part *m_activePart; + +// still hoping for a fix for KDE-3.1 +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION < KDE_MAKE_VERSION(3,1,90) + QMap<KParts::Part*, QString> m_map; +# endif +#endif +}; + +#endif + diff --git a/kexi/main/ksplitter.h b/kexi/main/ksplitter.h new file mode 100644 index 00000000..db72ec88 --- /dev/null +++ b/kexi/main/ksplitter.h @@ -0,0 +1,256 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru> + Copyright (C) 2005 Dominik Haumann <dhdev@gmx.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* + IMPORTANT Note: This file compiles also in Qt-only mode by using the NO_KDE2 precompiler definition +*/ + +#ifndef KDOCKWIDGET_PRIVATE_H +#define KDOCKWIDGET_PRIVATE_H + +#include <qwidget.h> +#include <qpushbutton.h> + +#include <kdeversion.h> + +#ifndef NO_KDE2 +#include <netwm_def.h> +#endif + +class QFrame; +class KDockContainer; +class KDockWidget; + + +/** + * Like QSplitter but specially designed for dockwidgets stuff. + * @internal + * + * @author Max Judin. + */ +class KDockSplitter : public QWidget +{ + //Q_OBJECT +public: + /** + * Constructor. + * @param parent parent widget + * @param name name + * @param orient orientation. Either @p Vertical or @p Horizontal + * @param pos procentual position of the splitter. Must be int [0...100]. + */ + KDockSplitter(QWidget *parent= 0, const char *name= 0, Orientation orient= Vertical, int pos= 50); + virtual ~KDockSplitter(){}; + + /** + * Initialize the splitter. If @p c0 or @p c1 is 0L the child will not + * be replaced. So if you want to change @p c1 and not change c0, you'd + * call @p activate(0L,new_widget); + * + * @param c0 the widget on top/left + * @param c1 the widget on borrom/right + */ + void activate(QWidget *c0, QWidget *c1 = 0L); + /** + * Disables the splitter. + */ + void deactivate(); + + /** + * Return the separator position in percent (%), so the range is [0..100] + * @return separator position in percent + */ + int separatorPosInPercent() +#if KDE_IS_VERSION(3,4,89) + ; +#else + { +// kdDebug() << "^^^^^^^^^^^^^^^^^^^^^ separatorPosInPercent() " << separatorPos() / (factor/100) << " " << separatorPos() / 100 << endl; + return separatorPos() / 100; + } +#endif + /** + * Set the separator position in percent (%), so the range must be [0..100] + * @param percent separator position in percent + */ + void setSeparatorPosInPercent(int percent) +#if KDE_IS_VERSION(3,4,89) + ; +#else + { +// kdDebug() << "^^^^^^^^^^^^^^^^^^^^^ setSeparatorPosInPercent() " << percent << " " << separatorPos() / 100 << endl; + setSeparatorPos( percent * 100, false ); + } +#endif + + /** + * Return the separator position in the range [0..100000] + * To get the separator position in procent (%), call + * @p separatorPositionInPercent()! + * + * @return high resolution separator position in range [0..100000], + * where 100000 is 100%. + */ + int separatorPos() const; + /** + * set separator position. + * @param pos the separator position in range [0..100000]. 100000 is 100%. + * @param do_resize true by default + */ + void setSeparatorPos(int pos, bool do_resize = true); + /** + * For usage from outside. + * If the splitter is in fixed position when called, + * the value of @p pos will be saved and used when the splitter + * is restored. + * If @p do_resize is true, the size will be changed unless the splitter + * is in fixed mode. + */ + // ### please come up with a nicer name + void setSeparatorPosX(int pos, bool do_resize=false); + + /** + * The eventfilter installed on the @p divider processes + * all splitter resizing events. + */ + virtual bool eventFilter(QObject *, QEvent *); + virtual bool event( QEvent * ); + + /** + * @return the top/left child widget. + */ + QWidget* getFirst() const { return child0; } + /** + * @return the bottom/right child widget. + */ + QWidget* getLast() const { return child1; } + /** + * If @p w is child0, return child1, otherwise child0. + * @return the other child widget + */ + QWidget* getAnother( QWidget* w ) const; + void updateName(); + + /** + * Set opaque flag. + * @param b if true, both child widgets are resized immediately, + * if false, the widgets only resize on MouseUpEvent. + */ + void setOpaqueResize(bool b=true); + bool opaqueResize() const; + + /** + * If @p b is true, the splitter will keep its size on resize events. + * If no @p KDockContainer is around, always the left child0 will be fixed size. + */ + void setKeepSize(bool b=true); + bool keepSize() const; + + + void setForcedFixedWidth(KDockWidget *dw,int w); + void setForcedFixedHeight(KDockWidget *dw,int h); + void restoreFromForcedFixedSize(KDockWidget *dw); + + /** + * The orientation is either @p Horizontal or @p Vertical. + */ + Orientation orientation(){return m_orientation;} + +protected: + friend class KDockContainer; + /** + * Make sure the splitter position is not out of bounds. + * @param position the current position + * @return a (new) valid splitter position. + */ + int checkValue(int position) const; + /** + * Make sure the splitter position is not out of bounds. It has + * to honor all child widgets' mimimumSize. + * @param position current divider position + * @param child the overlapping child + * @return the (new) splitter position. + */ + int checkValueOverlapped(int position, QWidget* child) const; + + /** + * The resize event resizes @p child0, @p child1 and the @p divider. + * The new sizes are dependant of + * - whether @p child0 or @p child1 is a KDockContainer + * - the current mode which may be + * - Closed + * - Overlapped (opened) + * - Nonoverlap (opened) + * . + * . + * So there are 3*2=6 different modes we have to face. + * @param ev the resize Event. If @p ev=0L the user changed + * the mode (for example from overlap to nonoverlap mode). + */ + virtual void resizeEvent(QResizeEvent *ev); + +/* +protected slots: + void delayedResize();*/ + +private: + /** + * updates the minimum and maximun sizes for the KDockSplitter. + * The sizes depend on the minimum and maximum sizes of the two child + * widgets. + */ + void setupMinMaxSize(); + /** + * child0 and child1 contain the embedded widgets. They are always valid + * so no need to make pointer checks. + * child[01]->getWidget() may be KDockContainer. + */ + QWidget *child0, *child1; + Orientation m_orientation; + /** + * If initialised is true, the divider!=0L. If false, the divider==0L! + */ + bool initialised; + /** + * The splitter controller which is between child0 and child1. + * Its size is 4 pixel. + */ + QFrame* divider; + /** + * @p xpos and @p savedXPos represent the current divider position. + * If the orientation is Horizontal @p xpos actually is "ypos". So + * do not get confused only because of the 'x'. + * + * xpos and savedXPos are internally high resolution. So *not* 0..100% + * but 0..100000=100%. This fixes rounding bugs. In fact, this should + * be a double, but due to binary compatibility we can not change this + * as we would have to change it in all kdockwidgets. + */ + int xpos, savedXPos; + bool mOpaqueResize, mKeepSize; + int fixedWidth0,fixedWidth1; + int fixedHeight0,fixedHeight1; + bool m_dontRecalc; + /** + * resolution factor, 0 = 0%, 100000=100% + */ + static const int factor = 100000; +}; + +#endif diff --git a/kexi/main/printing/Makefile.am b/kexi/main/printing/Makefile.am new file mode 100644 index 00000000..a9d49a54 --- /dev/null +++ b/kexi/main/printing/Makefile.am @@ -0,0 +1,32 @@ +include $(top_srcdir)/kexi/Makefile.global + +noinst_LTLIBRARIES = libkeximainprinting.la + +libkeximainprinting_la_SOURCES = \ +kexisimpleprintingengine.cpp \ +kexisimpleprintingpart.cpp \ +kexisimpleprintingpagesetupbase.ui \ +kexisimpleprintingpagesetup.cpp \ +kexisimpleprintpreviewwindow.cpp + +noinst_HEADERS = kexisimpleprintpreviewwindow_p.h + +libkeximainprinting_la_LDFLAGS = $(all_libraries) -Wnounresolved +libkeximainprinting_la_LIBADD = \ + $(top_builddir)/lib/kofficecore/libkofficecore.la \ + $(top_builddir)/lib/kofficeui/libkofficeui.la \ + ../../widget/libkexiextendedwidgets.la + +libkeximainprinting_la_METASOURCES = AUTO + +SUBDIRS = . + +# set the include path for X, qt and KDE + +INCLUDES= -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/main/printing \ + -I$(top_srcdir)/kexi/core -I$(top_srcdir)/kexi/widget \ + -I$(top_builddir)/lib/kofficeui -I$(top_srcdir)/lib/kofficeui \ + -I$(top_srcdir)/lib/kofficecore \ + -I$(top_builddir)/kexi/widget $(all_includes) + +#KDE_CXXFLAGS += -DSIMPLE_KOLIBS -DKOFFICECORE_EXPORT= -DKOFFICEUI_EXPORT= diff --git a/kexi/main/printing/kexisimpleprintingengine.cpp b/kexi/main/printing/kexisimpleprintingengine.cpp new file mode 100644 index 00000000..e021c912 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingengine.cpp @@ -0,0 +1,558 @@ +/* This file is part of the KDE project + Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; 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 "kexisimpleprintingengine.h" + +#include <core/keximainwindow.h> +#include <kexiutils/utils.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kfontdialog.h> +#include <kurllabel.h> +#include <kdebug.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qcheckbox.h> +#include <qwhatsthis.h> +#include <qpaintdevicemetrics.h> +#include <qimage.h> + +#include <kexiutils/tristate.h> +#include <kexidb/connection.h> +#include <kexidb/tableschema.h> +#include <kexidb/cursor.h> +#include <kexidb/utils.h> +#include <kexidb/queryschema.h> + +KexiSimplePrintingSettings::KexiSimplePrintingSettings() +{ + pageLayout = KoPageLayout::standardLayout(); + addPageNumbers = true; + addDateAndTime = true; + addTableBorders = false; + pageTitleFont = kapp->font(); + pageTitleFont.setPointSizeFloat( (double)QFontInfo(pageTitleFont).pointSize()*1.5 ); + pageTitleFont.setBold(true); +} + +KexiSimplePrintingSettings::~KexiSimplePrintingSettings() +{ +} + +KexiSimplePrintingSettings KexiSimplePrintingSettings::load() +{ + KexiSimplePrintingSettings settings; //this will set defaults + + KConfig *config = kapp->config(); + config->setGroup("Simple Printing"); + if (config->hasKey("pageTitleFont")) + settings.pageTitleFont = config->readFontEntry("pageTitleFont"); +//! @todo system default? + if (config->hasKey("pageFormat")) + settings.pageLayout.format = KoPageFormat::formatFromString( + config->readEntry("pageFormat" ) ); + if (config->readEntry("pageOrientation", "portrait").lower()=="landscape") + settings.pageLayout.orientation = PG_LANDSCAPE; + else + settings.pageLayout.orientation = PG_PORTRAIT; + if (config->hasKey("pageWidth")) + settings.pageLayout.ptWidth = config->readDoubleNumEntry("pageWidth"); + if (config->hasKey("pageHeight")) + settings.pageLayout.ptHeight = config->readDoubleNumEntry("pageHeight"); + if (config->hasKey("pageLeftMargin")) + settings.pageLayout.ptLeft = config->readDoubleNumEntry("pageLeftMargin"); + if (config->hasKey("pageRightMargin")) + settings.pageLayout.ptRight = config->readDoubleNumEntry("pageRightMargin"); + if (config->hasKey("pageTopMargin")) + settings.pageLayout.ptTop = config->readDoubleNumEntry("pageTopMargin"); + if (config->hasKey("pageBottomMargin")) + settings.pageLayout.ptBottom = config->readDoubleNumEntry("pageBottomMargin"); + settings.addPageNumbers = config->readBoolEntry("addPageNumbersToPage", true); + settings.addDateAndTime = config->readBoolEntry("addDateAndTimePage", true); + settings.addTableBorders = config->readBoolEntry("addTableBorders", false); + return settings; +} + +void KexiSimplePrintingSettings::save() +{ + KConfig *config = kapp->config(); + config->setGroup("Simple Printing"); + config->writeEntry( "pageTitleFont", pageTitleFont ); + config->writeEntry( "pageFormat", KoPageFormat::formatString( pageLayout.format ) ); + config->writeEntry("pageOrientation", + pageLayout.orientation == PG_PORTRAIT ? "portrait" : "landscape"); + config->writeEntry("pageWidth", pageLayout.ptWidth); + config->writeEntry("pageHeight", pageLayout.ptHeight); + config->writeEntry("pageLeftMargin", pageLayout.ptLeft); + config->writeEntry("pageRightMargin", pageLayout.ptRight); + config->writeEntry("pageTopMargin", pageLayout.ptTop); + config->writeEntry("pageBottomMargin", pageLayout.ptBottom); + config->writeEntry("addPageNumbersToPage", addPageNumbers); + config->writeEntry("addDateAndTimePage", addDateAndTime); + config->writeEntry("addTableBorders", addTableBorders); + config->sync(); +} + +//------------------------ + +KexiSimplePrintingEngine::KexiSimplePrintingEngine( + const KexiSimplePrintingSettings& settings, QObject* parent) + : QObject(parent, "KexiSimplePrintingEngine") + , m_settings(&settings) + , m_pdm(0) +{ + m_cursor = 0; + m_data = 0; + m_visibleFieldsCount = 0; + m_dataOffsets.setAutoDelete(true); + clear(); +} + +KexiSimplePrintingEngine::~KexiSimplePrintingEngine() +{ + done(); +} + +bool KexiSimplePrintingEngine::init(KexiDB::Connection& conn, + KexiDB::TableOrQuerySchema& tableOrQuery, const QString& titleText, QString& errorMessage) +{ + errorMessage = QString::null; + done(); + m_headerText = titleText; //tableOrQuery.captionOrName(); + + //open data source + KexiDB::QuerySchema *query = 0; + if (tableOrQuery.table()) + query = tableOrQuery.table()->query(); //all rows + else + query = tableOrQuery.query(); + if (!query) { + errorMessage = i18n("Could not load data from table or query."); + return false; + } + + m_cursor = conn.executeQuery(*query); + if (!m_cursor) { + conn.debugError(); + return false; + } + bool ok = !m_cursor->error(); + if (ok) { + m_data = new KexiTableViewData(m_cursor); +//! @todo primitive: data should be loaded on demand + m_data->preloadAllRows(); + m_fieldsExpanded = query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields ); + m_visibleFieldsCount = m_cursor->query()->fieldsExpanded().count(); //real fields count without internals + } + else { + conn.debugError(); + } + m_eof = !ok || m_data->count() == 0; + conn.deleteCursor(m_cursor); + m_cursor = 0; + return ok; +} + +bool KexiSimplePrintingEngine::done() +{ + bool result = true; + if (m_cursor && (m_cursor->error() || !m_cursor->connection()->deleteCursor(m_cursor))) { + m_cursor->debugError(); + result = false; + } + m_cursor = 0; + delete m_data; + m_data = 0; + m_pagesCount = 0; + m_paintInitialized = false; + m_fieldsExpanded.clear(); + m_visibleFieldsCount = 0; + return result; +} + +void KexiSimplePrintingEngine::clear() +{ + m_eof = false; + m_pagesCount = 0; + m_dataOffsets.clear(); + m_dataOffsets.append(new uint(0)); + m_paintInitialized = false; +} + +void KexiSimplePrintingEngine::paintPage(int pageNumber, QPainter& painter, bool paint) +{ + uint offset = 0; + if (pageNumber < (int)m_dataOffsets.count()) { + offset = *m_dataOffsets.at(pageNumber); + } + + double y = 0.0; + + const bool printing = painter.device()->devType() == QInternal::Printer; + m_SCALE = printing ? 1 : 20; + + double w, h; + m_pdm = QPaintDeviceMetrics( painter.device() ); + + if (dynamic_cast<QWidget*>(painter.device())) { + w = dynamic_cast<QWidget*>(painter.device())->width() * m_SCALE; + h = dynamic_cast<QWidget*>(painter.device())->height() * m_SCALE; + } + else if (dynamic_cast<QPixmap*>(painter.device())) { + w = dynamic_cast<QPixmap*>(painter.device())->width() * m_SCALE; + h = dynamic_cast<QPixmap*>(painter.device())->height() * m_SCALE; + } + else {//KPrinter... + w = m_pdm.widthMM(); + h = m_pdm.heightMM(); + } + + if (!m_paintInitialized) { + m_paintInitialized = true; + + double widthMM = KoPageFormat::width( + m_settings->pageLayout.format, m_settings->pageLayout.orientation); + double heightMM = KoPageFormat::height( + m_settings->pageLayout.format, m_settings->pageLayout.orientation); + + m_dpiY = m_pdm.logicalDpiY(); + m_dpiX = m_pdm.logicalDpiX(); +#ifdef Q_WS_WIN //fix for 120dpi + if (!printing) { + m_dpiY = 96; + m_dpiX = 96; +// m_dpiY = 86; +// m_dpiX = 86; + } +#endif + double pdWidthMM = m_pdm.widthMM(); + double pdHeightMM = m_pdm.heightMM(); + +// double screenF; +// screenF = 1.0; + + m_leftMargin = POINT_TO_INCH(m_settings->pageLayout.ptLeft)*m_dpiX * (double)m_SCALE;//* screenF; + m_rightMargin = POINT_TO_INCH(m_settings->pageLayout.ptRight)*m_dpiX * (double)m_SCALE;//* screenF; + m_topMargin = POINT_TO_INCH(m_settings->pageLayout.ptTop)*m_dpiY * (double)m_SCALE;//* screenF; + m_bottomMargin = POINT_TO_INCH(m_settings->pageLayout.ptBottom)*m_dpiY * (double)m_SCALE;//* screenF; + + m_fx = widthMM / (pdWidthMM);// * screenF); + m_fy = heightMM / (pdHeightMM);// * screenF); + + //screen only + // painter.fillRect(QRect(0,0,w,h), QBrush(white)); + m_pageWidth = uint( m_fx*double(m_pdm.width()) * m_SCALE - m_leftMargin - m_rightMargin ); + m_pageHeight = uint( m_fy*double(m_pdm.height()) * m_SCALE - m_topMargin - m_bottomMargin ); + m_headerFont = m_settings->pageTitleFont; + if(!printing) { + int pixelSize = int( POINT_TO_INCH((double)QFontInfo(m_headerFont).pointSize())*m_dpiX ) * m_SCALE; + m_headerFont.setPixelSize(pixelSize); + } + +//! @todo add setting + m_mainFont = kapp->font(); + if(!printing) { + int pixelSize = int( POINT_TO_INCH(m_mainFont.pointSizeFloat())*m_dpiX ) + * m_SCALE; + m_mainFont.setPixelSize(pixelSize); + } + painter.setFont(m_mainFont); + + m_dateTimeText = KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(), + true, false); + m_dateTimeWidth = painter.fontMetrics().width(m_dateTimeText+" "); + m_mainLineSpacing = painter.fontMetrics().lineSpacing(); + m_footerHeight = m_mainLineSpacing * 2; //2 lines + painter.setFont(m_headerFont); + m_headerTextRect = painter.fontMetrics().boundingRect( + (int)m_leftMargin, (int)m_topMargin, + m_pageWidth - m_dateTimeWidth, + m_pageHeight, Qt::AlignAuto|Qt::WordBreak, m_headerText); + m_headerTextRect.setRight(m_headerTextRect.right()+10); + m_headerTextRect.setWidth( + QMIN(int(m_pageWidth - m_dateTimeWidth), m_headerTextRect.width())); + + //--compute max width of field names + m_maxFieldNameWidth = 0; + + painter.setFont(m_mainFont); + for (uint i=0; i < m_visibleFieldsCount; i++) { + const int newW = + painter.fontMetrics().width(m_fieldsExpanded[i]->captionOrAliasOrName()+":"); +// kdDebug() << "row"<<i<<": "<<m_fieldsExpanded[i]->captionOrAliasOrName()<<" " +// << newW <<endl; + if (m_maxFieldNameWidth < newW) + m_maxFieldNameWidth = newW; + } + m_maxFieldNameWidth += painter.fontMetrics().width("ww"); //more space + } + + //screen only + if(!printing) { + painter.setWindow(0, 0, int(w*m_fx), int(h*m_fy)); + } + + //paint header + painter.setFont(m_headerFont); + if (paint) { + painter.drawText(m_headerTextRect, Qt::AlignAuto|Qt::WordBreak, m_headerText); + } + painter.setFont(m_mainFont); + if (paint) { + painter.drawText((int)m_leftMargin + m_pageWidth - m_dateTimeWidth, + (int)m_topMargin, m_dateTimeWidth, + m_headerTextRect.height(), Qt::AlignRight, m_dateTimeText); + //footer + QString pageNumString; + if (m_pagesCount>0) + pageNumString = i18n("Page (number) of (total)", "Page %1 of %2") + .arg(pageNumber+1).arg(m_pagesCount); + else + pageNumString = i18n("Page %1").arg(pageNumber+1); + painter.drawText((int)m_leftMargin, + (int)m_topMargin + m_pageHeight - m_mainLineSpacing, + m_pageWidth, m_mainLineSpacing, + Qt::AlignRight | Qt::AlignBottom, pageNumString); + painter.drawLine((int)m_leftMargin, + (int)m_topMargin + m_pageHeight - m_mainLineSpacing*3/2, + (int)m_leftMargin + m_pageWidth, + (int)m_topMargin + m_pageHeight - m_mainLineSpacing*3/2); + } + y = (double)m_topMargin + (double)m_headerTextRect.height() + double(m_mainLineSpacing)/2; + if (!m_settings->addTableBorders) { + //separator line + if (paint) + painter.drawLine((int)m_leftMargin, (int)y, (int)m_leftMargin + m_pageWidth-1, (int)y); + y += (double)m_mainLineSpacing; + } + + //--print records + KexiDB::RowData row; + KexiTableItem *item; +// const uint count = m_fieldsExpanded.count(); +// const uint count = m_cursor->query()->fieldsExpanded().count(); //real fields count without internals + const uint rows = m_data->count(); + const int cellMargin = m_settings->addTableBorders ? + painter.fontMetrics().width("i") : 0; + uint paintedRows = 0; + for (;offset < rows; ++offset) { + item = m_data->at(offset); + + //compute height of this record + double newY = y; + paintRecord(painter, item, cellMargin, newY, paintedRows, false, printing); +// if ((int(m_topMargin + m_pageHeight-newY-m_footerHeight)) < 0 /*(1)*/ && paintedRows > 0/*(2)*/) { + if (newY > (m_topMargin + m_pageHeight - m_mainLineSpacing*2 + m_mainLineSpacing) /*(1)*/ && paintedRows > 0/*(2)*/) { + //(1) do not break records between pages + //(2) but paint at least one record +//! @todo break large records anyway... + break; + } +/* if (int(count * m_mainLineSpacing) > int(m_topMargin + m_pageHeight-(int)y-m_footerHeight)) + { + //do not break records between pages + break; + }*/ +// kdDebug() << " -------- " << y << " / " << m_pageHeight << endl; + if (paint) + paintRecord(painter, item, cellMargin, y, paintedRows, paint, printing); + else + y = newY; //speedup + paintedRows++; + } + + if (int(m_dataOffsets.count()-1)==pageNumber) {//this was next page + m_dataOffsets.append(new uint(offset)); + } + m_eof = offset == rows; +} + +void KexiSimplePrintingEngine::paintRecord(QPainter& painter, KexiTableItem *item, + int cellMargin, double &y, uint paintedRows, bool paint, bool printing) +{ + if (paintedRows>0 && !m_settings->addTableBorders) {//separator + if (paint) { + painter.setPen(Qt::darkGray); + painter.drawLine( + int(m_leftMargin), int( y-(double)m_mainLineSpacing ), + int(m_leftMargin)+m_pageWidth-1, int(y-(double)m_mainLineSpacing)); + painter.setPen(Qt::black); + } + } + + for (uint i=0; i<m_visibleFieldsCount; i++) { +// kdDebug() << "row"<<i<<": "<<row.at(i).toString()<<endl; + if (paint) { + painter.drawText( + (int)m_leftMargin+cellMargin, (int)y, m_maxFieldNameWidth-cellMargin*2, m_mainLineSpacing, + Qt::AlignTop, m_fieldsExpanded[i]->captionOrAliasOrName() + + (m_settings->addTableBorders ? "" : ":")); + } + QString text; +//! @todo optimize like in KexiCSVExport::exportData() + //get real column and real index to get the visible value + KexiDB::QueryColumnInfo* ci; + int indexForVisibleLookupValue = m_fieldsExpanded[i]->indexForVisibleLookupValue(); + if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)item->count()/*sanity*/) + ci = m_fieldsExpanded[ indexForVisibleLookupValue ]; + else { + ci = m_fieldsExpanded[ i ]; + indexForVisibleLookupValue = i; + } + + QVariant v(item->at( indexForVisibleLookupValue )); + KexiDB::Field::Type ftype = ci->field->type(); + QRect rect( (int)m_leftMargin + m_maxFieldNameWidth + cellMargin, (int)y, + m_pageWidth - m_maxFieldNameWidth - cellMargin*2, m_pageHeight - (int)y); + + if (v.isNull() || !v.isValid()) { + //nothing to do + } +//! todo inherit format + else if (ftype==KexiDB::Field::DateTime) { + QDateTime dt(v.toDateTime()); + if (dt.isValid()) + text = KGlobal::locale()->formatDateTime(dt); + } +//! todo inherit format + else if (ftype==KexiDB::Field::Date) { + QDate date(v.toDate()); + if (date.isValid()) + text = KGlobal::locale()->formatDate(date, true/*short*/); + } +//! todo inherit format + else if (ftype==KexiDB::Field::Time) { + QTime time(v.toTime()); + if (time.isValid()) + text = KGlobal::locale()->formatTime(time); + } +//! todo currency, decimal... + else if (ci->field->isFPNumericType()) + text = KGlobal::locale()->formatNumber(v.toDouble()); + else if (ftype==KexiDB::Field::Boolean) + text = v.toBool() + ? i18n("Boolean Yes (true)","Yes") : i18n("Boolean No (false)", "No"); + else if (ftype==KexiDB::Field::BLOB) { + const QByteArray ba( v.toByteArray() ); + if (!ba.isEmpty()) { + QPixmap pixmap(ba); +#define MAX_PIXMAP_HEIGHT (m_mainLineSpacing * 5) + double pixmapHeight = MAX_PIXMAP_HEIGHT; + double pixmapWidth = double(MAX_PIXMAP_HEIGHT) * pixmap.width() / (double)pixmap.height(); + if (pixmapWidth > (double)rect.width()) { //too wide + pixmapHeight = pixmapHeight * (double)rect.width() / pixmapWidth; + pixmapWidth = rect.width(); + } + rect.setHeight( int( pixmapHeight + m_mainLineSpacing / 2 ) ); + if (paint && !pixmap.isNull()) { + if (printing) { + painter.drawPixmap( + QRect(rect.x(), rect.y()+m_mainLineSpacing/4, + int(pixmapWidth), int(pixmapHeight)), pixmap ); + } + else {// we're just previewing the pixmap, so let's resize it and cache + // so redrawing will be faster + painter.save(); + painter.setWindow( // set 1:1 scale to avoid unnecessary image scaling + QRect(painter.window().topLeft(), + painter.window().size() / (int)m_SCALE ) ); + painter.drawImage( + int(rect.x() / m_SCALE), + int( (rect.y()+m_mainLineSpacing/4) / m_SCALE), + pixmap.convertToImage().smoothScale( + int(pixmapWidth / m_SCALE), int(pixmapHeight / m_SCALE), + QImage::ScaleMin )); + painter.restore(); // back to m_SCALE:1 scale + } + } + } + } + else + text = v.toString(); + + if (ftype!=KexiDB::Field::BLOB || v.isNull() || !v.isValid()) + rect = QRect( painter.fontMetrics().boundingRect( + rect.x(), rect.y(), rect.width(), rect.height(), + Qt::AlignAuto|Qt::WordBreak, text) ); + if (!text.isEmpty() && paint) { +// kdDebug() << "print engine: painter.drawText: " +// << rect.x() <<" "<< rect.y() <<" "<< m_pageWidth - m_maxFieldNameWidth - cellMargin*2 +// <<" "<< m_topMargin + m_pageHeight - (int)y <<" "<<m_pageHeight<<" "<<y<<" "<< text << endl; + painter.drawText( +// rect.x(), rect.y(), rect.width(), rect.height(), + rect.x(), rect.y(), m_pageWidth - m_maxFieldNameWidth - cellMargin*2, + int(m_topMargin + m_pageHeight - (int)y), + Qt::AlignTop|Qt::WordBreak, text); + } + if (m_settings->addTableBorders) { + if (paint) { + painter.setPen(Qt::darkGray); + painter.drawLine( + (int)m_leftMargin, rect.top(), (int)m_leftMargin+m_pageWidth-1, rect.top()); + painter.drawLine( + (int)m_leftMargin, rect.top(), (int)m_leftMargin, rect.bottom()); + painter.drawLine( + (int)m_leftMargin+m_pageWidth-1, rect.top(), + (int)m_leftMargin+m_pageWidth-1, rect.bottom()); + painter.drawLine( + (int)m_leftMargin+m_maxFieldNameWidth, rect.top(), + (int)m_leftMargin+m_maxFieldNameWidth, rect.bottom()); + painter.setPen(Qt::black); + } + } + y += (double)rect.height(); + } + if (m_settings->addTableBorders) { + if (paint) { + painter.setPen(Qt::darkGray); + painter.drawLine( + (int)m_leftMargin, (int)y, (int)m_leftMargin+m_pageWidth-1, (int)y); + painter.setPen(Qt::black); + } + } + //record spacing + y += double(m_mainLineSpacing)*3.0/2.0; +// if (m_settings->addTableBorders) +// y -= m_mainLineSpacing; //a bit less +} + +void KexiSimplePrintingEngine::calculatePagesCount(QPainter& painter) +{ + if (m_eof || !m_data) { + m_pagesCount = 0; + return; + } + + uint pageNumber = 0; + for(;!m_eof; ++pageNumber) { + paintPage(pageNumber, painter, false /* !paint */); + } + m_pagesCount = pageNumber; +} + +void KexiSimplePrintingEngine::setTitleText(const QString& titleText) +{ + m_headerText = titleText; +} + +#include "kexisimpleprintingengine.moc" diff --git a/kexi/main/printing/kexisimpleprintingengine.h b/kexi/main/printing/kexisimpleprintingengine.h new file mode 100644 index 00000000..551ed248 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingengine.h @@ -0,0 +1,130 @@ +/* This file is part of the KDE project + Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; 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 KEXISIMPLEPRINTINGENGINE_H +#define KEXISIMPLEPRINTINGENGINE_H + +class KexiSimplePrintingSettings; + +#include <kexidb/connection.h> +#include <kexidb/tableschema.h> +#include <kexidb/cursor.h> +#include <kexidb/utils.h> +#include <kexidb/queryschema.h> +#include <widget/tableview/kexitableviewdata.h> +#include <KoPageLayoutDia.h> + +#include <qpaintdevicemetrics.h> +#include <qfontmetrics.h> +#include <qfont.h> + +//! @short Settings data for simple printing engine. +class KexiSimplePrintingSettings +{ + public: + KexiSimplePrintingSettings(); + ~KexiSimplePrintingSettings(); + + static KexiSimplePrintingSettings load(); + void save(); + + KoPageLayout pageLayout; + KoUnit::Unit unit; + QFont pageTitleFont; + bool addPageNumbers : 1; + bool addDateAndTime : 1; + bool addTableBorders : 1; +}; + +/*! @short An engine painting data on pages using QPainter. + The engine allows for random access to any page. */ +class KexiSimplePrintingEngine : public QObject +{ + Q_OBJECT + + public: + KexiSimplePrintingEngine( const KexiSimplePrintingSettings& settings, QObject* parent ); + ~KexiSimplePrintingEngine(); + + bool init(KexiDB::Connection& conn, KexiDB::TableOrQuerySchema& tableOrQuery, + const QString& titleText, QString& errorMessage); + + void setTitleText(const QString& titleText); + + //! Calculates pafe count that can be later obtained using pagesCount(). + //! Page count can depend on \a painter (printer/screen) and on printing settings. + void calculatePagesCount(QPainter& painter); + + bool done(); + void clear(); + const KexiSimplePrintingSettings* settings() const { return m_settings; } + + //! \return true when all records has been painted + bool eof() const { return m_eof; } + + //! \return number of pages. Can be used after calculatePagesCount(). + uint pagesCount() const { return m_pagesCount; } + + //! \return number of painted pages so far. + //! If eof() is true, this number is equal to total page count. + uint paintedPages() const { return m_dataOffsets.count(); } + + public slots: + /*! Paints a page number \a pageNumber (counted from 0) on \a painter. + If \a paint is false, drawings are only computed but not painted, + so this can be used for calculating page number before printing or previewing. */ + void paintPage(int pageNumber, QPainter& painter, bool paint = true); + + protected: + void paintRecord(QPainter& painter, KexiTableItem *item, + int cellMargin, double &y, uint paintedRows, bool paint, bool printing); + + const KexiSimplePrintingSettings* m_settings; + +// QPainter* m_painter; + QFont m_mainFont, m_headerFont; + QPaintDeviceMetrics m_pdm; + double m_dpiX, m_dpiY; + uint m_pageWidth, m_pageHeight; + uint m_SCALE; + //QFontMetrics m_headerFM, m_mainFM; + KexiDB::Cursor *m_cursor; + KexiTableViewData *m_data; +// KexiTableViewData::Iterator *m_dataIterator; + QPtrList<uint> m_dataOffsets; + QString m_headerText; + QString m_dateTimeText; + uint m_dateTimeWidth; + QRect m_headerTextRect; + int m_maxFieldNameWidth; + int m_mainLineSpacing; + int m_footerHeight; + KexiDB::QueryColumnInfo::Vector m_fieldsExpanded; + uint m_visibleFieldsCount; + uint m_pagesCount; + bool m_eof; + bool m_paintInitialized; //!< used by paintPage() + double m_leftMargin; + double m_rightMargin; + double m_topMargin; + double m_bottomMargin; + double m_fx, m_fy; +}; + +#endif diff --git a/kexi/main/printing/kexisimpleprintingpagesetup.cpp b/kexi/main/printing/kexisimpleprintingpagesetup.cpp new file mode 100644 index 00000000..5d20f36e --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingpagesetup.cpp @@ -0,0 +1,550 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; 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 "kexisimpleprintingpagesetup.h" +#include "kexisimpleprintingpagesetupbase.h" +#include "kexisimpleprintpreviewwindow.h" + +#include <core/keximainwindow.h> +#include <kexiutils/utils.h> +#include <kexi_version.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kfontdialog.h> +#include <kurllabel.h> +#include <kdebug.h> +#include <klineedit.h> +#include <kprinter.h> +#include <kpushbutton.h> +#include <kdeversion.h> + +#include <qlabel.h> +#include <qtimer.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qcheckbox.h> +#include <qwhatsthis.h> +#include <qtooltip.h> + +#include <kexiutils/tristate.h> + +KexiSimplePrintingCommand::KexiSimplePrintingCommand( + KexiMainWindow* mainWin, int objectId, QObject* parent) + : QObject(parent, "KexiSimplePrintCommand") + , m_previewEngine(0) + , m_mainWin(mainWin) + , m_objectId(objectId) + , m_previewWindow(0) + , m_printPreviewNeedsReloading(false) +{ + connect(this, SIGNAL(showPageSetupRequested(KexiPart::Item*)), + m_mainWin, SLOT(showPageSetupForItem(KexiPart::Item*))); +} + +KexiSimplePrintingCommand::~KexiSimplePrintingCommand() +{ + delete m_previewWindow; + delete m_previewEngine; +// delete m_settings; +} + + +bool KexiSimplePrintingCommand::print(const KexiSimplePrintingSettings& settings, + const QString& aTitleText) +{ + m_settings = settings; + return print(aTitleText); +} + +bool KexiSimplePrintingCommand::print(const QString& aTitleText) +{ + KexiDB::Connection *conn = m_mainWin->project()->dbConnection(); + KexiDB::TableOrQuerySchema tableOrQuery(conn, m_objectId); + if (!tableOrQuery.table() && !tableOrQuery.query()) { +//! @todo item not found + return false; + } + QString titleText(aTitleText.stripWhiteSpace()); + if (titleText.isEmpty()) + titleText = tableOrQuery.captionOrName(); + + KexiSimplePrintingEngine engine(m_settings, this); + QString errorMessage; + if (!engine.init(*conn, tableOrQuery, titleText, errorMessage)) { + if (!errorMessage.isEmpty()) + KMessageBox::sorry(m_mainWin, errorMessage, i18n("Printing")); + return false; + } + + //setup printing +#ifdef Q_WS_WIN + QPrinter printer(QPrinter::HighResolution); + printer.setOrientation( m_settings.pageLayout.orientation == PG_PORTRAIT + ? QPrinter::Portrait : QPrinter::Landscape ); + printer.setPageSize( + (QPrinter::PageSize)KoPageFormat::printerPageSize( m_settings.pageLayout.format ) ); + + // "chicken-egg" problem: + // we cannot use real from/to values in setMinMax() and setFromTo() + // because page count is known after obtaining print settings + printer.setFromTo(1,1); +#else + KPrinter printer; + printer.setOrientation( m_settings.pageLayout.orientation == PG_PORTRAIT + ? KPrinter::Portrait : KPrinter::Landscape ); + printer.setPageSize( + (KPrinter::PageSize)KoPageFormat::printerPageSize( m_settings.pageLayout.format ) ); +#endif + + printer.setFullPage(true); + QString docName( titleText ); + printer.setDocName( docName ); + printer.setCreator(KEXI_APP_NAME); + if ( !printer.setup( m_mainWin ) ) { + return true; + } + + // now we have final settings + +//! @todo get printer.pageOrder() (for reversed order requires improved engine) + QPainter painter; + + if (!painter.begin(&printer)) { +//! @todo msg + return false; + } + engine.calculatePagesCount(painter); + + uint loops, loopsPerPage; + QValueList<int> pagesToPrint; + int fromPage = 0; +#ifdef Q_WS_WIN + int toPage = 0; + if (QPrinter::PageRange == printer.printRange()) { + fromPage = printer.fromPage(); + toPage = printer.toPage(); + } + if (fromPage==0 || toPage==0) { + fromPage = 0; + toPage = (int)engine.pagesCount()-1; + } + else { + fromPage--; + if (toPage > (int)engine.pagesCount()) + toPage = (int)engine.pagesCount(); + toPage--; + } + // win32 only supports one range, build the list + for (int i = fromPage; i<=toPage; i++) { + pagesToPrint.append(i); + } + // on win32 the OS does perform buffering (only when collation is off, each copy needs to be repeated) + loops = 1; + loopsPerPage = printer.collateCopies() ? 1 : printer.numCopies(); +#else + // on !win32 print QPrinter::numCopies() times (the OS does not perform buffering) + pagesToPrint = printer.pageList(); + kdDebug() << pagesToPrint << endl; + if (pagesToPrint.isEmpty()) { + fromPage = 0; + for (int i = 0; i<(int)engine.pagesCount(); i++) { + pagesToPrint.append(i); + } + } + else + fromPage = pagesToPrint.first(); + if (printer.collate()==KPrinter::Collate) { + //collation: p1, p2,..pn; p1, p2,..pn; ......; p1, p2,..pn + loops = printer.numCopies(); + loopsPerPage = 1; + } + else { + //no collation: p1, p1, ..., p1; p2, p2, ..., p2; ......; pn, pn,..pn + loops = 1; + loopsPerPage = printer.numCopies(); + } +//! @todo also look at printer.pageSet() option : all/odd/even pages +#endif + // now, total number of printed pages is printer.numCopies()*printer.pageList().count() + + kdDebug() << "printing..." << endl; + bool firstPage = true; + for (uint copy = 0;copy < loops; copy++) { + kdDebug() << "copy " << (copy+1) << " of " << loops << endl; + uint pageNumber = fromPage; + QValueList<int>::ConstIterator pagesIt = pagesToPrint.constBegin(); + for(;(int)pageNumber == fromPage || !engine.eof(); ++pageNumber) { + kdDebug() << "printing..." << endl; + if (pagesIt == pagesToPrint.constEnd()) //no more pages to print + break; + if ((int)pageNumber < *pagesIt) { //skip pages without printing (needed for computation) + engine.paintPage(pageNumber, painter, false); + continue; + } + if (*pagesIt < (int)pageNumber) { //sanity + ++pagesIt; + continue; + } + for (uint onePageCounter = 0; onePageCounter < loopsPerPage; onePageCounter++) { + if (!firstPage) + printer.newPage(); + else + firstPage = false; + kdDebug() << "page #" << pageNumber << endl; + engine.paintPage(pageNumber, painter); + } + ++pagesIt; + } + } + kdDebug() << "end of printing." << endl; + + // stop painting, this will automatically send the print data to the printer + if (!painter.end()) + return false; + + if (!engine.done()) + return false; + + return true; +} + +bool KexiSimplePrintingCommand::showPrintPreview(const KexiSimplePrintingSettings& settings, + const QString& aTitleText, bool reload) +{ + m_settings = settings; + if (!m_previewEngine) + m_previewEngine = new KexiSimplePrintingEngine(m_settings, this); + + if (reload) + m_printPreviewNeedsReloading = true; + + bool backToPage0 = true; + QString titleText(aTitleText.stripWhiteSpace()); + KexiDB::Connection *conn = m_mainWin->project()->dbConnection(); + KexiDB::TableOrQuerySchema tableOrQuery(conn, m_objectId); + if (!tableOrQuery.table() && !tableOrQuery.query()) { +//! @todo item not found + return false; + } + if (titleText.isEmpty()) + titleText = tableOrQuery.captionOrName(); + if (!m_previewWindow || m_printPreviewNeedsReloading) { + QString errorMessage; + if (!m_previewEngine->init( + *conn, tableOrQuery, titleText, errorMessage)) { + if (!errorMessage.isEmpty()) + KMessageBox::sorry(m_mainWin, errorMessage, i18n("Print Preview")); + return false; + } + } + if (!m_previewWindow) { + backToPage0 = false; + m_previewWindow = new KexiSimplePrintPreviewWindow( + *m_previewEngine, tableOrQuery.captionOrName(), 0, + Qt::WStyle_Customize|Qt::WStyle_NormalBorder|Qt::WStyle_Title| + Qt::WStyle_SysMenu|Qt::WStyle_MinMax|Qt::WStyle_ContextHelp); + connect(m_previewWindow, SIGNAL(printRequested()), this, SLOT(print())); + connect(m_previewWindow, SIGNAL(pageSetupRequested()), this, SLOT(slotShowPageSetupRequested())); + m_previewWindow->show(); + KDialog::centerOnScreen(m_previewWindow); + m_printPreviewNeedsReloading = false; + } + + if (m_printPreviewNeedsReloading) {//dirty + m_previewEngine->clear(); +//! @todo progress bar... + m_previewEngine->setTitleText( titleText ); + m_previewWindow->setFullWidth(); + m_previewWindow->updatePagesCount(); + m_printPreviewNeedsReloading = false; + } + if (backToPage0) + m_previewWindow->goToPage(0); + m_previewWindow->show(); + m_previewWindow->raise(); +// m_previewWindow->setPagesCount(INT_MAX); //will be properly set on demand + return true; +} + +void KexiSimplePrintingCommand::slotShowPageSetupRequested() +{ + m_mainWin->raise(); + emit showPageSetupRequested( m_mainWin->project()->item( m_objectId ) ); +} + +/*void KexiSimplePrintingCommand::setPrintPreviewNeedsReloading() +{ + m_printPreviewNeedsReloading = true; +}*/ + +//---------------------------------------------------------- + +KexiSimplePrintingPageSetup::KexiSimplePrintingPageSetup( KexiMainWindow *mainWin, QWidget *parent, + QMap<QString,QString>* args ) + : KexiViewBase( mainWin, parent, "KexiSimplePrintingPageSetup" ) + , m_settings( KexiSimplePrintingSettings::load() ) +// , m_command(0) +{ + // object to print + bool ok = args; + int objectId; + if (ok) + objectId = (*args)["identifier"].toInt(); + ok = objectId<=0; + m_item = mainWin->project()->item( objectId ); + ok = m_item; + + bool printPreview = false; + bool print = false; + bool pageSetup = false; + if (ok) { + printPreview = (*args)["action"]=="printPreview"; + print = (*args)["action"]=="print"; + pageSetup = (*args)["action"]=="pageSetup"; + ok = printPreview || print || pageSetup; + } + + // settings +//! @todo default? + m_unit = KLocale::Metric == KGlobal::locale()->measureSystem() ? KoUnit::U_CM : KoUnit::U_INCH; + + // GUI + QVBoxLayout *lyr = new QVBoxLayout(this); + m_contents = new KexiSimplePrintingPageSetupBase(this, "KexiSimplePrintingPageSetupBase"); + lyr->addWidget(m_contents); + + setViewWidget(m_contents, true); +// setFocusPolicy(WheelFocus); + m_contents->setFocusProxy(m_contents->headerTitleLineEdit); + + m_contents->printButton->setIconSet( KStdGuiItem::print().iconSet(KIcon::Small) ); + m_contents->printButton->setText( KStdGuiItem::print().text() ); + connect(m_contents->printButton, SIGNAL(clicked()), this, SLOT(print())); + + m_contents->printPreviewButton->setIconSet( SmallIconSet("filequickprint") ); + m_contents->printPreviewButton->setText( i18n("Print Previe&w...") ); + connect(m_contents->printPreviewButton, SIGNAL(clicked()), this, SLOT(printPreview())); + + m_contents->iconLabel->setFixedWidth(32+6); + m_contents->iconLabel->setPixmap( DesktopIcon("document", 32) ); + QWhatsThis::add(m_contents->headerTitleFontButton, i18n("Changes font for title text.")); + connect(m_contents->headerTitleFontButton, SIGNAL(clicked()), + this, SLOT(slotChangeTitleFont())); + + if (m_item) { + m_origCaptionLabelText = m_contents->captionLabel->text(); + m_contents->headerTitleLineEdit->setText( m_item->captionOrName() ); + if (m_item->mimeType()=="kexi/query") { + m_contents->openDataLink->setText( i18n("Open This Query") ); + m_origCaptionLabelText = i18n("<h2>Page setup for printing \"%1\" query data</h2>"); + } + m_contents->captionLabel->setText( m_origCaptionLabelText.arg(m_item->name()) ); + } + connect(m_contents->headerTitleLineEdit,SIGNAL(textChanged(const QString&)), + this, SLOT(slotTitleTextChanged(const QString&))); + m_contents->headerTitleLineEdit->setFont( m_settings.pageTitleFont ); + + QWhatsThis::add(m_contents->openDataLink, + i18n("Shows data for table or query associated with this page setup.")); + QToolTip::add(m_contents->openDataLink, + i18n("Shows data for table or query associated with this page setup.")); + connect(m_contents->openDataLink, SIGNAL(leftClickedURL()), this, SLOT(slotOpenData())); + + QWhatsThis::add(m_contents->saveSetupLink, i18n("Saves settings for this setup as default.")); + connect(m_contents->saveSetupLink, SIGNAL(leftClickedURL()), this, SLOT(slotSaveSetup())); +#if !KDE_IS_VERSION(3,5,1) && !defined(Q_WS_WIN) + //a fix for problems with focusable KUrlLabel on KDElibs<=3.5.0 + m_contents->openDataLink->setFocusPolicy(NoFocus); + m_contents->saveSetupLink->setFocusPolicy(NoFocus); +#endif + + QWhatsThis::add(m_contents->addDateTimeCheckbox, i18n("Adds date and time to the header.")); + QWhatsThis::add(m_contents->addPageNumbersCheckbox, i18n("Adds page numbers to the footer.")); + QWhatsThis::add(m_contents->addTableBordersCheckbox, i18n("Adds table borders.")); + +#ifdef KEXI_NO_UNFINISHED + m_contents->addDateTimeCheckbox->hide(); + m_contents->addPageNumbersCheckbox->hide(); +#endif + + updatePageLayoutAndUnitInfo(); + QWhatsThis::add(m_contents->changePageSizeAndMarginsButton, + i18n("Changes page size and margins.")); + connect(m_contents->changePageSizeAndMarginsButton, SIGNAL(clicked()), + this, SLOT(slotChangePageSizeAndMargins())); + + connect(m_contents->addPageNumbersCheckbox, SIGNAL(toggled(bool)), + this, SLOT(slotAddPageNumbersCheckboxToggled(bool))); + connect(m_contents->addDateTimeCheckbox, SIGNAL(toggled(bool)), + this, SLOT(slotAddDateTimeCheckboxToggled(bool))); + connect(m_contents->addTableBordersCheckbox, SIGNAL(toggled(bool)), + this, SLOT(slotAddTableBordersCheckboxToggled(bool))); + + if (!ok) { + // no data! + setEnabled(false); + } + + m_contents->addPageNumbersCheckbox->setChecked( m_settings.addPageNumbers ); + m_contents->addDateTimeCheckbox->setChecked( m_settings.addDateAndTime ); + m_contents->addTableBordersCheckbox->setChecked( m_settings.addTableBorders ); + setDirty(false); + +// m_engine = new KexiSimplePrintingEngine(m_settings, this); + + //clear it back to false after widgets initialization + m_printPreviewNeedsReloading = false; + +/* if (printPreview) + QTimer::singleShot(50, this, SLOT(printPreview())); + else if (print) + QTimer::singleShot(50, this, SLOT(print()));*/ + connect(this, SIGNAL(printItemRequested(KexiPart::Item*,const KexiSimplePrintingSettings&, + const QString&)), + m_mainWin, SLOT(printItem(KexiPart::Item*,const KexiSimplePrintingSettings&, + const QString&))); + connect(this, SIGNAL(printPreviewForItemRequested(KexiPart::Item*, + const KexiSimplePrintingSettings&,const QString&,bool)), + m_mainWin, SLOT(printPreviewForItem(KexiPart::Item*, + const KexiSimplePrintingSettings&,const QString&,bool))); +} + +KexiSimplePrintingPageSetup::~KexiSimplePrintingPageSetup() +{ +} + +void KexiSimplePrintingPageSetup::slotSaveSetup() +{ + m_settings.save(); + setDirty(false); +} + +void KexiSimplePrintingPageSetup::updatePageLayoutAndUnitInfo() +{ + QString s; + if (m_settings.pageLayout.format == PG_CUSTOM) { + s += QString(" (%1 %2 x %3 %4)") + .arg(m_settings.pageLayout.ptWidth).arg(KoUnit::unitName(m_unit)) + .arg(m_settings.pageLayout.ptHeight).arg(KoUnit::unitName(m_unit)); + } + else + s += KoPageFormat::name(m_settings.pageLayout.format); + s += QString(", ") + + (m_settings.pageLayout.orientation == PG_PORTRAIT ? i18n("Portrait") : i18n("Landscape")) + + ", " + i18n("margins:") + + " " + KoUnit::toUserStringValue(m_settings.pageLayout.ptLeft, m_unit) + + "/" + KoUnit::toUserStringValue(m_settings.pageLayout.ptRight, m_unit) + + "/" + KoUnit::toUserStringValue(m_settings.pageLayout.ptTop, m_unit) + + "/" + KoUnit::toUserStringValue(m_settings.pageLayout.ptBottom, m_unit) + + " " + KoUnit::unitName(m_unit); + m_contents->pageSizeAndMarginsLabel->setText( s ); +} + +/*void KexiSimplePrintingPageSetup::setupPrintingCommand() +{ + if (!m_command) { + m_command = new KexiSimplePrintingCommand( + m_mainWin, m_item->identifier(), m_settings, false/!owned/, this); + } +}*/ + +void KexiSimplePrintingPageSetup::print() +{ +// setupPrintingCommand(); +// m_command->print(m_contents->headerTitleLineEdit->text()); + emit printItemRequested(m_item, m_settings, m_contents->headerTitleLineEdit->text()); +} + +void KexiSimplePrintingPageSetup::printPreview() +{ +// setupPrintingCommand(); +// m_command->showPrintPreview(m_contents->headerTitleLineEdit->text()); + emit printPreviewForItemRequested(m_item, m_settings, + m_contents->headerTitleLineEdit->text(), m_printPreviewNeedsReloading); + m_printPreviewNeedsReloading = false; +} + +void KexiSimplePrintingPageSetup::slotOpenData() +{ + bool openingCancelled; + m_mainWin->openObject(m_item, Kexi::DataViewMode, openingCancelled); +} + +void KexiSimplePrintingPageSetup::slotTitleTextChanged(const QString&) +{ + if (m_contents->headerTitleLineEdit->isModified()) { + m_printPreviewNeedsReloading = true; +// if (m_command) +// m_command->setPrintPreviewNeedsReloading(); + } + + m_contents->headerTitleLineEdit->clearModified(); +} + +void KexiSimplePrintingPageSetup::slotChangeTitleFont() +{ + if (QDialog::Accepted != KFontDialog::getFont(m_settings.pageTitleFont, false, this)) + return; + m_contents->headerTitleLineEdit->setFont( m_settings.pageTitleFont ); + setDirty(true); +} + +void KexiSimplePrintingPageSetup::slotChangePageSizeAndMargins() +{ + KoHeadFoot headfoot; //dummy + + if (int(QDialog::Accepted) != KoPageLayoutDia::pageLayout( + m_settings.pageLayout, headfoot, FORMAT_AND_BORDERS | DISABLE_UNIT, m_unit, this )) + return; + + //update + updatePageLayoutAndUnitInfo(); + setDirty(true); +} + +void KexiSimplePrintingPageSetup::setDirty(bool set) +{ + m_contents->saveSetupLink->setEnabled(set); +// if (m_command) +// m_command->setPrintPreviewNeedsReloading(); + if (set) + m_printPreviewNeedsReloading = true; +} + +void KexiSimplePrintingPageSetup::slotAddPageNumbersCheckboxToggled(bool set) +{ + m_settings.addPageNumbers = set; + setDirty(true); +} + +void KexiSimplePrintingPageSetup::slotAddDateTimeCheckboxToggled(bool set) +{ + m_settings.addDateAndTime = set; + setDirty(true); +} + +void KexiSimplePrintingPageSetup::slotAddTableBordersCheckboxToggled(bool set) +{ + m_settings.addTableBorders = set; + setDirty(true); +} + +#include "kexisimpleprintingpagesetup.moc" diff --git a/kexi/main/printing/kexisimpleprintingpagesetup.h b/kexi/main/printing/kexisimpleprintingpagesetup.h new file mode 100644 index 00000000..e4e99bd5 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingpagesetup.h @@ -0,0 +1,117 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; 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 KEXISIMPLEPRINTINGPAGESETUP_H +#define KEXISIMPLEPRINTINGPAGESETUP_H + +#include "kexisimpleprintingengine.h" +#include <kexiviewbase.h> + +class KexiSimplePrintingPageSetupBase; +class KoPageLayoutSize; +class KexiSimplePrintPreviewWindow; + +/*! @short A command for simple printing and print preview. + This class is instantiated in KexiMainWindowImpl so there's: + - a single print preview window per part item regardless of a way how user invoked + the 'print preview' command (using 'File->Print Preview' command or 'Print Preview' button + of the 'Page Setup' dialog) + - a single printing engine per part item regardless of a way how user started + (using 'File->Print' command or 'Print' button of the 'Page Setup' dialog) +*/ +class KexiSimplePrintingCommand : public QObject +{ + Q_OBJECT + + public: + KexiSimplePrintingCommand(KexiMainWindow* mainWin, int objectId, + QObject* parent = 0); + ~KexiSimplePrintingCommand(); + + public slots: + bool print(const KexiSimplePrintingSettings& settings, + const QString& aTitleText = QString::null); + bool print(const QString& aTitleText = QString::null); + bool showPrintPreview(const KexiSimplePrintingSettings& settings, + const QString& aTitleText = QString::null, bool reload = false); +// void setPrintPreviewNeedsReloading(); + + signals: + //! connected to Kexi Main Window + void showPageSetupRequested(KexiPart::Item* item); + + protected slots: + void slotShowPageSetupRequested(); + + protected: + KexiSimplePrintingEngine* m_previewEngine; + KexiMainWindow* m_mainWin; + int m_objectId; + KexiSimplePrintingSettings m_settings; + KexiSimplePrintPreviewWindow *m_previewWindow; + bool m_printPreviewNeedsReloading : 1; +}; + +//! @short A window for displaying settings for simple printing. +class KexiSimplePrintingPageSetup : public KexiViewBase +{ + Q_OBJECT + + public: + KexiSimplePrintingPageSetup( KexiMainWindow *mainWin, QWidget *parent, QMap<QString,QString>* args ); + ~KexiSimplePrintingPageSetup(); + + public slots: + void print(); + void printPreview(); + + signals: + void printItemRequested(KexiPart::Item* item, + const KexiSimplePrintingSettings& settings, const QString& titleText); + void printPreviewForItemRequested(KexiPart::Item* item, + const KexiSimplePrintingSettings& settings, const QString& titleText, bool reload); + + protected slots: + void slotOpenData(); + void slotSaveSetup(); + void slotChangeTitleFont(); + void slotChangePageSizeAndMargins(); + void slotAddPageNumbersCheckboxToggled(bool set); + void slotAddDateTimeCheckboxToggled(bool set); + void slotAddTableBordersCheckboxToggled(bool set); + void slotTitleTextChanged(const QString&); + + protected: + void setupPrintingCommand(); + void updatePageLayoutAndUnitInfo(); + void setDirty(bool set); + + KexiSimplePrintingSettings m_settings; +// KexiSimplePrintingEngine *m_engine; + KoUnit::Unit m_unit; + KexiSimplePrintingPageSetupBase *m_contents; + KoPageLayoutSize *m_pageLayoutWidget; + KexiPart::Item *m_item; +// KexiSimplePrintingCommand *m_command; + QString m_origCaptionLabelText; + bool m_printPreviewNeedsReloading : 1; + +}; + +#endif diff --git a/kexi/main/printing/kexisimpleprintingpagesetupbase.ui b/kexi/main/printing/kexisimpleprintingpagesetupbase.ui new file mode 100644 index 00000000..13c29ab0 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingpagesetupbase.ui @@ -0,0 +1,447 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiSimplePrintingPageSetupBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiSimplePrintingPageSetupBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>338</width> + <height>451</height> + </rect> + </property> + <property name="caption"> + <string>.</string> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="6"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>iconLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignVCenter</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>captionLabel</cstring> + </property> + <property name="text"> + <string><h2>Page Setup for Printing "%1" Table Data</h2></string> + </property> + <property name="buddy" stdset="0"> + <cstring>headerTitleLineEdit</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="KLineEdit" row="5" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>headerTitleLineEdit</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>2</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KPushButton" row="5" column="5"> + <property name="name"> + <cstring>headerTitleFontButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Set Font...</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Page title:</string> + </property> + <property name="alignment"> + <set>AlignBottom</set> + </property> + <property name="buddy" stdset="0"> + <cstring>headerTitleLineEdit</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="6"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>printButton</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>printPreviewButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>230</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QCheckBox" row="8" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>addPageNumbersCheckbox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Add page numbers</string> + </property> + </widget> + <widget class="QGroupBox" row="7" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Page Size && Margins</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>pageSizeAndMarginsLabel</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </vbox> + </widget> + <widget class="KPushButton" row="7" column="5"> + <property name="name"> + <cstring>changePageSizeAndMarginsButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Change...</string> + </property> + </widget> + <widget class="QLayoutWidget" row="12" column="0" rowspan="1" colspan="6"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="1"> + <property name="name"> + <cstring>spacer23</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>80</width> + <height>6</height> + </size> + </property> + </spacer> + <widget class="KURLLabel" row="2" column="0"> + <property name="name"> + <cstring>saveSetupLink</cstring> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <property name="margin"> + <number>3</number> + </property> + <property name="text"> + <string>Save This Setup as Default</string> + </property> + <property name="indent"> + <number>6</number> + </property> + <property name="url" stdset="0"> + <string></string> + </property> + <property name="tipText"> + <string></string> + </property> + </widget> + <widget class="KURLLabel" row="1" column="0"> + <property name="name"> + <cstring>openDataLink</cstring> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <property name="margin"> + <number>3</number> + </property> + <property name="text"> + <string>Open This Table</string> + </property> + <property name="indent"> + <number>6</number> + </property> + <property name="url" stdset="0"> + <string></string> + </property> + <property name="tipText"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>Related actions:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="9" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>addDateTimeCheckbox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Add date and time</string> + </property> + </widget> + <widget class="QCheckBox" row="10" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>addTableBordersCheckbox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Add table borders</string> + </property> + </widget> + <spacer row="13" column="4"> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <spacer row="1" column="3"> + <property name="name"> + <cstring>spacer15</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>4</height> + </size> + </property> + </spacer> + <spacer row="6" column="0"> + <property name="name"> + <cstring>spacer10</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>4</height> + </size> + </property> + </spacer> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer12</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>4</height> + </size> + </property> + </spacer> + <spacer row="11" column="2"> + <property name="name"> + <cstring>spacer14</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>4</height> + </size> + </property> + </spacer> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>printButton</tabstop> + <tabstop>printPreviewButton</tabstop> + <tabstop>headerTitleLineEdit</tabstop> + <tabstop>headerTitleFontButton</tabstop> + <tabstop>changePageSizeAndMarginsButton</tabstop> + <tabstop>addPageNumbersCheckbox</tabstop> + <tabstop>addDateTimeCheckbox</tabstop> + <tabstop>addTableBordersCheckbox</tabstop> + <tabstop>openDataLink</tabstop> + <tabstop>saveSetupLink</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurllabel.h</includehint> + <includehint>kurllabel.h</includehint> +</includehints> +</UI> diff --git a/kexi/main/printing/kexisimpleprintingpart.cpp b/kexi/main/printing/kexisimpleprintingpart.cpp new file mode 100644 index 00000000..765f6db2 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingpart.cpp @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "kexisimpleprintingpart.h" +#include "kexisimpleprintingpagesetup.h" + +#include <kdebug.h> +#include <kgenericfactory.h> + +#include <keximainwindow.h> +#include <kexidialogbase.h> +#include <kexiproject.h> +#include <kexipartinfo.h> + +KexiSimplePrintingPart::KexiSimplePrintingPart() + : KexiPart::StaticPart("kexi/simpleprinting", "fileprint", i18n("Printing")) +{ + // REGISTERED ID: +//?? m_registeredPartID = (int)KexiPart::QueryObjectType; + +/* m_names["instanceName"] + = i18n("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.", + "query");*/ + m_names["instanceCaption"] = i18n("Printing"); + m_supportedViewModes = Kexi::DesignViewMode; + m_supportedUserViewModes = Kexi::DesignViewMode; +} + +KexiSimplePrintingPart::~KexiSimplePrintingPart() +{ +} + +KexiViewBase* KexiSimplePrintingPart::createView(QWidget *parent, KexiDialogBase* dialog, + KexiPart::Item &item, int viewMode, QMap<QString,QString>* args) +{ + Q_UNUSED( item ); + if (viewMode == Kexi::DesignViewMode) { + KexiSimplePrintingPageSetup *w = new KexiSimplePrintingPageSetup( dialog->mainWin(), parent, args ); + return w; + } + + return 0; +} + +#include "kexisimpleprintingpart.moc" diff --git a/kexi/main/printing/kexisimpleprintingpart.h b/kexi/main/printing/kexisimpleprintingpart.h new file mode 100644 index 00000000..1d2df3be --- /dev/null +++ b/kexi/main/printing/kexisimpleprintingpart.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXISIMPLEPRINTINGPART_H +#define KEXISIMPLEPRINTINGPART_H + +#include <kexidialogbase.h> +#include <kexistaticpart.h> +#include <kexipartitem.h> + +class KexiMainWin; +namespace KexiDB +{ + class QuerySchema; + class Connection; +} + +class KexiProject; + +//! @short Internal Kexi Simple Printing Plugin. +class KexiSimplePrintingPart : public KexiPart::StaticPart +{ + Q_OBJECT + + public: + KexiSimplePrintingPart(); + virtual ~KexiSimplePrintingPart(); + + protected: + virtual KexiViewBase* createView(QWidget *parent, KexiDialogBase* dialog, + KexiPart::Item &item, int viewMode, QMap<QString,QString>* staticObjectArgs); +}; + +#endif + diff --git a/kexi/main/printing/kexisimpleprintpreviewwindow.cpp b/kexi/main/printing/kexisimpleprintpreviewwindow.cpp new file mode 100644 index 00000000..4ba487d9 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintpreviewwindow.cpp @@ -0,0 +1,381 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "kexisimpleprintpreviewwindow.h" +#include "kexisimpleprintingengine.h" +#include "kexisimpleprintpreviewwindow_p.h" +#include <kexi_version.h> + +#include <qlayout.h> +#include <qaccel.h> +#include <qtimer.h> +#include <qlabel.h> + +#include <kdialogbase.h> +#include <ktoolbarbutton.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <kpushbutton.h> +#include <kapplication.h> + +KexiSimplePrintPreviewView::KexiSimplePrintPreviewView( + QWidget *parent, KexiSimplePrintPreviewWindow *window) + : QWidget(parent, "KexiSimplePrintPreviewView", WStaticContents)//|WNoAutoErase) + , m_window(window) +{ + enablePainting = false; +// resize(300,400); +// resizeContents(200, 400); +} + +void KexiSimplePrintPreviewView::paintEvent( QPaintEvent *pe ) +{ + Q_UNUSED(pe); + if (!enablePainting) + return; + QPixmap pm(size()); //dbl buffered + QPainter p; + p.begin(&pm, this); +//! @todo only for screen! + p.fillRect(QRect(QPoint(0,0),pm.size()), QBrush(white));//pe->rect(), QBrush(white)); + if (m_window->currentPage()>=0) + m_window->m_engine.paintPage(m_window->currentPage(), p); +// emit m_window->paintingPageRequested(m_window->currentPage(), p); + p.end(); + bitBlt(this, 0, 0, &pm); +} + +//-------------------------- + +#define KexiSimplePrintPreviewScrollView_MARGIN KDialogBase::marginHint() + +KexiSimplePrintPreviewScrollView::KexiSimplePrintPreviewScrollView( + KexiSimplePrintPreviewWindow *window) + : QScrollView(window, "scrollview", WStaticContents|WNoAutoErase) + , m_window(window) +{ +// this->settings = settings; + widget = new KexiSimplePrintPreviewView(viewport(), m_window); + +/* int widthMM = KoPageFormat::width( + settings.pageLayout.format, settings.pageLayout.orientation); + int heightMM = KoPageFormat::height( + settings.pageLayout.format, settings.pageLayout.orientation); +// int constantHeight = 400; +// widget->resize(constantHeight * widthMM / heightMM, constantHeight ); //keep aspect +*/ + addChild(widget); +} + +void KexiSimplePrintPreviewScrollView::resizeEvent( QResizeEvent *re ) +{ + QScrollView::resizeEvent(re); +// kdDebug() << re->size().width() << " " << re->size().height() << endl; +// kdDebug() << contentsWidth() << " " << contentsHeight() << endl; +// kdDebug() << widget->width() << " " << widget->height() << endl; + setUpdatesEnabled(false); + if (re->size().width() > (widget->width()+2*KexiSimplePrintPreviewScrollView_MARGIN) + || re->size().height() > (widget->height()+2*KexiSimplePrintPreviewScrollView_MARGIN)) + { + resizeContents( + QMAX(re->size().width(), widget->width()+2*KexiSimplePrintPreviewScrollView_MARGIN), + QMAX(re->size().height(), widget->height()+2*KexiSimplePrintPreviewScrollView_MARGIN)); + int vscrbarWidth = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0; + int newContentsWidth + = QMAX(re->size().width(), widget->width()+2*KexiSimplePrintPreviewScrollView_MARGIN); + int newContentsHeight + = QMAX(re->size().height(), widget->height()+2*KexiSimplePrintPreviewScrollView_MARGIN); + moveChild(widget, (newContentsWidth - vscrbarWidth - widget->width())/2, + (newContentsHeight - widget->height())/2); + resizeContents( newContentsWidth, newContentsHeight ); + } + setUpdatesEnabled(true); +} + +void KexiSimplePrintPreviewScrollView::setFullWidth() +{ + viewport()->setUpdatesEnabled(false); + double widthMM = KoPageFormat::width( + m_window->settings().pageLayout.format, + m_window->settings().pageLayout.orientation); + double heightMM = KoPageFormat::height( + m_window->settings().pageLayout.format, m_window->settings().pageLayout.orientation); +// int constantWidth = m_window->width()- KexiSimplePrintPreviewScrollView_MARGIN*6; + double constantWidth = width()- KexiSimplePrintPreviewScrollView_MARGIN*6; + double heightForWidth = constantWidth * heightMM / widthMM; +// heightForWidth = QMIN(kapp->desktop()->height()*4/5, heightForWidth); + kdDebug() << "1: " << heightForWidth << endl; +#if 0 //todo we can use this if we want to fix the height to width of the page + heightForWidth = QMIN(height(), heightForWidth); + kdDebug() << "2: " << heightForWidth << endl; +#endif + constantWidth = heightForWidth * widthMM / heightMM; + widget->resize((int)constantWidth, (int)heightForWidth); //keep aspect + resizeContents(int(widget->width() + 2*KexiSimplePrintPreviewScrollView_MARGIN), + int(widget->height() + 2*KexiSimplePrintPreviewScrollView_MARGIN)); + moveChild(widget, (contentsWidth()-widget->width())/2, + (contentsHeight()-widget->height())/2); + viewport()->setUpdatesEnabled(true); + resize(size()+QSize(1,1)); //to update pos. + widget->enablePainting = true; + widget->repaint(); +} + +void KexiSimplePrintPreviewScrollView::setContentsPos(int x, int y) +{ +// kdDebug() << "############" << x << " " << y << " " << contentsX()<< " " <<contentsY() << endl; + if (x<0 || y<0) //to avoid endless loop on Linux + return; + QScrollView::setContentsPos(x,y); +} + +//------------------ + +KexiSimplePrintPreviewWindow::KexiSimplePrintPreviewWindow( + KexiSimplePrintingEngine &engine, const QString& previewName, + QWidget *parent, WFlags f) + : QWidget(parent, "KexiSimplePrintPreviewWindow", f) + , m_engine(engine) + , m_settings(*m_engine.settings()) + , m_pageNumber(-1) + , m_pagesCount(-1) +{ + setCaption(i18n("%1 - Print Preview - %2").arg(previewName).arg(KEXI_APP_NAME)); + setIcon(DesktopIcon("filequickprint")); + QVBoxLayout *lyr = new QVBoxLayout(this, 6); + + int id; + m_toolbar = new KToolBar(0, this); + m_toolbar->setLineWidth(0); + m_toolbar->setFrameStyle(QFrame::NoFrame); + m_toolbar->setIconText(KToolBar::IconTextRight); + lyr->addWidget(m_toolbar); + + id = m_toolbar->insertWidget( -1, 0, new KPushButton(KStdGuiItem::print(), m_toolbar) ); + m_toolbar->addConnection(id, SIGNAL(clicked()), this, SLOT(slotPrintClicked())); + static_cast<KPushButton*>(m_toolbar->getWidget(id))->setAccel(Qt::CTRL|Qt::Key_P); + m_toolbar->insertSeparator(); + + id = m_toolbar->insertWidget(-1, 0, new KPushButton(i18n("Page Set&up..."), m_toolbar)); + m_toolbar->addConnection(id, SIGNAL(clicked()), this, SLOT(slotPageSetup())); + m_toolbar->insertSeparator(); + + +#ifndef KEXI_NO_UNFINISHED +//! @todo unfinished + id = m_toolbar->insertWidget( -1, 0, new KPushButton(BarIconSet("viewmag+"), i18n("Zoom In"), m_toolbar)); + m_toolbar->addConnection(id, SIGNAL(clicked()), this, SLOT(slotZoomInClicked())); + m_toolbar->insertSeparator(); + + id = m_toolbar->insertWidget( -1, 0, new KPushButton(BarIconSet("viewmag-"), i18n("Zoom Out"), m_toolbar)); + m_toolbar->addConnection(id, SIGNAL(clicked()), this, SLOT(slotZoomOutClicked())); + m_toolbar->insertSeparator(); +#endif + + id = m_toolbar->insertWidget(-1, 0, new KPushButton(KStdGuiItem::close(), m_toolbar)); + m_toolbar->addConnection(id, SIGNAL(clicked()), this, SLOT(close())); + m_toolbar->alignItemRight(id); + + m_scrollView = new KexiSimplePrintPreviewScrollView(this); + m_scrollView->setUpdatesEnabled(false); + m_view = m_scrollView->widget; + m_scrollView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + lyr->addWidget(m_scrollView); + + QWidget* navToolbarWidget = new QWidget(this); //widget used to center the navigator toolbar + navToolbarWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + QHBoxLayout *navToolbarLyr = new QHBoxLayout(navToolbarWidget); + lyr->addWidget(navToolbarWidget); + + m_navToolbar = new KToolBar(0, navToolbarWidget); + navToolbarLyr->addStretch(1); + navToolbarLyr->addWidget(m_navToolbar); + navToolbarLyr->addStretch(1); +// m_navToolbar->setFullWidth(true); + m_navToolbar->setLineWidth(0); + m_navToolbar->setFrameStyle(QFrame::NoFrame); + m_navToolbar->setIconText(KToolBar::IconTextRight); + + m_idFirst = m_navToolbar->insertWidget( -1, 0, new KPushButton(BarIconSet("start"), i18n("First Page"), m_navToolbar)); + m_navToolbar->addConnection(m_idFirst, SIGNAL(clicked()), this, SLOT(slotFirstClicked())); + m_navToolbar->insertSeparator(); + + m_idPrevious = m_navToolbar->insertWidget( -1, 0, new KPushButton(BarIconSet("previous"), i18n("Previous Page"), m_navToolbar)); + m_navToolbar->addConnection(m_idPrevious, SIGNAL(clicked()), this, SLOT(slotPreviousClicked())); + m_navToolbar->insertSeparator(); + + m_idPageNumberLabel = m_navToolbar->insertWidget( -1, 0, new QLabel(m_navToolbar)); + m_navToolbar->insertSeparator(); + + m_idNext = m_navToolbar->insertWidget( -1, 0, new KPushButton(BarIconSet("next"), i18n("Next Page"), m_navToolbar)); + m_navToolbar->addConnection(m_idNext, SIGNAL(clicked()), this, SLOT(slotNextClicked())); + m_navToolbar->insertSeparator(); + + m_idLast = m_navToolbar->insertWidget( -1, 0, new KPushButton(BarIconSet("finish"), i18n("Last Page"), m_navToolbar)); + m_navToolbar->addConnection(m_idLast, SIGNAL(clicked()), this, SLOT(slotLastClicked())); + m_navToolbar->insertSeparator(); + + resize(width(), kapp->desktop()->height()*4/5); + +//! @todo progress bar... + + QTimer::singleShot(50, this, SLOT(initLater())); +} + +void KexiSimplePrintPreviewWindow::initLater() +{ + setFullWidth(); + updatePagesCount(); + goToPage(0); +} + +KexiSimplePrintPreviewWindow::~KexiSimplePrintPreviewWindow() +{ +} + +/*void KexiSimplePrintPreviewWindow::setPagesCount(int pagesCount) +{ + m_pagesCount = pagesCount; + goToPage(0); +}*/ + +void KexiSimplePrintPreviewWindow::slotPrintClicked() +{ + hide(); + emit printRequested(); + show(); + raise(); +} + +void KexiSimplePrintPreviewWindow::slotPageSetup() +{ + lower(); + emit pageSetupRequested(); +} + +void KexiSimplePrintPreviewWindow::slotZoomInClicked() +{ + //! @todo +} + +void KexiSimplePrintPreviewWindow::slotZoomOutClicked() +{ + //! @todo +} + +void KexiSimplePrintPreviewWindow::slotFirstClicked() +{ + goToPage(0); +} + +void KexiSimplePrintPreviewWindow::slotPreviousClicked() +{ + goToPage(m_pageNumber-1); +} + +void KexiSimplePrintPreviewWindow::slotNextClicked() +{ + goToPage(m_pageNumber+1); +} + +void KexiSimplePrintPreviewWindow::slotLastClicked() +{ + goToPage(m_engine.pagesCount()-1); +} + +void KexiSimplePrintPreviewWindow::goToPage(int pageNumber) +{ + if ((pageNumber==m_pageNumber && m_pagesCount == (int)m_engine.pagesCount()) + || pageNumber < 0 || pageNumber > ((int)m_engine.pagesCount()-1)) + return; + m_pageNumber = pageNumber; + m_pagesCount = m_engine.pagesCount(); + + m_view->repaint(); //this will automatically paint a new page + + m_navToolbar->setItemEnabled(m_idNext, pageNumber < ((int)m_engine.pagesCount()-1)); + m_navToolbar->setItemEnabled(m_idLast, pageNumber < ((int)m_engine.pagesCount()-1)); + m_navToolbar->setItemEnabled(m_idPrevious, pageNumber > 0); + m_navToolbar->setItemEnabled(m_idFirst, pageNumber > 0); + static_cast<QLabel*>(m_navToolbar->getWidget(m_idPageNumberLabel))->setText( + i18n("Page (number) of (total)", "Page %1 of %2").arg(m_pageNumber+1).arg(m_engine.pagesCount())); +} + +void KexiSimplePrintPreviewWindow::setFullWidth() +{ + m_scrollView->setFullWidth(); +} + +void KexiSimplePrintPreviewWindow::updatePagesCount() +{ + QPixmap pm(m_view->size()); //dbl buffered + QPainter p(m_view); + //p.begin(&pm, this); +////! @todo only for screen! +// p.fillRect(pe->rect(), QBrush(white)); + m_engine.calculatePagesCount(p); + p.end(); +} + +bool KexiSimplePrintPreviewWindow::event( QEvent * e ) +{ + QEvent::Type t = e->type(); + if (t==QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + const int k = ke->key(); + bool ok = true; + if (k==Qt::Key_Equal || k==Qt::Key_Plus) + slotZoomInClicked(); + else if (k==Qt::Key_Minus) + slotZoomOutClicked(); + else if (k==Qt::Key_Home) + slotFirstClicked(); + else if (k==Qt::Key_End) + slotLastClicked(); + else + ok = false; + + if (ok) { + ke->accept(); + return true; + } + } + else if (t==QEvent::AccelOverride) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + const int k = ke->key(); + bool ok = true; + if (k==Qt::Key_PageUp) + slotPreviousClicked(); + else if (k==Qt::Key_PageDown) + slotNextClicked(); + else + ok = false; + + if (ok) { + ke->accept(); + return true; + } + } + return QWidget::event(e); +} + + +#include "kexisimpleprintpreviewwindow.moc" +#include "kexisimpleprintpreviewwindow_p.moc" diff --git a/kexi/main/printing/kexisimpleprintpreviewwindow.h b/kexi/main/printing/kexisimpleprintpreviewwindow.h new file mode 100644 index 00000000..c91fa2f2 --- /dev/null +++ b/kexi/main/printing/kexisimpleprintpreviewwindow.h @@ -0,0 +1,83 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXISIMPLEPRINTPREVIEWWINDOW_H +#define KEXISIMPLEPRINTPREVIEWWINDOW_H + +#include <qpainter.h> +#include <qscrollview.h> +#include <ktoolbar.h> +#include <KoPageLayoutDia.h> + +class KexiSimplePrintPreviewScrollView; +class KexiSimplePrintPreviewView; +class KexiSimplePrintingSettings; +class KexiSimplePrintingEngine; + +//! @short A window for displaying print preview for simple printing. +class KexiSimplePrintPreviewWindow : public QWidget +{ + Q_OBJECT + + public: + KexiSimplePrintPreviewWindow(KexiSimplePrintingEngine &engine, + const QString& previewName, QWidget *parent, WFlags f = 0); + ~KexiSimplePrintPreviewWindow(); + + int currentPage() const { return m_pageNumber; } + + const KexiSimplePrintingSettings& settings() const { return m_settings; } + + public slots: + void updatePagesCount(); +// void setPagesCount(int pagesCount); + void goToPage(int pageNumber); + void setFullWidth(); + + signals: + void printRequested(); + void pageSetupRequested(); + + protected slots: + void slotPageSetup(); + void slotPrintClicked(); + void slotZoomInClicked(); + void slotZoomOutClicked(); + void slotFirstClicked(); + void slotPreviousClicked(); + void slotNextClicked(); + void slotLastClicked(); + void initLater(); + + protected: + virtual bool event( QEvent * e ); + + KexiSimplePrintingEngine &m_engine; + const KexiSimplePrintingSettings& m_settings; + KToolBar *m_toolbar, *m_navToolbar; + int m_pageNumber; + int m_pagesCount; //!< needed to know that pages could has been changed + int m_idFirst, m_idLast, m_idPrevious, m_idNext, m_idPageNumberLabel; + KexiSimplePrintPreviewScrollView *m_scrollView; + KexiSimplePrintPreviewView *m_view; + + friend class KexiSimplePrintPreviewView; +}; + +#endif diff --git a/kexi/main/printing/kexisimpleprintpreviewwindow_p.h b/kexi/main/printing/kexisimpleprintpreviewwindow_p.h new file mode 100644 index 00000000..e7a3804d --- /dev/null +++ b/kexi/main/printing/kexisimpleprintpreviewwindow_p.h @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXISIMPLEPRINTPREVIEWWINDOW_P_H +#define KEXISIMPLEPRINTPREVIEWWINDOW_P_H + +#include <kexisimpleprintpreviewwindow.h> + +class KexiSimplePrintPreviewView : public QWidget +{ + public: + KexiSimplePrintPreviewView(QWidget *parent, KexiSimplePrintPreviewWindow *window); + + virtual void paintEvent( QPaintEvent *pe ); + + bool enablePainting; + protected: + KexiSimplePrintPreviewWindow *m_window; +}; + +class KexiSimplePrintPreviewScrollView : public QScrollView +{ + Q_OBJECT + + public: + KexiSimplePrintPreviewScrollView(KexiSimplePrintPreviewWindow *window); + + KexiSimplePrintPreviewView *widget; + + public slots: + void setFullWidth(); + void setContentsPos(int x, int y); + + protected: + virtual void resizeEvent( QResizeEvent *re ); + KexiSimplePrintPreviewWindow *m_window; +}; + +#endif diff --git a/kexi/main/startup/KexiConnSelector.cpp b/kexi/main/startup/KexiConnSelector.cpp new file mode 100644 index 00000000..454f1e08 --- /dev/null +++ b/kexi/main/startup/KexiConnSelector.cpp @@ -0,0 +1,432 @@ +/* This file is part of the KDE project + Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "KexiConnSelector.h" + +#include <kexidb/drivermanager.h> +#include <kexidb/connectiondata.h> + +#include <kexi.h> +#include "KexiConnSelectorBase.h" +//#include "KexiOpenExistingFile.h" +#include <widget/kexiprjtypeselector.h> +#include <widget/kexidbconnectionwidget.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <kmimetype.h> +#include <klocale.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kurlcombobox.h> +#include <ktoolbar.h> +#include <kpopupmenu.h> +#include <ktoolbarbutton.h> +#include <kactionclasses.h> + +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qcheckbox.h> +#include <qtooltip.h> +#include <qtextedit.h> +#include <qgroupbox.h> +#include <qwidgetstack.h> +#include <qbuttongroup.h> + +ConnectionDataLVItem::ConnectionDataLVItem(KexiDB::ConnectionData *data, + const KexiDB::Driver::Info& info, QListView *list) + : QListViewItem(list) + , m_data(data) +{ + update(info); +} + +ConnectionDataLVItem::~ConnectionDataLVItem() +{ +} + +void ConnectionDataLVItem::update(const KexiDB::Driver::Info& info) +{ + setText(0, m_data->caption+" "); + const QString &sfile = i18n("File"); + QString drvname = info.caption.isEmpty() ? m_data->driverName : info.caption; + if (info.fileBased) + setText(1, sfile + " ("+drvname+") " ); + else + setText(1, drvname+" " ); + setText(2, (info.fileBased ? (QString("<")+sfile.lower()+">") : m_data->serverInfoString(true))+" " ); +} + +/*================================================================*/ + +//! @internal +class KexiConnSelectorWidgetPrivate +{ +public: + KexiConnSelectorWidgetPrivate() + : conn_sel_shown(false) + , file_sel_shown(false) + , confirmOverwrites(true) + { + } + + QWidget* openExistingWidget; + KexiPrjTypeSelector* prjTypeSelector; + QString startDirOrVariable; + QWidgetStack *stack; + QGuardedPtr<KexiDBConnectionSet> conn_set; + KexiDB::DriverManager manager; + bool conn_sel_shown;//! helper + bool file_sel_shown; + bool confirmOverwrites; +}; + +/*================================================================*/ + +KexiConnSelectorWidget::KexiConnSelectorWidget( KexiDBConnectionSet& conn_set, + const QString& startDirOrVariable, QWidget* parent, const char* name ) + : QWidget( parent, name ) + ,d(new KexiConnSelectorWidgetPrivate()) +{ + d->conn_set = &conn_set; + d->startDirOrVariable = startDirOrVariable; + QString none, iconname = KMimeType::mimeType( KexiDB::Driver::defaultFileBasedDriverMimeType() )->icon(none,0); + const QPixmap &icon = KGlobal::iconLoader()->loadIcon( iconname, KIcon::Desktop ); + setIcon( icon ); + + QVBoxLayout* globalLyr = new QVBoxLayout( this ); + + //create header with radio buttons + d->openExistingWidget = new QWidget(this, "openExistingWidget"); + QVBoxLayout* openExistingWidgetLyr = new QVBoxLayout( d->openExistingWidget ); +// QLabel* lbl = new QLabel(i18n("<b>Select existing Kexi project to open:</b>"), openExistingWidget); +// openExistingWidgetLyr->addWidget( lbl ); + d->prjTypeSelector = new KexiPrjTypeSelector( d->openExistingWidget ); + connect(d->prjTypeSelector->buttonGroup,SIGNAL(clicked(int)),this,SLOT(slotPrjTypeSelected(int))); + openExistingWidgetLyr->addWidget( d->prjTypeSelector ); + openExistingWidgetLyr->addSpacing( KDialogBase::spacingHint() ); + QFrame* line = new QFrame( d->openExistingWidget, "line" ); + line->setFrameShape( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + openExistingWidgetLyr->addWidget( line ); + globalLyr->addWidget(d->openExistingWidget); + + d->stack = new QWidgetStack(this, "stack"); + globalLyr->addWidget(d->stack); + +// m_file = new KexiOpenExistingFile( this, "KexiOpenExistingFile"); +// m_file->btn_advanced->setIconSet( SmallIconSet("1downarrow") ); + m_fileDlg = 0; + +// addWidget(m_file); +// connect(m_file->btn_advanced,SIGNAL(clicked()),this,SLOT(showAdvancedConn())); + + m_remote = new KexiConnSelectorBase(d->stack, "conn_sel"); + m_remote->icon->setPixmap( DesktopIcon("network") ); + m_remote->icon->setFixedSize( m_remote->icon->pixmap()->size() ); +// m_remote->btn_back->setIconSet( SmallIconSet("1uparrow") ); + connect(m_remote->btn_add, SIGNAL(clicked()), this, SLOT(slotRemoteAddBtnClicked())); + connect(m_remote->btn_edit, SIGNAL(clicked()), this, SLOT(slotRemoteEditBtnClicked())); + connect(m_remote->btn_remove, SIGNAL(clicked()), this, SLOT(slotRemoteRemoveBtnClicked())); + QToolTip::add(m_remote->btn_add, i18n("Add a new database connection")); + QToolTip::add(m_remote->btn_edit, i18n("Edit selected database connection")); + QToolTip::add(m_remote->btn_remove, i18n("Remove selected database connections")); + d->stack->addWidget(m_remote); + if (m_remote->layout()) + m_remote->layout()->setMargin(0); +// connect(m_remote->btn_back,SIGNAL(clicked()),this,SLOT(showSimpleConn())); + connect(m_remote->list,SIGNAL(doubleClicked(QListViewItem*)), + this,SLOT(slotConnectionItemExecuted(QListViewItem*))); + connect(m_remote->list,SIGNAL(returnPressed(QListViewItem*)), + this,SLOT(slotConnectionItemExecuted(QListViewItem*))); + connect(m_remote->list,SIGNAL(selectionChanged()), + this,SLOT(slotConnectionSelectionChanged())); +} + +KexiConnSelectorWidget::~KexiConnSelectorWidget() +{ + delete d; +} + +/*void KexiConnSelectorWidget::disconnectShowSimpleConnButton() +{ + m_remote->btn_back->disconnect(this,SLOT(showSimpleConn())); +}*/ + +void KexiConnSelectorWidget::showAdvancedConn() +{ + slotPrjTypeSelected(2); + d->prjTypeSelector->buttonGroup->setButton(2); +} + +//void KexiConnSelectorWidget::showAdvancedConn() +void KexiConnSelectorWidget::slotPrjTypeSelected(int id) +{ + if (id==1) {//file-based prj type + showSimpleConn(); + } + else if (id==2) {//server-based prj type + if (!d->conn_sel_shown) { + d->conn_sel_shown=true; + + //show connections (on demand): + for (KexiDB::ConnectionData::ListIterator it(d->conn_set->list()); it.current(); ++it) { + addConnectionData( it.current() ); + // else { + //this error should be more verbose: + // kdWarning() << "KexiConnSelector::KexiConnSelector(): no driver found for '" << it.current()->driverName << "'!" << endl; + // } + } + if (m_remote->list->firstChild()) { + m_remote->list->setSelected(m_remote->list->firstChild(),true); + } + m_remote->descriptionEdit->setPaletteBackgroundColor(palette().active().background()); + m_remote->descGroupBox->layout()->setMargin(2); + m_remote->list->setFocus(); + slotConnectionSelectionChanged(); + } + d->stack->raiseWidget(m_remote); + } +} + +ConnectionDataLVItem* KexiConnSelectorWidget::addConnectionData( KexiDB::ConnectionData* data ) +{ + const KexiDB::Driver::Info info( d->manager.driverInfo(data->driverName) ); +// if (!info.name.isEmpty()) { + return new ConnectionDataLVItem(data, info, m_remote->list); +// } +} + +void KexiConnSelectorWidget::showSimpleConn() +{ + d->prjTypeSelector->buttonGroup->setButton(1); + if (!d->file_sel_shown) { + d->file_sel_shown=true; + m_fileDlg = new KexiStartupFileDialog( d->startDirOrVariable, KexiStartupFileDialog::Opening, + d->stack, "openExistingFileDlg"); + m_fileDlg->setConfirmOverwrites( d->confirmOverwrites ); +// static_cast<QVBoxLayout*>(m_file->layout())->insertWidget( 2, m_fileDlg ); + d->stack->addWidget(m_fileDlg); + + for (QWidget *w = parentWidget(true);w;w=w->parentWidget(true)) { + if (w->isDialog()) { +//#ifndef Q_WS_WIN + connect(m_fileDlg,SIGNAL(rejected()),static_cast<QDialog*>(w),SLOT(reject())); +//#endif +// connect(m_fileDlg,SIGNAL(cancelled()),static_cast<QDialog*>(w),SLOT(reject())); + break; + } + } + } + d->stack->raiseWidget(m_fileDlg); +} + +int KexiConnSelectorWidget::selectedConnectionType() const +{ + return (d->stack->visibleWidget()==m_fileDlg) ? FileBased : ServerBased; +} + +/*ConnectionDataLVItem* KexiConnSelectorWidget::selectedConnectionDataItem() const +{ + if (selectedConnectionType()!=KexiConnSelectorWidget::ServerBased) + return 0; + ConnectionDataLVItem *item = 0; // = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem()); + for (QListViewItemIterator it(m_remote->list); it.current(); ++it) { + if (it.current()->isSelected()) { + if (item) + return 0; //multiple + item = static_cast<ConnectionDataLVItem*>(it.current()); + } + } + return item; +}*/ + +KexiDB::ConnectionData* KexiConnSelectorWidget::selectedConnectionData() const +{ + ConnectionDataLVItem *item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem()); //ConnectionDataItem(); + if (!item) + return 0; + return item->data(); +} + +QString KexiConnSelectorWidget::selectedFileName() +{ + if (selectedConnectionType()!=KexiConnSelectorWidget::FileBased) + return QString::null; + return m_fileDlg->currentFileName(); +} + +void KexiConnSelectorWidget::setSelectedFileName(const QString& fileName) +{ + if (selectedConnectionType()!=KexiConnSelectorWidget::FileBased) + return; + return m_fileDlg->setSelection(fileName); +} + +void KexiConnSelectorWidget::slotConnectionItemExecuted(QListViewItem *item) +{ + emit connectionItemExecuted(static_cast<ConnectionDataLVItem*>(item)); +} + +void KexiConnSelectorWidget::slotConnectionSelectionChanged() +{ + ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem()); + //update buttons availability +/* ConnectionDataLVItem *singleItem = 0; + bool multi = false; + for (QListViewItemIterator it(m_remote->list); it.current(); ++it) { + if (it.current()->isSelected()) { + if (singleItem) { + singleItem = 0; + multi = true; + break; + } + else + singleItem = static_cast<ConnectionDataLVItem*>(it.current()); + } + }*/ + m_remote->btn_edit->setEnabled(item); + m_remote->btn_remove->setEnabled(item); + m_remote->descriptionEdit->setText(item ? item->data()->description : QString::null); + emit connectionItemHighlighted(item); +} + +QListView* KexiConnSelectorWidget::connectionsList() const +{ + return m_remote->list; +} + +void KexiConnSelectorWidget::setFocus() +{ + QWidget::setFocus(); + if (d->stack->visibleWidget()==m_fileDlg) + m_fileDlg->setFocus(); //m_fileDlg->locationWidget()->setFocus(); + else + m_remote->list->setFocus(); +} + +void KexiConnSelectorWidget::hideHelpers() +{ + d->openExistingWidget->hide(); + +/* m_file->lbl->hide(); + m_file->line->hide(); + m_file->spacer->hide(); + m_file->label->hide(); + m_remote->label->hide(); + m_remote->label_back->hide(); + m_remote->btn_back->hide(); + m_remote->icon->hide();*/ +} + +void KexiConnSelectorWidget::setConfirmOverwrites(bool set) +{ + d->confirmOverwrites = set; + if (m_fileDlg) + m_fileDlg->setConfirmOverwrites( d->confirmOverwrites ); +} + +bool KexiConnSelectorWidget::confirmOverwrites() const +{ + return d->confirmOverwrites; +} + +/*static QString msgUnfinished() { + return i18n("To define or change a connection, use command line options or click on .kexis file. " + "You can find example .kexis file at <a href=\"%1\">here</a>.").arg("") //temporary, please do not change for 0.8! + + "\nhttp://www.kexi-project.org/resources/testdb.kexis"; */ +// .arg("http://websvn.kde.org/*checkout*/branches/kexi/0.9/koffice/kexi/tests/startup/testdb.kexis"); +//} + +void KexiConnSelectorWidget::slotRemoteAddBtnClicked() +{ + KexiDB::ConnectionData data; + KexiDBConnectionDialog dlg(data, QString::null, + KGuiItem(i18n("&Add"), "button_ok", i18n("Add database connection")) ); + dlg.setCaption(i18n("Add New Database Connection")); + if (QDialog::Accepted!=dlg.exec()) + return; + + //store this conn. data + KexiDB::ConnectionData *newData = new KexiDB::ConnectionData(*dlg.currentProjectData().connectionData()); + if (!d->conn_set->addConnectionData(newData)) { + //! @todo msg? + delete newData; + return; + } + + ConnectionDataLVItem* item = addConnectionData(newData); +// m_remote->list->clearSelection(); + m_remote->list->setSelected(item, true); + slotConnectionSelectionChanged(); +} + +void KexiConnSelectorWidget::slotRemoteEditBtnClicked() +{ + ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem()); + if (!item) + return; + KexiDBConnectionDialog dlg(*item->data(), QString::null, + KGuiItem(i18n("&Save"), "filesave", i18n("Save changes made to this database connection")) ); + dlg.setCaption(i18n("Edit Database Connection")); + if (QDialog::Accepted!=dlg.exec()) + return; + + KexiDB::ConnectionData *newData = new KexiDB::ConnectionData( *dlg.currentProjectData().connectionData() ); + if (!d->conn_set->saveConnectionData(item->data(), newData)) { + //! @todo msg? + delete newData; + return; + } + const KexiDB::Driver::Info info( d->manager.driverInfo(item->data()->driverName) ); + item->update(info); + slotConnectionSelectionChanged(); //to update descr. edit +} + +void KexiConnSelectorWidget::slotRemoteRemoveBtnClicked() +{ + ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(m_remote->list->selectedItem()); + if (!item) + return; + if (KMessageBox::Continue!=KMessageBox::warningContinueCancel(0, + i18n("Do you want to remove database connection \"%1\" from the list of available connections?") + .arg(item->data()->serverInfoString(true)), QString::null, KStdGuiItem::del(), QString::null, + KMessageBox::Notify|KMessageBox::Dangerous)) + return; + + QListViewItem* nextItem = item->itemBelow(); + if (!nextItem) + nextItem = item->itemAbove(); + if (!d->conn_set->removeConnectionData(item->data())) + return; + + m_remote->list->removeItem(item); + if (nextItem) + m_remote->list->setSelected(nextItem, true); + slotConnectionSelectionChanged(); +} + +void KexiConnSelectorWidget::hideConnectonIcon() +{ + m_remote->icon->setFixedWidth(0); + m_remote->icon->setPixmap(QPixmap()); +} + +#include "KexiConnSelector.moc" diff --git a/kexi/main/startup/KexiConnSelector.h b/kexi/main/startup/KexiConnSelector.h new file mode 100644 index 00000000..a52dd8ae --- /dev/null +++ b/kexi/main/startup/KexiConnSelector.h @@ -0,0 +1,142 @@ +/* This file is part of the KDE project + Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KEXICONNSELECTOR_H +#define KEXICONNSELECTOR_H + +#include <kexidbconnectionset.h> +#include <kexidb/driver.h> +#include "KexiStartupFileDialog.h" + +#include <kdialogbase.h> +#include <klistview.h> + +#include <qguardedptr.h> + +class KexiConnSelectorBase; + +//! helper class +class ConnectionDataLVItem : public QListViewItem +{ + public: + ConnectionDataLVItem(KexiDB::ConnectionData *data, + const KexiDB::Driver::Info& info, QListView *list); + ~ConnectionDataLVItem(); + + void update(const KexiDB::Driver::Info& info); + KexiDB::ConnectionData *data() const { return m_data; } + + protected: + KexiDB::ConnectionData *m_data; +}; + + +//class KexiOpenExistingFile; +class KexiConnSelectorWidgetPrivate; + +/*! Widget that allows to select a database connection (without choosing database itself) +*/ +class KEXIMAIN_EXPORT KexiConnSelectorWidget : public QWidget +{ + Q_OBJECT + + public: + enum ConnType { FileBased=1, ServerBased=2 }; + + /*! Constructs a KexiConnSelector which contain \a conn_set as connection set. + \a conn_set can be altered, because Add/Edit/Remove buttons are available + to users. \a startDirOrVariable can be provided to specify a start dir for file browser + (it can also contain a configuration variable name with ":" prefix as described + in KRecentDirs documentation). */ + KexiConnSelectorWidget( KexiDBConnectionSet& conn_set, + const QString& startDirOrVariable, + QWidget* parent = 0, const char* name = 0 ); + + virtual ~KexiConnSelectorWidget(); + + /*! After accepting this dialog this method returns wherher user selected + file- or server- based connection (ConnType enum). */ + int selectedConnectionType() const; + + /*! \return data of selected connection, if server-based connection was selected. + Returns NULL if no selection has been made or file-based connection + has been selected. + @see selectedConnectionType() + */ + KexiDB::ConnectionData* selectedConnectionData() const; + + /*! \return the name of database file, if file-based connection was selected. + Returns null string if no selection has been made or server-based connection + has been selected. + @see selectedConnectionType() + */ + QString selectedFileName(); + + /*! Sets selected filename to \a fileName. + Only works when selectedConnectionType()==FileBased. */ + void setSelectedFileName(const QString& fileName); + +// //! Usable when we want to do other things for "back" button +// void disconnectShowSimpleConnButton(); + + QListView* connectionsList() const; + + KexiConnSelectorBase *m_remote; +// KexiOpenExistingFile *m_file; + KexiStartupFileDialog *m_fileDlg; + + /*! If true, user will be asked to accept overwriting existing project. + This is true by default. */ + void setConfirmOverwrites(bool set); + + bool confirmOverwrites() const; + + signals: + void connectionItemExecuted(ConnectionDataLVItem *item); + void connectionItemHighlighted(ConnectionDataLVItem *item); + + public slots: + void showSimpleConn(); + void showAdvancedConn(); + virtual void setFocus(); + + /*! Hides helpers on the server based connection page + (sometimes it's convenient not to have these): + - "Select existing database server's connection..." (label at the top) + - "Click "Back" button" (label at the bottom) + - "Back" button itself */ + void hideHelpers(); + void hideConnectonIcon(); + + protected slots: + void slotConnectionItemExecuted(QListViewItem *item); + void slotRemoteAddBtnClicked(); + void slotRemoteEditBtnClicked(); + void slotRemoteRemoveBtnClicked(); + void slotConnectionSelectionChanged(); + void slotPrjTypeSelected(int id); + + private: + ConnectionDataLVItem* addConnectionData( KexiDB::ConnectionData* data ); + ConnectionDataLVItem* selectedConnectionDataItem() const; + + KexiConnSelectorWidgetPrivate *d; +}; + +#endif // KEXICONNSELECTOR_H diff --git a/kexi/main/startup/KexiConnSelectorBase.ui b/kexi/main/startup/KexiConnSelectorBase.ui new file mode 100644 index 00000000..dde800f3 --- /dev/null +++ b/kexi/main/startup/KexiConnSelectorBase.ui @@ -0,0 +1,285 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiConnSelectorBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiConnSelectorBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>628</width> + <height>289</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QListView" row="1" column="0" rowspan="1" colspan="6"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Type</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Server Information</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>list</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>60</height> + </size> + </property> + <property name="selectionMode"> + <enum>Single</enum> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="showSortIndicator"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>LastColumn</enum> + </property> + </widget> + <widget class="QPushButton" row="2" column="4"> + <property name="name"> + <cstring>btn_edit</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Edit...</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="3"> + <property name="name"> + <cstring>btn_add</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Add...</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="5"> + <property name="name"> + <cstring>btn_remove</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Remove</string> + </property> + </widget> + <spacer row="2" column="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="3" column="4"> + <property name="name"> + <cstring>spacer4_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>41</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="2" column="0" rowspan="2" colspan="2"> + <property name="name"> + <cstring>descGroupBox</cstring> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>80</height> + </size> + </property> + <property name="title"> + <string>Description</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <widget class="QTextEdit"> + <property name="name"> + <cstring>descriptionEdit</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>50</height> + </size> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="textFormat"> + <enum>PlainText</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + <widget class="QLabel" row="0" column="1" rowspan="1" colspan="5"> + <property name="name"> + <cstring>label</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><b>Select Existing Database Server's Connection From the List Below</b> +<p>You will see existing Kexi projects available for the selected connection. Here you may also add, edit or remove connections from the list. +</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + <property name="buddy" stdset="0"> + <cstring>list</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>icon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>list</tabstop> + <tabstop>btn_add</tabstop> + <tabstop>btn_edit</tabstop> + <tabstop>btn_remove</tabstop> + <tabstop>descriptionEdit</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kexi/main/startup/KexiDBTitlePage.cpp b/kexi/main/startup/KexiDBTitlePage.cpp new file mode 100644 index 00000000..3b048793 --- /dev/null +++ b/kexi/main/startup/KexiDBTitlePage.cpp @@ -0,0 +1,35 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "KexiDBTitlePage.h" + +#include <qlabel.h> + +KexiDBTitlePage::KexiDBTitlePage( const QString& labelText, QWidget* parent, const char* name ) + : KexiDBTitlePageBase( parent, name ) +{ + if (!labelText.isEmpty()) + label->setText(labelText); +} + +KexiDBTitlePage::~KexiDBTitlePage() +{ +} + +#include "KexiDBTitlePage.moc" diff --git a/kexi/main/startup/KexiDBTitlePage.h b/kexi/main/startup/KexiDBTitlePage.h new file mode 100644 index 00000000..98341946 --- /dev/null +++ b/kexi/main/startup/KexiDBTitlePage.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KEXIDBTITLEPAGE_H +#define KEXIDBTITLEPAGE_H + +#include "KexiDBTitlePageBase.h" + +//! @short A helper widget used to displaying a line edit with a label and layout +class KEXIMAIN_EXPORT KexiDBTitlePage : public KexiDBTitlePageBase +{ + Q_OBJECT + +public: + //! Constructs title page. \a labelText can be provided to change default + //! "Project caption:" label. + KexiDBTitlePage( const QString& labelText, QWidget* parent = 0, const char* name = 0 ); + ~KexiDBTitlePage(); + +protected slots: + virtual void languageChange() { KexiDBTitlePageBase::languageChange(); } + +}; + +#endif // KEXIDBTITLEPAGE_H + diff --git a/kexi/main/startup/KexiDBTitlePageBase.ui b/kexi/main/startup/KexiDBTitlePageBase.ui new file mode 100644 index 00000000..991bc73f --- /dev/null +++ b/kexi/main/startup/KexiDBTitlePageBase.ui @@ -0,0 +1,94 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiDBTitlePageBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiDBTitlePageBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>379</width> + <height>87</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>label</cstring> + </property> + <property name="text"> + <string>Project caption: </string> + </property> + <property name="buddy" stdset="0"> + <cstring>le_caption</cstring> + </property> + </widget> + <spacer row="1" column="1"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>111</height> + </size> + </property> + </spacer> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KLineEdit" row="0" column="1"> + <property name="name"> + <cstring>le_caption</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>2</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/kexi/main/startup/KexiNewPrjTypeSelector.ui b/kexi/main/startup/KexiNewPrjTypeSelector.ui new file mode 100644 index 00000000..30adfb06 --- /dev/null +++ b/kexi/main/startup/KexiNewPrjTypeSelector.ui @@ -0,0 +1,94 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiNewPrjTypeSelector</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiNewPrjTypeSelector</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>328</width> + <height>203</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="KListView" row="1" column="0"> + <column> + <property name="text"> + <string></string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>lv_types</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>LastColumn</enum> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>lbl</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Kexi will create a new database project. Select a storage method which will be used to store the new project. +</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> +</tabstops> +<functions> + <function access="private" specifier="non virtual">init()</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/kexi/main/startup/KexiNewProjectWizard.cpp b/kexi/main/startup/KexiNewProjectWizard.cpp new file mode 100644 index 00000000..15102864 --- /dev/null +++ b/kexi/main/startup/KexiNewProjectWizard.cpp @@ -0,0 +1,422 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "KexiNewProjectWizard.h" + +#include "KexiConnSelector.h" +#include "KexiConnSelectorBase.h" +#include "KexiNewPrjTypeSelector.h" +#include "KexiOpenExistingFile.h" +#include "KexiDBTitlePage.h" +#include "KexiServerDBNamePage.h" +#include "KexiProjectSelector.h" +#include "kexi.h" + +#include <kexiutils/identifier.h> +#include <kexiutils/utils.h> +#include <kexiguimsghandler.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <kmimetype.h> +#include <klocale.h> +#include <kdebug.h> +#include <kconfig.h> +#include <klistview.h> +#include <kurlcombobox.h> +#include <kmessagebox.h> +#include <klineedit.h> + +#include <qobjectlist.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qcheckbox.h> +#include <qheader.h> + +//! @internal +class KexiNewProjectWizardPrivate +{ + public: + KexiNewProjectWizardPrivate() + { + le_dbname_txtchanged_disable = false; + le_dbname_autofill = true; +// conndata_to_show = 0; +// project_set_to_show = 0; + } + ~KexiNewProjectWizardPrivate() + { +// delete conndata_to_show; +// delete project_set_to_show; + delete msgHandler; + } +// KListView *lv_types; + KListViewItem *lvi_file, *lvi_server; + QString chk_file_txt, chk_server_txt; //!< helper + + QString server_db_name_dblist_lbl_txt; //!< helper + + //for displaying db list of the selected conn. + QGuardedPtr<KexiDB::ConnectionData> conndata_to_show; + KexiProjectSet *project_set_to_show; + + KexiGUIMessageHandler* msgHandler; + + bool le_dbname_txtchanged_disable : 1; + bool le_dbname_autofill : 1; +}; + +KexiNewProjectWizard::KexiNewProjectWizard(KexiDBConnectionSet& conn_set, + QWidget *parent, const char *name, bool modal, WFlags f) +: KWizard(parent, name, modal, f) +, d(new KexiNewProjectWizardPrivate() ) +{ + d->msgHandler = new KexiGUIMessageHandler(this); + setIcon( DesktopIcon("filenew") ); + setCaption( i18n("Creating New Project") ); + finishButton()->setText(i18n("Create")); + + //page: type selector + m_prjtype_sel = new KexiNewPrjTypeSelector(this, "KexiNewPrjTypeSelector"); +// lv_types = new KListView(m_prjtype_sel, "types listview"); +// m_prjtype_sel->lv_types->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum, 0, 2)); +#if KDE_IS_VERSION(3,3,9) + m_prjtype_sel->lv_types->setShadeSortColumn(false); +#endif + m_prjtype_sel->lv_types->header()->hide(); + m_prjtype_sel->lv_types->setSorting(-1); + m_prjtype_sel->lv_types->setAlternateBackground(QColor()); //disable altering + m_prjtype_sel->lv_types->setItemMargin( KDialogBase::marginHint() ); + QString none; + d->lvi_file = new KListViewItem( m_prjtype_sel->lv_types, i18n("New Project Stored in File") ); + d->lvi_file->setPixmap(0, + KGlobal::iconLoader()->loadIcon( KMimeType::mimeType( + KexiDB::Driver::defaultFileBasedDriverMimeType() )->icon(none,0), KIcon::Desktop + ) + ); + d->lvi_file->setMultiLinesEnabled( true ); + d->lvi_server = new KListViewItem( m_prjtype_sel->lv_types, d->lvi_file, + i18n("New Project Stored on Database Server") ); + d->lvi_server->setPixmap(0, DesktopIcon("network") ); + d->lvi_server->setMultiLinesEnabled( true ); +// m_prjtype_sel->lv_types->resize(d->m_prjtype_sel->lv_types->width(), d->lvi_file->height()*3); + m_prjtype_sel->lv_types->setFocus(); +// QString txt_dns = i18n("Don't show me this question again."); +// d->chk_file_txt = m_prjtype_sel->chk_always->text() +"\n"+txt_dns; +// d->chk_server_txt = i18n("Always &use database server for creating new projects.") +// +"\n"+txt_dns; + + connect(m_prjtype_sel->lv_types,SIGNAL(executed(QListViewItem*)),this,SLOT(slotLvTypesExecuted(QListViewItem*))); + connect(m_prjtype_sel->lv_types,SIGNAL(returnPressed(QListViewItem*)),this,SLOT(slotLvTypesExecuted(QListViewItem*))); + connect(m_prjtype_sel->lv_types,SIGNAL(selectionChanged( QListViewItem*)),this,SLOT(slotLvTypesSelected(QListViewItem*))); + +// static_cast<QVBoxLayout*>(m_prjtype_sel->layout())->insertWidget(1,d->m_prjtype_sel->lv_types); +// static_cast<QVBoxLayout*>(m_prjtype_sel->layout())->insertStretch(3,1); +// updateGeometry(); + + addPage(m_prjtype_sel, i18n("Select Storage Method")); +// d->m_prjtype_sel->lv_types->setMinimumHeight(QMAX(d->lvi_file->height(),d->lvi_server->height())+25); + + //page: db title + m_db_title = new KexiDBTitlePage(QString::null, this, "KexiDBTitlePage"); + addPage(m_db_title, i18n("Select Project's Caption")); + + //page: connection selector + m_conn_sel_widget = new QWidget(this); + QVBoxLayout* conn_sel_lyr = new QVBoxLayout(m_conn_sel_widget); + QLabel *conn_sel_label = new QLabel(i18n("Enter a new Kexi project's file name:"), m_conn_sel_widget); + conn_sel_label->setAlignment(Qt::AlignAuto|Qt::AlignTop|Qt::WordBreak); + conn_sel_lyr->addWidget( conn_sel_label ); + conn_sel_lyr->addSpacing(KDialogBase::spacingHint()); + + m_conn_sel = new KexiConnSelectorWidget(conn_set, ":OpenExistingOrCreateNewProject", + m_conn_sel_widget, "KexiConnSelectorWidget"); + conn_sel_lyr->addWidget( m_conn_sel ); + + //"Select database server connection" +// m_conn_sel->m_file->btn_advanced->hide(); +// m_conn_sel->m_file->label->hide(); +//TODO m_conn_sel->m_file->lbl->setText( i18n("Enter a new Kexi project's file name:") ); + m_conn_sel->hideHelpers(); + + m_conn_sel->m_remote->label->setText( + i18n("Select database server's connection you wish to use to create a new Kexi project. " + "<p>Here you may also add, edit or remove connections from the list.")); +// m_conn_sel->m_remote->label_back->hide(); +// m_conn_sel->m_remote->btn_back->hide(); + + m_conn_sel->showSimpleConn(); + //anyway, db files will be _saved_ + m_conn_sel->m_fileDlg->setMode( KexiStartupFileDialog::SavingFileBasedDB ); +// m_conn_sel->m_fileDlg->setMode( KFile::LocalOnly | KFile::File ); +// m_conn_sel->m_fileDlg->setOperationMode( KFileDialog::Saving ); +////js connect(m_conn_sel->m_fileDlg,SIGNAL(rejected()),this,SLOT(reject())); +// connect(m_conn_sel->m_fileDlg,SIGNAL(fileHighlighted(const QString&)),this,SLOT(slotFileHighlighted(const QString&))); + connect(m_conn_sel->m_fileDlg,SIGNAL(accepted()),this,SLOT(accept())); + m_conn_sel->showAdvancedConn(); + connect(m_conn_sel,SIGNAL(connectionItemExecuted(ConnectionDataLVItem*)), + this,SLOT(next())); + + addPage(m_conn_sel_widget, i18n("Select Project's Location")); + + //page: server db name + m_server_db_name = new KexiServerDBNamePage(this, "KexiServerDBNamePage"); + d->server_db_name_dblist_lbl_txt = i18n("Existing project databases on <b>%1</b> database server:"); + connect(m_server_db_name->le_caption, SIGNAL(textChanged(const QString&)), + this,SLOT(slotServerDBCaptionTxtChanged(const QString&))); + connect(m_server_db_name->le_dbname, SIGNAL(textChanged(const QString&)), + this,SLOT(slotServerDBNameTxtChanged(const QString&))); + connect(m_server_db_name->le_caption, SIGNAL(returnPressed()), + this,SLOT(accept())); + connect(m_server_db_name->le_dbname, SIGNAL(returnPressed()), + this,SLOT(accept())); + m_server_db_name->le_caption->setText(i18n("New database")); + m_server_db_name->le_dbname->setValidator(new KexiUtils::IdentifierValidator(this, "id_val")); + m_project_selector = new KexiProjectSelectorWidget( + m_server_db_name->frm_dblist, "KexiProjectSelectorWidget", 0, false, false ); + GLUE_WIDGET(m_project_selector, m_server_db_name->frm_dblist); + m_project_selector->setFocusPolicy(NoFocus); + m_project_selector->setSelectable(false); + + addPage(m_server_db_name, i18n("Select Project's Caption & Database Name")); + + setFinishEnabled(m_prjtype_sel,false); + setFinishEnabled(m_db_title,false); + setFinishEnabled(m_server_db_name,true); + + //finish: + updateGeometry(); + m_prjtype_sel->lv_types->setSelected(d->lvi_file, true); +} + +KexiNewProjectWizard::~KexiNewProjectWizard() +{ + delete d; +} + +void KexiNewProjectWizard::show() +{ + KDialog::centerOnScreen(this); + KWizard::show(); +} + +void KexiNewProjectWizard::slotLvTypesExecuted(QListViewItem *) +{ + next(); +} + +void KexiNewProjectWizard::slotLvTypesSelected(QListViewItem *item) +{ +/* if (item==d->lvi_file) { + m_prjtype_sel->chk_always->setText(d->chk_file_txt); + } + else if (item==d->lvi_server) { + m_prjtype_sel->chk_always->setText(d->chk_server_txt); + }*/ + setAppropriate( m_db_title, item==d->lvi_file ); + setAppropriate( m_server_db_name, item==d->lvi_server ); +} + +void KexiNewProjectWizard::showPage(QWidget *page) +{ + if (page==m_prjtype_sel) {//p 1 + m_prjtype_sel->lv_types->setFocus(); + m_prjtype_sel->lv_types->setCurrentItem(m_prjtype_sel->lv_types->currentItem()); + } else if (page==m_db_title) {//p 2 + if (m_db_title->le_caption->text().stripWhiteSpace().isEmpty()) + m_db_title->le_caption->setText(i18n("New database")); + m_db_title->le_caption->selectAll(); + m_db_title->le_caption->setFocus(); + } else if (page==m_conn_sel_widget) {//p 3 + if (m_prjtype_sel->lv_types->currentItem()==d->lvi_file) { + m_conn_sel->showSimpleConn(); + QString fn = KexiUtils::string2FileName( m_db_title->le_caption->text() ); + if (!fn.endsWith(".kexi")) + fn += ".kexi"; + m_conn_sel->m_fileDlg->setLocationText(fn); + setFinishEnabled(m_conn_sel_widget,true); + m_conn_sel->setFocus(); + } + else { + m_conn_sel->showAdvancedConn(); + setFinishEnabled(m_conn_sel_widget,false); + m_conn_sel->setFocus(); + m_server_db_name->le_caption->selectAll(); + } + } else if (page==m_server_db_name) { + if (m_conn_sel->selectedConnectionData() + && (static_cast<KexiDB::ConnectionData*>(d->conndata_to_show) != m_conn_sel->selectedConnectionData())) { + m_project_selector->setProjectSet(0); +// delete d->project_set_to_show; + d->conndata_to_show = 0; + d->project_set_to_show = new KexiProjectSet(*m_conn_sel->selectedConnectionData(), d->msgHandler); + if (d->project_set_to_show->error()) { + delete d->project_set_to_show; + d->project_set_to_show = 0; + return; + } + d->conndata_to_show = m_conn_sel->selectedConnectionData(); + //-refresh projects list + m_project_selector->setProjectSet( d->project_set_to_show ); + } + } + KWizard::showPage(page); +} + +void KexiNewProjectWizard::next() +{ + //let's check if move to next page is allowed: + if (currentPage()==m_db_title) { //pg 2 + if (m_db_title->le_caption->text().stripWhiteSpace().isEmpty()) { + KMessageBox::information(this, i18n("Enter project caption.")); + m_db_title->le_caption->setText(""); + m_db_title->le_caption->setFocus(); + return; + } + } else if (currentPage()==m_conn_sel_widget) {//p 3 + if (m_prjtype_sel->lv_types->currentItem()==d->lvi_file) { + //test for db file selection + } + else { + //test for db conn selection + if (!m_conn_sel->selectedConnectionData()) { + KMessageBox::information(this, i18n("Select server connection for a new project.")); + return; + } + m_project_selector->label->setText( + d->server_db_name_dblist_lbl_txt.arg(m_conn_sel->selectedConnectionData()->serverInfoString(false)) ); + m_server_db_name->le_caption->setFocus(); + + } + } + KWizard::next(); +} + +void KexiNewProjectWizard::accept() +{ + if (m_prjtype_sel->lv_types->currentItem()==d->lvi_file) {//FILE: + //check if new db file name is ok + kdDebug() << "********** sender() " << sender()->className() << endl; + if (sender()==finishButton()) { /*(only if signal does not come from filedialog)*/ + kdDebug() << "********** sender()==finishButton() ********" << endl; +// if (!m_conn_sel->m_fileDlg->checkURL()) { + if (!m_conn_sel->m_fileDlg->checkFileName()) { + return; + } + } + } else {//SERVER: + //check if we have enough of data + if (m_server_db_name->le_caption->text().stripWhiteSpace().isEmpty()) { + KMessageBox::information(this, i18n("Enter project caption.")); + m_server_db_name->le_caption->setText(""); + m_server_db_name->le_caption->setFocus(); + return; + } + QString dbname = m_server_db_name->le_dbname->text().stripWhiteSpace(); + if (dbname.isEmpty()) { + KMessageBox::information(this, i18n("Enter project's database name.")); + m_server_db_name->le_dbname->setText(""); + m_server_db_name->le_dbname->setFocus(); + return; + } + //check for duplicated dbname + if (m_conn_sel->confirmOverwrites() && m_project_selector->projectSet() && m_project_selector->projectSet() + ->findProject( m_server_db_name->le_dbname->text() )) { + if (KMessageBox::Continue!=KMessageBox::warningContinueCancel( this, "<qt>" + +i18n("<b>A project with database name \"%1\" already exists</b>" + "<p>Do you want to delete it and create a new one?") + .arg( m_server_db_name->le_dbname->text() ), QString::null, KStdGuiItem::del(), + QString::null, KMessageBox::Notify|KMessageBox::Dangerous )) + { + m_server_db_name->le_dbname->setFocus(); + return; + } + } + } + + KWizard::accept(); +} + +void KexiNewProjectWizard::done(int r) +{ +/* //save state (always, no matter if dialog is accepted or not) + KGlobal::config()->setGroup("Startup"); + if (!m_prjtype_sel->chk_always->isChecked()) + KGlobal::config()->deleteEntry("DefaultStorageForNewProjects"); + else if (m_prjtype_sel->lv_types->currentItem()==d->lvi_file) + KGlobal::config()->writeEntry("DefaultStorageForNewProjects","File"); + else + KGlobal::config()->writeEntry("DefaultStorageForNewProjects","Server");*/ + + KGlobal::config()->sync(); + KWizard::done(r); +} + +QString KexiNewProjectWizard::projectDBName() const +{ + if (m_prjtype_sel->lv_types->currentItem()==d->lvi_server) + return m_server_db_name->le_dbname->text(); + return m_conn_sel->selectedFileName(); +} + +QString KexiNewProjectWizard::projectCaption() const +{ + if (m_prjtype_sel->lv_types->currentItem()==d->lvi_server) { + return m_server_db_name->le_caption->text(); + } + return m_db_title->le_caption->text(); +} + +KexiDB::ConnectionData* KexiNewProjectWizard::projectConnectionData() const +{ + if (m_prjtype_sel->lv_types->currentItem()==d->lvi_file) + return 0; + return m_conn_sel->selectedConnectionData(); +} + +void KexiNewProjectWizard::slotServerDBCaptionTxtChanged(const QString &capt) +{ + if (m_server_db_name->le_dbname->text().isEmpty()) + d->le_dbname_autofill=true; + if (d->le_dbname_autofill) { + d->le_dbname_txtchanged_disable = true; + QString captionAsId = KexiUtils::string2Identifier(capt); + m_server_db_name->le_dbname->setText(captionAsId); + d->le_dbname_txtchanged_disable = false; + } +} + +void KexiNewProjectWizard::slotServerDBNameTxtChanged(const QString &) +{ + if (d->le_dbname_txtchanged_disable) + return; + d->le_dbname_autofill = false; +} + +/*! If true, user will be asked to accept overwriting existing file. + This is true by default. */ +void KexiNewProjectWizard::setConfirmOverwrites(bool set) +{ + m_conn_sel->setConfirmOverwrites(set); +} + + +#include "KexiNewProjectWizard.moc" + diff --git a/kexi/main/startup/KexiNewProjectWizard.h b/kexi/main/startup/KexiNewProjectWizard.h new file mode 100644 index 00000000..9f9eaa62 --- /dev/null +++ b/kexi/main/startup/KexiNewProjectWizard.h @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KexiNewProjectWizard_H +#define KexiNewProjectWizard_H + +#include "kexidbconnectionset.h" +#include <kexidb/connectiondata.h> + +#include <kwizard.h> + +class QListViewItem; + +class KexiNewPrjTypeSelector; +class KexiConnSelectorWidget; +class KexiNewProjectWizardPrivate; +class KexiDBTitlePage; +class KexiServerDBNamePage; +class KexiProjectSelectorWidget; + +class KEXIMAIN_EXPORT KexiNewProjectWizard : public KWizard +{ + Q_OBJECT + public: + KexiNewProjectWizard(KexiDBConnectionSet& conn_set, QWidget *parent=0, + const char *name=0, bool modal=false, WFlags f=0); + ~KexiNewProjectWizard(); + + /*! \return name for a new project's database if server-based project + type was selected. Returns file name if file-based project was selected. */ + QString projectDBName() const; + + /*! \return name for a new project. Used for both file- and serever- based projects. */ + QString projectCaption() const; + + /*! \return data of selected connection for new project, + if server-based project type was selected. + Returns NULL if no selection has been made or file-based project + has been selected. */ + KexiDB::ConnectionData* projectConnectionData() const; + + /*! Reimplemented for internal reasons */ + virtual void show(); + + /*! If true, user will be asked to accept overwriting existing project. + This is true by default. */ + void setConfirmOverwrites(bool set); + + protected slots: + void slotLvTypesSelected(QListViewItem *); + void slotLvTypesExecuted(QListViewItem *); + void slotServerDBCaptionTxtChanged(const QString &capt); + void slotServerDBNameTxtChanged(const QString &n); + + virtual void done(int r); + virtual void next(); + virtual void accept(); + + protected: + virtual void showPage(QWidget *page); + + KexiNewPrjTypeSelector *m_prjtype_sel; + KexiDBTitlePage *m_db_title; + KexiServerDBNamePage *m_server_db_name; + KexiProjectSelectorWidget* m_project_selector; + + KexiConnSelectorWidget *m_conn_sel; + QWidget *m_conn_sel_widget; + + KexiNewProjectWizardPrivate *d; +}; + +#endif + diff --git a/kexi/main/startup/KexiOpenExistingFile.ui b/kexi/main/startup/KexiOpenExistingFile.ui new file mode 100644 index 00000000..ae4c05a9 --- /dev/null +++ b/kexi/main/startup/KexiOpenExistingFile.ui @@ -0,0 +1,127 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>KexiOpenExistingFile</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiOpenExistingFile</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>328</width> + <height>108</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>lbl</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><b>Select existing Kexi project file to open:</b> +</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>line</cstring> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>8</height> + </size> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>spacer</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>6</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>6</height> + </size> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>btn_advanced</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Advanced </string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>label</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Click "Advanced" button if you want to find an existing project on a server rather than a file.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>btn_advanced</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kexi/main/startup/KexiProjectSelector.cpp b/kexi/main/startup/KexiProjectSelector.cpp new file mode 100644 index 00000000..c28ab6d5 --- /dev/null +++ b/kexi/main/startup/KexiProjectSelector.cpp @@ -0,0 +1,297 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "KexiProjectSelector.h" + +#include <kexidb/drivermanager.h> +#include <kexidb/connectiondata.h> +#include "core/kexi.h" + +#include <kapplication.h> +#include <kiconloader.h> +#include <kmimetype.h> +#include <klocale.h> +#include <kdebug.h> + +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qlistview.h> + +#include <assert.h> + +//! @internal +class KexiProjectSelectorWidgetPrivate +{ +public: + KexiProjectSelectorWidgetPrivate() + { + selectable = true; + } + QPixmap fileicon, dbicon; + bool showProjectNameColumn : 1; + bool showConnectionColumns : 1; + bool selectable : 1; +}; + +/*================================================================*/ + +//! helper class +class ProjectDataLVItem : public QListViewItem +{ +public: + ProjectDataLVItem(KexiProjectData *d, + const KexiDB::Driver::Info& info, KexiProjectSelectorWidget *selector ) + : QListViewItem(selector->list) + , data(d) + { + int colnum = 0; + const KexiDB::ConnectionData *cdata = data->constConnectionData(); + if (selector->d->showProjectNameColumn) + setText(colnum++, data->caption()+" "); + + setText(colnum++, data->databaseName()+" "); + + if (selector->d->showConnectionColumns) { + QString drvname = info.caption.isEmpty() ? cdata->driverName : info.caption; + if (info.fileBased) { + setText(colnum++, i18n("File") + " ("+drvname+") " ); + } else { + setText(colnum++, drvname+" " ); + } + + QString conn; + if (!cdata->caption.isEmpty()) + conn = cdata->caption + ": "; + conn += cdata->serverInfoString(); + setText(3, conn + " "); + } + } + ~ProjectDataLVItem() {} + + KexiProjectData *data; +}; + +/*================================================================*/ + +/*! + * Constructs a KexiProjectSelector which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + */ +KexiProjectSelectorWidget::KexiProjectSelectorWidget( + QWidget* parent, const char* name, + KexiProjectSet* prj_set, bool showProjectNameColumn, + bool showConnectionColumns ) + : KexiProjectSelectorBase( parent, name ) + ,m_prj_set(prj_set) + ,d(new KexiProjectSelectorWidgetPrivate()) +{ + d->showProjectNameColumn = showProjectNameColumn; + d->showConnectionColumns = showConnectionColumns; + QString none, iconname = KMimeType::mimeType( KexiDB::Driver::defaultFileBasedDriverMimeType() )->icon(none,0); + d->fileicon = KGlobal::iconLoader()->loadIcon( iconname, KIcon::Desktop ); + setIcon( d->fileicon ); + d->dbicon = SmallIcon("database"); +// list->setHScrollBarMode( QScrollView::AlwaysOn ); + + if (!d->showConnectionColumns) { + list->removeColumn(2); + list->removeColumn(2); + } + if (!d->showProjectNameColumn) { + list->removeColumn(0); + } + setFocusProxy(list); + + //show projects + setProjectSet( m_prj_set ); + connect(list,SIGNAL(doubleClicked(QListViewItem*)),this,SLOT(slotItemExecuted(QListViewItem*))); + connect(list,SIGNAL(returnPressed(QListViewItem*)),this,SLOT(slotItemExecuted(QListViewItem*))); + connect(list,SIGNAL(selectionChanged()),this,SLOT(slotItemSelected())); +} + +/*! + * Destroys the object and frees any allocated resources + */ +KexiProjectSelectorWidget::~KexiProjectSelectorWidget() +{ + delete d; +} + +KexiProjectData* KexiProjectSelectorWidget::selectedProjectData() const +{ + ProjectDataLVItem *item = static_cast<ProjectDataLVItem*>(list->selectedItem()); + if (item) + return item->data; + return 0; +} + +void KexiProjectSelectorWidget::slotItemExecuted(QListViewItem *item) +{ + if (!d->selectable) + return; + ProjectDataLVItem *ditem = static_cast<ProjectDataLVItem*>(item); + if (ditem) + emit projectExecuted( ditem->data ); +} + +void KexiProjectSelectorWidget::slotItemSelected() +{ + if (!d->selectable) + return; + ProjectDataLVItem *ditem = static_cast<ProjectDataLVItem*>(list->selectedItem()); + emit selectionChanged( ditem ? ditem->data : 0 ); +} + +void KexiProjectSelectorWidget::setProjectSet( KexiProjectSet* prj_set ) +{ + if (prj_set) { + //old list + list->clear(); + } + m_prj_set = prj_set; + if (!m_prj_set) + return; +//TODO: what with project set's ownership? + if (m_prj_set->error()) { + kdDebug() << "KexiProjectSelectorWidget::setProjectSet() : m_prj_set->error() !"<<endl; + return; + } + KexiDB::DriverManager manager; + KexiProjectData::List prjlist = m_prj_set->list(); + KexiProjectData *data = prjlist.first(); + while (data) { + KexiDB::Driver::Info info = manager.driverInfo(data->constConnectionData()->driverName); + if (!info.name.isEmpty()) { + ProjectDataLVItem *item = new ProjectDataLVItem(data, info, this); + if (!d->selectable) + item->setSelectable(false); + if (info.fileBased) + item->setPixmap( 0, d->fileicon ); + else + item->setPixmap( 0, d->dbicon ); + } + else { + kdWarning() << "KexiProjectSelector::KexiProjectSelector(): no driver found for '" + << data->constConnectionData()->driverName << "'!" << endl; + } + data=prjlist.next(); + } + if (list->firstChild()) { + list->setSelected(list->firstChild(),true); + } +} + +void KexiProjectSelectorWidget::setSelectable(bool set) +{ + if (d->selectable == set) + return; + d->selectable = set; + //update items' state + QListViewItemIterator it( list ); + while ( it.current() ) { + it.current()->setSelectable( d->selectable ); + } +} + +bool KexiProjectSelectorWidget::isSelectable() const +{ + return d->selectable; +} + +/*================================================================*/ + +KexiProjectSelectorDialog::KexiProjectSelectorDialog( QWidget *parent, const char *name, + KexiProjectSet* prj_set, bool showProjectNameColumn, bool showConnectionColumns) + : KDialogBase( Plain, i18n("Open Recent Project"), +#ifndef KEXI_NO_UNFINISHED + //! @todo re-add Help when doc is available + Help | +#endif + Ok | Cancel, Ok, parent, name ) +{ + init(prj_set, showProjectNameColumn, showConnectionColumns); +} + +KexiProjectSelectorDialog::KexiProjectSelectorDialog( QWidget *parent, const char *name, + KexiDB::ConnectionData* cdata, + bool showProjectNameColumn, bool showConnectionColumns) + : KDialogBase( + Plain, i18n("Open Project"), +#ifndef KEXI_NO_UNFINISHED + //! @todo re-add Help when doc is available + Help | +#endif + Ok | Cancel, Ok, parent, name, true/*modal*/, false/*sep*/ ) +{ + setButtonGuiItem(Ok, KGuiItem(i18n("&Open"), "fileopen", i18n("Open Database Connection"))); + assert(cdata); + if (!cdata) + return; + KexiProjectSet *prj_set = new KexiProjectSet( *cdata ); + init(prj_set, showProjectNameColumn, showConnectionColumns); + + m_sel->label->setText( i18n("Select a project on <b>%1</b> database server to open:") + .arg(cdata->serverInfoString(false)) ); +} + +KexiProjectSelectorDialog::~KexiProjectSelectorDialog() +{ +} + +void KexiProjectSelectorDialog::init(KexiProjectSet* prj_set, bool showProjectNameColumn, + bool showConnectionColumns) +{ + setSizeGripEnabled(true); + + QVBoxLayout *lyr = new QVBoxLayout(plainPage(), 0, KDialogBase::spacingHint(), "lyr"); + m_sel = new KexiProjectSelectorWidget(plainPage(), "sel", + prj_set, showProjectNameColumn, showConnectionColumns); + lyr->addWidget(m_sel); + setIcon(*m_sel->icon()); + m_sel->setFocus(); + + connect(m_sel,SIGNAL(projectExecuted(KexiProjectData*)), + this,SLOT(slotProjectExecuted(KexiProjectData*))); + connect(m_sel,SIGNAL(selectionChanged(KexiProjectData*)), + this,SLOT(slotProjectSelectionChanged(KexiProjectData*))); +} + +KexiProjectData* KexiProjectSelectorDialog::selectedProjectData() const +{ + return m_sel->selectedProjectData(); +} + +void KexiProjectSelectorDialog::slotProjectExecuted(KexiProjectData*) +{ + accept(); +} + +void KexiProjectSelectorDialog::slotProjectSelectionChanged(KexiProjectData* pdata) +{ + enableButtonOK(pdata); +} + +void KexiProjectSelectorDialog::show() +{ + KDialogBase::show(); + KDialog::centerOnScreen(this); +} + +#include "KexiProjectSelector.moc" diff --git a/kexi/main/startup/KexiProjectSelector.h b/kexi/main/startup/KexiProjectSelector.h new file mode 100644 index 00000000..3151be3b --- /dev/null +++ b/kexi/main/startup/KexiProjectSelector.h @@ -0,0 +1,134 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl> + + This program 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 program 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 program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KEXIPROJECTSELECTOR_H +#define KEXIPROJECTSELECTOR_H + +#include "KexiProjectSelectorBase.h" +#include "kexiprojectset.h" + +#include <kdialogbase.h> +#include <qwidgetstack.h> + +class KexiNewFileDBWidget; +class KexiProjectSelectorWidgetPrivate; + +/*! Widget that allows to select a kexi project (or database) +*/ +class KEXIMAIN_EXPORT KexiProjectSelectorWidget : public KexiProjectSelectorBase +{ + Q_OBJECT + +public: +// enum ConnType { FileBased=1, ServerBased=2 }; + + /*! Constructs a project selector widget. + If \a showProjectNameColumn is true (the default) + project names' column is visible. If \a showConnectionColumns is true (the default) + information about database driver and connection columns are added. + \a prj_set may be NULL - you can assign a set later with setProjectSet(). + */ + KexiProjectSelectorWidget( QWidget* parent = 0, const char* name = 0, + KexiProjectSet* prj_set = 0, bool showProjectNameColumn = true, + bool showConnectionColumns = true ); + + ~KexiProjectSelectorWidget(); + + /*! \return data of selected project. Returns NULL if no selection has been made. + */ + KexiProjectData* selectedProjectData() const; + + /*! Assigns a new project set \a prj_set. Old project set is not destoyed + - it is just left unassigned. + If new project set is in error state (Object::error() == true), nothing is displayed. */ + void setProjectSet( KexiProjectSet* prj_set ); + + /*! \return currently assigned project set or NULL if no project set is assigned. */ + inline KexiProjectSet *projectSet() { return m_prj_set; } + + /*! Sets selectable state on or off. In this state one project item can be selected + and executed by mouse double clicking or return key pressing. + The property is true by default. */ + void setSelectable(bool set); + + /*! \return if a witget has selectable state set. */ + bool isSelectable() const; + +public slots: + +signals: + void projectExecuted(KexiProjectData*); + void selectionChanged(KexiProjectData*); + +protected slots: + void slotItemExecuted(QListViewItem*); + void slotItemSelected(); + virtual void languageChange() { KexiProjectSelectorBase::languageChange(); } + +protected: + KexiProjectSet *m_prj_set; + + KexiProjectSelectorWidgetPrivate *d; + + friend class ProjectDataLVItem; +}; + +/*! Dialog container for KexiProjectSelectorWidget */ +class KexiProjectSelectorDialog : public KDialogBase +{ + Q_OBJECT +public: + /*! Constructor 1, used for displaying recent projects list + Label "there are recently opened projects" is displayed automatically + */ + KexiProjectSelectorDialog( QWidget *parent, const char *name, + KexiProjectSet* prj_set, + bool showProjectNameColumn = true, bool showConnectionColumns = true); + + /*! Constructor 2, used for displaying projects list for given connection + Label "Select one of these existing projects on server" is displayed automatically + You should test if project set was properly loaded using projectSet()->error(). + */ + KexiProjectSelectorDialog( QWidget *parent, const char *name, + KexiDB::ConnectionData* cdata, + bool showProjectNameColumn = true, bool showConnectionColumns = true); + + ~KexiProjectSelectorDialog(); + + /*! \return data of selected project. Returns NULL if no selection has been made. + */ + KexiProjectData* selectedProjectData() const; + + /*! \return currently assigned project set or NULL if no project set is assigned. */ + inline KexiProjectSet *projectSet() { return m_sel->projectSet(); } + + virtual void show(); + +protected slots: + void slotProjectExecuted(KexiProjectData*); + void slotProjectSelectionChanged(KexiProjectData*); + +protected: + void init(KexiProjectSet* prj_set, bool showProjectNameColumn, bool showConnectionColumns); + + KexiProjectSelectorWidget* m_sel; +}; + +#endif + diff --git a/kexi/main/startup/KexiProjectSelectorBase.ui b/kexi/main/startup/KexiProjectSelectorBase.ui new file mode 100644 index 00000000..4d51751b --- /dev/null +++ b/kexi/main/startup/KexiProjectSelectorBase.ui @@ -0,0 +1,128 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KexiProjectSelectorBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiProjectSelectorBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>405</width> + <height>164</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>label</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><b>There are Kexi projects you have recently opened.</b> Select one you wish to open: +</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QListView"> + <column> + <property name="text"> + <string>Project Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Database</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Type</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Connection</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>list</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>60</height> + </size> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="showSortIndicator"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>LastColumn</enum> + </property> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>list</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kexi/main/startup/KexiServerDBNamePage.ui b/kexi/main/startup/KexiServerDBNamePage.ui new file mode 100644 index 00000000..3ea61dc3 --- /dev/null +++ b/kexi/main/startup/KexiServerDBNamePage.ui @@ -0,0 +1,141 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>KexiServerDBNamePage</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KexiServerDBNamePage</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>477</width> + <height>299</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Project caption: </string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Project's database name: </string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>le_caption</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>le_dbname</cstring> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + </widget> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>MinimumExpanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>70</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>70</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QFrame" row="4" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>frm_dblist</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>12</height> + </size> + </property> + </spacer> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kexi/main/startup/KexiStartup.cpp b/kexi/main/startup/KexiStartup.cpp new file mode 100644 index 00000000..19ae8d28 --- /dev/null +++ b/kexi/main/startup/KexiStartup.cpp @@ -0,0 +1,965 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 "KexiStartup.h" +#ifdef Q_WS_WIN +# include "KexiStartup_p_win.h" +#else +# include "KexiStartup_p.h" +#endif + +#include "kexiproject.h" +#include "kexiprojectdata.h" +#include "kexiprojectset.h" +#include "kexiguimsghandler.h" + +#include <kexidb/driver.h> +#include <kexidb/drivermanager.h> +#include "KexiStartupDialog.h" +#include "KexiConnSelector.h" +#include "KexiProjectSelectorBase.h" +#include "KexiProjectSelector.h" +#include "KexiNewProjectWizard.h" +#include <kexidbconnectionwidget.h> +#include <kexidbshortcutfile.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmimetype.h> +#include <kmessagebox.h> +#include <kcmdlineargs.h> +#include <kdeversion.h> +#include <kprogress.h> +#include <ktextedit.h> +#include <kstaticdeleter.h> +#include <kuser.h> + +#include <unistd.h> + +#include <qcstring.h> +#include <qapplication.h> +#include <qlayout.h> + +namespace Kexi { + static KStaticDeleter<KexiStartupHandler> Kexi_startupHandlerDeleter; + KexiStartupHandler* _startupHandler = 0; + + KexiStartupHandler& startupHandler() + { + if (!_startupHandler) + Kexi_startupHandlerDeleter.setObject( _startupHandler, new KexiStartupHandler() ); + return *_startupHandler; + } +} + +//--------------------------------- + +//! @internal +class KexiStartupHandlerPrivate +{ + public: + KexiStartupHandlerPrivate() + : passwordDialog(0)//, showConnectionDetailsExecuted(false) + , shortcutFile(0), connShortcutFile(0), connDialog(0), startupDialog(0) + { + } + + ~KexiStartupHandlerPrivate() + { + delete passwordDialog; + delete connDialog; + delete startupDialog; + } + + KexiDBPasswordDialog* passwordDialog; +// bool showConnectionDetailsExecuted : 1; + KexiDBShortcutFile *shortcutFile; + KexiDBConnShortcutFile *connShortcutFile; + KexiDBConnectionDialog *connDialog; + QString shortcutFileGroupKey; + KexiStartupDialog *startupDialog; +}; + +//--------------------------------- + +static bool stripQuotes(const QString &item, QString &name) +{ + if (item.left(1)=="\"" && item.right(1)=="\"") { + name = item.mid(1, item.length()-2); + return true; + } + name = item; + return false; +} + +void updateProgressBar(KProgressDialog *pd, char *buffer, int buflen) +{ + char *p = buffer; + QCString line(80); + for (int i=0; i<buflen; i++, p++) { + if ((i==0 || buffer[i-1]=='\n') && buffer[i]=='%') { + bool ok; + int j=0; +// char *q=++p; + ++i; + line=""; + for (;i<buflen && *p>='0' && *p<='9'; j++, i++, p++) + line+=QChar(*p); + --i; --p; + int percent = line.toInt(&ok); + if (ok && percent>=0 && percent<=100 && pd->progressBar()->progress()<percent) { +// kdDebug() << percent << endl; + pd->progressBar()->setProgress(percent); + qApp->processEvents(100); + } + } + } +} + +//--------------------------------- + +KexiDBPasswordDialog::KexiDBPasswordDialog(QWidget *parent, KexiDB::ConnectionData& cdata, bool showDetailsButton) + : KPasswordDialog( KPasswordDialog::Password, false/*keep*/, + showDetailsButton ? (int)KDialogBase::User1 : 0, parent ) + , m_cdata(&cdata) + , m_showConnectionDetailsRequested(false) +{ + QString msg = "<H2>" + i18n("Opening database") + "</H2><p>" + + i18n("Please enter the password.") + "</p>"; +/* msg += cdata.userName.isEmpty() ? + "<p>"+i18n("Please enter the password.") + : "<p>"+i18n("Please enter the password for user.").arg("<b>"+cdata.userName+"</b>");*/ + + QString srv = cdata.serverInfoString(false); + if (srv.isEmpty() || srv.lower()=="localhost") + srv = i18n("local database server"); + + msg += ("</p><p>"+i18n("Database server: %1").arg(QString("<nobr>")+srv+"</nobr>")+"</p>"); + + QString usr; + if (cdata.userName.isEmpty()) + usr = i18n("unspecified user", "(unspecified)"); + else + usr = cdata.userName; + + msg += ("<p>"+i18n("Username: %1").arg(usr)+"</p>"); + + setPrompt( msg ); + if (showDetailsButton) { + connect( this, SIGNAL(user1Clicked()), + this, SLOT(slotShowConnectionDetails()) ); + setButtonText(KDialogBase::User1, i18n("&Details")+ " >>"); + } + setButtonOK(KGuiItem(i18n("&Open"), "fileopen")); +} + +KexiDBPasswordDialog::~KexiDBPasswordDialog() +{ +} + +void KexiDBPasswordDialog::done(int r) +{ + if (r == QDialog::Accepted) { + m_cdata->password = QString::fromLatin1(password()); + } +// if (d->showConnectionDetailsExecuted || ret == QDialog::Accepted) { +/* } else { + m_action = Exit; + return true; + } + }*/ + KPasswordDialog::done(r); +} + +void KexiDBPasswordDialog::slotShowConnectionDetails() +{ + m_showConnectionDetailsRequested = true; + close(); +} + +//--------------------------------- +KexiStartupHandler::KexiStartupHandler() + : QObject(0,"KexiStartupHandler") + , KexiStartupData() + , d( new KexiStartupHandlerPrivate() ) +{ +} + +KexiStartupHandler::~KexiStartupHandler() +{ + delete d; +} + +bool KexiStartupHandler::getAutoopenObjects(KCmdLineArgs *args, const QCString &action_name) +{ + QCStringList list = args->getOptionList(action_name); + QCStringList::ConstIterator it; + bool atLeastOneFound = false; + for ( it = list.constBegin(); it!=list.constEnd(); ++it) { + QString type_name, obj_name, item=*it; + int idx; + bool name_required = true; + if (action_name=="new") { + obj_name = ""; + stripQuotes(item, type_name); + name_required = false; + } + else {//open, design, text... + QString defaultType; + if (action_name=="execute") + defaultType = "macro"; + else + defaultType = "table"; + + //option with " " (set default type) + if (stripQuotes(item, obj_name)) { + type_name = defaultType; + } + else if ((idx = item.find(':'))!=-1) { + //option with type name specified: + type_name = item.left(idx).lower(); + obj_name = item.mid(idx+1); + //optional: remove "" + if (obj_name.left(1)=="\"" && obj_name.right(1)=="\"") + obj_name = obj_name.mid(1, obj_name.length()-2); + } + else { + //just obj. name: set default type name + obj_name = item; + type_name = defaultType; + } + } + if (type_name.isEmpty()) + continue; + if (name_required && obj_name.isEmpty()) + continue; + + KexiProjectData::ObjectInfo info; + info["name"]=obj_name; + info["type"]=type_name; + info["action"]=action_name; + //ok, now add info for this object + atLeastOneFound = true; + if (projectData()) + projectData()->autoopenObjects.append( info ); + else + return true; //no need to find more because we do not have projectData() anyway + } //for + return atLeastOneFound; +} + +tristate KexiStartupHandler::init(int /*argc*/, char ** /*argv*/) +{ + m_action = DoNothing; +// d->showConnectionDetailsExecuted = false; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(0); + if (!args) + return true; + + KexiDB::ConnectionData cdata; + + const QString connectionShortcutFileName( args->getOption("connection") ); + if (!connectionShortcutFileName.isEmpty()) { + KexiDBConnShortcutFile connectionShortcut( connectionShortcutFileName ); + if (!connectionShortcut.loadConnectionData(cdata)) { +//! @todo Show error message from KexiDBConnShortcutFile when there's one implemented. +//! For we're displaying generic error msg. + KMessageBox::sorry( 0, "<qt>" + +i18n("Could not read connection information from connection shortcut " + "file <nobr>\"%1\"</nobr>.<br><br>Check whether the file has valid contents.") + .arg(QDir::convertSeparators(connectionShortcut.fileName()))); + return false; + } + } + + if (!args->getOption("dbdriver").isEmpty()) + cdata.driverName = args->getOption("dbdriver"); + + QString fileType( args->getOption("type").lower() ); + if (args->count()>0 && (!fileType.isEmpty() && fileType!="project" && fileType!="shortcut" && fileType!="connection")) { + KMessageBox::sorry( 0, + i18n("You have specified invalid argument (\"%1\") for \"type\" command-line option.") + .arg(fileType)); + return false; + } + +// if (cdata.driverName.isEmpty()) +// cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName(); + if (!args->getOption("host").isEmpty()) + cdata.hostName = args->getOption("host"); + if (!args->getOption("local-socket").isEmpty()) + cdata.localSocketFileName = args->getOption("local-socket"); + if (!args->getOption("user").isEmpty()) + cdata.userName = args->getOption("user"); +// cdata.password = args->getOption("password"); + bool fileDriverSelected; + if (cdata.driverName.isEmpty()) + fileDriverSelected = true; + else { + KexiDB::DriverManager dm; + KexiDB::Driver::Info dinfo = dm.driverInfo(cdata.driverName); + if (dinfo.name.isEmpty()) { + //driver name provided explicitly, but not found + KMessageBox::sorry(0, dm.errorMsg()); + return false; + } + fileDriverSelected = dinfo.fileBased; + } + bool projectFileExists = false; + + //obfuscate the password, if present +//removed +/* + for (int i=1; i<(argc-1); i++) { + if (qstrcmp("--password",argv[i])==0 + || qstrcmp("-password",argv[i])==0) + { + QCString pwd(argv[i+1]); + if (!pwd.isEmpty()) { + pwd.fill(' '); + pwd[0]='x'; + qstrcpy(argv[i+1], (const char*)pwd); + } + break; + } + } + */ + + const QString portStr = args->getOption("port"); + if (!portStr.isEmpty()) { + bool ok; + const int p = portStr.toInt(&ok); + if (ok && p > 0) + cdata.port = p; + else { + KMessageBox::sorry( 0, + i18n("You have specified invalid port number \"%1\".")); + return false; + } + } + + m_forcedUserMode = args->isSet("user-mode"); + m_forcedDesignMode = args->isSet("design-mode"); + m_isProjectNavigatorVisible = args->isSet("show-navigator"); + bool createDB = args->isSet("createdb"); + const bool alsoOpenDB = args->isSet("create-opendb"); + if (alsoOpenDB) + createDB = true; + const bool dropDB = args->isSet("dropdb"); + const bool openExisting = !createDB && !dropDB; + const bool readOnly = args->isSet("readonly"); + const QString couldnotMsg = QString::fromLatin1("\n") + +i18n("Could not start Kexi application this way."); + + if (createDB && dropDB) { + KMessageBox::sorry( 0, i18n( + "You have used both \"createdb\" and \"dropdb\" startup options.")+couldnotMsg); + return false; + }; + + if (createDB || dropDB) { + if (args->count()<1) { + KMessageBox::sorry( 0, i18n("No project name specified.") ); + return false; + } + m_action = Exit; + } + +//TODO: add option for non-gui; integrate with KWallet; +// move to static KexiProject method + if (!fileDriverSelected && !cdata.driverName.isEmpty() && cdata.password.isEmpty()) { + + if (cdata.password.isEmpty()) { + delete d->passwordDialog; + d->passwordDialog = new KexiDBPasswordDialog(0, cdata, true); +// connect( d->passwordDialog, SIGNAL(user1Clicked()), +// this, SLOT(slotShowConnectionDetails()) ); + const int ret = d->passwordDialog->exec(); + if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) { +// if ( ret == QDialog::Accepted ) { + // if (QDialog::Accepted == KPasswordDialog::getPassword(pwd, msg)) { +//moved cdata.password = QString(pwd); +// } + } else { + m_action = Exit; + return true; + } + } + } + +/* kdDebug() << "ARGC==" << args->count() << endl; + for (int i=0;i<args->count();i++) { + kdDebug() << "ARG" <<i<< "= " << args->arg(i) <<endl; + }*/ + + if (m_forcedUserMode && m_forcedDesignMode) { + KMessageBox::sorry( 0, i18n( + "You have used both \"user-mode\" and \"design-mode\" startup options.")+couldnotMsg); + return false; + } + + //database filenames, shortcut filenames or db names on a server + if (args->count()>=1) { + QString prjName; + QString fileName; + if (fileDriverSelected) { + fileName = QFile::decodeName(args->arg(0)); + } + else { + prjName = QString::fromLocal8Bit(args->arg(0)); + } + + if (fileDriverSelected) { + QFileInfo finfo(fileName); + prjName = finfo.fileName(); //filename only, to avoid messy names like when Kexi is started with "../../db" arg + cdata.setFileName( finfo.absFilePath() ); + projectFileExists = finfo.exists(); + + if (dropDB && !projectFileExists) { + KMessageBox::sorry(0, + i18n("Could not remove project.\nThe file \"%1\" does not exist.") + .arg(QDir::convertSeparators(cdata.dbFileName()))); + return 0; + } + } + + if (createDB) { + if (cdata.driverName.isEmpty()) + cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName(); + m_projectData = new KexiProjectData(cdata, prjName); //dummy + } + else { + if (fileDriverSelected) { + int detectOptions = 0; + if (fileType=="project") + detectOptions |= ThisIsAProjectFile; + else if (fileType=="shortcut") + detectOptions |= ThisIsAShortcutToAProjectFile; + else if (fileType=="connection") + detectOptions |= ThisIsAShortcutToAConnectionData; + + if (dropDB) + detectOptions |= DontConvert; + + QString detectedDriverName; + const tristate res = detectActionForFile( m_importActionData, detectedDriverName, + cdata.driverName, cdata.fileName(), 0, detectOptions ); + if (true != res) + return res; + + if (m_importActionData) { //importing action + m_action = ImportProject; + return true; + } + + //opening action + cdata.driverName = detectedDriverName; + if (cdata.driverName=="shortcut") { + //get information for a shortcut file + d->shortcutFile = new KexiDBShortcutFile(cdata.fileName()); + m_projectData = new KexiProjectData(); + if (!d->shortcutFile->loadProjectData(*m_projectData, &d->shortcutFileGroupKey)) { + KMessageBox::sorry(0, i18n("Could not open shortcut file\n\"%1\".") + .arg(QDir::convertSeparators(cdata.fileName()))); + delete m_projectData; + m_projectData = 0; + delete d->shortcutFile; + d->shortcutFile = 0; + return false; + } + d->connDialog = new KexiDBConnectionDialog( + *m_projectData, d->shortcutFile->fileName()); + connect(d->connDialog, SIGNAL(saveChanges()), + this, SLOT(slotSaveShortcutFileChanges())); + int res = d->connDialog->exec(); + if (res == QDialog::Accepted) { + //get (possibly changed) prj data + *m_projectData = d->connDialog->currentProjectData(); + } + + delete d->connDialog; + d->connDialog = 0; + delete d->shortcutFile; + d->shortcutFile = 0; + + if (res == QDialog::Rejected) { + delete m_projectData; + m_projectData = 0; + return cancelled; + } + } + else if (cdata.driverName=="connection") { + //get information for a connection file + d->connShortcutFile = new KexiDBConnShortcutFile(cdata.fileName()); + if (!d->connShortcutFile->loadConnectionData(cdata, &d->shortcutFileGroupKey)) { + KMessageBox::sorry(0, i18n("Could not open connection data file\n\"%1\".") + .arg(QDir::convertSeparators(cdata.fileName()))); + delete d->connShortcutFile; + d->connShortcutFile = 0; + return false; + } + bool cancel = false; + const bool showConnectionDialog = !args->isSet("skip-conn-dialog"); + while (true) { + if (showConnectionDialog) { + //show connection dialog, so user can change parameters + if (!d->connDialog) { + d->connDialog = new KexiDBConnectionDialog( + cdata, d->connShortcutFile->fileName()); + connect(d->connDialog, SIGNAL(saveChanges()), + this, SLOT(slotSaveShortcutFileChanges())); + } + const int res = d->connDialog->exec(); + if (res == QDialog::Accepted) { + //get (possibly changed) prj data + cdata = *d->connDialog->currentProjectData().constConnectionData(); + } + else { + cancel = true; + break; + } + } + m_projectData = selectProject(&cdata, cancel); + if (m_projectData || cancel || !showConnectionDialog) + break; + } + + delete d->connShortcutFile; + d->connShortcutFile = 0; + delete d->connDialog; + d->connDialog = 0; + + if (cancel) + return cancelled; + } + else + m_projectData = new KexiProjectData(cdata, prjName); + } + else + m_projectData = new KexiProjectData(cdata, prjName); + + } +// if (!m_projectData) +// return false; + } + if (args->count()>1) { + //TODO: KRun another Kexi instances + } + + //let's show connection details, user asked for that in the "password dialog" + if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) { + d->connDialog = new KexiDBConnectionDialog(*m_projectData); +// connect(d->connDialog->tabWidget->mainWidget, SIGNAL(saveChanges()), +// this, SLOT(slotSaveShortcutFileChanges())); + int res = d->connDialog->exec(); + + if (res == QDialog::Accepted) { + //get (possibly changed) prj data + *m_projectData = d->connDialog->currentProjectData(); + } + + delete d->connDialog; + d->connDialog = 0; + + if (res == QDialog::Rejected) { + delete m_projectData; + m_projectData = 0; + return cancelled; + } + } + + //---autoopen objects: + const bool atLeastOneAOOFound = getAutoopenObjects(args, "open") + || getAutoopenObjects(args, "design") + || getAutoopenObjects(args, "edittext") + || getAutoopenObjects(args, "execute") + || getAutoopenObjects(args, "new") + || getAutoopenObjects(args, "print") + || getAutoopenObjects(args, "print-preview"); + + if (atLeastOneAOOFound && !openExisting) { + KMessageBox::information( 0, + i18n("You have specified a few database objects to be opened automatically, " + "using startup options.\n" + "These options will be ignored because it is not available while creating " + "or dropping projects.")); + } + + if (createDB) { + bool creationNancelled; + KexiGUIMessageHandler gui; + KexiProject *prj = KexiProject::createBlankProject(creationNancelled, projectData(), &gui); + bool ok = prj!=0; + delete prj; + if (creationNancelled) + return cancelled; + if (!alsoOpenDB) { + if (ok) { + KMessageBox::information( 0, i18n("Project \"%1\" created successfully.") + .arg( QDir::convertSeparators(projectData()->databaseName()) )); + } + return ok; + } + } + else if (dropDB) { + KexiGUIMessageHandler gui; + tristate res = KexiProject::dropProject(projectData(), &gui, false/*ask*/); + if (res==true) + KMessageBox::information( 0, i18n("Project \"%1\" dropped successfully.") + .arg( QDir::convertSeparators(projectData()->databaseName()) )); + return res!=false; + } + + //------ + +/* if (m_forcedFinalMode || (m_projectData && projectData->finalMode())) { + //TODO: maybe also auto allow to open objects... + KexiMainWindowImpl::initFinal(m_projectData); + return; + }*/ + + if (!m_projectData) { + cdata = KexiDB::ConnectionData(); //clear + + if (args->isSet("skip-startup-dialog") || !KexiStartupDialog::shouldBeShown()) + return true; + + if (!d->startupDialog) { + //create d->startupDialog for reuse because it can be used again after conn err. + d->startupDialog = new KexiStartupDialog( + KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain, + Kexi::connset(), Kexi::recentProjects(), 0, "KexiStartupDialog"); + } + if (d->startupDialog->exec()!=QDialog::Accepted) + return true; + + const int r = d->startupDialog->result(); + if (r == KexiStartupDialog::CreateBlankResult) { + m_action = CreateBlankProject; + return true; + } + else if (r == KexiStartupDialog::ImportResult) { + m_action = ImportProject; + return true; + } + else if (r == KexiStartupDialog::CreateFromTemplateResult) { + const QString selFile( d->startupDialog->selectedFileName() ); + cdata.setFileName( selFile ); + QString detectedDriverName; + const tristate res = detectActionForFile( m_importActionData, detectedDriverName, + cdata.driverName, selFile ); + if (true != res) + return res; + if (m_importActionData || detectedDriverName.isEmpty()) + return false; + cdata.driverName = detectedDriverName; + m_projectData = new KexiProjectData(cdata, selFile); + m_projectData->autoopenObjects = d->startupDialog->autoopenObjects(); + m_action = CreateFromTemplate; + return true; + } + else if (r == KexiStartupDialog::OpenExistingResult) { +// kdDebug() << "Existing project --------" << endl; + const QString selFile( d->startupDialog->selectedFileName() ); + if (!selFile.isEmpty()) { + //file-based project +// kdDebug() << "Project File: " << selFile << endl; + cdata.setFileName( selFile ); + QString detectedDriverName; + const tristate res = detectActionForFile( m_importActionData, detectedDriverName, + cdata.driverName, selFile ); + if (true != res) + return res; + if (m_importActionData) { //importing action + m_action = ImportProject; + return true; + } + + if (detectedDriverName.isEmpty()) + return false; + cdata.driverName = detectedDriverName; + m_projectData = new KexiProjectData(cdata, selFile); + } + else if (d->startupDialog->selectedExistingConnection()) { +// kdDebug() << "Existing connection: " << +// d->startupDialog->selectedExistingConnection()->serverInfoString() << endl; + KexiDB::ConnectionData *cdata = d->startupDialog->selectedExistingConnection(); + //ok, now we will try to show projects for this connection to the user + bool cancelled; + m_projectData = selectProject( cdata, cancelled ); + if (!m_projectData && !cancelled || cancelled) { + //try again + return init(0, 0); + } + //not needed anymore + delete d->startupDialog; + d->startupDialog = 0; + } + } + else if (r==KexiStartupDialog::OpenRecentResult) { +// kdDebug() << "Recent project --------" << endl; + const KexiProjectData *data = d->startupDialog->selectedProjectData(); + if (data) { +// kdDebug() << "Selected project: database=" << data->databaseName() +// << " connection=" << data->constConnectionData()->serverInfoString() << endl; + } +//! @todo + return data!=0; + } + + if (!m_projectData) + return true; + } + + if (m_projectData && (openExisting || (createDB && alsoOpenDB))) { + m_projectData->setReadOnly( readOnly ); + m_action = OpenProject; + } + //show if wasn't show yet +// importantInfo(true); + + return true; +} + +tristate KexiStartupHandler::detectActionForFile( + KexiStartupData::Import& detectedImportAction, QString& detectedDriverName, + const QString& _suggestedDriverName, const QString &dbFileName, QWidget *parent, int options ) +{ + detectedImportAction = KexiStartupData::Import(); //clear + QString suggestedDriverName(_suggestedDriverName); //safe + detectedDriverName = QString::null; + QFileInfo finfo(dbFileName); + if (dbFileName.isEmpty() || !finfo.isReadable()) { + if (!(options & SkipMessages)) + KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>") + +i18n("<p>The file <nobr>\"%1\"</nobr> does not exist or is not readable.</p>") + .arg(QDir::convertSeparators(dbFileName)) + +i18n("Check the file's permissions and whether it is already opened " + "and locked by another application.")); + return false; + } + + KMimeType::Ptr ptr; + QString mimename; + + const bool thisIsShortcut = (options & ThisIsAShortcutToAProjectFile) + || (options & ThisIsAShortcutToAConnectionData); + + if ((options & ThisIsAProjectFile) || !thisIsShortcut) { + //try this detection if "project file" mode is forced or no type is forced: + ptr = KMimeType::findByFileContent(dbFileName); + mimename = ptr.data()->name(); + kdDebug() << "KexiStartupHandler::detectActionForFile(): found mime is: " + << mimename << endl; + if (mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain") { + //try by URL: + ptr = KMimeType::findByURL(dbFileName); + mimename = ptr.data()->name(); + } + } + if (mimename.isEmpty() || mimename=="application/octet-stream") { + // perhaps the file is locked + QFile f(dbFileName); + if (!f.open(IO_ReadOnly)) { + // BTW: similar error msg is provided in SQLiteConnection::drv_useDatabase() + if (!(options & SkipMessages)) + KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>") + +i18n("<p>The file <nobr>\"%1\"</nobr> is not readable.</p>") + .arg(QDir::convertSeparators(dbFileName)) + +i18n("Check the file's permissions and whether it is already opened " + "and locked by another application.")); + return false; + } + } + if ((options & ThisIsAShortcutToAProjectFile) || mimename=="application/x-kexiproject-shortcut") { + detectedDriverName = "shortcut"; + return true; + } + + if ((options & ThisIsAShortcutToAConnectionData) || mimename=="application/x-kexi-connectiondata") { + detectedDriverName = "connection"; + return true; + } + + //! @todo rather check this using migration drivers' + //! X-KexiSupportedMimeTypes [strlist] property + if (ptr.data()) { + if (mimename=="application/x-msaccess") { + if ((options & SkipMessages) || KMessageBox::Yes != KMessageBox::questionYesNo( + parent, i18n("\"%1\" is an external file of type:\n\"%2\".\n" + "Do you want to import the file as a Kexi project?") + .arg(QDir::convertSeparators(dbFileName)).arg(ptr.data()->comment()), + i18n("Open External File"), KGuiItem(i18n("Import...")), KStdGuiItem::cancel() ) ) + { + return cancelled; + } + detectedImportAction.mimeType = mimename; + detectedImportAction.fileName = dbFileName; + return true; + } + } + + if (!finfo.isWritable()) { + //! @todo if file is ro: change project mode (but do not care if we're jsut importing) + } + + // "application/x-kexiproject-sqlite", etc.: + QString tmpDriverName = Kexi::driverManager().lookupByMime(mimename).latin1(); +//@todo What about trying to reuse KOFFICE FILTER CHAINS here? + bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower(); + if (!useDetectedDriver) { + int res = KMessageBox::Yes; + if (!(options & SkipMessages)) + res = KMessageBox::warningYesNoCancel(parent, i18n( + "The project file \"%1\" is recognized as compatible with \"%2\" database driver, " + "while you have asked for \"%3\" database driver to be used.\n" + "Do you want to use \"%4\" database driver?") + .arg(QDir::convertSeparators(dbFileName)) + .arg(tmpDriverName).arg(suggestedDriverName).arg(tmpDriverName)); + if (KMessageBox::Yes == res) + useDetectedDriver = true; + else if (KMessageBox::Cancel == res) + return cancelled; + } + if (useDetectedDriver) { + detectedDriverName = tmpDriverName; + } + else {//use suggested driver + detectedDriverName = suggestedDriverName; + } +// kdDebug() << "KexiStartupHandler::detectActionForFile(): driver name: " << detectedDriverName << endl; +//hardcoded for convenience: + const QString newFileFormat = "SQLite3"; + if (!(options & DontConvert || options & SkipMessages) + && detectedDriverName.lower()=="sqlite2" && detectedDriverName.lower()!=suggestedDriverName.lower() + && KMessageBox::Yes == KMessageBox::questionYesNo(parent, i18n( + "Previous version of database file format (\"%1\") is detected in the \"%2\" " + "project file.\nDo you want to convert the project to a new \"%3\" format (recommended)?") + .arg(detectedDriverName).arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat)) ) + { +// SQLite2ToSQLite3Migration *migr = new + SQLite2ToSQLite3Migration migr( finfo.absFilePath() ); + tristate res = migr.run(); +// kdDebug() << "--- migr.run() END ---" <<endl; + if (!res) { + //TODO msg + KMessageBox::sorry(parent, i18n( + "Failed to convert project file \"%1\" to a new \"%2\" format.\n" + "The file format remains unchanged.") + .arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat) ); + //continue... + } + if (res==true) + detectedDriverName = newFileFormat; + } +// action.driverName = detectedDriverName; + if (detectedDriverName.isEmpty()) { + QString possibleProblemsInfoMsg( Kexi::driverManager().possibleProblemsInfoMsg() ); + if (!possibleProblemsInfoMsg.isEmpty()) { + possibleProblemsInfoMsg.prepend(QString::fromLatin1("<p>")+i18n("Possible problems:")); + possibleProblemsInfoMsg += QString::fromLatin1("</p>"); + } + if (!(options & SkipMessages)) + KMessageBox::detailedSorry(parent, + i18n( "The file \"%1\" is not recognized as being supported by Kexi.") + .arg(QDir::convertSeparators(dbFileName)), + QString::fromLatin1("<p>") + +i18n("Database driver for this file type not found.\nDetected MIME type: %1") + .arg(mimename) + +(ptr.data()->comment().isEmpty() + ? QString::fromLatin1(".") : QString::fromLatin1(" (%1).").arg(ptr.data()->comment())) + +QString::fromLatin1("</p>") + +possibleProblemsInfoMsg); + return false; + } + return true; +} + +KexiProjectData* +KexiStartupHandler::selectProject(KexiDB::ConnectionData *cdata, bool& cancelled, QWidget *parent) +{ + clearStatus(); + cancelled = false; + if (!cdata) + return 0; + if (!cdata->savePassword && cdata->password.isEmpty()) { + if (!d->passwordDialog) + d->passwordDialog = new KexiDBPasswordDialog(0, *cdata, false); + const int ret = d->passwordDialog->exec(); + if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) { + + } else { + cancelled = true; + return 0; + } + } + KexiProjectData* projectData = 0; + //dialog for selecting a project + KexiProjectSelectorDialog prjdlg( parent, "prjdlg", cdata, true, false ); + if (!prjdlg.projectSet() || prjdlg.projectSet()->error()) { + KexiGUIMessageHandler msgh; + if (prjdlg.projectSet()) + msgh.showErrorMessage(prjdlg.projectSet(), + i18n("Could not load list of available projects for <b>%1</b> database server.") + .arg(cdata->serverInfoString(true))); + else + msgh.showErrorMessage( + i18n("Could not load list of available projects for <b>%1</b> database server.") + .arg(cdata->serverInfoString(true))); +// setStatus(i18n("Could not load list of available projects for database server \"%1\"") +// .arg(cdata->serverInfoString(true)), prjdlg.projectSet()->errorMsg()); + return 0; + } + if (prjdlg.exec()!=QDialog::Accepted) { + cancelled = true; + return 0; + } + if (prjdlg.selectedProjectData()) { + //deep copy + projectData = new KexiProjectData(*prjdlg.selectedProjectData()); + } + return projectData; +} + +void KexiStartupHandler::slotSaveShortcutFileChanges() +{ + bool ok = true; + if (d->shortcutFile) + ok = d->shortcutFile->saveProjectData(d->connDialog->currentProjectData(), + d->connDialog->savePasswordOptionSelected(), + &d->shortcutFileGroupKey ); + else if (d->connShortcutFile) + ok = d->connShortcutFile->saveConnectionData( + *d->connDialog->currentProjectData().connectionData(), + d->connDialog->savePasswordOptionSelected(), + &d->shortcutFileGroupKey ); + + if (!ok) { + KMessageBox::sorry(0, i18n("Failed saving connection data to\n\"%1\" file.") + .arg(QDir::convertSeparators(d->shortcutFile->fileName()))); + } +} + +/*void KexiStartupHandler::slotShowConnectionDetails() +{ + d->passwordDialog->close(); + d->showConnectionDetailsExecuted = true; +}*/ + +#include "KexiStartup.moc" diff --git a/kexi/main/startup/KexiStartup.h b/kexi/main/startup/KexiStartup.h new file mode 100644 index 00000000..294ad7dd --- /dev/null +++ b/kexi/main/startup/KexiStartup.h @@ -0,0 +1,136 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl> + + 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 KEXI_STARTUPHANDLER_H +#define KEXI_STARTUPHANDLER_H + +#include <qstring.h> +#include <qwidget.h> +#include <kpassdlg.h> + +#include <core/kexistartupdata.h> +#include <core/kexi.h> +#include <kexiutils/tristate.h> + +class KexiProjectData; +class KexiProjectData; +class KCmdLineArgs; +class KexiStartupHandlerPrivate; +namespace KexiDB { + class ConnectionData; +} + +/*! */ +class KEXIMAIN_EXPORT KexiDBPasswordDialog : public KPasswordDialog +{ + Q_OBJECT + public: + KexiDBPasswordDialog(QWidget *parent, KexiDB::ConnectionData& cdata, bool showDetailsButton = false); + virtual ~KexiDBPasswordDialog(); + + bool showConnectionDetailsRequested() const { return m_showConnectionDetailsRequested; } + + protected slots: + virtual void done(int r); + void slotShowConnectionDetails(); + + protected: + KexiDB::ConnectionData *m_cdata; + bool m_showConnectionDetailsRequested : 1; +}; + +/*! Handles startup actions for Kexi application. +*/ +class KEXIMAIN_EXPORT KexiStartupHandler + : public QObject, public KexiStartupData, public Kexi::ObjectStatus +{ + Q_OBJECT + + public: + KexiStartupHandler(); + virtual ~KexiStartupHandler(); + + virtual tristate init(int argc, char **argv); + + #if 0 + /*! Used for opening existing projects. + Detects project file type by mime type and returns project data, if it can be detected, + otherwise - NULL. \a parent is passed as parent for potential error message boxes. + Also uses \a cdata connection data for server-based projects. + cdata.driverName is adjusted, if a file-based project has been detected. + */ + static KexiProjectData* detectProjectData( + KexiDB::ConnectionData& cdata, const QString &dbname, QWidget *parent); + #endif + + /*! Options for detectDriverForFile() */ + enum DetectDriverForFileOptions { + DontConvert = 1, //!< skip asking for conversion (used e.g. when dropdb is called) + ThisIsAProjectFile = 2, //!< a hint, forces detection of the file as a project file + ThisIsAShortcutToAProjectFile = 4, //!< a hint, forces detection of the file + //!< as a shortcut to a project file + ThisIsAShortcutToAConnectionData = 8, //!< a hint, forces detection of the file + //!< as a shortcut to a connection data + SkipMessages = 16 //!< do not display error or warning messages + }; + + /*! Used for opening existing file-based projects. + Detects actions that should be performed for by looking at the file's mime type. + \return true if actions should be performed or cancelled if action should be cancelled + In this case there are two possibilities: + - \a detectedImportAction == true means "import action" should be performed + - nonempty \a detectedDriverName means "open action" should be performed. + + \a detectedDriverName can contain following special strings: + - "shortcut" if the file looks like a shortcut to a project/connection file + - "connection" if the file looks like a connection data file. + + \a parent is passed as a parent for potential error message boxes. + \a driverName is a preferred driver name. + \a options should be a combination of DetectDriverForFileOptions enum values. */ + static tristate detectActionForFile( + KexiStartupData::Import& detectedImportAction, QString& detectedDriverName, + const QString& _suggestedDriverName, + const QString &dbFileName, QWidget *parent = 0, int options = 0 ); + + /*! Allows user to select a project with KexiProjectSelectorDialog. + \return selected project's data + Returns NULL and sets cancelled to true if the dialog was cancelled. + Returns NULL and sets cancelled to false if there was an error. + */ + KexiProjectData* selectProject(KexiDB::ConnectionData *cdata, bool& cancelled, QWidget *parent = 0); + + protected slots: + void slotSaveShortcutFileChanges(); +// void slotShowConnectionDetails(); + + protected: + bool getAutoopenObjects(KCmdLineArgs *args, const QCString &action_name); + + KexiStartupHandlerPrivate *d; +}; + +namespace Kexi +{ + //! \return singleton Startup Handler singleton. + KEXIMAIN_EXPORT KexiStartupHandler& startupHandler(); +} + +#endif + diff --git a/kexi/main/startup/KexiStartupDialog.cpp b/kexi/main/startup/KexiStartupDialog.cpp new file mode 100644 index 00000000..3b524492 --- /dev/null +++ b/kexi/main/startup/KexiStartupDialog.cpp @@ -0,0 +1,699 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 "KexiStartupDialog.h" +#include "KexiStartupDialogTemplatesPage.h" +#include "kexi.h" +#include "KexiProjectSelector.h" +#include "KexiOpenExistingFile.h" +#include "KexiConnSelector.h" +#include "KexiConnSelectorBase.h" + +#include <qlayout.h> +#include <qtabwidget.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qpoint.h> +#include <qobjectlist.h> +#include <qvgroupbox.h> +#include <qapplication.h> +#include <qtooltip.h> +#include <qwidgetstack.h> + +#include <klocale.h> +#include <kdeversion.h> +#include <kinstance.h> +#include <kdebug.h> +#include <kpushbutton.h> +#include <kjanuswidget.h> +#include <kglobalsettings.h> +#include <ktextedit.h> +#include <kfileiconview.h> +#include <kfileitem.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kmimetype.h> +#include <ktextbrowser.h> +#include <kconfig.h> + +#ifdef KEXI_SHOW_UNIMPLEMENTED +#define KEXI_STARTUP_SHOW_TEMPLATES +#define KEXI_STARTUP_SHOW_RECENT +#endif + +//! @internal +class KexiStartupDialogPrivate { +public: + KexiStartupDialogPrivate() + : pageTemplates(0), pageOpenExisting(0), pageOpenRecent(0) + , pageTemplatesID(-1) + , pageOpenExistingID(-1) + , pageOpenRecentID(-1) + { + result = 0; + QString none, iconname; + iconname = KMimeType::mimeType( KexiDB::Driver::defaultFileBasedDriverMimeType() )->icon(none,0); + kexi_sqlite_icon = KGlobal::iconLoader()->loadIcon( iconname, KIcon::Desktop ); + iconname = KMimeType::mimeType("application/x-kexiproject-shortcut")->icon(none,0); + kexi_shortcut_icon = KGlobal::iconLoader()->loadIcon( iconname, KIcon::Desktop ); + prj_selector = 0; + chkDoNotShow = 0; + openExistingConnWidget = 0; + templatesWidget = 0; + templatesWidget_IconListBox = 0; + } + ~KexiStartupDialogPrivate() + {} + + int dialogType, dialogOptions; + + QFrame *pageTemplates, *pageOpenExisting, *pageOpenRecent; + int pageTemplatesID; + int pageOpenExistingID, pageOpenRecentID; + int templatesSectionID_blank, templatesSectionID_import; +#ifdef DB_TEMPLATES + int templatesSectionID_templates; //, templatesSectionID_custom2; +#endif + QCheckBox *chkDoNotShow; + + //widgets for template tab: + KJanusWidget* templatesWidget; + QObject *templatesWidget_IconListBox;//helper + + QWidgetStack *viewBlankTempl; + KexiStartupDialogTemplatesPage *viewTemplates; + //TemplatesPage *viewBusinessTempl; + + int result; + + QPixmap kexi_sqlite_icon, kexi_shortcut_icon; + +// //! Key string of selected database template. \sa selectedTemplateKey() +// QString selectedTemplateKey; + + //! used for "open existing" + KexiDBConnectionSet *connSet; + KexiStartupFileDialog *openExistingFileDlg; //! embedded file dialog + KexiConnSelectorWidget *openExistingConnWidget; + QString existingFileToOpen; //! helper for returning a file name to open + KexiDB::ConnectionData* selectedExistingConnection; //! helper for returning selected connection + + //! used for "open recent" + KexiProjectSet *recentProjects; + KexiProjectSelectorWidget* prj_selector; + + //! true if the dialog contain single page, not tabs + bool singlePage : 1; +}; + +bool dlgSinglePage(int type) +{ + return (type==KexiStartupDialog::Templates) + || (type==KexiStartupDialog::OpenExisting) + || (type==KexiStartupDialog::OpenRecent); +} + +QString captionForDialogType(int type) +{ + if (type==KexiStartupDialog::Templates) + return i18n("Create Project"); + else if (type==KexiStartupDialog::OpenExisting) + return i18n("Open Existing Project"); + else if (type==KexiStartupDialog::OpenRecent) + return i18n("Open Recent Project"); + + return i18n("Choose Project"); +} + +/*================================================================*/ +/*KexiStartupDialog::KexiStartupDialog(QWidget *parent, const char *name, KInstance* global, + const QCString &format, const QString &nativePattern, + const QString &nativeName, const DialogType &dialogType, + const QCString& templateType) : + KDialogBase(parent, name, true, i18n("Open Document"), KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Ok) { +*/ +KexiStartupDialog::KexiStartupDialog( + int dialogType, int dialogOptions, + KexiDBConnectionSet& connSet, KexiProjectSet& recentProjects, + QWidget *parent, const char *name ) + : KDialogBase( + dlgSinglePage(dialogType) ? Plain : Tabbed + ,captionForDialogType(dialogType) + ,Help | Ok | Cancel, Ok, parent, name ) + , d(new KexiStartupDialogPrivate()) +{ + d->recentProjects = &recentProjects; + d->connSet = &connSet; + d->dialogType = dialogType; + d->dialogOptions = dialogOptions; + d->singlePage = dlgSinglePage(dialogType); + + if (dialogType==OpenExisting) {//this dialog has "open" tab only! + setIcon(DesktopIcon("fileopen")); + } else { + setIcon(d->kexi_sqlite_icon); + } + + setSizeGripEnabled(true); + int id=0; + if (d->dialogType & Templates) { + setupPageTemplates(); + d->pageTemplatesID = id++; + d->templatesWidget->setFocus(); + } + if (d->dialogType & OpenExisting) { + setupPageOpenExisting(); + d->pageOpenExistingID = id++; + if (d->singlePage) + d->openExistingConnWidget->setFocus(); + } +#ifdef KEXI_STARTUP_SHOW_RECENT + if (d->dialogType & OpenRecent) { + setupPageOpenRecent(); + d->pageOpenRecentID = id++; + if (d->singlePage) + d->prj_selector->setFocus(); + } +#endif + + if (!d->singlePage) { + connect(this, SIGNAL(aboutToShowPage(QWidget*)), this, SLOT(slotPageShown(QWidget*))); + d->templatesWidget->setFocus(); + } + showPage(0); + adjustSize(); +} + +KexiStartupDialog::~KexiStartupDialog() +{ + delete d; +} + +bool KexiStartupDialog::shouldBeShown() +{ + KGlobal::config()->setGroup("Startup"); + return KGlobal::config()->readBoolEntry("ShowStartupDialog",true); +} + +void KexiStartupDialog::show() +{ + //just some cleanup +// d->selectedTemplateKey=QString::null; + d->existingFileToOpen=QString::null; + d->result=-1; + + KDialog::centerOnScreen(this); + KDialogBase::show(); +} + +int KexiStartupDialog::result() const +{ + return d->result; +} + +void KexiStartupDialog::done(int r) +{ + if (d->result!=-1) //already done! + return; + +// kdDebug() << "KexiStartupDialog::done(" << r << ")" << endl; +// updateSelectedTemplateKeyInfo(); + + if (r==QDialog::Rejected) { + d->result = CancelResult; + } else { + const int idx = activePageIndex(); + if (idx == d->pageTemplatesID) { + const int templateIdx = d->templatesWidget->activePageIndex(); + if (templateIdx == d->templatesSectionID_blank) + d->result = CreateBlankResult; +#ifdef DB_TEMPLATES + else if (templateIdx == d->templatesSectionID_templates) + d->result = CreateFromTemplateResult; +#endif + else if (templateIdx == d->templatesSectionID_import) + d->result = ImportResult; + } + else if (idx == d->pageOpenExistingID) { + // return file or connection: + if (d->openExistingConnWidget->selectedConnectionType()==KexiConnSelectorWidget::FileBased) { + if (!d->openExistingFileDlg->checkFileName()) + return; + d->existingFileToOpen = d->openExistingFileDlg->currentFileName(); +// d->existingFileToOpen = d->openExistingFileDlg->currentURL().path(); + d->selectedExistingConnection = 0; + } else { + d->existingFileToOpen = QString::null; + d->selectedExistingConnection + = d->openExistingConnWidget->selectedConnectionData(); + } + d->result = OpenExistingResult; + } + else { + d->result = OpenRecentResult; + } + } + + //save settings + KGlobal::config()->setGroup("Startup"); + if (d->openExistingConnWidget) + KGlobal::config()->writeEntry("OpenExistingType", + (d->openExistingConnWidget->selectedConnectionType() == KexiConnSelectorWidget::FileBased) + ? "File" : "Server"); + if (d->chkDoNotShow) + KGlobal::config()->writeEntry("ShowStartupDialog",!d->chkDoNotShow->isChecked()); + + KGlobal::config()->sync(); + + KDialogBase::done(r); +} + +void KexiStartupDialog::reject() +{ +// d->result = CancelResult; + KDialogBase::reject(); +} + +void KexiStartupDialog::setupPageTemplates() +{ + d->pageTemplates = addPage( i18n("&Create Project") ); + QVBoxLayout *lyr = new QVBoxLayout( d->pageTemplates, 0, KDialogBase::spacingHint() ); + + d->templatesWidget = new KJanusWidget( + d->pageTemplates, "templatesWidget", KJanusWidget::IconList); + {//aaa! dirty hack + d->templatesWidget_IconListBox = d->templatesWidget->child(0,"KListBox"); + if (d->templatesWidget_IconListBox) + d->templatesWidget_IconListBox->installEventFilter(this); + } + lyr->addWidget(d->templatesWidget); + connect(d->templatesWidget, SIGNAL(aboutToShowPage(QWidget*)), this, SLOT(slotPageShown(QWidget*))); + + if (d->dialogOptions & CheckBoxDoNotShowAgain) { + d->chkDoNotShow = new QCheckBox(i18n("Don't show me this dialog again"), d->pageTemplates, "chkDoNotShow"); + lyr->addWidget(d->chkDoNotShow); + } + + //template groups: + QFrame *templPageFrame; + QVBoxLayout *tmplyr; + int itemID = 0; //used just to set up templatesSectionID_* + + //- page "blank db" + d->templatesSectionID_blank = itemID++; + QString clickMsg( "\n\n" + i18n("Click \"OK\" button to proceed.") ); + templPageFrame = d->templatesWidget->addPage( + i18n("Blank Database"), i18n("New Blank Database Project"), DesktopIcon("empty") ); + tmplyr = new QVBoxLayout(templPageFrame, 0, KDialogBase::spacingHint()); + QLabel *lbl_blank = new QLabel( + i18n("Kexi will create a new blank database project.")+clickMsg, templPageFrame ); + lbl_blank->setAlignment(Qt::AlignAuto|Qt::AlignTop|Qt::WordBreak); + lbl_blank->setMargin(0); + tmplyr->addWidget( lbl_blank ); + tmplyr->addStretch(1); + +#ifdef DB_TEMPLATES + //- page "templates" + d->templatesSectionID_templates = itemID++; + QString none; + QString kexi_sqlite_icon_name + = KMimeType::mimeType( KexiDB::Driver::defaultFileBasedDriverMimeType() )->icon(none,0); + templPageFrame = d->templatesWidget->addPage ( + i18n("Keep this text narrow: split to multiple rows if needed", "Create From\nTemplate"), + i18n("New Database Project From Template"), DesktopIcon(kexi_sqlite_icon_name) ); + tmplyr = new QVBoxLayout(templPageFrame, 0, KDialogBase::spacingHint()); + QLabel *lbl_templ = new QLabel( + i18n("Kexi will create a new database project using selected template.\n" + "Select template and click \"OK\" button to proceed."), templPageFrame ); + lbl_templ->setAlignment(Qt::AlignAuto|Qt::AlignTop|Qt::WordBreak); + lbl_templ->setMargin(0); + tmplyr->addWidget( lbl_templ ); + + d->viewTemplates = new KexiStartupDialogTemplatesPage( templPageFrame ); + tmplyr->addWidget( d->viewTemplates ); + connect(d->viewTemplates,SIGNAL(selected(const QString&)), + this,SLOT(templateSelected(const QString&))); +/* connect(d->viewTemplates->templates,SIGNAL(returnPressed(QIconViewItem*)), + this,SLOT(templateItemExecuted(QIconViewItem*))); + connect(d->viewTemplates->templates,SIGNAL(currentChanged(QIconViewItem*)), + this,SLOT(templateItemSelected(QIconViewItem*)));*/ +/*later + templPageFrame = d->templatesWidget->addPage ( + i18n("Personal Databases"), i18n("New Personal Database Project Templates"), DesktopIcon("folder_home") ); + tmplyr = new QVBoxLayout(templPageFrame, 0, KDialogBase::spacingHint()); + d->viewPersonalTempl = new TemplatesPage( Vertical, templPageFrame, "personal_page" ); + tmplyr->addWidget( d->viewPersonalTempl ); + connect(d->viewPersonalTempl->templates,SIGNAL(doubleClicked(QIconViewItem*)),this,SLOT(templateItemExecuted(QIconViewItem*))); + connect(d->viewPersonalTempl->templates,SIGNAL(returnPressed(QIconViewItem*)),this,SLOT(templateItemExecuted(QIconViewItem*))); + connect(d->viewPersonalTempl->templates,SIGNAL(currentChanged(QIconViewItem*)),this,SLOT(templateItemSelected(QIconViewItem*))); +*/ + + //- page "business db" +/*later + d->templatesSectionID_custom2 = itemID++; + templPageFrame = d->templatesWidget->addPage ( + i18n("Business Databases"), i18n("New Business Database Project Templates"), + DesktopIcon( "business_user" )); + tmplyr = new QVBoxLayout(templPageFrame, 0, KDialogBase::spacingHint()); + d->viewBusinessTempl = new TemplatesPage( Vertical, templPageFrame, "business_page" ); + tmplyr->addWidget( d->viewBusinessTempl ); + connect(d->viewBusinessTempl->templates,SIGNAL(doubleClicked(QIconViewItem*)),this,SLOT(templateItemExecuted(QIconViewItem*))); + connect(d->viewBusinessTempl->templates,SIGNAL(returnPressed(QIconViewItem*)),this,SLOT(templateItemExecuted(QIconViewItem*))); + connect(d->viewBusinessTempl->templates,SIGNAL(currentChanged(QIconViewItem*)),this,SLOT(templateItemSelected(QIconViewItem*))); +*/ +#endif //DB_TEMPLATES + + //- page "import db" + d->templatesSectionID_import = itemID++; + templPageFrame = d->templatesWidget->addPage( + i18n("Import Existing\nDatabase"), i18n("Import Existing Database as New Database Project"), + DesktopIcon("database_import") ); + tmplyr = new QVBoxLayout(templPageFrame, 0, KDialogBase::spacingHint()); + QLabel *lbl_import = new QLabel( + i18n("Kexi will import the structure and data of an existing database as a new database project.") + +clickMsg, templPageFrame ); + lbl_import->setAlignment(Qt::AlignAuto|Qt::AlignTop|Qt::WordBreak); + lbl_import->setMargin(0); + tmplyr->addWidget( lbl_import ); + tmplyr->addStretch(1); +} + +void KexiStartupDialog::slotPageShown(QWidget *page) +{ + int idx = d->templatesWidget->pageIndex(page); +// KIconView *templ = 0; + if (idx==d->templatesSectionID_blank) {//blank +// kdDebug() << "blank" << endl; + } + else if (idx==d->templatesSectionID_import) { + } +#ifdef DB_TEMPLATES + else if (idx==d->templatesSectionID_templates) { + d->viewTemplates->populate(); + } +/*later? KIconView *templ = d->viewTemplates->templates; + if (templ->count()==0) { + //add items (on demand): + d->viewTemplates->addItem("cd_catalog", i18n("CD Catalog"), + i18n("Easy-to-use database for storing information about your CD collection."), + DesktopIcon("cdrom_unmount")); + d->viewTemplates->addItem("expenses", i18n("Expenses"), + i18n("A database for managing your personal expenses."), + DesktopIcon("kcalc")); + d->viewTemplates->addItem("image_gallery", i18n("Image Gallery"), + i18n("A database for archiving your image collection in a form of gallery."), + DesktopIcon("icons")); + } + } + else if (idx==d->templatesSectionID_custom2) {//business + templ = d->viewBusinessTempl->templates; + if (templ->count()==0) { + //add items (on demand): + d->viewBusinessTempl->addItem("address_book", i18n("Address Book"), + i18n("A database that offers you a contact information"), + DesktopIcon("contents")); + } + }*/ +#endif + updateDialogOKButton(d->pageTemplates); +} + +#if 0 +void KexiStartupDialog::templateItemSelected(QIconViewItem *) +{ + updateDialogOKButton(d->pageTemplates); +} + +void KexiStartupDialog::templateItemExecuted(QIconViewItem *item) +{ + if (!item) + return; +// updateSelectedTemplateKeyInfo(); +#ifdef DB_TEMPLATES + accept(); +#endif +} + +void KexiStartupDialog::updateSelectedTemplateKeyInfo() +{ + if (activePageIndex()!=d->pageTemplatesID) {//not a 'new db' tab is selected + d->selectedTemplateKey=QString::null; + return; + } + QIconViewItem *item; + if (d->templatesWidget->activePageIndex()==d->templatesSectionID_blank) { + d->selectedTemplateKey = "blank"; + } + else if (d->templatesWidget->activePageIndex()==d->templatesSectionID_import) { + d->selectedTemplateKey = "import"; + } +#ifdef DB_TEMPLATES + else if (d->templatesWidget->activePageIndex()==d->templatesSectionID_templates) { + item = d->viewTemplates->templates->currentItem(); + if (!item) { + d->selectedTemplateKey=QString::null; + return; + } + d->selectedTemplateKey=QString("personal/")+static_cast<TemplateItem*>(item)->key; + } +/*later? + else if (d->templatesWidget->activePageIndex()==d->templatesSectionID_custom2) { + item = d->viewBusinessTempl->templates->currentItem(); + if (!item) { + d->selectedTemplateKey=QString::null; + return; + } + d->selectedTemplateKey=QString("business/")+static_cast<TemplateItem*>(item)->key; + }*/ +#endif +} +#endif // 0 + +void KexiStartupDialog::tabShown(QWidget *w) +{ +// kdDebug() << "KexiStartupDialog::tabShown " << (long)w << " "<< long(d->pageTemplates)<<endl; + + updateDialogOKButton(w); + + if (w==d->pageOpenExisting) { + d->openExistingConnWidget->setFocus(); + } +} + +void KexiStartupDialog::updateDialogOKButton(QWidget *w) +{ + if (!w) { + int idx = activePageIndex(); + if (idx==d->pageTemplatesID) + w = d->pageTemplates; + else if (idx==d->pageOpenExistingID) + w = d->pageOpenExisting; + else if (idx==d->pageOpenRecentID) + w = d->pageOpenRecent; + + if (!w) + return; + } + bool enable = true; + if (w==d->pageTemplates) { + int t_id = d->templatesWidget->activePageIndex(); +#ifdef DB_TEMPLATES + enable = (t_id==d->templatesSectionID_blank || d->templatesSectionID_import + || (t_id==d->templatesSectionID_templates && !d->viewTemplates->selectedFileName().isEmpty())); +#else + enable = (t_id==d->templatesSectionID_blank || d->templatesSectionID_import); +#endif + } + else if (w==d->pageOpenExisting) { +// enable = !d->openExistingFileDlg->currentURL().path().isEmpty(); + enable = + (d->openExistingConnWidget->selectedConnectionType()==KexiConnSelectorWidget::FileBased) + ? !d->openExistingFileDlg->currentFileName().isEmpty() + : (bool)d->openExistingConnWidget->selectedConnectionData(); + } + else if (w==d->pageOpenRecent) { + enable = (d->prj_selector->selectedProjectData()!=0); + } + enableButton(Ok,enable); +} + +/*QString KexiStartupDialog::selectedTemplateKey() const +{ + return d->selectedTemplateKey; +}*/ + +void KexiStartupDialog::setupPageOpenExisting() +{ + if (d->singlePage) + d->pageOpenExisting = plainPage(); + else + d->pageOpenExisting = addPage( i18n("Open &Existing Project") ); + QVBoxLayout *lyr = new QVBoxLayout( d->pageOpenExisting, 0, KDialogBase::spacingHint() ); + + d->openExistingConnWidget = new KexiConnSelectorWidget(*d->connSet, + ":OpenExistingOrCreateNewProject", + d->pageOpenExisting, "KexiConnSelectorWidget"); + d->openExistingConnWidget->hideConnectonIcon(); + lyr->addWidget( d->openExistingConnWidget ); + if (KGlobal::config()->readEntry("OpenExistingType","File")=="File") + d->openExistingConnWidget->showSimpleConn(); + else { + d->openExistingConnWidget->showSimpleConn(); + d->openExistingConnWidget->showAdvancedConn(); + } + d->openExistingFileDlg = d->openExistingConnWidget->m_fileDlg; + connect(d->openExistingFileDlg,SIGNAL(accepted()),this,SLOT(accept())); + connect(d->openExistingConnWidget,SIGNAL(connectionItemExecuted(ConnectionDataLVItem*)), + this,SLOT(connectionItemForOpenExistingExecuted(ConnectionDataLVItem*))); + connect(d->openExistingConnWidget,SIGNAL(connectionItemHighlighted(ConnectionDataLVItem*)), + this,SLOT(connectionItemForOpenExistingHighlighted(ConnectionDataLVItem*))); +} + +void KexiStartupDialog::connectionItemForOpenExistingExecuted(ConnectionDataLVItem *item) +{ + if (!item) + return; + accept(); +} + +void KexiStartupDialog::connectionItemForOpenExistingHighlighted(ConnectionDataLVItem *item) +{ + actionButton(KDialogBase::Ok)->setEnabled(item); +} + +void KexiStartupDialog::slotOk() { +// kdDebug()<<"KexiStartupDialog::slotOk()"<<endl; + if (activePageIndex()==d->pageOpenExistingID) { + if (d->openExistingFileDlg) { + if (d->openExistingFileDlg->okButton()) + d->openExistingFileDlg->okButton()->animateClick(); +// return; + } + } + KDialogBase::slotOk(); +} + +void KexiStartupDialog::showSimpleConnForOpenExisting() +{ +// kdDebug() << "simple" << endl; + d->openExistingConnWidget->showSimpleConn(); +} + +void KexiStartupDialog::showAdvancedConnForOpenExisting() +{ +// kdDebug() << "adv" << endl; + d->openExistingConnWidget->showAdvancedConn(); +} + +QString KexiStartupDialog::selectedFileName() const +{ + if (d->result == OpenExistingResult) + return d->existingFileToOpen; + else if (d->result == CreateFromTemplateResult && d->viewTemplates) + return d->viewTemplates->selectedFileName(); + else + return QString::null; +} + +KexiDB::ConnectionData* KexiStartupDialog::selectedExistingConnection() const +{ + return d->selectedExistingConnection; +} + +void KexiStartupDialog::existingFileSelected(const QString &f) +{ + if (f.isEmpty()) + return; + d->existingFileToOpen=f; + updateDialogOKButton(d->openExistingFileDlg); +} + +void KexiStartupDialog::setupPageOpenRecent() +{ +#ifdef KEXI_STARTUP_SHOW_RECENT + d->pageOpenRecent = addPage( i18n("Open &Recent Project") ); + QVBoxLayout *lyr = new QVBoxLayout( d->pageOpenRecent, 0, KDialogBase::spacingHint() ); + lyr->addWidget( d->prj_selector = new KexiProjectSelectorWidget( + d->pageOpenRecent, "prj_selector", d->recentProjects ) ); + connect(d->prj_selector,SIGNAL(projectExecuted(KexiProjectData*)), + this,SLOT(recentProjectItemExecuted(KexiProjectData*))); +#endif +} + +KexiProjectData* KexiStartupDialog::selectedProjectData() const +{ + if (activePageIndex()==d->pageOpenRecentID) { + return d->prj_selector->selectedProjectData(); + } + return 0; +} + +void KexiStartupDialog::recentProjectItemExecuted(KexiProjectData *data) +{ + updateDialogOKButton(d->pageOpenRecent); + if (!data) + return; + accept(); +} + +//! used for accepting templates dialog with just return key press +bool KexiStartupDialog::eventFilter( QObject *o, QEvent *e ) +{ + if (o==d->templatesWidget_IconListBox && d->templatesWidget_IconListBox) { + if (e->type()==QEvent::KeyPress + && (static_cast<QKeyEvent*>(e)->key()==Key_Enter || static_cast<QKeyEvent*>(e)->key()==Key_Return) + || e->type()==QEvent::MouseButtonDblClick) + { + const int t_id = d->templatesWidget->activePageIndex(); + if (t_id==d->templatesSectionID_blank || t_id==d->templatesSectionID_import) { + + accept(); + } + } + } + return KDialogBase::eventFilter(o,e); +} + +// internal reimplementation +int KexiStartupDialog::activePageIndex() const +{ + if (!d->singlePage) { +// kdDebug() << "int KexiStartupDialog::activePageIndex()" << KDialogBase::activePageIndex() << endl; + return KDialogBase::activePageIndex(); + } + kdDebug() << "int KexiStartupDialog::activePageIndex() == " << 0 << endl; + return 0; //there is always "plain page" #0 selected +} + +void KexiStartupDialog::templateSelected(const QString& fileName) +{ + if (!fileName.isEmpty()) + accept(); +} + +QValueList<KexiProjectData::ObjectInfo> KexiStartupDialog::autoopenObjects() const +{ + if (d->result != CreateFromTemplateResult || !d->viewTemplates) + QValueList<KexiProjectData::ObjectInfo>(); + + return d->viewTemplates->autoopenObjectsForSelectedTemplate(); +} + +#include "KexiStartupDialog.moc" diff --git a/kexi/main/startup/KexiStartupDialog.h b/kexi/main/startup/KexiStartupDialog.h new file mode 100644 index 00000000..41f6064b --- /dev/null +++ b/kexi/main/startup/KexiStartupDialog.h @@ -0,0 +1,185 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 KexiStartupDialog_h +#define KexiStartupDialog_h + +#include <kdialogbase.h> +#include <kicondialog.h> +#include <kiconview.h> +#include <kfileiconview.h> +#include <kfiledialog.h> + +#include <qlabel.h> +#include <qsplitter.h> + +#include <kexidb/connectiondata.h> +#include <core/kexiprojectdata.h> + +class KexiStartupDialogPrivate; +class KexiProjectData; +class KexiProjectSet; +class KexiDBConnectionSet; +class ConnectionDataLVItem; + +/*! + This class is used to show the template/open-existing/open-recent tabbed dialog + on Kexi startup. If only one page is shown, tab is no displayed, so dialog + becomes a normal "plain" type dialog. + */ +class KEXIMAIN_EXPORT KexiStartupDialog : public KDialogBase +{ + Q_OBJECT + +public: + /*! The Dialog returns one of these values depending + on the input of the user. + CancelResult The user pressed 'Cancel' + CreateBlankResult The user selected a template + CreateFromTemplateResult The user selected a template + ImportResult The user selected a template + OpenExistingResult The user has chosen an existing connection or db file + OpenRecentResult The user selected one of recently used databases + */ + enum Result { + CancelResult, //!< The user has pressed 'Cancel' + CreateBlankResult, //!< The user has selected a template + CreateFromTemplateResult, //!< The user has selected a template to be used for creating a new db + ImportResult, //!< The user has chosen to import db + OpenExistingResult, //!< The user has chosen an existing connection or db file + OpenRecentResult //!< The user has selected one of recently used databases + }; + + /*! + To configure the dialog you have to use this enum + (any !=0 or'ed value is ok) + - Templates Show "Templates" tab + - OpenExisting Show "Open existing" tab + - OpenRecent Show "Recent" tab + - Everything Show everything above + */ + enum DialogType { Templates = 1, OpenExisting = 2, OpenRecent = 4, Everything = (1+2+4) }; + + /*! Options for a dialog + (any or'ed value or 0 is ok) + - CheckBoxDoNotShowAgain Adds "do not show this window" checkbox at the bottom + */ + enum DialogOptions { CheckBoxDoNotShowAgain = 1 }; + + /*! Creates a dialog. + @param dialogType see DialogType description + @param dialogOptions see dialogOptions description + @param recentProjects a set of recent projects' info, used for "Open recent" tab + @param connSet conenction set used to present available conenctions + in "Open Existing" tab. Pass an empty object is this tab is not used. + @param parent parent widget, if any. + @param name name of this object. + */ + KexiStartupDialog( + int dialogType, + int dialogOptions, + KexiDBConnectionSet& connSet, + KexiProjectSet& recentProjects, + QWidget *parent = 0, const char *name = 0 ); + ~KexiStartupDialog(); + + /*! \return true if startup dialog should be shown (info is taken from kexi config) + */ + static bool shouldBeShown(); + + /*! Executes dialog. + \return one of Result values. Use this after dialog is closed. */ + int result() const; + + /*! \return data of selected Kexi project (if "Open Recent" tab was selected). + Returns NULL if no selection has been made or other tab was selected. + */ + KexiProjectData* selectedProjectData() const; + + /*! \return name of selected Kexi project file + (if result() == OpenExistingResult) + or name of template file to be used for creating a new database. + (if result() == CreateFromTemplateResult). + Returns empty string if no such selection has been made or other tab was selected. + */ + QString selectedFileName() const; + + /*! \return "autoopen" objects defined for selected template. + Only makes sense if template was used. */ + QValueList<KexiProjectData::ObjectInfo> autoopenObjects() const; + + /*! \return a pointer to selected Kexi connection data. + (if "Open Existing" tab was selected and this connection data was clicked). + Returns NULL if no such selection has been made or other tab was selected. + */ + KexiDB::ConnectionData* selectedExistingConnection() const; + + /*! Reimplemented for internal reasons */ + virtual void show(); + +public slots: + +protected slots: + virtual void done(int r); + virtual void reject(); + virtual void slotOk(); + + //! slot activated when one of page in templates window is shown + void slotPageShown(QWidget *page); +/* + //! Any icon view item has been executed (dblclicked) + void templateItemExecuted(QIconViewItem *item); + + //! Any icon view item has been selected + void templateItemSelected(QIconViewItem *item);*/ + + //! Any tab has been selected + void tabShown(QWidget *w); + + void templateSelected(const QString& fileName); + + //! helper + void recentProjectItemExecuted(KexiProjectData *data); + void existingFileSelected(const QString &f); + void showSimpleConnForOpenExisting(); + void showAdvancedConnForOpenExisting(); + void connectionItemForOpenExistingExecuted(ConnectionDataLVItem *item); + void connectionItemForOpenExistingHighlighted(ConnectionDataLVItem *item); + +protected: + virtual bool eventFilter( QObject *o, QEvent *e ); + + //! helper: updates a state of dialog's OK button + void updateDialogOKButton(QWidget *w); + + //! internal reimplementation + int activePageIndex() const; +private: + void setupPageTemplates(); + void setupPageOpenExisting(); + void setupPageOpenRecent(); + + //! used internally on accepting templates selection +// void updateSelectedTemplateKeyInfo(); + + KexiStartupDialogPrivate *d; +}; + +#endif + diff --git a/kexi/main/startup/KexiStartupDialogTemplatesPage.cpp b/kexi/main/startup/KexiStartupDialogTemplatesPage.cpp new file mode 100644 index 00000000..3a64fbac --- /dev/null +++ b/kexi/main/startup/KexiStartupDialogTemplatesPage.cpp @@ -0,0 +1,157 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl> + + 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 "KexiStartupDialogTemplatesPage.h" + +#include <core/kexi.h> +#include <core/kexitemplateloader.h> +#include "KexiProjectSelector.h" +#include "KexiOpenExistingFile.h" +#include "KexiConnSelector.h" +#include "KexiConnSelectorBase.h" + +#include <qheader.h> + +#include <kdebug.h> +#include <kiconloader.h> + +#ifdef KEXI_SHOW_UNIMPLEMENTED +#define KEXI_STARTUP_SHOW_TEMPLATES +#define KEXI_STARTUP_SHOW_RECENT +#endif + +/*QPixmap createIcon() +{ + +}*/ + +/*QString createText(const QString& name, const QString& description) +{ + QString txt = "<H2>" + name + "</H2>"; + if (description.isEmpty()) + return name + description +}*/ + +//! @internal +class TemplateItem : public KListViewItem +{ + public: + TemplateItem(QListView* parent, const QString& aFilename, + const QString& name, const QString& description, const QPixmap& icon, + const QValueList<KexiProjectData::ObjectInfo>& aAutoopenObjects) + : KListViewItem(parent, name + "\n" + description) + , autoopenObjects(aAutoopenObjects) + , filename(aFilename) + { + setPixmap(0, icon); + } + ~TemplateItem() {} + + QValueList<KexiProjectData::ObjectInfo> autoopenObjects; + QString filename; +}; + +//----------------------- + +KexiStartupDialogTemplatesPage::KexiStartupDialogTemplatesPage( QWidget * parent ) + : KListView(parent, "KexiStartupDialogTemplatesPage") + , m_popuplated(false) +{ + addColumn(QString::null); + header()->hide(); + setColumnWidthMode(0, Maximum); + setResizeMode(LastColumn); + setItemMargin(6); + connect(this,SIGNAL(executed(QListViewItem*)), this, SLOT(slotExecuted(QListViewItem*))); +} + +KexiStartupDialogTemplatesPage::~KexiStartupDialogTemplatesPage() +{ +} + +void KexiStartupDialogTemplatesPage::populate() +{ + if (m_popuplated) + return; + m_popuplated = true; + KexiTemplateInfo::List list = KexiTemplateLoader::loadListInfo(); + foreach( QValueList<KexiTemplateInfo>::ConstIterator, it, list ) { + new TemplateItem(this, (*it).filename, (*it).name, + (*it).description, (*it).icon, (*it).autoopenObjects); + } + if (firstChild()) + setSelected(firstChild(), true); + +// templates = new KIconView(this, "templates"); +// templates->setItemsMovable(false); +// templates->setShowToolTips(false); +// info = new KTextBrowser(this,"info"); +// setResizeMode(templates,KeepSize); +// setResizeMode(info,KeepSize); +// connect(templates,SIGNAL(selectionChanged(QIconViewItem*)),this,SLOT(itemClicked(QIconViewItem*))); +} + +/* +void TemplatesPage::addItem(const QString& key, const QString& name, + const QString& description, const QPixmap& icon) +{ + TemplateItem *item = new TemplateItem(templates, name, icon); + item->key=key; + item->name=name; + item->description=description; +} + +void TemplatesPage::itemClicked(QIconViewItem *item) { + if (!item) { + info->setText(""); + return; + } + QString t = QString("<h2>%1</h2><p>%2</p>") + .arg(static_cast<TemplateItem*>(item)->name) + .arg(static_cast<TemplateItem*>(item)->description); +#ifndef DB_TEMPLATES + t += QString("<p>") + i18n("We are sorry, templates are not yet available.") +"</p>"; +#endif + + info->setText( t ); +}*/ + +QString KexiStartupDialogTemplatesPage::selectedFileName() const +{ + TemplateItem* templateItem = static_cast<TemplateItem*>(selectedItem()); + return templateItem ? templateItem->filename : QString::null; +} + +QValueList<KexiProjectData::ObjectInfo> +KexiStartupDialogTemplatesPage::autoopenObjectsForSelectedTemplate() const +{ + TemplateItem* templateItem = static_cast<TemplateItem*>(selectedItem()); + return templateItem ? templateItem->autoopenObjects : QValueList<KexiProjectData::ObjectInfo>(); +} + +void KexiStartupDialogTemplatesPage::slotExecuted(QListViewItem* item) +{ + TemplateItem* templateItem = static_cast<TemplateItem*>(item); + if (!templateItem) + return; + + emit selected(templateItem->filename); +} + +#include "KexiStartupDialogTemplatesPage.moc" diff --git a/kexi/main/startup/KexiStartupDialogTemplatesPage.h b/kexi/main/startup/KexiStartupDialogTemplatesPage.h new file mode 100644 index 00000000..8613065f --- /dev/null +++ b/kexi/main/startup/KexiStartupDialogTemplatesPage.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl> + + 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 KexiStartupDialogTemplatesPage_h +#define KexiStartupDialogTemplatesPage_h + +#include <klistview.h> +#include <core/kexiprojectdata.h> + +/*! Helper class for displaying templates set with description. */ +class KEXIMAIN_EXPORT KexiStartupDialogTemplatesPage : public KListView +{ + Q_OBJECT + + public: + KexiStartupDialogTemplatesPage( QWidget * parent = 0 ); + ~KexiStartupDialogTemplatesPage(); +// void addItem(const QString& key, const QString& name, +// const QString& description, const QPixmap& icon); + + QString selectedFileName() const; + + QValueList<KexiProjectData::ObjectInfo> autoopenObjectsForSelectedTemplate() const; + + void populate(); + + signals: + void selected(const QString& filename); + + protected slots: + void slotExecuted(QListViewItem* item); + +// void itemClicked(QIconViewItem *item); + + private: + bool m_popuplated : 1; +// KIconView *templates; +// KTextBrowser *info; +}; + +#endif diff --git a/kexi/main/startup/KexiStartupFileDialog.cpp b/kexi/main/startup/KexiStartupFileDialog.cpp new file mode 100644 index 00000000..d2869925 --- /dev/null +++ b/kexi/main/startup/KexiStartupFileDialog.cpp @@ -0,0 +1,422 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl> + + 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 "KexiStartupFileDialog.h" + +#include <kexidb/driver.h> +#include <core/kexi.h> +#include <kexiutils/utils.h> + +#include <qlayout.h> +#include <qobjectlist.h> +#include <qpushbutton.h> +#include <qapplication.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmimetype.h> +#include <kfile.h> +#include <kurlcombobox.h> + +KexiStartupFileDialog::KexiStartupFileDialog( + const QString& startDirOrVariable, int mode, + QWidget *parent, const char *name) + : KexiStartupFileDialogBase(startDirOrVariable, "", parent, name, 0) + , m_confirmOverwrites(true) + , m_filtersUpdated(false) +{ + setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); + setMode( mode ); + + QPoint point( 0, 0 ); + reparent( parentWidget(), point ); + + if (layout()) + layout()->setMargin(0); + setMinimumHeight(100); + setSizeGripEnabled ( false ); + + //dirty hack to customize filedialog view: + { + QObjectList *l = queryList( "QPushButton" ); + QObjectListIt it( *l ); + QObject *obj; + while ( (obj = it.current()) != 0 ) { + ++it; + static_cast<QPushButton*>(obj)->hide(); + } + delete l; + } + { + QObjectList *l = queryList("QWidget"); + QObjectListIt it( *l ); + QObject *obj; + while ( (obj = it.current()) != 0 ) { + ++it; + static_cast<QWidget*>(obj)->installEventFilter(this); + } + delete l; + } + +#ifdef Q_WS_WIN + if (startDirOrVariable.startsWith(":")) + m_lastVisitedPathsVariable = startDirOrVariable; //store for later use +#else + toggleSpeedbar(false); + setFocusProxy( locationEdit );//locationWidget() ); +#endif +} + +KexiStartupFileDialog::~KexiStartupFileDialog() +{ +#ifdef Q_WS_WIN + saveLastVisitedPath(currentFileName()); +#endif +} + +void KexiStartupFileDialog::setMode(int mode) +{ + //delayed + m_mode = mode; + m_filtersUpdated = false; +} + +QStringList KexiStartupFileDialog::additionalFilters() const +{ + return m_additionalMimeTypes; +} + +void KexiStartupFileDialog::setAdditionalFilters(const QStringList &mimeTypes) +{ + //delayed + m_additionalMimeTypes = mimeTypes; + m_filtersUpdated = false; +} + +QStringList KexiStartupFileDialog::excludedFilters() const +{ + return m_excludedMimeTypes; +} + +void KexiStartupFileDialog::setExcludedFilters(const QStringList &mimeTypes) +{ + //delayed + m_excludedMimeTypes = mimeTypes; + m_filtersUpdated = false; +} + +void KexiStartupFileDialog::updateFilters() +{ + if (m_filtersUpdated) + return; + m_filtersUpdated = true; + + m_lastFileName = QString::null; +// m_lastUrl = KURL(); + + clearFilter(); + + QString filter; + KMimeType::Ptr mime; + QStringList allfilters; + + const bool normalOpeningMode = m_mode & Opening && !(m_mode & Custom); + const bool normalSavingMode = m_mode & SavingFileBasedDB && !(m_mode & Custom); + + if (normalOpeningMode || normalSavingMode) { + mime = KMimeType::mimeType( KexiDB::Driver::defaultFileBasedDriverMimeType() ); + if (mime && m_excludedMimeTypes.find(mime->name())==m_excludedMimeTypes.end()) { + filter += KexiUtils::fileDialogFilterString(mime); + allfilters += mime->patterns(); + } + } + if (normalOpeningMode || m_mode & SavingServerBasedDB) { + mime = KMimeType::mimeType("application/x-kexiproject-shortcut"); + if (mime && m_excludedMimeTypes.find(mime->name())==m_excludedMimeTypes.end()) { + filter += KexiUtils::fileDialogFilterString(mime); + allfilters += mime->patterns(); + } + } + if (normalOpeningMode || m_mode & SavingServerBasedDB) { + mime = KMimeType::mimeType("application/x-kexi-connectiondata"); + if (mime && m_excludedMimeTypes.find(mime->name())==m_excludedMimeTypes.end()) { + filter += KexiUtils::fileDialogFilterString(mime); + allfilters += mime->patterns(); + } + } + +//! @todo hardcoded for MSA: + if (normalOpeningMode) { + mime = KMimeType::mimeType("application/x-msaccess"); + if (mime && m_excludedMimeTypes.find(mime->name())==m_excludedMimeTypes.end()) { + filter += KexiUtils::fileDialogFilterString(mime); + allfilters += mime->patterns(); + } + } + + foreach (QStringList::ConstIterator, it, m_additionalMimeTypes) { + if (*it == "all/allfiles") + continue; + if (m_excludedMimeTypes.find(*it)!=m_excludedMimeTypes.end()) + continue; + filter += KexiUtils::fileDialogFilterString(*it); + mime = KMimeType::mimeType(*it); + allfilters += mime->patterns(); + } + + if (m_excludedMimeTypes.find("all/allfiles")==m_excludedMimeTypes.end()) + filter += KexiUtils::fileDialogFilterString("all/allfiles"); +// mime = KMimeType::mimeType("all/allfiles"); +// if (mime) { +// filter += QString(mime->patterns().isEmpty() ? "*" : mime->patterns().join(" ")) +// + "|" + mime->comment()+ " (*)\n"; +// } + //remove duplicates made because upper- and lower-case extenstions are used: + QStringList allfiltersUnique; + QDict<char> uniqueDict(499, false); + foreach (QStringList::ConstIterator, it, allfilters) { +// kdDebug() << *it << endl; + uniqueDict.insert(*it, (char*)1); + } + foreach_dict (QDictIterator<char>, it, uniqueDict) { + allfiltersUnique += it.currentKey(); + } + allfiltersUnique.sort(); + + if (allfiltersUnique.count()>1) {//prepend "all supoported files" entry + filter.prepend(allfilters.join(" ")+"|" + i18n("All Supported Files") + +" ("+allfiltersUnique.join(" ")+")\n"); + } + + if (filter.right(1)=="\n") + filter.truncate(filter.length()-1); + setFilter(filter); + + if (m_mode & Opening) { + KexiStartupFileDialogBase::setMode( KFile::ExistingOnly | KFile::LocalOnly | KFile::File ); + setOperationMode( KFileDialog::Opening ); + } else { + KexiStartupFileDialogBase::setMode( KFile::LocalOnly | KFile::File ); + setOperationMode( KFileDialog::Saving ); + } +} + +void KexiStartupFileDialog::show() +{ + m_filtersUpdated = false; + updateFilters(); + KexiStartupFileDialogBase::show(); +} + +//KURL KexiStartupFileDialog::currentURL() +QString KexiStartupFileDialog::currentFileName() +{ + setResult( QDialog::Accepted ); // selectedURL tests for it + +#ifdef Q_WS_WIN +// QString path = selectedFile(); + //js @todo +// kdDebug() << "selectedFile() == " << path << " '" << url().fileName() << "' " << m_lineEdit->text() << endl; + QString path = dir()->absPath(); + if (!path.endsWith("/") && !path.endsWith("\\")) + path.append("/"); + path += m_lineEdit->text(); +// QString path = QFileInfo(selectedFile()).dirPath(true) + "/" + m_lineEdit->text(); +#else +// QString path = locationEdit->currentText().stripWhiteSpace(); //url.path().stripWhiteSpace(); that does not work, if the full path is not in the location edit !!!!! + QString path=KexiStartupFileDialogBase::selectedURL().path(); + kdDebug() << "prev selectedURL() == " << path <<endl; + kdDebug() << "locationEdit == " << locationEdit->currentText().stripWhiteSpace() <<endl; + //make sure user-entered path is acceped: + setSelection( locationEdit->currentText().stripWhiteSpace() ); + + path=KexiStartupFileDialogBase::selectedURL().path(); + kdDebug() << "selectedURL() == " << path <<endl; + +#endif + + if (!currentFilter().isEmpty()) { + if (m_mode & SavingFileBasedDB) { + QStringList filters = QStringList::split(" ", currentFilter()); //.first().stripWhiteSpace(); + kdDebug()<< " filter == " << filters << endl; + QString ext = QFileInfo(path).extension(false); + bool hasExtension = false; + for (QStringList::ConstIterator filterIt = filters.constBegin(); + filterIt != filters.constEnd() && !hasExtension; ++filterIt) + { + QString f( (*filterIt).stripWhiteSpace() ); + hasExtension = !f.mid(2).isEmpty() && ext==f.mid(2); + } + if (!hasExtension) { + //no extension: add one + QString defaultExtension( m_defaultExtension ); + if (defaultExtension.isEmpty()) + defaultExtension = filters.first().stripWhiteSpace().mid(2); //first one + path+=(QString(".")+defaultExtension); + kdDebug() << "KexiStartupFileDialog::checkURL(): append extension, " << path << endl; + setSelection( path ); + } + } + } + kdDebug() << "KexiStartupFileDialog::currentFileName() == " << path <<endl; + return path; +// return KFileDialog::selectedURL(); +} + +//bool KexiStartupFileDialog::checkURL() +bool KexiStartupFileDialog::checkFileName() +{ +// KURL url = currentURL(); +// QString path = url.path().stripWhiteSpace(); + QString path = currentFileName().stripWhiteSpace(); + +// if (url.fileName().stripWhiteSpace().isEmpty()) { + if (path.isEmpty()) { + KMessageBox::error( this, i18n( "Enter a filename." )); + return false; + } + + kdDebug() << "KexiStartupFileDialog::checkURL() path: " << path << endl; +// kdDebug() << "KexiStartupFileDialog::checkURL() fname: " << url.fileName() << endl; +//todo if ( url.isLocalFile() ) { + QFileInfo fi(path); + if (mode() & KFile::ExistingOnly) { + if ( !fi.exists() ) { + KMessageBox::error( this, "<qt>"+i18n( "The file \"%1\" does not exist." ) + .arg( QDir::convertSeparators(path) ) ); + return false; + } + else if (mode() & KFile::File) { + if (!fi.isFile()) { + KMessageBox::error( this, "<qt>"+i18n( "Enter a filename." ) ); + return false; + } + else if (!fi.isReadable()) { + KMessageBox::error( this, "<qt>"+i18n( "The file \"%1\" is not readable." ) + .arg( QDir::convertSeparators(path) ) ); + return false; + } + } + } + else if (m_confirmOverwrites && !askForOverwriting( path, this )) { + return false; + } +// } + return true; +} + +//static +bool KexiStartupFileDialog::askForOverwriting(const QString& filePath, QWidget *parent) +{ + QFileInfo fi(filePath); + if (!fi.exists()) + return true; + const int res = KMessageBox::warningYesNo( parent, i18n( "The file \"%1\" already exists.\n" + "Do you want to overwrite it?").arg( QDir::convertSeparators(filePath) ), QString::null, + i18n("Overwrite"), KStdGuiItem::no() ); + if (res == KMessageBox::Yes) + return true; + return false; +} + +void KexiStartupFileDialog::accept() +{ +// locationEdit->setFocus(); +// QKeyEvent ev(QEvent::KeyPress, Qt::Key_Enter, '\n', 0); +// QApplication::sendEvent(locationEdit, &ev); +// QApplication::postEvent(locationEdit, &ev); + +// kdDebug() << "KexiStartupFileDialog::accept() m_lastUrl == " << m_lastUrl.path() << endl; +// if (m_lastUrl.path()==currentURL().path()) {//(js) to prevent more multiple kjob signals (I do not know why this is) + if (m_lastFileName==currentFileName()) {//(js) to prevent more multiple kjob signals (I do not know why this is) +// m_lastUrl=KURL(); + m_lastFileName=QString::null; + kdDebug() << "m_lastFileName==currentFileName()" << endl; +#ifdef Q_WS_WIN + return; +#endif + } +// kdDebug() << "KexiStartupFileDialog::accept(): url = " << currentURL().path() << " " << endl; + kdDebug() << "KexiStartupFileDialog::accept(): path = " << currentFileName() << endl; +// if ( checkURL() ) { + if ( checkFileName() ) { + emit accepted(); + } +// else { +// m_lastUrl = KURL(); +// } +// m_lastUrl = currentURL(); + m_lastFileName = currentFileName(); + +#ifdef Q_WS_WIN + saveLastVisitedPath(m_lastFileName); +#endif +} + +void KexiStartupFileDialog::reject() +{ + kdDebug() << "KexiStartupFileDialog: reject!" << endl; + emit rejected(); +} + +/*#ifndef Q_WS_WIN +KURLComboBox *KexiStartupFileDialog::locationWidget() const +{ + return locationEdit; +} +#endif +*/ + +void KexiStartupFileDialog::setLocationText(const QString& fn) +{ +#ifdef Q_WS_WIN + //js @todo + setSelection(fn); +#else + setSelection(fn); +// locationEdit->setCurrentText(fn); +// locationEdit->lineEdit()->setEdited( true ); +// setSelection(fn); +#endif +} + +void KexiStartupFileDialog::setFocus() +{ +#ifdef Q_WS_WIN + m_lineEdit->setFocus(); +#else + locationEdit->setFocus(); +#endif +} + +bool KexiStartupFileDialog::eventFilter ( QObject * watched, QEvent * e ) +{ + //filter-out ESC key + if (e->type()==QEvent::KeyPress && static_cast<QKeyEvent*>(e)->key()==Qt::Key_Escape + && static_cast<QKeyEvent*>(e)->state()==Qt::NoButton) { + static_cast<QKeyEvent*>(e)->accept(); + emit rejected(); + return true; + } + return KexiStartupFileDialogBase::eventFilter(watched,e); +} + +#include "KexiStartupFileDialog.moc" + diff --git a/kexi/main/startup/KexiStartupFileDialog.h b/kexi/main/startup/KexiStartupFileDialog.h new file mode 100644 index 00000000..87ebf7f4 --- /dev/null +++ b/kexi/main/startup/KexiStartupFileDialog.h @@ -0,0 +1,132 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl> + + 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 _KexiStartupFileDialog_h_ +#define _KexiStartupFileDialog_h_ + +#include <kfiledialog.h> + +#ifdef Q_WS_WIN +# include "KexiStartupFileDialogBase_win.h" +#else + typedef KFileDialog KexiStartupFileDialogBase; +#endif + + +//! @short Widget for opening/saving files supported by Kexi +class KEXIMAIN_EXPORT KexiStartupFileDialog : public KexiStartupFileDialogBase +{ + Q_OBJECT + +public: + /*! Dialog mode: + - Opening opens existing database (or shortcut) + - SavingFileBasedDB saves file-based database file + - SavingServerBasedDB saves server-based (shortcut) file + - CustomOpening can be used for opening other files, like CSV + */ + typedef enum Mode { + Opening = 1, + SavingFileBasedDB = 2, + SavingServerBasedDB = 4, + Custom = 256 + }; + + KexiStartupFileDialog( + const QString& startDirOrVariable, int mode, QWidget *parent=0, const char *name=0); + + virtual ~KexiStartupFileDialog(); + + /*! Helper. Displays "The file %1 already exists. Do you want to overwrite it?" yes/no message box. + \a parent is used as a parent of the KMessageBox. + \return true if \a filePath file does not exists or user has agreed on overwriting, + false in user do not want to overwrite. */ + static bool askForOverwriting(const QString& filePath, QWidget *parent = 0); + + void setMode(int mode); + + QStringList additionalFilters() const; + + //! Sets additional filters list, e.g. "text/x-csv" + void setAdditionalFilters(const QStringList &mimeTypes); + + QStringList excludedFilters() const; + + //! Excludes filters list + void setExcludedFilters(const QStringList &mimeTypes); + +// KURL currentURL(); + QString currentFileName(); + +//#ifndef Q_WS_WIN +// KURLComboBox *locationWidget() const; +//#endif + //! just sets locationWidget()->setCurrentText(fn) + //! (and something similar on win32) + void setLocationText(const QString& fn); + + //! Sets default extension which will be added after accepting + //! if user didn't provided one. This method is usable when there is + //! more than one filter so there is no rule what extension should be selected + //! (by default first one is selected). + void setDefaultExtension(const QString& ext) { m_defaultExtension = ext; } + + /*! \return true if the current URL meets requies constraints + (i.e. exists or doesn't exist); + shows appropriate message box if needed. */ + bool checkFileName(); +// bool checkURL(); + + /*! If true, user will be asked to accept overwriting existing file. + This is true by default. */ + void setConfirmOverwrites(bool set) { m_confirmOverwrites = set; } + + virtual bool eventFilter ( QObject * watched, QEvent * e ); + +public slots: + virtual void show(); + + virtual void setFocus(); + + // Typing a file that doesn't exist closes the file dialog, we have to + // handle this case better here. + virtual void accept(); + +signals: + //entered file name is accepted + void accepted(); + void rejected(); + +protected slots: + virtual void reject(); + +private: + void updateFilters(); + +// KURL m_lastUrl; + QString m_lastFileName; + int m_mode; + QStringList m_additionalMimeTypes, m_excludedMimeTypes; + QString m_defaultExtension; + bool m_confirmOverwrites : 1; + bool m_filtersUpdated : 1; +}; + +#endif + diff --git a/kexi/main/startup/KexiStartupFileDialogBase_win.h b/kexi/main/startup/KexiStartupFileDialogBase_win.h new file mode 100644 index 00000000..7d7f56e0 --- /dev/null +++ b/kexi/main/startup/KexiStartupFileDialogBase_win.h @@ -0,0 +1,67 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl> + + 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 _KexiStartupFileDialogBase_win_h_ +#define _KexiStartupFileDialogBase_win_h_ + +#include <qfiledialog.h> +#include <qpushbutton.h> + +class KexiStartupFileDialogBasePrivate; + +/*! Wrapper for win32-like file dialog. QFileDialog is used for this. + Temporary moved from QKW KFileDialog implementation. + TODO: move to KDElibs/win32 KFileDialog wrapper +*/ +class KexiStartupFileDialogBase : public QFileDialog +{ +public: + KexiStartupFileDialogBase(const QString & dirName, const QString & filter = QString::null, + QWidget * parent = 0, const char * name = 0, bool modal = false ); + ~KexiStartupFileDialogBase(); + + QPushButton * okButton() const { return m_okBtn; } + + void clearFilter(); + void setFilter(const QString& filter); + void setOperationMode( KFileDialog::OperationMode mode ); + void setMode( KFile::Mode m ); + void setMode( unsigned int m ); + QString currentFilter() const; + void setMimeFilter( const QStringList& mimeTypes, const QString& defaultType = QString::null ); + + KFile::Mode mode() const; + +protected: + void init(const QString& startDir, const QString& filter, QWidget* widget); + void updateAutoSelectExtension() {}; + + //! Helper added because QFileDialog on win32 doesn't support ":" prefixes + //! for recent dir's storage. + QString realStartDir(const QString& startDir); + + void saveLastVisitedPath(const QString& path); + + QPushButton* m_okBtn; + QLineEdit* m_lineEdit; + QString m_lastVisitedPathsVariable; //!< Used by win32; @see realStartDir() + KexiStartupFileDialogBasePrivate* d; +}; + +#endif diff --git a/kexi/main/startup/KexiStartupFileDialog_win.cpp b/kexi/main/startup/KexiStartupFileDialog_win.cpp new file mode 100644 index 00000000..aa06fb9a --- /dev/null +++ b/kexi/main/startup/KexiStartupFileDialog_win.cpp @@ -0,0 +1,476 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl> + + 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. +*/ + +/*! + Temporary moved from QKW KFileDialog implementation. + TODO: move to KDElibs/win32 KFileDialog wrapper +*/ + +#include "KexiStartupFileDialog.h" +#include <kexiutils/utils.h> + +#include <kiconloader.h> +#include <kdebug.h> +#include <krecentdirs.h> + +#include <qobjectlist.h> +#include <qlineedit.h> + +#include <win/win32_utils.h> + +//! @internal +class KexiStartupFileDialogBasePrivate +{ + public: + KexiStartupFileDialogBasePrivate() + {} + KFile::Mode mode; + QString kde_filters; + QStringList mimetypes; +}; + +KexiStartupFileDialogBase::KexiStartupFileDialogBase( + const QString & dirName, const QString & filter, + QWidget * parent, const char * name, bool modal ) + : QFileDialog( realStartDir(dirName), filter, parent, name, modal ) + , d(new KexiStartupFileDialogBasePrivate()) +{ +// QString _dirName = dirName; + QString _dirName = dirPath(); + //make default 'My Documents' folder +//TODO: store changes in the app's config file? + if (_dirName.isEmpty()) + _dirName = KGlobalSettings::documentPath(); + + init(_dirName, filter, parent); + + //find "OK" button + QObjectList *l = queryList( "QPushButton", "OK", false ); + m_okBtn = dynamic_cast<QPushButton*>(l->first()); + delete l; + l = queryList( "QLineEdit", "name/filter editor", false ); + m_lineEdit = dynamic_cast<QLineEdit*>(l->first()); + delete l; + + adjustSize(); +} + +KexiStartupFileDialogBase::~KexiStartupFileDialogBase() +{ +} + +void KexiStartupFileDialogBase::init(const QString& startDir, const QString& filter, QWidget* widget) +{ +//TODO initStatic(); +//TODO d = new KFileDialogPrivate(); + +//(js) d->boxLayout = 0; +//TODO d->keepLocation = false; +//TODO d->operationMode = Opening; + setMode(KFile::File | KFile::ExistingOnly); //(js) default: open action + setIcon( KGlobal::iconLoader()->loadIcon("fileopen", KIcon::Desktop) ); + setDir(QDir(startDir)); +//TODO d->hasDefaultFilter = false; +//TODO d->hasView = false; +//(js) d->mainWidget = new QWidget( this, "KFileDialog::mainWidget"); +//(js) setMainWidget( d->mainWidget ); +//(js) d->okButton = new KPushButton( KStdGuiItem::ok(), d->mainWidget ); +//(js) d->okButton->setDefault( true ); +//(js) d->cancelButton = new KPushButton(KStdGuiItem::cancel(), d->mainWidget); +//(js) connect( d->okButton, SIGNAL( clicked() ), SLOT( slotOk() )); +//(js) connect( d->cancelButton, SIGNAL( clicked() ), SLOT( slotCancel() )); +//(js) d->customWidget = widget; +//(js) d->autoSelectExtCheckBox = 0; // delayed loading +//TODO d->autoSelectExtChecked = false; +//(js) d->urlBar = 0; // delayed loading +//TODO KConfig *config = KGlobal::config(); +//TODO KConfigGroupSaver cs( config, ConfigGroup ); +//TODO d->initializeSpeedbar = config->readBoolEntry( "Set speedbar defaults", +//TODO true ); +//TODO d->completionLock = false; + +//TODO QtMsgHandler oldHandler = qInstallMsgHandler( silenceQToolBar ); +//TODO toolbar = 0; //(js) +//(js) toolbar = new KToolBar( d->mainWidget, "KFileDialog::toolbar", true); +//(js) toolbar->setFlat(true); +//TODO qInstallMsgHandler( oldHandler ); + +//(js) d->pathCombo = new KURLComboBox( KURLComboBox::Directories, true, +//(js) toolbar, "path combo" ); +//(js) QToolTip::add( d->pathCombo, i18n("Often used directories") ); +//(js) QWhatsThis::add( d->pathCombo, "<qt>" + i18n("Commonly used locations are listed here. " +//(js) "This includes standard locations, such as your home directory, as well as " +//(js) "locations that have been visited recently.") + autocompletionWhatsThisText); +/* + KURL u; + u.setPath( QDir::rootDirPath() ); + QString text = i18n("Root Directory: %1").arg( u.path() ); + d->pathCombo->addDefaultURL( u, + KMimeType::pixmapForURL( u, 0, KIcon::Small ), + text ); + + u.setPath( QDir::homeDirPath() ); + text = i18n("Home Directory: %1").arg( u.path( +1 ) ); + d->pathCombo->addDefaultURL( u, KMimeType::pixmapForURL( u, 0, KIcon::Small ), + text ); + + KURL docPath; + docPath.setPath( KGlobalSettings::documentPath() ); + if ( u.path(+1) != docPath.path(+1) ) { + text = i18n("Documents: %1").arg( docPath.path( +1 ) ); + d->pathCombo->addDefaultURL( u, + KMimeType::pixmapForURL( u, 0, KIcon::Small ), + text ); + } + + u.setPath( KGlobalSettings::desktopPath() ); + text = i18n("Desktop: %1").arg( u.path( +1 ) ); + d->pathCombo->addDefaultURL( u, + KMimeType::pixmapForURL( u, 0, KIcon::Small ), + text ); + + u.setPath( "/tmp" ); + + d->url = getStartURL( startDir, d->fileClass ); + d->selection = d->url.url(); + + // If local, check it exists. If not, go up until it exists. + if ( d->url.isLocalFile() ) + { + if ( !QFile::exists( d->url.path() ) ) + { + d->url = d->url.upURL(); + QDir dir( d->url.path() ); + while ( !dir.exists() ) + { + d->url = d->url.upURL(); + dir.setPath( d->url.path() ); + } + } + } + + ops = new KDirOperator(d->url, d->mainWidget, "KFileDialog::ops"); + ops->setOnlyDoubleClickSelectsFiles( true ); + connect(ops, SIGNAL(urlEntered(const KURL&)), + SLOT(urlEntered(const KURL&))); + connect(ops, SIGNAL(fileHighlighted(const KFileItem *)), + SLOT(fileHighlighted(const KFileItem *))); + connect(ops, SIGNAL(fileSelected(const KFileItem *)), + SLOT(fileSelected(const KFileItem *))); + connect(ops, SIGNAL(finishedLoading()), + SLOT(slotLoadingFinished())); + + ops->setupMenu(KDirOperator::SortActions | + KDirOperator::FileActions | + KDirOperator::ViewActions); + KActionCollection *coll = ops->actionCollection(); + + // plug nav items into the toolbar + coll->action( "up" )->plug( toolbar ); + coll->action( "up" )->setWhatsThis(i18n("<qt>Click this button to enter the parent directory.<p>" + "For instance, if the current location is file:/home/%1 clicking this " + "button will take you to file:/home.</qt>").arg(getlogin())); + coll->action( "back" )->plug( toolbar ); + coll->action( "back" )->setWhatsThis(i18n("Click this button to move backwards one step in the browsing history.")); + coll->action( "forward" )->plug( toolbar ); + coll->action( "forward" )->setWhatsThis(i18n("Click this button to move forward one step in the browsing history.")); + coll->action( "reload" )->plug( toolbar ); + coll->action( "reload" )->setWhatsThis(i18n("Click this button to reload the contents of the current location.")); + coll->action( "mkdir" )->setShortcut(Key_F10); + coll->action( "mkdir" )->plug( toolbar ); + coll->action( "mkdir" )->setWhatsThis(i18n("Click this button to create a new directory.")); + + d->bookmarkHandler = new KFileBookmarkHandler( this ); + toolbar->insertButton(QString::fromLatin1("bookmark"), + (int)HOTLIST_BUTTON, true, + i18n("Bookmarks")); + toolbar->getButton(HOTLIST_BUTTON)->setPopup( d->bookmarkHandler->menu(), + true); + QWhatsThis::add(toolbar->getButton(HOTLIST_BUTTON), + i18n("<qt>This button allows you to bookmark specific locations. " + "Click on this button to open the bookmark menu where you may add, " + "edit or select a bookmark.<p>" + "These bookmarks are specific to the file dialog, but otherwise operate " + "like bookmarks elsewhere in KDE.</qt>")); + connect( d->bookmarkHandler, SIGNAL( openURL( const QString& )), + SLOT( enterURL( const QString& ))); + + KToggleAction *showSidebarAction = + new KToggleAction(i18n("Show Quick Access Navigation Panel"), Key_F9, coll,"toggleSpeedbar"); + connect( showSidebarAction, SIGNAL( toggled( bool ) ), + SLOT( toggleSpeedbar( bool )) ); + + KActionMenu *menu = new KActionMenu( i18n("Configure"), "configure", this, "extra menu" ); + menu->setWhatsThis(i18n("<qt>This is the configuration menu for the file dialog. " + "Various options can be accessed from this menu including: <ul>" + "<li>how files are sorted in the list</li>" + "<li>types of view, including icon and list</li>" + "<li>showing of hidden files</li>" + "<li>the Quick Access navigation panel</li>" + "<li>file previews</li>" + "<li>separating directories from files</li></ul></qt>")); + menu->insert( coll->action( "sorting menu" )); + menu->insert( coll->action( "separator" )); + coll->action( "short view" )->setShortcut(Key_F6); + menu->insert( coll->action( "short view" )); + coll->action( "detailed view" )->setShortcut(Key_F7); + menu->insert( coll->action( "detailed view" )); + menu->insert( coll->action( "separator" )); + coll->action( "show hidden" )->setShortcut(Key_F8); + menu->insert( coll->action( "show hidden" )); + menu->insert( showSidebarAction ); + coll->action( "preview" )->setShortcut(Key_F11); + menu->insert( coll->action( "preview" )); + coll->action( "separate dirs" )->setShortcut(Key_F12); + menu->insert( coll->action( "separate dirs" )); + + menu->setDelayed( false ); + connect( menu->popupMenu(), SIGNAL( aboutToShow() ), + ops, SLOT( updateSelectionDependentActions() )); + menu->plug( toolbar ); +*/ + /* + * ugly little hack to have a 5 pixel space between the buttons + * and the combo box + */ +/* QWidget *spacerWidget = new QWidget(toolbar); +//(js) spacerWidget->setMinimumWidth(spacingHint()); +//(js) spacerWidget->setMaximumWidth(spacingHint()); + d->m_pathComboIndex = toolbar->insertWidget(-1, -1, spacerWidget); + toolbar->insertWidget(PATH_COMBO, 0, d->pathCombo); + + + toolbar->setItemAutoSized (PATH_COMBO); + toolbar->setIconText(KToolBar::IconOnly); + toolbar->setBarPos(KToolBar::Top); + toolbar->setMovingEnabled(false); + toolbar->adjustSize(); + + d->pathCombo->setCompletionObject( ops->dirCompletionObject(), false ); + + connect( d->pathCombo, SIGNAL( urlActivated( const KURL& )), + this, SLOT( enterURL( const KURL& ) )); + connect( d->pathCombo, SIGNAL( returnPressed( const QString& )), + this, SLOT( enterURL( const QString& ) )); + connect( d->pathCombo, SIGNAL(textChanged( const QString& )), + SLOT( pathComboChanged( const QString& ) )); + connect( d->pathCombo, SIGNAL( completion( const QString& )), + SLOT( dirCompletion( const QString& ))); + connect( d->pathCombo, SIGNAL( textRotation(KCompletionBase::KeyBindingType) ), + d->pathCombo, SLOT( rotateText(KCompletionBase::KeyBindingType) )); + + QString whatsThisText; + + // the Location label/edit + d->locationLabel = new QLabel(i18n("&Location:"), d->mainWidget); + locationEdit = new KURLComboBox(KURLComboBox::Files, true, + d->mainWidget, "LocationEdit"); + updateLocationWhatsThis (); + d->locationLabel->setBuddy(locationEdit); + + // to get the completionbox-signals connected: + locationEdit->setHandleSignals( true ); + (void) locationEdit->completionBox(); + + locationEdit->setFocus(); +// locationEdit->setCompletionObject( new KURLCompletion() ); +// locationEdit->setAutoDeleteCompletionObject( true ); + locationEdit->setCompletionObject( ops->completionObject(), false ); + + connect( locationEdit, SIGNAL( returnPressed() ), + this, SLOT( slotOk())); + connect(locationEdit, SIGNAL( activated( const QString& )), + this, SLOT( locationActivated( const QString& ) )); + connect( locationEdit, SIGNAL( completion( const QString& )), + SLOT( fileCompletion( const QString& ))); + connect( locationEdit, SIGNAL( textRotation(KCompletionBase::KeyBindingType) ), + locationEdit, SLOT( rotateText(KCompletionBase::KeyBindingType) )); + + // the Filter label/edit + whatsThisText = i18n("<qt>This is the filter to apply to the file list. " + "File names that do not match the filter will not be shown.<p>" + "You may select from one of the preset filters in the " + "drop down menu, or you may enter a custom filter " + "directly into the text area.<p>" + "Wildcards such as * and ? are allowed.</qt>"); + d->filterLabel = new QLabel(i18n("&Filter:"), d->mainWidget); + QWhatsThis::add(d->filterLabel, whatsThisText); + filterWidget = new KFileFilterCombo(d->mainWidget, + "KFileDialog::filterwidget"); + QWhatsThis::add(filterWidget, whatsThisText); + setFilter(filter); + d->filterLabel->setBuddy(filterWidget); + connect(filterWidget, SIGNAL(filterChanged()), SLOT(slotFilterChanged())); + + // the Automatically Select Extension checkbox + // (the text, visibility etc. is set in updateAutoSelectExtension(), which is called by readConfig()) + d->autoSelectExtCheckBox = new QCheckBox (d->mainWidget); + connect(d->autoSelectExtCheckBox, SIGNAL(clicked()), SLOT(slotAutoSelectExtClicked())); + + initGUI(); // activate GM + + readRecentFiles( config ); + + adjustSize(); + + // we set the completionLock to avoid entering pathComboChanged() when + // inserting the list of URLs into the combo. + d->completionLock = true; + ops->setViewConfig( config, ConfigGroup ); + readConfig( config, ConfigGroup ); + setSelection(d->selection); + d->completionLock = false; + */ +} + +void KexiStartupFileDialogBase::clearFilter() +{ + d->kde_filters = "";//(js) + QFileDialog::setFilter(""); //(js); +//todo d->mimetypes.clear(); +//todo d->hasDefaultFilter = false; + + updateAutoSelectExtension (); +} + +KFile::Mode KexiStartupFileDialogBase::mode() const +{ + return d->mode; +} + +void KexiStartupFileDialogBase::setMode( KFile::Mode m ) +{ + //(js) translate mode for QFileDialog + d->mode = m; + QFileDialog::Mode qm = (QFileDialog::Mode)0; + if (m & KFile::File) qm = Mode(qm | QFileDialog::AnyFile); + else if (m & KFile::Directory) qm = Mode(qm | QFileDialog::DirectoryOnly); + if (m & KFile::Files) qm = Mode(qm | QFileDialog::ExistingFiles); + if (m & KFile::ExistingOnly) qm = Mode(qm | QFileDialog::ExistingFile); + + QFileDialog::setMode( qm ); +/*(js) ops->setMode(m); + if ( ops->dirOnlyMode() ) { +//(js) filterWidget->setDefaultFilter( i18n("*|All Directories") ); + } + else { +//(js) filterWidget->setDefaultFilter( i18n("*|All Files") ); + } + + updateAutoSelectExtension ();*/ +} + +void KexiStartupFileDialogBase::setMode( unsigned int m ) +{ + setMode(static_cast<KFile::Mode>( m )); +} + +void KexiStartupFileDialogBase::setOperationMode( KFileDialog::OperationMode mode ) +{ +// d->operationMode = mode; + // d->keepLocation = (mode == Saving); + if (mode == KFileDialog::Saving) { + setMode( KFile::File ); + setIcon( KGlobal::iconLoader()->loadIcon("filesave", KIcon::Desktop) ); + } +//(js) filterWidget->setEditable( !d->hasDefaultFilter || mode != Saving ); +//(js) d->okButton->setGuiItem( (mode == Saving) ? KStdGuiItem::save() : KStdGuiItem::ok() ); +//TODO updateLocationWhatsThis (); + updateAutoSelectExtension (); +} + +QString KexiStartupFileDialogBase::currentFilter() const +{ + //(js)filterWidget->currentFilter(); + + //we need to convert Qt filter format to KDE format + //Qt format: "some text (*.first *.second)" or "All (*)" + //KDE format: "*.first *.second" or "*" + QString f = selectedFilter(); + if (f.find('(')!=-1) + f = f.mid(f.find('(')+1); + if (f.mid(f.find(')')!=-1)) + f = f.left(f.find(')')); + return f; +} + +void KexiStartupFileDialogBase::setFilter(const QString& filter) +{ + d->kde_filters = filter; + int pos = d->kde_filters.find('/'); + + // Check for an un-escaped '/', if found + // interpret as a MIME filter. + + if (pos > 0 && filter[pos - 1] != '\\') { + QStringList filters = QStringList::split( " ", d->kde_filters ); + setMimeFilter( filters ); + return; + } + QFileDialog::setFilters( convertKFileDialogFilterToQFileDialogFilter(filter) ); + //</js> +//(js) ops->clearFilter(); +//(js) filterWidget->setFilter(copy); +//(js) ops->setNameFilter(filterWidget->currentFilter()); +//(js) d->hasDefaultFilter = false; +//(js) filterWidget->setEditable( true ); + + updateAutoSelectExtension (); +} + +void KexiStartupFileDialogBase::setMimeFilter( const QStringList& mimeTypes, + const QString& defaultType ) +{ + d->mimetypes = mimeTypes; +//(js) filterWidget->setMimeFilter( mimeTypes, defaultType ); + +//(js) QStringList types = QStringList::split(" ", filterWidget->currentFilter()); +//(js) types.append( QString::fromLatin1( "inode/directory" )); +//(js) ops->clearFilter(); +//(js) ops->setMimeFilter( types ); +//(js) d->hasDefaultFilter = !defaultType.isEmpty(); +//(js) filterWidget->setEditable( !d->hasDefaultFilter || +//(js) d->operationMode != Saving ); + +//TODO updateAutoSelectExtension (); +} + +QString KexiStartupFileDialogBase::realStartDir(const QString& startDir) +{ + if (!startDir.startsWith(":")) + return startDir; + QString recentDir; //dummy + QString path( KFileDialog::getStartURL(startDir, recentDir).path() ); + if (path.isEmpty()) + return QString::null; + QFileInfo fi(path); + return fi.isDir() ? fi.absFilePath() : fi.dir(true).absPath(); +} + +void KexiStartupFileDialogBase::saveLastVisitedPath(const QString& path) +{ + if (!m_lastVisitedPathsVariable.isEmpty()) { + //save last visited dir path +// QString dir = QDir(path).absPath(); + QFileInfo fi(path); + QString dir( fi.isDir() ? fi.absFilePath() : fi.dir(true).absPath() ); + if (!dir.isEmpty()) + KRecentDirs::add(m_lastVisitedPathsVariable, dir); + } +} diff --git a/kexi/main/startup/KexiStartup_p.cpp b/kexi/main/startup/KexiStartup_p.cpp new file mode 100644 index 00000000..df7cddc6 --- /dev/null +++ b/kexi/main/startup/KexiStartup_p.cpp @@ -0,0 +1,127 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl> + + 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 "KexiStartup_p.h" + +#include <kstandarddirs.h> +#include <kprogress.h> +#include <kprocess.h> +#include <kdebug.h> +#include <klocale.h> + +#include <qfileinfo.h> +#include <qdir.h> +#include <qapplication.h> + +SQLite2ToSQLite3Migration::SQLite2ToSQLite3Migration(const QString& filePath) +: m_filePath(filePath) +{ + m_process = 0; + m_dlg = 0; + result = false; + m_run = false; +} + +SQLite2ToSQLite3Migration::~SQLite2ToSQLite3Migration() +{ + delete m_process; + m_dlg->close(); + delete m_dlg; +} + +tristate SQLite2ToSQLite3Migration::run() +{ + if (m_run) + return false; + m_run = true; + const QString ksqlite2to3_app = KStandardDirs::findExe( "ksqlite2to3" ); + if (ksqlite2to3_app.isEmpty()) + return false; + + QFileInfo fi(m_filePath); + if (fi.isSymLink()) { + m_filePath = fi.readLink(); + fi = QFileInfo(m_filePath); + } + //remember permissions of m_filePath + m_restoreStat = (0==stat(QFile::encodeName(m_filePath), &m_st)); + + m_process = new KProcess(this, "process"); + *m_process << ksqlite2to3_app << m_filePath; + m_process->setWorkingDirectory( fi.dir(true).absPath() ); + connect( m_process, SIGNAL(receivedStderr(KProcess*,char*,int)), + this, SLOT(receivedStderr(KProcess*,char*,int))); + connect( m_process, SIGNAL(processExited(KProcess*)), this, SLOT(processExited(KProcess*)) ); + if (!m_process->start(KProcess::NotifyOnExit, KProcess::Stderr)) + return false; + + m_dlg = new KProgressDialog(0, 0, QString::null, + i18n("Saving \"%1\" project file to a new \"%2\" database format...") + .arg(QDir::convertSeparators(QFileInfo(m_filePath).fileName())).arg("SQLite3") + ); + m_dlg->setModal(true); + connect(m_dlg, SIGNAL(cancelClicked()), this, SLOT(cancelClicked())); + m_dlg->setMinimumDuration(1000); + m_dlg->setAutoClose(true); + m_dlg->progressBar()->setTotalSteps(100); + m_dlg->progressBar()->setProgress(0); + m_dlg->exec(); + + if (result!=true) + return result; + + return result; +} + +extern void updateProgressBar(KProgressDialog *pd, char *buffer, int buflen); + +void SQLite2ToSQLite3Migration::receivedStderr(KProcess *, char *buffer, int buflen) +{ + updateProgressBar(m_dlg, buffer, buflen); +} + +void SQLite2ToSQLite3Migration::processExited(KProcess* process) +{ + kdDebug() << "EXIT " << process->name() << endl; + + kdDebug() << process->isRunning() << " " << process->exitStatus() << endl; + m_dlg->close(); + result = !process->isRunning() && 0==process->exitStatus();//m_process->normalExit(); + kdDebug() << result.toString() << endl; + if (result == true) { + if (m_restoreStat) { + //restore permissions for m_filePath + chmod(QFile::encodeName(m_filePath), m_st.st_mode); + chown(QFile::encodeName(m_filePath), m_st.st_uid, m_st.st_gid); + } + } +} + +void SQLite2ToSQLite3Migration::cancelClicked() +{ + kdDebug() << result.toString() << " cancelClicked() " <<m_process->isRunning() << " " + << m_process->exitStatus() << endl; + if (!m_process->isRunning() && 0==m_process->exitStatus()) + return; + result = cancelled; + m_process->kill(); +} + +#include "KexiStartup_p.moc" + diff --git a/kexi/main/startup/KexiStartup_p.h b/kexi/main/startup/KexiStartup_p.h new file mode 100644 index 00000000..1e60d702 --- /dev/null +++ b/kexi/main/startup/KexiStartup_p.h @@ -0,0 +1,59 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + + 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 KEXI_STARTUPHANDLER_P_H +#define KEXI_STARTUPHANDLER_P_H + +#include <qobject.h> +#include <qstring.h> + +#include <sys/stat.h> + +#include <kexiutils/tristate.h> + +class KProcess; +class KProgressDialog; + +class SQLite2ToSQLite3Migration : public QObject +{ + Q_OBJECT + public: + SQLite2ToSQLite3Migration(const QString& filePath); + ~SQLite2ToSQLite3Migration(); + + tristate run(); + + public slots: + void processExited(KProcess*); + void receivedStderr(KProcess*,char*,int); + void cancelClicked(); + + protected: + QString m_filePath; + KProcess *m_process; + KProgressDialog* m_dlg; + + struct stat m_st; + bool m_restoreStat : 1; + bool m_run : 1; + + tristate result; +}; + +#endif diff --git a/kexi/main/startup/Makefile.am b/kexi/main/startup/Makefile.am new file mode 100644 index 00000000..a7f2f30e --- /dev/null +++ b/kexi/main/startup/Makefile.am @@ -0,0 +1,47 @@ +include $(top_srcdir)/kexi/Makefile.global + +noinst_LTLIBRARIES = libkeximainstartup.la + +libkeximainstartup_la_SOURCES = KexiConnSelectorBase.ui KexiProjectSelectorBase.ui \ + KexiOpenExistingFile.ui \ + KexiNewPrjTypeSelector.ui KexiDBTitlePageBase.ui \ + KexiServerDBNamePage.ui \ + KexiDBTitlePage.cpp \ + KexiConnSelector.cpp KexiProjectSelector.cpp \ + KexiStartupDialog.cpp \ + KexiStartupFileDialog.cpp KexiNewProjectWizard.cpp \ + KexiStartup.cpp KexiStartup_p.cpp KexiStartupDialogTemplatesPage.cpp + +noinst_HEADERS = KexiStartup_p.h + +libkeximainstartup_la_LDFLAGS = $(all_libraries) -Wnounresolved +libkeximainstartup_la_LIBADD = \ + ../../widget/libkexiextendedwidgets.la + +libkeximainstartup_la_METASOURCES = AUTO + +SUBDIRS = . + +# kde_appsdir Where your application's menu entry (.desktop) should go to. +# kde_icondir Where your icon should go to - better use KDE_ICON. +# kde_sounddir Where your sounds should go to. +# kde_htmldir Where your docs should go to. (contains lang subdirs) +# kde_datadir Where you install application data. (Use a subdir) +# kde_locale Where translation files should go to. (contains lang subdirs) +# kde_cgidir Where cgi-bin executables should go to. +# kde_confdir Where config files should go to (system-wide ones with default values). +# kde_mimedir Where mimetypes .desktop files should go to. +# kde_servicesdir Where services .desktop files should go to. +# kde_servicetypesdir Where servicetypes .desktop files should go to. +# kde_toolbardir Where general toolbar icons should go to (deprecated, use KDE_ICON). +# kde_wallpaperdir Where general wallpapers should go to. +# kde_templatesdir Where templates for the "New" menu (Konqueror/KDesktop) should go to. +# kde_bindir Where executables should go to. Use bin_PROGRAMS or bin_SCRIPTS. +# kde_libdir Where shared libraries should go to. Use lib_LTLIBRARIES. +# kde_moduledir Where modules (e.g. parts) should go to. Use kde_module_LTLIBRARIES. +# kde_styledir Where Qt/KDE widget styles should go to (new in KDE 3). +# kde_designerdir Where Qt Designer plugins should go to (new in KDE 3). + +# set the include path for X, qt and KDE +INCLUDES= -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/main/startup -I$(top_srcdir)/kexi/core -I$(top_srcdir)/kexi/widget -I$(top_builddir)/kexi/widget $(all_includes) + |