From 649ef6f12010b2bbd24521edab214867e14bddcc Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Mon, 2 Sep 2013 11:58:05 +0200
Subject: [PATCH 01/12] moved list of enum literals from ViewManager to Columns
 (which makes them available to the rest of model now)

---
 apps/opencs/model/world/columns.cpp     | 81 ++++++++++++++++++++
 apps/opencs/model/world/columns.hpp     |  6 ++
 apps/opencs/view/doc/viewmanager.cpp    | 99 +++++++------------------
 apps/opencs/view/world/enumdelegate.cpp | 12 +++
 apps/opencs/view/world/enumdelegate.hpp |  3 +
 5 files changed, 129 insertions(+), 72 deletions(-)

diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp
index b20632258..73a58ac82 100644
--- a/apps/opencs/model/world/columns.cpp
+++ b/apps/opencs/model/world/columns.cpp
@@ -196,4 +196,85 @@ int CSMWorld::Columns::getId (const std::string& name)
             return sNames[i].mId;
 
     return -1;
+}
+
+namespace
+{
+    static const char *sSpecialisations[] =
+    {
+        "Combat", "Magic", "Stealth", 0
+    };
+
+    static const char *sAttributes[] =
+    {
+        "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality",
+        "Luck", 0
+    };
+
+    static const char *sSpellTypes[] =
+    {
+        "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
+    };
+
+    static const char *sApparatusTypes[] =
+    {
+        "Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
+    };
+
+    static const char *sArmorTypes[] =
+    {
+        "Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
+        "Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
+    };
+
+    static const char *sClothingTypes[] =
+    {
+        "Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
+        "Amulet", 0
+    };
+
+    static const char *sCreatureTypes[] =
+    {
+        "Creature", "Deadra", "Undead", "Humanoid", 0
+    };
+
+    static const char *sWeaponTypes[] =
+    {
+        "Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
+        "Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
+        "Bolt", 0
+    };
+
+    const char **getEnumNames (CSMWorld::Columns::ColumnId column)
+    {
+        switch (column)
+        {
+            case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations;
+            case CSMWorld::Columns::ColumnId_Attribute: return sAttributes;
+            case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes;
+            case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes;
+            case CSMWorld::Columns::ColumnId_ArmorType: return sArmorTypes;
+            case CSMWorld::Columns::ColumnId_ClothingType: return sClothingTypes;
+            case CSMWorld::Columns::ColumnId_CreatureType: return sCreatureTypes;
+            case CSMWorld::Columns::ColumnId_WeaponType: return sWeaponTypes;
+
+            default: return 0;
+        }
+    }
+}
+
+bool CSMWorld::Columns::hasEnums (ColumnId column)
+{
+    return getEnumNames (column)!=0;
+}
+
+std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
+{
+    std::vector<std::string> enums;
+
+    if (const char **table = getEnumNames (column))
+        for (int i=0; table[i]; ++i)
+            enums.push_back (table[i]);
+
+    return enums;
 }
\ No newline at end of file
diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp
index 9a39e1678..69b20583a 100644
--- a/apps/opencs/model/world/columns.hpp
+++ b/apps/opencs/model/world/columns.hpp
@@ -2,6 +2,7 @@
 #define CSM_WOLRD_COLUMNS_H
 
 #include <string>
+#include <vector>
 
 namespace CSMWorld
 {
@@ -180,6 +181,11 @@ namespace CSMWorld
 
         int getId (const std::string& name);
         ///< Will return -1 for an invalid name.
+
+        bool hasEnums (ColumnId column);
+
+        std::vector<std::string> getEnums (ColumnId column);
+        ///< Returns an empty vector, if \æ column isn't an enum type column.
     }
 }
 
diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp
index 6d06e4248..7c7c0f28b 100644
--- a/apps/opencs/view/doc/viewmanager.cpp
+++ b/apps/opencs/view/doc/viewmanager.cpp
@@ -8,6 +8,7 @@
 
 #include "../../model/doc/documentmanager.hpp"
 #include "../../model/doc/document.hpp"
+#include "../../model/world/columns.hpp"
 
 #include "../world/util.hpp"
 #include "../world/enumdelegate.hpp"
@@ -43,51 +44,6 @@ void CSVDoc::ViewManager::updateIndices()
 CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
     : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false)
 {
-    static const char *sSpecialisations[] =
-    {
-        "Combat", "Magic", "Stealth", 0
-    };
-
-    static const char *sAttributes[] =
-    {
-        "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality",
-        "Luck", 0
-    };
-
-    static const char *sSpellTypes[] =
-    {
-        "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
-    };
-
-    static const char *sApparatusTypes[] =
-    {
-        "Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
-    };
-
-    static const char *sArmorTypes[] =
-    {
-        "Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
-        "Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
-    };
-
-    static const char *sClothingTypes[] =
-    {
-        "Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
-        "Amulet", 0
-    };
-
-    static const char *sCreatureTypes[] =
-    {
-        "Creature", "Deadra", "Undead", "Humanoid", 0
-    };
-
-    static const char *sWeaponTypes[] =
-    {
-        "Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
-        "Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
-        "Bolt", 0
-    };
-
     mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
 
     mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
@@ -96,38 +52,37 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
     mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
         new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
 
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation,
-        new CSVWorld::EnumDelegateFactory (sSpecialisations));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute,
-        new CSVWorld::EnumDelegateFactory (sAttributes, true));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType,
-        new CSVWorld::EnumDelegateFactory (sSpellTypes));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_ApparatusType,
-        new CSVWorld::EnumDelegateFactory (sApparatusTypes));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_ArmorType,
-        new CSVWorld::EnumDelegateFactory (sArmorTypes));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_ClothingType,
-        new CSVWorld::EnumDelegateFactory (sClothingTypes));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_CreatureType,
-        new CSVWorld::EnumDelegateFactory (sCreatureTypes));
-
-    mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType,
-        new CSVWorld::EnumDelegateFactory (sWeaponTypes));
-
     mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState,
-        new CSVWorld::RecordStatusDelegateFactory() );
+        new CSVWorld::RecordStatusDelegateFactory());
 
     mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
-        new CSVWorld::RefIdTypeDelegateFactory() );
+        new CSVWorld::RefIdTypeDelegateFactory());
+
+    struct Mapping
+    {
+        CSMWorld::ColumnBase::Display mDisplay;
+        CSMWorld::Columns::ColumnId mColumnId;
+        bool mAllowNone;
+    };
+
+    static const Mapping sMapping[] =
+    {
+        { CSMWorld::ColumnBase::Display_Specialisation, CSMWorld::Columns::ColumnId_Specialisation, false },
+        { CSMWorld::ColumnBase::Display_Attribute, CSMWorld::Columns::ColumnId_Attribute, true },
+        { CSMWorld::ColumnBase::Display_SpellType, CSMWorld::Columns::ColumnId_SpellType, false },
+        { CSMWorld::ColumnBase::Display_ApparatusType, CSMWorld::Columns::ColumnId_ApparatusType, false },
+        { CSMWorld::ColumnBase::Display_ArmorType, CSMWorld::Columns::ColumnId_ArmorType, false },
+        { CSMWorld::ColumnBase::Display_ClothingType, CSMWorld::Columns::ColumnId_ClothingType, false },
+        { CSMWorld::ColumnBase::Display_CreatureType, CSMWorld::Columns::ColumnId_CreatureType, false },
+        { CSMWorld::ColumnBase::Display_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false }
+    };
+
+    for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
+        mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory (
+            CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone));
 
     connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
-             this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
+        this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
 }
 
 CSVDoc::ViewManager::~ViewManager()
diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp
index dd194abe9..fc9b7ee3b 100644
--- a/apps/opencs/view/world/enumdelegate.cpp
+++ b/apps/opencs/view/world/enumdelegate.cpp
@@ -109,6 +109,18 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool all
         add (i, names[i]);
 }
 
+CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::string>& names,
+    bool allowNone)
+{
+    if (allowNone)
+        add (-1, "");
+
+    int size = static_cast<int> (names.size());
+
+    for (int i=0; i<size; ++i)
+        add (i, names[i].c_str());
+}
+
 CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack,
     QObject *parent) const
 {
diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp
index b79516a09..606f9278a 100644
--- a/apps/opencs/view/world/enumdelegate.hpp
+++ b/apps/opencs/view/world/enumdelegate.hpp
@@ -54,6 +54,9 @@ namespace CSVWorld
             ///< \param names Array of char pointer with a 0-pointer as end mark
             /// \param allowNone Use value of -1 for "none selected" (empty string)
 
+            EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
+            /// \param allowNone Use value of -1 for "none selected" (empty string)
+
             virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
             ///< The ownership of the returned CommandDelegate is transferred to the caller.
 

From 9cb121bd049d2ce381f80a3c0c2165d5093933c2 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Mon, 2 Sep 2013 12:23:19 +0200
Subject: [PATCH 02/12] allow specifying enums as text in filters

---
 apps/opencs/model/filter/textnode.cpp | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp
index 9987c66d2..a826a2d54 100644
--- a/apps/opencs/model/filter/textnode.cpp
+++ b/apps/opencs/model/filter/textnode.cpp
@@ -28,13 +28,30 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row,
 
     QVariant data = table.data (index);
 
-    if (data.type()!=QVariant::String)
+    QString string;
+
+    if (data.type()==QVariant::String)
+    {
+        string = data.toString();
+    }
+    else if (data.type()==QVariant::Int || data.type()==QVariant::UInt ||
+        CSMWorld::Columns::hasEnums (static_cast<CSMWorld::Columns::ColumnId> (mColumnId)))
+    {
+        int value = data.toInt();
+
+        std::vector<std::string> enums =
+            CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mColumnId));
+
+        if (value>=0 && value<static_cast<int> (enums.size()))
+            string = QString::fromUtf8 (enums[value].c_str());
+    }
+    else
         return false;
 
     /// \todo make pattern syntax configurable
     QRegExp regExp (QString::fromUtf8 (mText.c_str()), Qt::CaseInsensitive);
 
-    return regExp.exactMatch (data.toString());
+    return regExp.exactMatch (string);
 }
 
 std::vector<int> CSMFilter::TextNode::getReferencedColumns() const

From 1744a64f77ac1740df6338d4657b66c15dd5fd11 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Tue, 3 Sep 2013 12:32:06 +0200
Subject: [PATCH 03/12] in filters allow specifiying boolean columns as strings

---
 apps/opencs/model/filter/parser.cpp   | 2 +-
 apps/opencs/model/filter/textnode.cpp | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp
index d334a7f63..15cdbfce2 100644
--- a/apps/opencs/model/filter/parser.cpp
+++ b/apps/opencs/model/filter/parser.cpp
@@ -120,7 +120,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken()
         }
 
         if (string[0]=='"')
-            string = string.substr (1, string.size()-2);
+            return string.substr (1, string.size()-2);
     }
 
     return checkKeywords (string);
diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp
index a826a2d54..f3d98ce53 100644
--- a/apps/opencs/model/filter/textnode.cpp
+++ b/apps/opencs/model/filter/textnode.cpp
@@ -45,6 +45,10 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row,
         if (value>=0 && value<static_cast<int> (enums.size()))
             string = QString::fromUtf8 (enums[value].c_str());
     }
+    else if (data.type()==QVariant::Bool)
+    {
+        string = data.toBool() ? "true" : " false";
+    }
     else
         return false;
 

From f80373a8494cf0720a192ff634aee98842f2e2d1 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Tue, 3 Sep 2013 12:53:45 +0200
Subject: [PATCH 04/12] removed two unused files

---
 .../view/world/refrecordtypedelegate.cpp      | 25 --------
 .../view/world/refrecordtypedelegate.hpp      | 58 -------------------
 2 files changed, 83 deletions(-)
 delete mode 100644 apps/opencs/view/world/refrecordtypedelegate.cpp
 delete mode 100644 apps/opencs/view/world/refrecordtypedelegate.hpp

diff --git a/apps/opencs/view/world/refrecordtypedelegate.cpp b/apps/opencs/view/world/refrecordtypedelegate.cpp
deleted file mode 100644
index 2bcb7ca50..000000000
--- a/apps/opencs/view/world/refrecordtypedelegate.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "refrecordtypedelegate.hpp"
-#include "../../model/world/universalid.hpp"
-
-CSVWorld::RefRecordTypeDelegate::RefRecordTypeDelegate
-    (const std::vector<std::pair<int, QString> > &values, QUndoStack& undoStack, QObject *parent)
-        : EnumDelegate (values, undoStack, parent)
-{}
-
-CSVWorld::RefRecordTypeDelegateFactory::RefRecordTypeDelegateFactory()
-{
-    unsigned int argSize = CSMWorld::UniversalId::getIdArgSize();
-
-    for (unsigned int i = 0; i < argSize; i++)
-    {
-        std::pair<int, const char *> idPair = CSMWorld::UniversalId::getIdArgPair(i);
-
-        mValues.push_back (std::pair<int, QString>(idPair.first, QString::fromUtf8(idPair.second)));
-    }
-}
-
-CSVWorld::CommandDelegate *CSVWorld::RefRecordTypeDelegateFactory::makeDelegate (QUndoStack& undoStack,
-    QObject *parent) const
-{
-    return new RefRecordTypeDelegate (mValues, undoStack, parent);
-}
diff --git a/apps/opencs/view/world/refrecordtypedelegate.hpp b/apps/opencs/view/world/refrecordtypedelegate.hpp
deleted file mode 100644
index baec2cc2e..000000000
--- a/apps/opencs/view/world/refrecordtypedelegate.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef REFRECORDTYPEDELEGATE_HPP
-#define REFRECORDTYPEDELEGATE_HPP
-
-#include "enumdelegate.hpp"
-#include "util.hpp"
-
-namespace CSVWorld
-{
-    class RefRecordTypeDelegate : public EnumDelegate
-    {
-        public:
-            RefRecordTypeDelegate (const std::vector<std::pair<int, QString> > &mValues, QUndoStack& undoStack, QObject *parent);
-    };
-
-    class RefRecordTypeDelegateFactory : public CommandDelegateFactory
-    {
-
-        std::vector<std::pair<int, QString> > mValues;
-
-        public:
-            RefRecordTypeDelegateFactory();
-
-            virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
-            ///< The ownership of the returned CommandDelegate is transferred to the caller.
-    };
-}
-/*
-    class VarTypeDelegate : public EnumDelegate
-    {
-        private:
-
-            virtual void addCommands (QAbstractItemModel *model,
-                const QModelIndex& index, int type) const;
-
-        public:
-
-            VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
-                QUndoStack& undoStack, QObject *parent);
-    };
-
-    class VarTypeDelegateFactory : public CommandDelegateFactory
-    {
-            std::vector<std::pair<int, QString> > mValues;
-
-        public:
-
-            VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown,
-                ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown,
-                ESM::VarType type3 = ESM::VT_Unknown);
-
-            virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
-            ///< The ownership of the returned CommandDelegate is transferred to the caller.
-
-            void add (ESM::VarType type);
-    };
-*/
-
-#endif // REFRECORDTYPEDELEGATE_HPP

From 80f8024da790b8f2490c037df317f8308fbc0f93 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Tue, 3 Sep 2013 13:03:02 +0200
Subject: [PATCH 05/12] allow specifying record modification status column enum
 via strings

---
 apps/opencs/model/world/columns.cpp            |  6 ++++++
 .../opencs/view/world/recordstatusdelegate.cpp | 18 +++++++++++++-----
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp
index 73a58ac82..2a47a73fb 100644
--- a/apps/opencs/model/world/columns.cpp
+++ b/apps/opencs/model/world/columns.cpp
@@ -245,6 +245,11 @@ namespace
         "Bolt", 0
     };
 
+    static const char *sModificationEnums[] =
+    {
+        "Base", "Modified", "Added", "Deleted", "Deleted", 0
+    };
+
     const char **getEnumNames (CSMWorld::Columns::ColumnId column)
     {
         switch (column)
@@ -257,6 +262,7 @@ namespace
             case CSMWorld::Columns::ColumnId_ClothingType: return sClothingTypes;
             case CSMWorld::Columns::ColumnId_CreatureType: return sCreatureTypes;
             case CSMWorld::Columns::ColumnId_WeaponType: return sWeaponTypes;
+            case CSMWorld::Columns::ColumnId_Modification: return sModificationEnums;
 
             default: return 0;
         }
diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp
index a0ffd3063..8085ec7be 100644
--- a/apps/opencs/view/world/recordstatusdelegate.cpp
+++ b/apps/opencs/view/world/recordstatusdelegate.cpp
@@ -1,8 +1,11 @@
 #include "recordstatusdelegate.hpp"
+
 #include <QPainter>
 #include <QApplication>
 #include <QUndoStack>
+
 #include "../../model/settings/usersettings.hpp"
+#include "../../model/world/columns.hpp"
 
 CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
                                                      const IconList & icons,
@@ -37,9 +40,14 @@ bool CSVWorld::RecordStatusDelegate::updateEditorSetting (const QString &setting
 
 CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()
 {
-    DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_BaseOnly,     "Base",     ":./base.png");
-    DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Deleted,      "Deleted",  ":./removed.png");
-    DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Erased,       "Deleted",  ":./removed.png");
-    DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Modified,     "Modified", ":./modified.png");
-    DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_ModifiedOnly, "Added",    ":./added.png");
+    std::vector<std::string> enums =
+        CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification);
+
+    static const char *sIcons[] =
+    {
+        ":./base.png", ":./modified.png", ":./added.png", ":./removed.png", ":./removed.png", 0
+    };
+
+    for (int i=0; sIcons[i]; ++i)
+        add (i, enums.at (i).c_str(), sIcons[i]);
 }

From 842a616909fee9e1c79d78789125e629d095354f Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Tue, 3 Sep 2013 14:18:34 +0200
Subject: [PATCH 06/12] more cleanup

---
 apps/opencs/model/world/universalid.cpp      | 21 ----------
 apps/opencs/model/world/universalid.hpp      |  3 --
 apps/opencs/view/world/refidtypedelegate.cpp | 40 ++++++++++----------
 3 files changed, 21 insertions(+), 43 deletions(-)

diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp
index 42ebd1f80..1cc4ca3c4 100644
--- a/apps/opencs/model/world/universalid.cpp
+++ b/apps/opencs/model/world/universalid.cpp
@@ -90,8 +90,6 @@ namespace
 
         { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
     };
-
-    static const unsigned int IDARG_SIZE = sizeof (sIdArg) / sizeof (TypeData);
 }
 
 CSMWorld::UniversalId::UniversalId (const std::string& universalId)
@@ -293,25 +291,6 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl
     return list;
 }
 
-std::pair<int, const char *> CSMWorld::UniversalId::getIdArgPair (unsigned int index)
-{
-    std::pair<int, const char *> retPair;
-
-    if ( index < IDARG_SIZE )
-    {
-        retPair.first = sIdArg[index].mType;
-        retPair.second = sIdArg[index].mName;
-    }
-
-    return retPair;
-}
-
-unsigned int CSMWorld::UniversalId::getIdArgSize()
-{
-   return IDARG_SIZE;
-}
-
-
 bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
 {
     return left.isEqual (right);
diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp
index 8042c3dfd..341b941e6 100644
--- a/apps/opencs/model/world/universalid.hpp
+++ b/apps/opencs/model/world/universalid.hpp
@@ -134,9 +134,6 @@ namespace CSMWorld
             ///< Will return an empty string, if no icon is available.
 
             static std::vector<Type> listReferenceableTypes();
-
-            static std::pair<int, const char *> getIdArgPair (unsigned int index);
-            static unsigned int getIdArgSize ();
     };
 
     bool operator== (const UniversalId& left, const UniversalId& right);
diff --git a/apps/opencs/view/world/refidtypedelegate.cpp b/apps/opencs/view/world/refidtypedelegate.cpp
index bf3acbb20..7cffbf3dd 100755
--- a/apps/opencs/view/world/refidtypedelegate.cpp
+++ b/apps/opencs/view/world/refidtypedelegate.cpp
@@ -1,4 +1,5 @@
 #include "refidtypedelegate.hpp"
+
 #include "../../model/world/universalid.hpp"
 
 CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate
@@ -6,6 +7,26 @@ CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate
     : DataDisplayDelegate (values, icons, undoStack, parent)
 {}
 
+bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
+{
+    if (settingName == "Referenceable ID Type Display")
+    {
+        if (settingValue == "Icon and Text")
+            mDisplayMode = Mode_IconAndText;
+
+        else if (settingValue == "Icon Only")
+            mDisplayMode = Mode_IconOnly;
+
+        else if (settingValue == "Text Only")
+            mDisplayMode = Mode_TextOnly;
+
+        return true;
+    }
+
+    return false;
+}
+
+
 CSVWorld::RefIdTypeDelegateFactory::RefIdTypeDelegateFactory()
 {
     UidTypeList uIdList = buildUidTypeList();
@@ -39,22 +60,3 @@ CSVWorld::RefIdTypeDelegateFactory::UidTypeList CSVWorld::RefIdTypeDelegateFacto
 
     return list;
 }
-
-bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
-{
-    if (settingName == "Referenceable ID Type Display")
-    {
-        if (settingValue == "Icon and Text")
-            mDisplayMode = Mode_IconAndText;
-
-        else if (settingValue == "Icon Only")
-            mDisplayMode = Mode_IconOnly;
-
-        else if (settingValue == "Text Only")
-            mDisplayMode = Mode_TextOnly;
-
-        return true;
-    }
-
-    return false;
-}

From 8bebe7179cb08cd750eef2020e01a0d3a2dadfc8 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Thu, 5 Sep 2013 13:58:36 +0200
Subject: [PATCH 07/12] some UniversalId fixes

---
 apps/opencs/model/world/universalid.cpp | 18 +++++++++++++++++-
 apps/opencs/model/world/universalid.hpp |  5 +++--
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp
index 1cc4ca3c4..d360fde8f 100644
--- a/apps/opencs/model/world/universalid.cpp
+++ b/apps/opencs/model/world/universalid.cpp
@@ -80,7 +80,7 @@ namespace
         { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
         { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
         { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
-
+        { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", 0 },
         { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
     };
 
@@ -149,6 +149,22 @@ CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_Non
             return;
         }
 
+    for (int i=0; sIdArg[i].mName; ++i)
+        if (type==sIdArg[i].mType)
+        {
+            mArgumentType = ArgumentType_Id;
+            mClass = sIdArg[i].mClass;
+            return;
+        }
+
+    for (int i=0; sIndexArg[i].mName; ++i)
+        if (type==sIndexArg[i].mType)
+        {
+            mArgumentType = ArgumentType_Index;
+            mClass = sIndexArg[i].mClass;
+            return;
+        }
+
     throw std::logic_error ("invalid argument-less UniversalId type");
 }
 
diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp
index 341b941e6..aa0cdacc0 100644
--- a/apps/opencs/model/world/universalid.hpp
+++ b/apps/opencs/model/world/universalid.hpp
@@ -34,7 +34,7 @@ namespace CSMWorld
 
             enum Type
             {
-                Type_None,
+                Type_None = 0,
                 Type_Globals,
                 Type_Global,
                 Type_VerificationResults,
@@ -89,6 +89,8 @@ namespace CSMWorld
                 Type_Filters
             };
 
+            enum { NumberOfTypes = Type_Filters+1 };
+
         private:
 
             Class mClass;
@@ -102,7 +104,6 @@ namespace CSMWorld
             UniversalId (const std::string& universalId);
 
             UniversalId (Type type = Type_None);
-            ///< Using a type for a non-argument-less UniversalId will throw an exception.
 
             UniversalId (Type type, const std::string& id);
             ///< Using a type for a non-ID-argument UniversalId will throw an exception.

From f2e86e860e4100e1c15b6f6eef8850f6e99bcaea Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Thu, 5 Sep 2013 13:59:09 +0200
Subject: [PATCH 08/12] allow the use of record types in string filters

---
 apps/opencs/model/world/columns.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp
index 2a47a73fb..80525b59e 100644
--- a/apps/opencs/model/world/columns.cpp
+++ b/apps/opencs/model/world/columns.cpp
@@ -3,6 +3,8 @@
 
 #include <components/misc/stringops.hpp>
 
+#include "universalid.hpp"
+
 namespace CSMWorld
 {
     namespace Columns
@@ -271,7 +273,7 @@ namespace
 
 bool CSMWorld::Columns::hasEnums (ColumnId column)
 {
-    return getEnumNames (column)!=0;
+    return getEnumNames (column)!=0 || column==ColumnId_RecordType;
 }
 
 std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
@@ -281,6 +283,13 @@ std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
     if (const char **table = getEnumNames (column))
         for (int i=0; table[i]; ++i)
             enums.push_back (table[i]);
+    else if (column==ColumnId_RecordType)
+    {
+        enums.push_back (""); // none
+
+        for (int i=UniversalId::Type_None+1; i<UniversalId::NumberOfTypes; ++i)
+            enums.push_back (UniversalId (static_cast<UniversalId::Type> (i)).getTypeName());
+    }
 
     return enums;
 }
\ No newline at end of file

From 9332684335befac65612392b99a30b6adf5f73df Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Thu, 5 Sep 2013 15:05:49 +0200
Subject: [PATCH 09/12] allow the use of value types in string filters

---
 apps/opencs/model/world/columns.cpp        |  6 +++++
 apps/opencs/view/world/vartypedelegate.cpp | 29 +++++-----------------
 components/esm/variant.hpp                 |  2 +-
 3 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp
index 80525b59e..5616a4a48 100644
--- a/apps/opencs/model/world/columns.cpp
+++ b/apps/opencs/model/world/columns.cpp
@@ -252,6 +252,11 @@ namespace
         "Base", "Modified", "Added", "Deleted", "Deleted", 0
     };
 
+    static const char *sVarTypeEnums[] =
+    {
+        "unknown", "none", "short", "integer", "long", "float", "string", 0
+    };
+
     const char **getEnumNames (CSMWorld::Columns::ColumnId column)
     {
         switch (column)
@@ -265,6 +270,7 @@ namespace
             case CSMWorld::Columns::ColumnId_CreatureType: return sCreatureTypes;
             case CSMWorld::Columns::ColumnId_WeaponType: return sWeaponTypes;
             case CSMWorld::Columns::ColumnId_Modification: return sModificationEnums;
+            case CSMWorld::Columns::ColumnId_ValueType: return sVarTypeEnums;
 
             default: return 0;
         }
diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp
index 72cbaae42..15ce2dbaf 100644
--- a/apps/opencs/view/world/vartypedelegate.cpp
+++ b/apps/opencs/view/world/vartypedelegate.cpp
@@ -4,6 +4,7 @@
 #include <QUndoStack>
 
 #include "../../model/world/commands.hpp"
+#include "../../model/world/columns.hpp"
 
 void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type)
     const
@@ -75,29 +76,11 @@ CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndo
 
 void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
 {
-    struct Name
-    {
-        ESM::VarType mType;
-        const char *mName;
-    };
+    std::vector<std::string> enums =
+        CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_ValueType);
 
-    static const Name sNames[] =
-    {
-        { ESM::VT_None, "empty" },
-        { ESM::VT_Short, "short" },
-        { ESM::VT_Int, "integer" },
-        { ESM::VT_Long, "long" },
-        { ESM::VT_Float, "float" },
-        { ESM::VT_String, "string" },
-        { ESM::VT_Unknown, 0 } // end marker
-    };
+    if (type<0 && type>=enums.size())
+        throw std::logic_error ("Unsupported variable type");
 
-    for (int i=0; sNames[i].mName; ++i)
-        if (sNames[i].mType==type)
-        {
-            mValues.push_back (std::make_pair (type, sNames[i].mName));
-            return;
-        }
-
-    throw std::logic_error ("Unsupported variable type");
+    mValues.push_back (std::make_pair (type, QString::fromUtf8 (enums[type].c_str())));
 }
diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp
index 8c5f3b3d4..2bba60a15 100644
--- a/components/esm/variant.hpp
+++ b/components/esm/variant.hpp
@@ -11,7 +11,7 @@ namespace ESM
 
     enum VarType
     {
-        VT_Unknown,
+        VT_Unknown = 0,
         VT_None,
         VT_Short, // stored as a float, kinda
         VT_Int,

From f3ce9c22a1a6439f3b6bb489cf20658c7934bc0a Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Thu, 5 Sep 2013 15:22:14 +0200
Subject: [PATCH 10/12] rewrote value node to support half-sided intervals
 (meaning infinity or -infinity for the missing half)

---
 apps/opencs/model/filter/parser.cpp    | 12 +++----
 apps/opencs/model/filter/valuenode.cpp | 44 ++++++++++++++++++++------
 apps/opencs/model/filter/valuenode.hpp | 15 +++++++--
 3 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp
index 15cdbfce2..5b1679cdd 100644
--- a/apps/opencs/model/filter/parser.cpp
+++ b/apps/opencs/model/filter/parser.cpp
@@ -437,22 +437,22 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
     // parse value
     double lower = 0;
     double upper = 0;
-    bool min = false;
-    bool max = false;
+    ValueNode::Type lowerType = ValueNode::Type_Open;
+    ValueNode::Type upperType = ValueNode::Type_Open;
 
     token = getNextToken();
 
     if (token.mType==Token::Type_Number)
     {
         // single value
-        min = max = true;
         lower = upper = token.mNumber;
+        lowerType = upperType = ValueNode::Type_Closed;
     }
     else
     {
         // interval
         if (token.mType==Token::Type_OpenSquare)
-            min = true;
+            lowerType = ValueNode::Type_Closed;
         else if (token.mType!=Token::Type_CloseSquare && token.mType!=Token::Type_Open)
         {
             error();
@@ -490,7 +490,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
         token = getNextToken();
 
         if (token.mType==Token::Type_CloseSquare)
-            max = true;
+            upperType = ValueNode::Type_Closed;
         else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close)
         {
             error();
@@ -506,7 +506,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
         return boost::shared_ptr<Node>();
     }
 
-    return boost::shared_ptr<Node> (new ValueNode (columnId, lower, upper, min, max));
+    return boost::shared_ptr<Node> (new ValueNode (columnId, lowerType, upperType, lower, upper));
 }
 
 void CSMFilter::Parser::error()
diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp
index f6cb20e4c..7eeb6beab 100644
--- a/apps/opencs/model/filter/valuenode.cpp
+++ b/apps/opencs/model/filter/valuenode.cpp
@@ -7,10 +7,9 @@
 #include "../world/columns.hpp"
 #include "../world/idtable.hpp"
 
-CSMFilter::ValueNode::ValueNode (int columnId,
-    double lower, double upper, bool min, bool max)
-: mColumnId (columnId), mLower (lower), mUpper (upper), mMin (min), mMax (max)
-{}
+CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType,
+    double lower, double upper)
+: mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){}
 
 bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
     const std::map<int, int>& columns) const
@@ -33,10 +32,21 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
 
     double value = data.toDouble();
 
-    if (mLower==mUpper && mMin && mMax)
-        return value==mLower;
+    switch (mLowerType)
+    {
+        case Type_Closed: if (value<mLower) return false; break;
+        case Type_Open: if (value<=mLower) return false; break;
+        case Type_Infinite: break;
+    }
 
-    return (mMin ? value>=mLower : value>mLower) && (mMax ? value<=mUpper : value<mUpper);
+    switch (mUpperType)
+    {
+        case Type_Closed: if (value>mUpper) return false; break;
+        case Type_Open: if (value>=mUpper) return false; break;
+        case Type_Infinite: break;
+    }
+
+    return true;
 }
 
 std::vector<int> CSMFilter::ValueNode::getReferencedColumns() const
@@ -60,10 +70,26 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const
 
     stream << ", \"";
 
-    if (mLower==mUpper && mMin && mMax)
+    if (mLower==mUpper && mLowerType!=Type_Infinite && mUpperType!=Type_Infinite)
         stream << mLower;
     else
-        stream << (mMin ? "[" : "(") << mLower << ", " << mUpper << (mMax ? "]" : ")");
+    {
+        switch (mLowerType)
+        {
+            case Type_Closed: stream << "[" << mLower; break;
+            case Type_Open: stream << "(" << mLower; break;
+            case Type_Infinite: stream << "("; break;
+        }
+
+        stream << ", ";
+
+        switch (mUpperType)
+        {
+            case Type_Closed: stream << mUpper << "]"; break;
+            case Type_Open: stream << mUpper << ")"; break;
+            case Type_Infinite: stream << ")"; break;
+        }
+    }
 
     stream << ")";
 
diff --git a/apps/opencs/model/filter/valuenode.hpp b/apps/opencs/model/filter/valuenode.hpp
index faaa1e2ff..b1050709d 100644
--- a/apps/opencs/model/filter/valuenode.hpp
+++ b/apps/opencs/model/filter/valuenode.hpp
@@ -7,16 +7,25 @@ namespace CSMFilter
 {
     class ValueNode : public LeafNode
     {
+        public:
+
+            enum Type
+            {
+                Type_Closed, Type_Open, Type_Infinite
+            };
+
+        private:
+
             int mColumnId;
             std::string mText;
             double mLower;
             double mUpper;
-            bool mMin;
-            bool mMax;
+            Type mLowerType;
+            Type mUpperType;
 
         public:
 
-            ValueNode (int columnId, double lower, double upper, bool min, bool max);
+            ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper);
 
             virtual bool test (const CSMWorld::IdTable& table, int row,
                 const std::map<int, int>& columns) const;

From 645b50ef36150f47d799919e5353cddd67670798 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Thu, 5 Sep 2013 15:38:28 +0200
Subject: [PATCH 11/12] added support for half-sided intervals to filter parser

---
 apps/opencs/model/filter/parser.cpp | 42 +++++++++++++++++------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp
index 5b1679cdd..8567e0a95 100644
--- a/apps/opencs/model/filter/parser.cpp
+++ b/apps/opencs/model/filter/parser.cpp
@@ -461,17 +461,23 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
 
         token = getNextToken();
 
-        if (token.mType!=Token::Type_Number)
+        if (token.mType==Token::Type_Number)
         {
-            error();
-            return boost::shared_ptr<Node>();
+            lower = token.mNumber;
+
+            token = getNextToken();
+
+            if (token.mType!=Token::Type_Comma)
+            {
+                error();
+                return boost::shared_ptr<Node>();
+            }
         }
-
-        lower = token.mNumber;
-
-        token = getNextToken();
-
-        if (token.mType!=Token::Type_Comma)
+        else if (token.mType==Token::Type_Comma)
+        {
+            lowerType = ValueNode::Type_Infinite;
+        }
+        else
         {
             error();
             return boost::shared_ptr<Node>();
@@ -479,18 +485,20 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
 
         token = getNextToken();
 
-        if (token.mType!=Token::Type_Number)
+        if (token.mType==Token::Type_Number)
         {
-            error();
-            return boost::shared_ptr<Node>();
+            upper = token.mNumber;
+
+            token = getNextToken();
         }
-
-        upper = token.mNumber;
-
-        token = getNextToken();
+        else
+            upperType = ValueNode::Type_Infinite;
 
         if (token.mType==Token::Type_CloseSquare)
-            upperType = ValueNode::Type_Closed;
+        {
+            if (upperType!=ValueNode::Type_Infinite)
+                upperType = ValueNode::Type_Closed;
+        }
         else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close)
         {
             error();

From 8f0ab29a9f5d9c5d44dcbd5b50e82949e52fbe27 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Thu, 5 Sep 2013 15:47:38 +0200
Subject: [PATCH 12/12] allow the use of keywords for strings without quotation
 marks

---
 apps/opencs/model/filter/parser.cpp | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp
index 8567e0a95..8f4fcb70c 100644
--- a/apps/opencs/model/filter/parser.cpp
+++ b/apps/opencs/model/filter/parser.cpp
@@ -49,19 +49,31 @@ namespace CSMFilter
 
         Token (Type type = Type_None);
 
+        Token (Type type, const std::string& string);
+        ///< Non-string type that can also be interpreted as a string.
+
         Token (const std::string& string);
 
         Token (double number);
 
         operator bool() const;
+
+        bool isString() const;
     };
 
     Token::Token (Type type) : mType (type) {}
 
+    Token::Token (Type type, const std::string& string) : mType (type), mString (string) {}
+
     Token::Token (const std::string& string) : mType (Type_String), mString (string) {}
 
     Token::Token (double number) : mType (Type_Number), mNumber (number) {}
 
+    bool Token::isString() const
+    {
+        return mType==Type_String || mType>=Type_Keyword_True;
+    }
+
     Token::operator bool() const
     {
         return mType!=Type_None;
@@ -182,7 +194,7 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token)
 
     for (int i=0; sKeywords[i]; ++i)
         if (sKeywords[i]==string || (string.size()==1 && sKeywords[i][0]==string[0]))
-            return Token (static_cast<Token::Type> (i+Token::Type_Keyword_True));
+            return Token (static_cast<Token::Type> (i+Token::Type_Keyword_True), token.mString);
 
     return token;
 }
@@ -351,7 +363,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
         if (static_cast<int> (token.mNumber)==token.mNumber)
             columnId = static_cast<int> (token.mNumber);
     }
-    else if (token.mType==Token::Type_String)
+    else if (token.isString())
     {
         columnId = CSMWorld::Columns::getId (token.mString);
     }
@@ -373,7 +385,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
     // parse text pattern
     token = getNextToken();
 
-    if (token.mType!=Token::Type_String)
+    if (!token.isString())
     {
         error();
         return boost::shared_ptr<Node>();
@@ -415,7 +427,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
         if (static_cast<int> (token.mNumber)==token.mNumber)
             columnId = static_cast<int> (token.mNumber);
     }
-    else if (token.mType==Token::Type_String)
+    else if (token.isString())
     {
         columnId = CSMWorld::Columns::getId (token.mString);
     }
@@ -561,6 +573,8 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
 
         return true;
     }
+    // We do not use isString() here, because there could be a pre-defined filter with an ID that is
+    // equal a filter keyword.
     else if (token.mType==Token::Type_String && allowPredefined)
     {
         if (getNextToken()!=Token (Token::Type_EOS))