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