1 /* This file is part of the KDE project
2    Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
3    Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
4    Copyright (C) 2003-2017 Jarosław Staniek <staniek@kde.org>
5 
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public License
17    along with this program; see the file COPYING.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20 
21    Original Author:  Till Busch <till@bux.at>
SybasePreparedStatement(StatementType type,ConnectionInternal & conn,KDbFieldList & fields)22    Original Project: buX (www.bux.at)
23 */
24 
25 #include "KDbTableViewColumn.h"
26 
27 #include "KDbConnection.h"
28 #include "KDbConnectionOptions.h"
29 #include "KDbCursor.h"
30 #include "KDb.h"
31 #include "KDbQuerySchema.h"
32 #include "KDbRecordEditBuffer.h"
33 #include "KDbTableViewData.h"
34 #include "KDbValidator.h"
35 
36 #include <QIcon>
37 
38 class Q_DECL_HIDDEN KDbTableViewColumn::Private
39 {
40 public:
41   Private()
42       : data(nullptr)
43       , validator(nullptr)
44       , relatedData(nullptr)
45       , field(nullptr)
46       , columnInfo(nullptr)
47       , visibleLookupColumnInfo(nullptr)
48       , width(0)
49       , readOnly(false)
50       , visible(true)
51       , relatedDataEditable(false)
52       , headerTextVisible(true)
53     {
54     }
55 
56     //! Data that this column is assigned to. Set by KDbTableViewColumn::setData()
57     KDbTableViewData* data;
58 
59     QString captionAliasOrName;
60 
61     QIcon icon;
62 
63     KDbValidator* validator;
64 
65     KDbTableViewData* relatedData;
66     int relatedDataPKeyID;
67 
68     KDbField* field;
69 
70     //! @see columnInfo()
71     KDbQueryColumnInfo* columnInfo;
72 
73     //! @see visibleLookupColumnInfo()
74     KDbQueryColumnInfo* visibleLookupColumnInfo;
75 
76     int width;
77     bool isDBAware; //!< true if data is stored in DB, not only in memeory
78     bool readOnly;
79     bool fieldOwned;
80     bool visible;
81     bool relatedDataEditable;
82     bool headerTextVisible;
83 };
84 
85 //------------------------
86 
87 KDbTableViewColumn::KDbTableViewColumn(KDbField *f, FieldIsOwned isOwned)
88         : d(new Private)
89 {
90     d->field = f;
91     d->isDBAware = false;
92     d->fieldOwned = isOwned == FieldIsOwned::Yes;
93     d->captionAliasOrName = d->field->captionOrName();
94 }
95 
96 KDbTableViewColumn::KDbTableViewColumn(const QString &name, KDbField::Type ctype,
97         KDbField::Constraints cconst,
98         KDbField::Options options,
99         int maxLength, int precision,
100         QVariant defaultValue,
101         const QString &caption, const QString &description)
102         : d(new Private)
103 {
104     d->field = new KDbField(
105         name, ctype, cconst, options, maxLength, precision, defaultValue, caption, description);
106 
107     d->isDBAware = false;
108     d->fieldOwned = true;
109     d->captionAliasOrName = d->field->captionOrName();
110 }
111 
112 KDbTableViewColumn::KDbTableViewColumn(const QString &name, KDbField::Type ctype,
113         const QString &caption, const QString &description)
114         : d(new Private)
115 {
116     d->field = new KDbField(
117         name, ctype,
118         KDbField::NoConstraints,
119         KDbField::NoOptions,
120         0, 0,
121         QVariant(),
122         caption, description);
123 
124     d->isDBAware = false;
125     d->fieldOwned = true;
126     d->captionAliasOrName = d->field->captionOrName();
127 }
128 
129 // db-aware
130 KDbTableViewColumn::KDbTableViewColumn(
131     const KDbQuerySchema &query, KDbQueryColumnInfo *aColumnInfo,
132     KDbQueryColumnInfo *aVisibleLookupColumnInfo)
133         : d(new Private)
134 {
135     Q_ASSERT(aColumnInfo);
136     d->field = aColumnInfo->field();
137     d->columnInfo = aColumnInfo;
138     d->visibleLookupColumnInfo = aVisibleLookupColumnInfo;
139     d->isDBAware = true;
140     d->fieldOwned = false;
141 
142     //setup column's caption:
143     if (!d->columnInfo->field()->caption().isEmpty()) {
144         d->captionAliasOrName = d->columnInfo->field()->caption();
145     } else {
146         //reuse alias if available:
147         d->captionAliasOrName = d->columnInfo->alias();
148         //last hance: use field name
149         if (d->captionAliasOrName.isEmpty())
150             d->captionAliasOrName = d->columnInfo->field()->name();
151         //! @todo compute other auto-name?
152     }
153     //setup column's readonly flag: true, if
154     // - it's not from parent table's field, or
155     // - if the query itself is coming from read-only connection, or
156     // - if the query itself is stored (i.e. has connection) and lookup column is defined
157     const bool columnFromMasterTable = query.masterTable() == d->columnInfo->field()->table();
158     d->readOnly = !columnFromMasterTable;
159 //! @todo remove this when queries become editable            ^^^^^^^^^^^^^^
160 // kdbDebug() << "KDbTableViewColumn: query.masterTable()=="
161 //  << (query.masterTable() ? query.masterTable()->name() : "notable") << ", columnInfo->field->table()=="
162 //  << (columnInfo->field->table() ? columnInfo->field->table()->name()  : "notable");
163 }
164 
165 KDbTableViewColumn::KDbTableViewColumn(bool)
166         : d(new Private)
167 {
168     d->isDBAware = false;
169 }
170 
171 KDbTableViewColumn::~KDbTableViewColumn()
172 {
173     if (d->fieldOwned)
174         delete d->field;
175     setValidator(nullptr);
176     delete d->relatedData;
177     delete d;
178 }
179 
180 void KDbTableViewColumn::setValidator(KDbValidator *v)
181 {
182     if (d->validator) {//remove old one
183         if (!d->validator->parent()) //destroy if has no parent
184             delete d->validator;
185     }
186     d->validator = v;
187 }
188 
189 void KDbTableViewColumn::setData(KDbTableViewData *data)
190 {
191     d->data = data;
192 }
193 
194 void KDbTableViewColumn::setRelatedData(KDbTableViewData *data)
195 {
196     if (d->isDBAware)
197         return;
198     if (d->relatedData)
199         delete d->relatedData;
200     d->relatedData = nullptr;
201     if (!data)
202         return;
203     //find a primary key
204     const QList<KDbTableViewColumn*> *columns = data->columns();
205     int id = -1;
206     foreach(KDbTableViewColumn* col, *columns) {
207         id++;
208         if (col->field()->isPrimaryKey()) {
209             //found, remember
210             d->relatedDataPKeyID = id;
211             d->relatedData = data;
212             return;
213         }
214     }
215 }
216 
217 bool KDbTableViewColumn::isReadOnly() const
218 {
219     return d->readOnly || (d->data && d->data->isReadOnly());
220 }
221 
222 void KDbTableViewColumn::setReadOnly(bool ro)
223 {
224     d->readOnly = ro;
225 }
226 
227 bool KDbTableViewColumn::isVisible() const
228 {
229     return d->columnInfo ? d->columnInfo->isVisible() : d->visible;
230 }
231 
232 void KDbTableViewColumn::setVisible(bool v)
233 {
234     bool changed = d->visible != v;
235     if (d->columnInfo && d->columnInfo->isVisible() != v) {
236         d->columnInfo->setVisible(v);
237         changed = true;
238     }
239     d->visible = v;
240     if (changed && d->data) {
241         d->data->columnVisibilityChanged(*this);
242     }
243 }
244 
245 void KDbTableViewColumn::setIcon(const QIcon& icon)
246 {
247     d->icon = icon;
248 }
249 
250 QIcon KDbTableViewColumn::icon() const
251 {
252     return d->icon;
253 }
254 
255 void KDbTableViewColumn::setHeaderTextVisible(bool visible)
256 {
257     d->headerTextVisible = visible;
258 }
259 
260 bool KDbTableViewColumn::isHeaderTextVisible() const
261 {
262     return d->headerTextVisible;
263 }
264 
265 QString KDbTableViewColumn::captionAliasOrName() const
266 {
267     return d->captionAliasOrName;
268 }
269 
270 KDbValidator* KDbTableViewColumn::validator() const
271 {
272     return d->validator;
273 }
274 
275 KDbTableViewData *KDbTableViewColumn::relatedData()
276 {
277     return d->relatedData;
278 }
279 
280 const KDbTableViewData *KDbTableViewColumn::relatedData() const
281 {
282     return d->relatedData;
283 }
284 
285 KDbField* KDbTableViewColumn::field()
286 {
287     return d->field;
288 }
289 
290 const KDbField* KDbTableViewColumn::field() const
291 {
292     return d->field;
293 }
294 
295 void KDbTableViewColumn::setRelatedDataEditable(bool set)
296 {
297     d->relatedDataEditable = set;
298 }
299 
300 bool KDbTableViewColumn::isRelatedDataEditable() const
301 {
302     return d->relatedDataEditable;
303 }
304 
305 KDbQueryColumnInfo* KDbTableViewColumn::columnInfo()
306 {
307     return d->columnInfo;
308 }
309 
310 const KDbQueryColumnInfo* KDbTableViewColumn::columnInfo() const
311 {
312     return d->columnInfo;
313 }
314 
315 KDbQueryColumnInfo* KDbTableViewColumn::visibleLookupColumnInfo()
316 {
317     return d->visibleLookupColumnInfo;
318 }
319 
320 const KDbQueryColumnInfo* KDbTableViewColumn::visibleLookupColumnInfo() const
321 {
322     return d->visibleLookupColumnInfo;
323 }
324 
325 bool KDbTableViewColumn::isDBAware() const
326 {
327     return d->isDBAware;
328 }
329 
330 
331 bool KDbTableViewColumn::acceptsFirstChar(const QChar &ch) const
332 {
333     // the field we're looking at can be related to "visible lookup column"
334     // if lookup column is present
335     KDbField *visibleField = d->visibleLookupColumnInfo
336                                   ? d->visibleLookupColumnInfo->field() : d->field;
337     const KDbField::Type type = visibleField->type(); // cache: evaluating type of expressions can be expensive
338     if (KDbField::isNumericType(type)) {
339         if (ch == QLatin1Char('.') || ch == QLatin1Char(','))
340             return KDbField::isFPNumericType(type);
341         if (ch == QLatin1Char('-'))
342             return !visibleField->isUnsigned();
343         if (ch == QLatin1Char('+') || (ch >= QLatin1Char('0') && ch <= QLatin1Char('9')))
344             return true;
345         return false;
346     }
347 
348     switch (type) {
349     case KDbField::Boolean:
350         return false;
351     case KDbField::Date:
352     case KDbField::DateTime:
353     case KDbField::Time:
354         return ch >= QLatin1Char('0') && ch <= QLatin1Char('9');
355     default:;
356     }
357     return true;
358 }
359 
360 void KDbTableViewColumn::setWidth(int w)
361 {
362     d->width = w;
363 }
364 
365 int KDbTableViewColumn::width() const
366 {
367     return d->width;
368 }
369 
370 QDebug operator<<(QDebug dbg, const KDbTableViewColumn &column)
371 {
372     dbg.nospace() << "TableViewColumn(";
373     dbg.space() << "columnInfo:";
374     if (column.columnInfo()) {
375         dbg.space() << *column.columnInfo();
376     } else {
377         dbg.space() << "<NONE>";
378     }
379     dbg.space() << "captionAliasOrName:" << column.captionAliasOrName();
380     dbg.space() << "visibleLookupColumnInfo:";
381     if (column.visibleLookupColumnInfo()) {
382         dbg.space() << *column.visibleLookupColumnInfo();
383     } else {
384         dbg.space() << "<NONE>";
385     }
386     dbg.space() << "data: KDbTableViewData(";
387     const KDbTableViewData *data = column.d->data;
388     if (data) {
389         dbg.space() << "count:" << data->count() << ")";
390     } else {
391         dbg.space() << "<NONE>)";
392     }
393     dbg.space() << "relatedData: KDbTableViewData(";
394     const KDbTableViewData *relatedData = column.d->relatedData;
395     if (relatedData) {
396         dbg.space() << "count:" << relatedData->count() << ")";
397     } else {
398         dbg.space() << "<NONE>)";
399     }
400     const KDbField *field = column.d->field;
401     if (data) {
402         dbg.space() << "field:" << *field;
403     } else {
404         dbg.space() << "<NONE>";
405     }
406     dbg.space() << "fieldOwned:" << column.d->fieldOwned;
407     dbg.space() << "validator:";
408     if (column.validator()) {
409         dbg.space() << "<YES>";
410     } else {
411         dbg.space() << "<NO>";
412     }
413     dbg.space() << "icon:" << column.icon().name();
414     dbg.space() << "fieldOwned:" << column.d->fieldOwned;
415     dbg.space() << "width:" << column.width();
416     dbg.space() << "isDBAware:" << column.isDBAware();
417     dbg.space() << "readOnly:" << column.isReadOnly();
418     dbg.space() << "visible:" << column.isVisible();
419     dbg.space() << "relatedDataEditable:" << column.isRelatedDataEditable();
420     dbg.space() << "headerTextVisible:" << column.isHeaderTextVisible();
421     return dbg.space();
422 }
423