+/****************************************************************************
+**
+** Copyright (C) Qxt Foundation. Some rights reserved.
+**
+** This file is part of the QxtGui module of the Qt eXTension library
+**
+** This library is free software; you can redistribute it and/or modify it
+** under the terms of th Common Public License, version 1.0, as published by
+** IBM.
+**
+** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
+** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
+** FITNESS FOR A PARTICULAR PURPOSE.
+**
+** You should have received a copy of the CPL along with this file.
+** See the LICENSE file and the cpl1.0.txt file included with the source
+** distribution for more information. If you did not receive a copy of the
+** license, contact the Qxt Foundation.
+**
+** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
+**
+****************************************************************************/
+
+#include "qxtstringvalidator.h"
+#include "qxtstringvalidator_p.h"
+
+#include <QDebug>
+#include <QAbstractItemModel>
+#include <QStringListModel>
+#include <QFlags>
+
+QxtStringValidatorPrivate::QxtStringValidatorPrivate() : isUserModel(false)
+ , model(0)
+ , cs(Qt::CaseSensitive)
+ , lookupRole(Qt::EditRole)
+ , userFlags(Qt::MatchWrap)
+ , lookupStartModelIndex(QModelIndex())
+{}
+
+QModelIndex QxtStringValidatorPrivate::lookupPartialMatch(const QString &value) const
+{
+ Qt::MatchFlags matchFlags = Qt::MatchStartsWith| userFlags;
+ if (cs == Qt::CaseSensitive)
+ matchFlags |= Qt::MatchCaseSensitive;
+
+ return lookup(value,matchFlags);
+}
+
+QModelIndex QxtStringValidatorPrivate::lookupExactMatch(const QString &value) const
+{
+ Qt::MatchFlags matchFlags = Qt::MatchFixedString | userFlags;
+ if (cs == Qt::CaseSensitive)
+ matchFlags |= Qt::MatchCaseSensitive;
+
+ return lookup(value,matchFlags);
+}
+
+QModelIndex QxtStringValidatorPrivate::lookup(const QString &value,const Qt::MatchFlags &matchFlags) const
+{
+ QModelIndex startIndex = lookupStartModelIndex.isValid() ? lookupStartModelIndex : model->index(0,0);
+
+ QModelIndexList list = model->match(startIndex,lookupRole,value,1,matchFlags);
+
+ if (list.size() > 0)
+ return list[0];
+ return QModelIndex();
+}
+
+
+/*!
+ \class QxtStringValidator QxtStringValidator
+ \ingroup QxtGui
+ \brief The QxtStringValidator class provides validation on a QStringList or a QAbstractItemModel
+
+ It provides a String based validation in a stringlist or a custom model.
+ QxtStringValidator uses QAbstractItemModel::match() to validate the input.
+ For a partial match it returns QValidator::Intermediate and for a full match QValidator::Acceptable.
+
+ Example usage:
+ \code
+
+ QLineEdit * testLineEdit = new QLineEdit();
+
+ QStringList testList;
+ testList << "StringTestString" << "sTrInGCaSe"<< "StringTest"<< "String"<< "Foobar"<< "BarFoo"<< "QxtLib";
+
+ QxtStringValidator *validator = new QxtStringValidator(ui.lineEdit);
+ validator->setStringList(testList);
+
+ //change lookup case sensitivity
+ validator->setCaseSensitivity(Qt::CaseInsensitive);
+
+ testLineEdit->setValidator(validator);
+
+ \endcode
+ */
+
+/*!
+ Constructs a validator object with a parent object that accepts any string in the stringlist.
+*/
+QxtStringValidator::QxtStringValidator(QObject * parent) : QValidator(parent)
+{
+ QXT_INIT_PRIVATE(QxtStringValidator);
+}
+
+QxtStringValidator::~QxtStringValidator(void)
+{}
+
+/*!
+ Fixes up the string input if there is no exact match in the stringlist/model.
+ The first match in the stringlist/model is used to fix the input.
+*/
+void QxtStringValidator::fixup ( QString & input ) const
+{
+ qDebug()<<"Fixup called";
+
+ if (!qxt_d().model)
+ return;
+
+ if (qxt_d().lookupExactMatch(input).isValid())
+ return;
+
+ QModelIndex partialMatch = qxt_d().lookupPartialMatch(input);
+ if (partialMatch.isValid())
+ input = partialMatch.data(qxt_d().lookupRole).toString();
+
+}
+
+/*!
+ uses stringlist as new validation list
+ if a model was set before it is not deleted
+*/
+void QxtStringValidator::setStringList(const QStringList &stringList)
+{
+ //delete model only if it is a model created by us
+ if (qxt_d().model && !qxt_d().isUserModel)
+ {
+ delete qxt_d().model;
+ qxt_d().model = 0;
+ }
+
+ qxt_d().isUserModel = false;
+ qxt_d().lookupStartModelIndex = QModelIndex();
+ qxt_d().lookupRole = Qt::EditRole;
+ qxt_d().model = new QStringListModel(stringList,this);
+}
+
+/*!
+ Returns Acceptable if the string input matches a item in the stringlist.
+ Returns Intermediate if the string input matches a item in the stringlist partial or if input is empty.
+ Returns Invalid otherwise.
+
+ Note: A partial match means the beginning of the strings are matching:
+ qxtL matches qxtLib but not testqxtLib
+*/
+QValidator::State QxtStringValidator::validate ( QString & input, int & pos ) const
+{
+ Q_UNUSED(pos);
+
+ // no model or a empty model has only Acceptable values (like no validator was set)
+ if (!qxt_d().model)
+ return QValidator::Acceptable;
+
+ if (qxt_d().model->rowCount() == 0)
+ return QValidator::Acceptable;
+
+ if (input.isEmpty())
+ return QValidator::Intermediate;
+
+ if (qxt_d().lookupExactMatch(input).isValid())
+ {
+ qDebug()<<input<<" is QValidator::Acceptable";
+ return QValidator::Acceptable;
+ }
+
+ if (qxt_d().lookupPartialMatch(input).isValid())
+ {
+ qDebug()<<input<<" is QValidator::Intermediate";
+ return QValidator::Intermediate;
+ }
+
+ qDebug()<<input<<" is QValidator::Invalid";
+ return QValidator::Invalid;
+}
+
+
+/*!
+ Returns the startModelIndex.
+ Note: The return value will only we valid if the user has set the model with setLookupModel().
+ \sa setStartModelIndex()
+*/
+QModelIndex QxtStringValidator::startModelIndex() const
+{
+ if (qxt_d().isUserModel && qxt_d().model)
+ {
+ if (qxt_d().lookupStartModelIndex.isValid())
+ return qxt_d().lookupStartModelIndex;
+ else
+ return qxt_d().model->index(0,0);
+ }
+ return QModelIndex();
+}
+
+/*!
+ Returns if recursive lookup is enabled.
+ \sa setRecursiveLookup()
+*/
+bool QxtStringValidator::recursiveLookup() const
+{
+ if (qxt_d().userFlags & Qt::MatchRecursive)
+ return true;
+ return false;
+}
+
+/*!
+ Returns if wrapping lookup is enabled.
+ \sa setWrappingLookup()
+*/
+bool QxtStringValidator::wrappingLookup() const
+{
+ if (qxt_d().userFlags & Qt::MatchWrap)
+ return true;
+ return false;
+}
+
+/*!
+ Returns the used model if it was set by the user.
+ \sa setLookupModel()
+*/
+QAbstractItemModel * QxtStringValidator::lookupModel() const
+{
+ if (qxt_d().isUserModel)
+ return qxt_d().model;
+ return 0;
+}
+
+/*!
+ Returns Qt::CaseSensitive if the QxtStringValidator is matched case sensitively; otherwise returns Qt::CaseInsensitive.
+ \sa setCaseSensitivity().
+*/
+Qt::CaseSensitivity QxtStringValidator::caseSensitivity () const
+{
+ return qxt_d().cs;
+}
+
+/*!
+ Sets case sensitive matching to cs.
+ If cs is Qt::CaseSensitive, inp matches input but not INPUT.
+ The default is Qt::CaseSensitive.
+ \sa caseSensitivity().
+*/
+void QxtStringValidator::setCaseSensitivity ( Qt::CaseSensitivity caseSensitivity )
+{
+ qxt_d().cs = caseSensitivity;
+}
+
+/*!
+ Sets the index the search should start at
+ The default is QModelIndex(0,0).
+ Note: this is set to default when the model changes.
+ Changing the startModelIndex is only possible if the validator uses a userdefined model
+ and the modelindex comes from the used model
+ \sa startModelIndex()
+*/
+void QxtStringValidator::setStartModelIndex(const QModelIndex &index)
+{
+ if (index.model() == qxt_d().model)
+ qxt_d().lookupStartModelIndex = index;
+ else
+ qWarning()<<"ModelIndex from different model. Ignoring.";
+}
+
+/*!
+ If enabled QxtStringValidator searches the entire hierarchy of the model.
+ This is disabled by default.
+ \sa recursiveLookup()
+*/
+void QxtStringValidator::setRecursiveLookup(bool enable)
+{
+ if (enable)
+ qxt_d().userFlags |= Qt::MatchRecursive;
+ else
+ qxt_d().userFlags &= ~Qt::MatchRecursive;
+
+}
+
+/*!
+ If enabled QxtStringValidator performs a search that wraps around,
+ so that when the search reaches the last item in the model, it begins again at the first item and continues until all items have been examined.
+ This is set by default.
+ \sa wrappingLookup()
+*/
+void QxtStringValidator::setWrappingLookup(bool enable)
+{
+ if (enable)
+ qxt_d().userFlags |= Qt::MatchWrap;
+ else
+ qxt_d().userFlags &= ~Qt::MatchWrap;
+}
+
+/*!
+ Uses model as new validation model.
+ Note: The validator does not take ownership of the model.
+ sa\ lookupModel()
+*/
+void QxtStringValidator::setLookupModel(QAbstractItemModel *model)
+{
+ if (!qxt_d().isUserModel && qxt_d().model)
+ {
+ delete qxt_d().model;
+ qxt_d().model = 0;
+ }
+
+ qxt_d().lookupRole = Qt::EditRole;
+ qxt_d().isUserModel = true;
+ qxt_d().lookupStartModelIndex = QModelIndex();
+ qxt_d().model = QPointer<QAbstractItemModel>(model);
+}
+
+/*!
+ Sets the item role to be used to query the contents of items for validation.
+ Note: this is only possible if the model was set with setLookupModel()
+ This is set to default Value Qt::EditRole when the model changes
+ \sa lookupRole()
+*/
+void QxtStringValidator::setLookupRole(const int role)
+{
+ if (qxt_d().isUserModel)
+ qxt_d().lookupRole = role;
+}
+
+/*!
+ Returns the item role to be used to query the contents of items for validation.
+ \sa setLookupRole()
+*/
+int QxtStringValidator::lookupRole() const
+{
+ return qxt_d().lookupRole;
+}