1 /* This file is part of the KDE project
2    Copyright (C) 2003-2011 Jarosław Staniek <staniek@kde.org>
3 
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public License
15    along with this program; see the file COPYING.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "KexiProjectSelectorWidget.h"
21 #include <core/kexi.h>
22 #include <KexiIcon.h>
23 
24 #include <KDbDriverManager>
25 #include <KDbDriverMetaData>
26 #include <KDbConnectionData>
27 #include <KDbUtils>
28 #include <KDbMessageHandler>
29 
30 #include <KLocalizedString>
31 #include <KGuiItem>
32 
33 #include <QDebug>
34 #include <QLabel>
35 #include <QPushButton>
36 #include <QKeyEvent>
37 
38 #include <assert.h>
39 
40 //! @internal
41 class Q_DECL_HIDDEN KexiProjectSelectorWidget::Private
42 {
43 public:
Private(KexiProjectSet * prj_set_)44     explicit Private(KexiProjectSet *prj_set_)
45          : prj_set(prj_set_)
46     {
47         selectable = true;
48     }
49 
50     QIcon fileicon, dbicon;
51     bool showProjectNameColumn;
52     bool showConnectionColumns;
53     bool selectable;
54 
55     KexiProjectSet *prj_set;
56 };
57 
58 class Q_DECL_HIDDEN KexiProjectSelectorDialog::Private
59 {
60 public:
Private()61   Private() {}
62   KexiProjectSelectorWidget* sel;
63 };
64 
65 /*================================================================*/
66 
67 //! helper class
68 class ProjectDataLVItem : public QTreeWidgetItem
69 {
70 public:
ProjectDataLVItem(KexiProjectData * d,const KDbDriverMetaData & driverMetaData,KexiProjectSelectorWidget * selector)71     ProjectDataLVItem(KexiProjectData *d,
72                       const KDbDriverMetaData &driverMetaData,
73                       KexiProjectSelectorWidget *selector)
74             : QTreeWidgetItem(selector->list())
75             , data(d)
76     {
77         int colnum = 0;
78         const KDbConnectionData cdata = *data->connectionData();
79         if (selector->d->showProjectNameColumn)
80             setText(colnum++, data->caption() + "  ");
81 
82         setText(colnum++, data->databaseName() + "  ");
83 
84         if (selector->d->showConnectionColumns) {
85             QString driverName = driverMetaData.name();
86             if (driverName.isEmpty()) {
87                 KDbDriverManager manager;
88                 const KDbDriverMetaData *driverMetaDataFromCdata = manager.driverMetaData(cdata.driverId());
89                 if (driverMetaDataFromCdata) {
90                     driverName = driverMetaDataFromCdata->name();
91                 }
92             }
93             if (driverMetaData.isFileBased()) {
94                 setText(colnum++, xi18n("File (%1)", driverName) + "  ");
95             } else {
96                 setText(colnum++, driverName + "  ");
97             }
98             QString conn;
99             if (cdata.caption().isEmpty()) {
100                 conn = cdata.toUserVisibleString();
101             }
102             else {
103                 conn = xi18nc("caption: server_info", "%1: %2",
104                               cdata.caption(), cdata.toUserVisibleString());
105             }
106             setText(colnum++, conn + "  ");
107         }
108     }
~ProjectDataLVItem()109     ~ProjectDataLVItem() {}
110 
111     KexiProjectData *data;
112 };
113 
114 /*================================================================*/
115 
116 /*!
117  *  Constructs a KexiProjectSelector which is a child of 'parent', with the
118  *  name 'name' and widget flags set to 'f'
119  */
KexiProjectSelectorWidget(QWidget * parent,KexiProjectSet * prj_set,bool showProjectNameColumn,bool showConnectionColumns)120 KexiProjectSelectorWidget::KexiProjectSelectorWidget(QWidget* parent,
121         KexiProjectSet* prj_set, bool showProjectNameColumn, bool showConnectionColumns)
122         : QWidget(parent)
123         , d(new Private(prj_set))
124 {
125     setupUi(this);
126     setObjectName("KexiProjectSelectorWidget");
127     d->showProjectNameColumn = showProjectNameColumn;
128     d->showConnectionColumns = showConnectionColumns;
129     list()->installEventFilter(this);
130 
131     d->fileicon = Kexi::defaultFileBasedDriverIcon();
132     setWindowIcon(d->fileicon);
133     d->dbicon = koIcon("server-database");
134 
135     QTreeWidgetItem *headerItem = list()->headerItem();
136     QTreeWidgetItem *newHeaderItem = new QTreeWidgetItem;
137     int newHeaderItemIndex = 0;
138     if (d->showProjectNameColumn) {
139         newHeaderItem->setText(newHeaderItemIndex++, headerItem->text(0)); // project name
140     }
141     newHeaderItem->setText(newHeaderItemIndex++, headerItem->text(1)); // database
142     if (d->showConnectionColumns) {
143         newHeaderItem->setText(newHeaderItemIndex++, headerItem->text(2)); // type
144         newHeaderItem->setText(newHeaderItemIndex++, headerItem->text(3)); // connection
145     }
146     list()->setHeaderItem(newHeaderItem);
147     setFocusProxy(list());
148 
149     //show projects
150     setProjectSet(d->prj_set);
151     connect(list(), SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
152             this, SLOT(slotItemExecuted(QTreeWidgetItem*)));
153     connect(list(), SIGNAL(itemSelectionChanged()),
154             this, SLOT(slotItemSelected()));
155 }
156 
157 /*!
158  *  Destroys the object and frees any allocated resources
159  */
~KexiProjectSelectorWidget()160 KexiProjectSelectorWidget::~KexiProjectSelectorWidget()
161 {
162     delete d;
163 }
164 
selectedProjectData() const165 KexiProjectData* KexiProjectSelectorWidget::selectedProjectData() const
166 {
167     QList<QTreeWidgetItem *> items = list()->selectedItems();
168     if (items.isEmpty())
169         return 0;
170     ProjectDataLVItem *item = static_cast<ProjectDataLVItem*>(items.first());
171     if (item)
172         return item->data;
173     return 0;
174 }
175 
slotItemExecuted(QTreeWidgetItem * item)176 void KexiProjectSelectorWidget::slotItemExecuted(QTreeWidgetItem *item)
177 {
178     if (!d->selectable)
179         return;
180     ProjectDataLVItem *ditem = static_cast<ProjectDataLVItem*>(item);
181     if (ditem)
182         emit projectExecuted(ditem->data);
183 }
184 
slotItemExecuted()185 void KexiProjectSelectorWidget::slotItemExecuted()
186 {
187     if (!d->selectable)
188         return;
189     QList<QTreeWidgetItem *> items = list()->selectedItems();
190     if (items.isEmpty())
191         return;
192     slotItemExecuted(items.first());
193 }
194 
slotItemSelected()195 void KexiProjectSelectorWidget::slotItemSelected()
196 {
197     if (!d->selectable)
198         return;
199     QList<QTreeWidgetItem *> items = list()->selectedItems();
200     ProjectDataLVItem *ditem = static_cast<ProjectDataLVItem*>(items.isEmpty() ? 0 : items.first());
201     emit selectionChanged(ditem ? ditem->data : 0);
202 }
203 
setProjectSet(KexiProjectSet * prj_set)204 void KexiProjectSelectorWidget::setProjectSet(KexiProjectSet* prj_set)
205 {
206     if (prj_set) {
207         //old list
208         list()->clear();
209     }
210     d->prj_set = prj_set;
211     if (!d->prj_set)
212         return;
213 //! @todo what with project set's ownership?
214     if (d->prj_set->result().isError()) {
215         qDebug() << "d->prj_set->error()" << d->prj_set->result();
216         return;
217     }
218     KDbDriverManager manager;
219     KexiProjectData::List prjlist = d->prj_set->list();
220     foreach(KexiProjectData* data, prjlist) {
221         KDbMessageGuard mg(manager.resultable());
222         const KDbDriverMetaData *driverMetaData = manager.driverMetaData(data->connectionData()->driverId());
223         if (driverMetaData) {
224             ProjectDataLVItem *item = new ProjectDataLVItem(data, *driverMetaData, this);
225             if (!d->selectable) {
226                 Qt::ItemFlags flags = item->flags();
227                 (flags |= Qt::ItemIsSelectable) ^= Qt::ItemIsSelectable;
228                 item->setFlags(flags);
229             }
230             if (driverMetaData->isFileBased())
231                 item->setIcon(0, d->fileicon);
232             else
233                 item->setIcon(0, d->dbicon);
234         }
235         else {
236             qWarning() << "no driver found for" << data->connectionData()->driverId();
237         }
238     }
239     list()->setSortingEnabled(true);
240     list()->sortItems(0, Qt::AscendingOrder);
241     list()->resizeColumnToContents(0);
242     if (list()->topLevelItemCount() > 0) {
243         list()->topLevelItem(0)->setSelected(true);
244     }
245 }
246 
projectSet()247 KexiProjectSet *KexiProjectSelectorWidget::projectSet() {
248     return d->prj_set;
249 }
250 
setSelectable(bool set)251 void KexiProjectSelectorWidget::setSelectable(bool set)
252 {
253     if (d->selectable == set)
254         return;
255     d->selectable = set;
256     //update items' state
257     QTreeWidgetItemIterator it(list());
258     while (*it) {
259         Qt::ItemFlags flags = (*it)->flags();
260         flags |= Qt::ItemIsSelectable;
261         if (!d->selectable)
262             flags ^= Qt::ItemIsSelectable;
263         (*it)->setFlags(flags);
264     }
265 }
266 
isSelectable() const267 bool KexiProjectSelectorWidget::isSelectable() const
268 {
269     return d->selectable;
270 }
271 
label() const272 QLabel *KexiProjectSelectorWidget::label() const
273 {
274     return Ui_KexiProjectSelector::label;
275 }
276 
list() const277 QTreeWidget* KexiProjectSelectorWidget::list() const
278 {
279     return Ui_KexiProjectSelector::list;
280 }
281 
eventFilter(QObject * watched,QEvent * event)282 bool KexiProjectSelectorWidget::eventFilter(QObject* watched, QEvent* event)
283 {
284     if (event->type() == QEvent::KeyPress) {
285         QKeyEvent *ke = static_cast<QKeyEvent*>(event);
286         if ((ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return)
287             && ke->modifiers() == Qt::NoModifier)
288         {
289             slotItemExecuted();
290             return true;
291         }
292     }
293     return QWidget::eventFilter(watched, event);
294 }
295 
296 /*================================================================*/
297 
KexiProjectSelectorDialog(QWidget * parent,const KDbConnectionData & cdata,bool showProjectNameColumn,bool showConnectionColumns)298 KexiProjectSelectorDialog::KexiProjectSelectorDialog(QWidget *parent,
299         const KDbConnectionData& cdata,
300         bool showProjectNameColumn, bool showConnectionColumns)
301         : KPageDialog(parent)
302         , d(new Private)
303 {
304     setWindowTitle(xi18nc("@title:window", "Open Project"));
305     KDbConnectionData _cdata(cdata);
306     // errors are handled in KexiStartupHandler::selectProject() ...
307     KexiProjectSet *prj_set = new KexiProjectSet;
308     init(prj_set, showProjectNameColumn, showConnectionColumns);
309     KGuiItem okItem(xi18nc("@action:button", "&Open"), koIconName("document-open"),
310                     xi18n("Open Database Connection"));
311     KGuiItem::assign(button(QDialogButtonBox::Ok), okItem);
312 
313     d->sel->label()->setText(
314         xi18n("Select a project on <resource>%1</resource> database server to open:",
315               _cdata.toUserVisibleString(KDbConnectionData::UserVisibleStringOption::None)));
316 }
317 
~KexiProjectSelectorDialog()318 KexiProjectSelectorDialog::~KexiProjectSelectorDialog()
319 {
320     delete d;
321 }
322 
init(KexiProjectSet * prj_set,bool showProjectNameColumn,bool showConnectionColumns)323 void KexiProjectSelectorDialog::init(KexiProjectSet* prj_set, bool showProjectNameColumn,
324                                      bool showConnectionColumns)
325 {
326     setObjectName("KexiProjectSelectorDialog");
327     setModal(true);
328     setStandardButtons(
329 #ifdef KEXI_SHOW_UNFINISHED
330         //! @todo re-add Help when doc is available
331         QDialogButtonBox::Help |
332 #endif
333         QDialogButtonBox::Ok | QDialogButtonBox::Cancel
334     );
335     button(QDialogButtonBox::Ok)->setDefault(true);
336     setFaceType(Plain);
337     setSizeGripEnabled(true);
338 
339     d->sel = new KexiProjectSelectorWidget(this, prj_set,
340                                           showProjectNameColumn, showConnectionColumns);
341     //! @todo KEXI3 test this
342     addPage(d->sel, QString());
343     setWindowIcon(d->sel->windowIcon());
344     d->sel->setFocus();
345 
346     connect(d->sel, SIGNAL(projectExecuted(KexiProjectData*)),
347             this, SLOT(slotProjectExecuted(KexiProjectData*)));
348     connect(d->sel, SIGNAL(selectionChanged(KexiProjectData*)),
349             this, SLOT(slotProjectSelectionChanged(KexiProjectData*)));
350 }
351 
selectedProjectData() const352 KexiProjectData* KexiProjectSelectorDialog::selectedProjectData() const
353 {
354     return d->sel->selectedProjectData();
355 }
356 
slotProjectExecuted(KexiProjectData *)357 void KexiProjectSelectorDialog::slotProjectExecuted(KexiProjectData*)
358 {
359     accept();
360 }
361 
slotProjectSelectionChanged(KexiProjectData * pdata)362 void KexiProjectSelectorDialog::slotProjectSelectionChanged(KexiProjectData* pdata)
363 {
364     button(QDialogButtonBox::Ok)->setEnabled(pdata);
365 }
366 
showEvent(QShowEvent * event)367 void KexiProjectSelectorDialog::showEvent(QShowEvent * event)
368 {
369     KPageDialog::showEvent(event);
370     //! @todo KPageDialog::centerOnScreen(this);
371 }
372 
projectSet() const373 KexiProjectSet* KexiProjectSelectorDialog::projectSet() const
374 {
375     return d->sel->projectSet();
376 }
377