Imported Upstream version 0.26.0

This commit is contained in:
Bret Curtis 2013-10-17 16:37:22 +02:00
commit 9a2b6c69b6
1398 changed files with 212217 additions and 0 deletions

View file

@ -0,0 +1,445 @@
#include <QTextDecoder>
#include <QTextCodec>
#include <QFileInfo>
#include <QDir>
#include <stdexcept>
#include <components/esm/esmreader.hpp>
#include "esm/esmfile.hpp"
#include "datafilesmodel.hpp"
#include <QDebug>
DataFilesModel::DataFilesModel(QObject *parent) :
QAbstractTableModel(parent)
{
mEncoding = QString("win1252");
}
DataFilesModel::~DataFilesModel()
{
}
void DataFilesModel::setEncoding(const QString &encoding)
{
mEncoding = encoding;
}
void DataFilesModel::setCheckState(const QModelIndex &index, Qt::CheckState state)
{
setData(index, state, Qt::CheckStateRole);
}
Qt::CheckState DataFilesModel::checkState(const QModelIndex &index)
{
EsmFile *file = item(index.row());
return mCheckStates[file->fileName()];
}
int DataFilesModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : 9;
}
int DataFilesModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : mFiles.count();
}
bool DataFilesModel::moveRow(int oldrow, int row, const QModelIndex &parent)
{
if (oldrow < 0 || row < 0 || oldrow == row)
return false;
emit layoutAboutToBeChanged();
//emit beginMoveRows(parent, oldrow, oldrow, parent, row);
mFiles.swap(oldrow, row);
//emit endInsertRows();
emit layoutChanged();
return true;
}
QVariant DataFilesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
EsmFile *file = item(index.row());
if (!file)
return QVariant();
const int column = index.column();
switch (role) {
case Qt::DisplayRole: {
switch (column) {
case 0:
return file->fileName();
case 1:
return file->author();
case 2:
return QString("%1 kB").arg(int((file->size() + 1023) / 1024));
case 3:
//return file->modified().toString(Qt::TextDate);
return file->modified().toString(Qt::ISODate);
case 4:
return file->accessed().toString(Qt::TextDate);
case 5:
return file->version();
case 6:
return file->path();
case 7:
return file->masters().join(", ");
case 8:
return file->description();
}
}
case Qt::TextAlignmentRole: {
switch (column) {
case 0:
case 1:
return Qt::AlignLeft + Qt::AlignVCenter;
case 2:
case 3:
case 4:
case 5:
return Qt::AlignRight + Qt::AlignVCenter;
default:
return Qt::AlignLeft + Qt::AlignVCenter;
}
}
case Qt::CheckStateRole: {
if (column != 0)
return QVariant();
return mCheckStates[file->fileName()];
}
case Qt::ToolTipRole:
{
if (column != 0)
return QVariant();
if (file->version() == 0.0f)
return QVariant(); // Data not set
QString tooltip =
QString("<b>Author:</b> %1<br/> \
<b>Version:</b> %2<br/> \
<br/><b>Description:</b><br/>%3<br/> \
<br/><b>Dependencies: </b>%4<br/>")
.arg(file->author())
.arg(QString::number(file->version()))
.arg(file->description())
.arg(file->masters().join(", "));
return tooltip;
}
default:
return QVariant();
}
}
Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
EsmFile *file = item(index.row());
if (!file)
return Qt::NoItemFlags;
if (canBeChecked(file)) {
if (index.column() == 0) {
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
} else {
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
} else {
if (index.column() == 0) {
return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
} else {
return Qt::NoItemFlags | Qt::ItemIsSelectable;
}
}
}
QVariant DataFilesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case 0: return tr("Name");
case 1: return tr("Author");
case 2: return tr("Size");
case 3: return tr("Modified");
case 4: return tr("Accessed");
case 5: return tr("Version");
case 6: return tr("Path");
case 7: return tr("Masters");
case 8: return tr("Description");
}
} else {
// Show row numbers
return ++section;
}
return QVariant();
}
bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
if (role == Qt::CheckStateRole) {
QString name = item(index.row())->fileName();
mCheckStates[name] = static_cast<Qt::CheckState>(value.toInt());
// Force a redraw of the view since unchecking one item can affect another
QModelIndex firstIndex = indexFromItem(mFiles.first());
QModelIndex lastIndex = indexFromItem(mFiles.last());
emit dataChanged(firstIndex, lastIndex);
emit checkedItemsChanged(checkedItems());
return true;
}
return false;
}
bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2)
{
//Masters first then alphabetically
if (e1->fileName().endsWith(".esm") && !e2->fileName().endsWith(".esm"))
return true;
if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm"))
return false;
return e1->fileName().toLower() < e2->fileName().toLower();
}
bool lessThanDate(const EsmFile *e1, const EsmFile *e2)
{
if (e1->modified().toString(Qt::ISODate) < e2->modified().toString(Qt::ISODate)) {
return true;
} else {
return false;
}
}
void DataFilesModel::sort(int column, Qt::SortOrder order)
{
emit layoutAboutToBeChanged();
if (column == 3) {
qSort(mFiles.begin(), mFiles.end(), lessThanDate);
} else {
qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile);
}
emit layoutChanged();
}
void DataFilesModel::addFile(EsmFile *file)
{
emit beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count());
mFiles.append(file);
emit endInsertRows();
}
void DataFilesModel::addFiles(const QString &path)
{
QDir dir(path);
QStringList filters;
filters << "*.esp" << "*.esm";
dir.setNameFilters(filters);
// Create a decoder for non-latin characters in esx metadata
QTextCodec *codec;
if (mEncoding == QLatin1String("win1252")) {
codec = QTextCodec::codecForName("windows-1252");
} else if (mEncoding == QLatin1String("win1251")) {
codec = QTextCodec::codecForName("windows-1251");
} else if (mEncoding == QLatin1String("win1250")) {
codec = QTextCodec::codecForName("windows-1250");
} else {
return; // This should never happen;
}
QTextDecoder *decoder = codec->makeDecoder();
foreach (const QString &path, dir.entryList()) {
QFileInfo info(dir.absoluteFilePath(path));
EsmFile *file = new EsmFile(path);
try {
ESM::ESMReader fileReader;
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString()));
fileReader.setEncoder(&encoder);
fileReader.open(dir.absoluteFilePath(path).toStdString());
std::vector<ESM::Header::MasterData> mlist = fileReader.getMasters();
QStringList masters;
for (unsigned int i = 0; i < mlist.size(); ++i) {
QString master = QString::fromStdString(mlist[i].name);
masters.append(master);
}
file->setAuthor(decoder->toUnicode(fileReader.getAuthor().c_str()));
file->setSize(info.size());
file->setDates(info.lastModified(), info.lastRead());
file->setVersion(fileReader.getFVer());
file->setPath(info.absoluteFilePath());
file->setMasters(masters);
file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str()));
// Put the file in the table
if (findItem(path) == 0)
addFile(file);
} catch(std::runtime_error &e) {
// An error occurred while reading the .esp
qWarning() << "Error reading esp: " << e.what();
continue;
}
}
delete decoder;
}
QModelIndex DataFilesModel::indexFromItem(EsmFile *item) const
{
if (item)
return createIndex(mFiles.indexOf(item), 0);
return QModelIndex();
}
EsmFile* DataFilesModel::findItem(const QString &name)
{
QList<EsmFile *>::ConstIterator it;
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
int i = 0;
for (it = mFiles.constBegin(); it != itEnd; ++it) {
EsmFile *file = item(i);
++i;
if (name == file->fileName())
return file;
}
// Not found
return 0;
}
EsmFile* DataFilesModel::item(int row) const
{
if (row >= 0 && row < mFiles.count())
return mFiles.at(row);
else
return 0;
}
QStringList DataFilesModel::checkedItems()
{
QStringList list;
QList<EsmFile *>::ConstIterator it;
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
int i = 0;
for (it = mFiles.constBegin(); it != itEnd; ++it) {
EsmFile *file = item(i);
++i;
QString name = file->fileName();
// Only add the items that are in the checked list and available
if (mCheckStates[name] == Qt::Checked && canBeChecked(file))
list << name;
}
return list;
}
QStringList DataFilesModel::checkedItemsPaths()
{
QStringList list;
QList<EsmFile *>::ConstIterator it;
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
int i = 0;
for (it = mFiles.constBegin(); it != itEnd; ++it) {
EsmFile *file = item(i);
++i;
if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file))
list << file->path();
}
return list;
}
void DataFilesModel::uncheckAll()
{
emit layoutAboutToBeChanged();
mCheckStates.clear();
emit layoutChanged();
}
QStringList DataFilesModel::uncheckedItems()
{
QStringList list;
QStringList checked = checkedItems();
QList<EsmFile *>::ConstIterator it;
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
int i = 0;
for (it = mFiles.constBegin(); it != itEnd; ++it) {
EsmFile *file = item(i);
++i;
// Add the items that are not in the checked list
if (!checked.contains(file->fileName()))
list << file->fileName();
}
return list;
}
bool DataFilesModel::canBeChecked(EsmFile *file) const
{
//element can be checked if all its dependencies are
bool canBeChecked = true;
foreach (const QString &master, file->masters())
{
if (!mCheckStates.contains(master) || mCheckStates[master] != Qt::Checked)
{
canBeChecked = false;
break;
}
}
return canBeChecked;
}

View file

@ -0,0 +1,66 @@
#ifndef DATAFILESMODEL_HPP
#define DATAFILESMODEL_HPP
#include <QAbstractTableModel>
#include <QStringList>
#include <QString>
#include <QHash>
class EsmFile;
class DataFilesModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit DataFilesModel(QObject *parent = 0);
virtual ~DataFilesModel();
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
bool moveRow(int oldrow, int row, const QModelIndex &parent = QModelIndex());
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
inline QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
{ return QAbstractTableModel::index(row, column, parent); }
void setEncoding(const QString &encoding);
void addFiles(const QString &path);
void uncheckAll();
QStringList checkedItems();
QStringList uncheckedItems();
QStringList checkedItemsPaths();
Qt::CheckState checkState(const QModelIndex &index);
void setCheckState(const QModelIndex &index, Qt::CheckState state);
QModelIndex indexFromItem(EsmFile *item) const;
EsmFile* findItem(const QString &name);
EsmFile* item(int row) const;
signals:
void checkedItemsChanged(const QStringList &items);
private:
bool canBeChecked(EsmFile *file) const;
void addFile(EsmFile *file);
QList<EsmFile *> mFiles;
QHash<QString, Qt::CheckState> mCheckStates;
QString mEncoding;
};
#endif // DATAFILESMODEL_HPP

View file

@ -0,0 +1,50 @@
#include "esmfile.hpp"
EsmFile::EsmFile(QString fileName, ModelItem *parent)
: ModelItem(parent)
{
mFileName = fileName;
mSize = 0;
mVersion = 0.0f;
}
void EsmFile::setFileName(const QString &fileName)
{
mFileName = fileName;
}
void EsmFile::setAuthor(const QString &author)
{
mAuthor = author;
}
void EsmFile::setSize(const int size)
{
mSize = size;
}
void EsmFile::setDates(const QDateTime &modified, const QDateTime &accessed)
{
mModified = modified;
mAccessed = accessed;
}
void EsmFile::setVersion(float version)
{
mVersion = version;
}
void EsmFile::setPath(const QString &path)
{
mPath = path;
}
void EsmFile::setMasters(const QStringList &masters)
{
mMasters = masters;
}
void EsmFile::setDescription(const QString &description)
{
mDescription = description;
}

View file

@ -0,0 +1,54 @@
#ifndef ESMFILE_HPP
#define ESMFILE_HPP
#include <QDateTime>
#include <QStringList>
#include "../modelitem.hpp"
class EsmFile : public ModelItem
{
Q_OBJECT
Q_PROPERTY(QString filename READ fileName)
public:
EsmFile(QString fileName = QString(), ModelItem *parent = 0);
~EsmFile()
{}
void setFileName(const QString &fileName);
void setAuthor(const QString &author);
void setSize(const int size);
void setDates(const QDateTime &modified, const QDateTime &accessed);
void setVersion(const float version);
void setPath(const QString &path);
void setMasters(const QStringList &masters);
void setDescription(const QString &description);
inline QString fileName() const { return mFileName; }
inline QString author() const { return mAuthor; }
inline int size() const { return mSize; }
inline QDateTime modified() const { return mModified; }
inline QDateTime accessed() const { return mAccessed; }
inline float version() const { return mVersion; }
inline QString path() const { return mPath; }
inline QStringList masters() const { return mMasters; }
inline QString description() const { return mDescription; }
private:
QString mFileName;
QString mAuthor;
int mSize;
QDateTime mModified;
QDateTime mAccessed;
float mVersion;
QString mPath;
QStringList mMasters;
QString mDescription;
};
#endif

View file

@ -0,0 +1,57 @@
#include "modelitem.hpp"
ModelItem::ModelItem(ModelItem *parent)
: mParentItem(parent)
, QObject(parent)
{
}
ModelItem::~ModelItem()
{
qDeleteAll(mChildItems);
}
ModelItem *ModelItem::parent()
{
return mParentItem;
}
int ModelItem::row() const
{
if (mParentItem)
return 1;
//return mParentItem->childRow(const_cast<ModelItem*>(this));
//return mParentItem->mChildItems.indexOf(const_cast<ModelItem*>(this));
return -1;
}
int ModelItem::childCount() const
{
return mChildItems.count();
}
int ModelItem::childRow(ModelItem *child) const
{
Q_ASSERT(child);
return mChildItems.indexOf(child);
}
ModelItem *ModelItem::child(int row)
{
return mChildItems.value(row);
}
void ModelItem::appendChild(ModelItem *item)
{
mChildItems.append(item);
}
void ModelItem::removeChild(int row)
{
mChildItems.removeAt(row);
}

View file

@ -0,0 +1,32 @@
#ifndef MODELITEM_HPP
#define MODELITEM_HPP
#include <QObject>
#include <QList>
class ModelItem : public QObject
{
Q_OBJECT
public:
ModelItem(ModelItem *parent = 0);
~ModelItem();
ModelItem *parent();
int row() const;
int childCount() const;
int childRow(ModelItem *child) const;
ModelItem *child(int row);
void appendChild(ModelItem *child);
void removeChild(int row);
//virtual bool acceptChild(ModelItem *child);
protected:
ModelItem *mParentItem;
QList<ModelItem*> mChildItems;
};
#endif

View file

@ -0,0 +1,17 @@
#include "pluginsproxymodel.hpp"
PluginsProxyModel::PluginsProxyModel(QObject *parent) :
QSortFilterProxyModel(parent)
{
}
PluginsProxyModel::~PluginsProxyModel()
{
}
QVariant PluginsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Vertical || role != Qt::DisplayRole)
return QSortFilterProxyModel::headerData(section, orientation, role);
return section + 1;
}

View file

@ -0,0 +1,18 @@
#ifndef PLUGINSPROXYMODEL_HPP
#define PLUGINSPROXYMODEL_HPP
#include <QSortFilterProxyModel>
class QVariant;
class PluginsProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit PluginsProxyModel(QObject *parent = 0);
~PluginsProxyModel();
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
};
#endif // PLUGINSPROXYMODEL_HPP

View file

@ -0,0 +1,35 @@
#include <QToolButton>
#include <QStyle>
#include "comboboxlineedit.hpp"
ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent)
: QLineEdit(parent)
{
mClearButton = new QToolButton(this);
QPixmap pixmap(":images/clear.png");
mClearButton->setIcon(QIcon(pixmap));
mClearButton->setIconSize(pixmap.size());
mClearButton->setCursor(Qt::ArrowCursor);
mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }");
mClearButton->hide();
connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear()));
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&)));
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
setObjectName(QString("ComboBoxLineEdit"));
setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
}
void ComboBoxLineEdit::resizeEvent(QResizeEvent *)
{
QSize sz = mClearButton->sizeHint();
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
mClearButton->move(rect().right() - frameWidth - sz.width(),
(rect().bottom() + 1 - sz.height())/2);
}
void ComboBoxLineEdit::updateClearButton(const QString& text)
{
mClearButton->setVisible(!text.isEmpty());
}

View file

@ -0,0 +1,35 @@
/****************************************************************************
**
** Copyright (c) 2007 Trolltech ASA <info@trolltech.com>
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#ifndef LINEEDIT_H
#define LINEEDIT_H
#include <QLineEdit>
class QToolButton;
class ComboBoxLineEdit : public QLineEdit
{
Q_OBJECT
public:
ComboBoxLineEdit(QWidget *parent = 0);
protected:
void resizeEvent(QResizeEvent *);
private slots:
void updateClearButton(const QString &text);
private:
QToolButton *mClearButton;
};
#endif // LIENEDIT_H

View file

@ -0,0 +1,38 @@
#include <QToolButton>
#include <QStyle>
#include "lineedit.hpp"
LineEdit::LineEdit(QWidget *parent)
: QLineEdit(parent)
{
mClearButton = new QToolButton(this);
QPixmap pixmap(":images/clear.png");
mClearButton->setIcon(QIcon(pixmap));
mClearButton->setIconSize(pixmap.size());
mClearButton->setCursor(Qt::ArrowCursor);
mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }");
mClearButton->hide();
connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear()));
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&)));
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
setObjectName(QString("LineEdit"));
setStyleSheet(QString("LineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
QSize msz = minimumSizeHint();
setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2),
qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2));
}
void LineEdit::resizeEvent(QResizeEvent *)
{
QSize sz = mClearButton->sizeHint();
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
mClearButton->move(rect().right() - frameWidth - sz.width(),
(rect().bottom() + 1 - sz.height())/2);
}
void LineEdit::updateClearButton(const QString& text)
{
mClearButton->setVisible(!text.isEmpty());
}

View file

@ -0,0 +1,35 @@
/****************************************************************************
**
** Copyright (c) 2007 Trolltech ASA <info@trolltech.com>
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#ifndef LINEEDIT_H
#define LINEEDIT_H
#include <QLineEdit>
class QToolButton;
class LineEdit : public QLineEdit
{
Q_OBJECT
public:
LineEdit(QWidget *parent = 0);
protected:
void resizeEvent(QResizeEvent *);
private slots:
void updateClearButton(const QString &text);
private:
QToolButton *mClearButton;
};
#endif // LIENEDIT_H

View file

@ -0,0 +1,105 @@
/*
* This file contains code found in the QtGui module of the Qt Toolkit.
* See Qt's qfilesystemmodel source files for more information
*/
#include "naturalsort.hpp"
static inline QChar getNextChar(const QString &s, int location)
{
return (location < s.length()) ? s.at(location) : QChar();
}
/*!
* Natural number sort, skips spaces.
*
* Examples:
* 1, 2, 10, 55, 100
* 01.jpg, 2.jpg, 10.jpg
*
* Note on the algorithm:
* Only as many characters as necessary are looked at and at most they all
* are looked at once.
*
* Slower then QString::compare() (of course)
*/
int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs)
{
for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) {
// skip spaces, tabs and 0's
QChar c1 = getNextChar(s1, l1);
while (c1.isSpace())
c1 = getNextChar(s1, ++l1);
QChar c2 = getNextChar(s2, l2);
while (c2.isSpace())
c2 = getNextChar(s2, ++l2);
if (c1.isDigit() && c2.isDigit()) {
while (c1.digitValue() == 0)
c1 = getNextChar(s1, ++l1);
while (c2.digitValue() == 0)
c2 = getNextChar(s2, ++l2);
int lookAheadLocation1 = l1;
int lookAheadLocation2 = l2;
int currentReturnValue = 0;
// find the last digit, setting currentReturnValue as we go if it isn't equal
for (
QChar lookAhead1 = c1, lookAhead2 = c2;
(lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
lookAhead1 = getNextChar(s1, ++lookAheadLocation1),
lookAhead2 = getNextChar(s2, ++lookAheadLocation2)
) {
bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
if (!is1ADigit && !is2ADigit)
break;
if (!is1ADigit)
return -1;
if (!is2ADigit)
return 1;
if (currentReturnValue == 0) {
if (lookAhead1 < lookAhead2) {
currentReturnValue = -1;
} else if (lookAhead1 > lookAhead2) {
currentReturnValue = 1;
}
}
}
if (currentReturnValue != 0)
return currentReturnValue;
}
if (cs == Qt::CaseInsensitive) {
if (!c1.isLower()) c1 = c1.toLower();
if (!c2.isLower()) c2 = c2.toLower();
}
int r = QString::localeAwareCompare(c1, c2);
if (r < 0)
return -1;
if (r > 0)
return 1;
}
// The two strings are the same (02 == 2) so fall back to the normal sort
return QString::compare(s1, s2, cs);
}
bool naturalSortLessThanCS( const QString &left, const QString &right )
{
return (naturalCompare( left, right, Qt::CaseSensitive ) < 0);
}
bool naturalSortLessThanCI( const QString &left, const QString &right )
{
return (naturalCompare( left, right, Qt::CaseInsensitive ) < 0);
}
bool naturalSortGreaterThanCS( const QString &left, const QString &right )
{
return (naturalCompare( left, right, Qt::CaseSensitive ) > 0);
}
bool naturalSortGreaterThanCI( const QString &left, const QString &right )
{
return (naturalCompare( left, right, Qt::CaseInsensitive ) > 0);
}

View file

@ -0,0 +1,11 @@
#ifndef NATURALSORT_H
#define NATURALSORT_H
#include <QString>
bool naturalSortLessThanCS( const QString &left, const QString &right );
bool naturalSortLessThanCI( const QString &left, const QString &right );
bool naturalSortGreaterThanCS( const QString &left, const QString &right );
bool naturalSortGreaterThanCI( const QString &left, const QString &right );
#endif

View file

@ -0,0 +1,92 @@
#include <QRegExpValidator>
#include <QLineEdit>
#include <QString>
#include <QApplication>
#include <QKeyEvent>
#include "profilescombobox.hpp"
#include "comboboxlineedit.hpp"
ProfilesComboBox::ProfilesComboBox(QWidget *parent) :
QComboBox(parent)
{
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
setEditEnabled(true);
setValidator(mValidator);
setCompleter(0);
connect(this, SIGNAL(currentIndexChanged(int)), this,
SLOT(slotIndexChanged(int)));
setInsertPolicy(QComboBox::NoInsert);
}
void ProfilesComboBox::setEditEnabled(bool editable)
{
if (isEditable() == editable)
return;
if (!editable) {
disconnect(lineEdit(), SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
disconnect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString)));
return setEditable(false);
}
// Reset the completer and validator
setEditable(true);
setValidator(mValidator);
ComboBoxLineEdit *edit = new ComboBoxLineEdit(this);
setLineEdit(edit);
setCompleter(0);
connect(lineEdit(), SIGNAL(editingFinished()), this,
SLOT(slotEditingFinished()));
connect(lineEdit(), SIGNAL(textChanged(QString)), this,
SLOT(slotTextChanged(QString)));
}
void ProfilesComboBox::slotTextChanged(const QString &text)
{
QPalette *palette = new QPalette();
palette->setColor(QPalette::Text,Qt::red);
int index = findText(text);
if (text.isEmpty() || (index != -1 && index != currentIndex())) {
lineEdit()->setPalette(*palette);
} else {
lineEdit()->setPalette(QApplication::palette());
}
}
void ProfilesComboBox::slotEditingFinished()
{
QString current = currentText();
QString previous = itemText(currentIndex());
if (currentIndex() == -1)
return;
if (current.isEmpty())
return;
if (current == previous)
return;
if (findText(current) != -1)
return;
setItemText(currentIndex(), current);
emit(profileRenamed(previous, current));
}
void ProfilesComboBox::slotIndexChanged(int index)
{
if (index == -1)
return;
emit(profileChanged(mOldProfile, currentText()));
mOldProfile = itemText(index);
}

View file

@ -0,0 +1,30 @@
#ifndef PROFILESCOMBOBOX_HPP
#define PROFILESCOMBOBOX_HPP
#include <QComboBox>
class QString;
class QRegExpValidator;
class ProfilesComboBox : public QComboBox
{
Q_OBJECT
public:
explicit ProfilesComboBox(QWidget *parent = 0);
void setEditEnabled(bool editable);
signals:
void profileChanged(const QString &previous, const QString &current);
void profileRenamed(const QString &oldName, const QString &newName);
private slots:
void slotEditingFinished();
void slotIndexChanged(int index);
void slotTextChanged(const QString &text);
private:
QString mOldProfile;
QRegExpValidator *mValidator;
};
#endif // PROFILESCOMBOBOX_HPP