diff --git a/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml b/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml
index c81c6e31a164380c112b9e67820a050c14273045..87c742be2378129fd2f00d04894aaf0d1c4afcf8 100644
--- a/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml
+++ b/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml
@@ -36,10 +36,18 @@ import widgets 1.0 as Widgets
 
 Item {
     id: exampleBrowserRoot
+    function appendTag(tag) {
+        var tagStr = "tag:" + '"' + tag + '"'
+        if (lineEdit.text == "")
+            lineEdit.text = tagStr
+        else
+            lineEdit.text += " " + tagStr
+    }
+
 
     Rectangle {
-        color:"#f4f4f4"
         id : lineEditRoot
+        color:"#f4f4f4"
         width: parent.width
         height: lineEdit.height + 6
         anchors.bottom: parent.bottom
@@ -50,14 +58,14 @@ Item {
         anchors.rightMargin: scrollArea.verticalScrollBar.visible ? 0 : -8
 
         Widgets.LineEdit {
+            id: lineEdit
             placeholderText: !checkBox.checked ? qsTr("Search in Tutorials") : qsTr("Search in Tutorials, Examples and Demos")
             focus: true
-            id: lineEdit
             anchors.left: parent.left
             anchors.leftMargin:4
             anchors.verticalCenter: parent.verticalCenter
             width: Math.max(lineEditRoot.width - checkBox.width - 28 - tagFilterButton.width, 100)
-            onTextChanged: examplesModel.filterRegExp = RegExp('.*'+text, "im")
+            onTextChanged: examplesModel.parseSearchString(text)
         }
 
         CheckBox {
@@ -74,12 +82,12 @@ Item {
         Button {
             id: tagFilterButton
             property string tag
-            onTagChanged: { examplesModel.filterTag = tag; examplesModel.updateFilter() }
+            onTagChanged: exampleBrowserRoot.appendTag(tag)
             anchors.left: checkBox.right
             anchors.leftMargin: 6
             anchors.verticalCenter: lineEdit.verticalCenter
             visible: !examplesModel.showTutorialsOnly
-            text: tag === "" ? qsTr("Filter by Tag") : qsTr("Tag Filter: %1").arg(tag)
+            text: qsTr("Tag List")
             onClicked: {
                 tagBrowserLoader.source = "TagBrowser.qml"
                 tagBrowserLoader.item.visible = true
@@ -96,7 +104,7 @@ Item {
             Repeater {
                 id: repeater
                 model: examplesModel
-                delegate: ExampleDelegate { width: scrollArea.width }
+                delegate: ExampleDelegate { width: scrollArea.width; onTagClicked: exampleBrowserRoot.appendTag(tag) }
             }
         }
         Component.onCompleted: verticalScrollBar.anchors.bottomMargin = -(scrollArea.anchors.bottomMargin + 8)
diff --git a/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml b/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml
index 8aa5d48893ccfaecb59c5393d19a6bfc72a7d48a..21106ca15e5df741ae346d286e2ffb829b8eb90b 100644
--- a/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml
+++ b/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml
@@ -37,6 +37,8 @@ Rectangle {
     id: root
     height: Math.max(image.height-20, description.paintedHeight) + 68
     color: "#00ffffff"
+    property variant tags : model.tags
+    signal tagClicked(string tag)
 
     Components.QStyleItem { cursor: "pointinghandcursor" ; anchors.fill: parent }
 
@@ -96,17 +98,6 @@ Rectangle {
         color:"#444"
     }
 
-    Row {
-        id: tagLine;
-        anchors.top: description.bottom
-        anchors.left: parent.left
-        anchors.topMargin: 5
-        anchors.leftMargin: 10
-        anchors.rightMargin: 26
-        Text { id: labelText; text: "Tags: " ; color: "#999"; font.pixelSize: 11}
-        Text { text: model.tags.join(", "); color: "#bbb"; font.pixelSize: 11}
-    }
-
     MouseArea {
         id: mouseArea
         anchors.fill: parent
@@ -121,7 +112,39 @@ Rectangle {
         onExited: parent.state = ""
     }
 
-
+    Row {
+        id: tagLine;
+        anchors.bottomMargin: 20
+        anchors.top: description.bottom
+        anchors.left: parent.left
+        anchors.leftMargin: 10
+        anchors.rightMargin: 26
+        spacing: 4
+        Text { id: labelText; text: qsTr("Tags:") ; color: "#999"; font.pixelSize: 11}
+        Repeater {
+            model: tags;
+            Text {
+                states: [ State { name: "hover"; PropertyChanges { target: tagText; color: "black" } } ]
+                id: tagText
+                text: model.modelData
+                color: "#bbb"
+                font.pixelSize: 11
+                MouseArea {
+                    anchors.fill: parent;
+                    hoverEnabled: true;
+                    onEntered: {
+                        root.state = "hover"
+                        parent.state = "hover"
+                    }
+                    onExited:{
+                        root.state = ""
+                        parent.state = ""
+                    }
+                    onClicked: root.tagClicked(model.modelData)
+                }
+            }
+        }
+    }
 
     states: [ State { name: "hover"; PropertyChanges { target: root; color: "#f9f9f9" } } ]
 }
diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp
index 191b7d4259b1a05c0ed3e489294892894a32d90f..d83a52f10a36bdfc6db53151a66c678b7d5ff974 100644
--- a/src/plugins/qtsupport/exampleslistmodel.cpp
+++ b/src/plugins/qtsupport/exampleslistmodel.cpp
@@ -374,17 +374,52 @@ void ExamplesListModelFilter::updateFilter()
     invalidateFilter();
 }
 
+bool containsSubString(const QStringList& list, const QString& substr, Qt::CaseSensitivity cs)
+{
+    foreach (const QString &elem, list) {
+        if (elem.contains(substr, cs))
+            return true;
+    }
+
+    return false;
+}
+
 bool ExamplesListModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
 {
     if (m_showTutorialsOnly) {
         int type = sourceModel()->index(sourceRow, 0, sourceParent).data(Type).toInt();
         if (type != Tutorial)
             return false;
-        // tag search only active if we are not in tutorial only mode
-    } else if (!m_filterTag.isEmpty()) {
-        QStringList tags = sourceModel()->index(sourceRow, 0, sourceParent).data(Tags).toStringList();
-        if (!tags.contains(m_filterTag, Qt::CaseInsensitive))
-            return false;
+    }
+
+    const QStringList tags = sourceModel()->index(sourceRow, 0, sourceParent).data(Tags).toStringList();
+
+    if (!m_filterTags.isEmpty()) {
+        foreach(const QString &tag, m_filterTags) {
+            if (!tags.contains(tag, Qt::CaseInsensitive))
+                return false;
+        }
+        return true;
+    }
+
+    if (!m_searchString.isEmpty()) {
+        const QString description = sourceModel()->index(sourceRow, 0, sourceParent).data(Description).toString();
+        const QString name = sourceModel()->index(sourceRow, 0, sourceParent).data(Name).toString();
+
+
+        foreach(const QString &subString, m_searchString) {
+            bool wordMatch = false;
+            wordMatch |= (bool)name.contains(subString, Qt::CaseInsensitive);
+            if (wordMatch)
+                continue;
+            // TODO: match substring
+            wordMatch |= containsSubString(tags, subString, Qt::CaseInsensitive);
+            if (wordMatch)
+                continue;
+            wordMatch |= (bool)description.contains(subString, Qt::CaseInsensitive);
+            if (!wordMatch)
+                return false;
+        }
     }
 
     bool ok = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
@@ -400,5 +435,113 @@ void ExamplesListModelFilter::setShowTutorialsOnly(bool showTutorialsOnly)
     emit showTutorialsOnlyChanged();
 }
 
+struct SearchStringLexer {
+    QString code;
+    const QChar *codePtr;
+    QChar yychar;
+    QString yytext;
+
+    enum TokenKind {
+        END_OF_STRING = 0,
+        TAG,
+        STRING_LITERAL,
+        UNKNOWN
+    };
+
+    inline void yyinp() { yychar = *codePtr++; }
+
+    SearchStringLexer(const QString &code)
+        : code(code)
+        , codePtr(code.unicode())
+        , yychar(' ') { }
+
+    int operator()() { return yylex(); }
+
+    int yylex() {
+        while (yychar.isSpace())
+            yyinp(); // skip all the spaces
+
+        yytext.clear();
+
+        if (yychar.isNull())
+            return END_OF_STRING;
+
+        QChar ch = yychar;
+        yyinp();
+
+        switch (ch.unicode()) {
+        case '"':
+        case '\'':
+        {
+            const QChar quote = ch;
+            yytext.clear();
+            while (!yychar.isNull()) {
+                if (yychar == quote) {
+                    yyinp();
+                    break;
+                } if (yychar == '\\') {
+                    yyinp();
+                    switch (yychar.unicode()) {
+                    case '"': yytext += '"'; yyinp(); break;
+                    case '\'': yytext += '\''; yyinp(); break;
+                    case '\\': yytext += '\\'; yyinp(); break;
+                    }
+                } else {
+                    yytext += yychar;
+                    yyinp();
+                }
+            }
+            return STRING_LITERAL;
+        }
+
+        default:
+            if (ch.isLetterOrNumber() || ch == '_') {
+                yytext.clear();
+                yytext += ch;
+                while (yychar.isLetterOrNumber() || yychar == '_') {
+                    yytext += yychar;
+                    yyinp();
+                }
+                if (yychar == ':' && yytext == QLatin1String("tag")) {
+                    yyinp();
+                    return TAG;
+                }
+                return STRING_LITERAL;
+            }
+        }
+
+        yytext += ch;
+        return UNKNOWN;
+    }
+};
+
+void ExamplesListModelFilter::parseSearchString(const QString &arg)
+{
+    QStringList tags;
+    QStringList searchTerms;
+    SearchStringLexer lex(arg);
+    bool isTag = false;
+    while (int tk = lex()) {
+        if (tk == SearchStringLexer::TAG) {
+            isTag = true;
+            searchTerms.append(lex.yytext);
+        }
+
+        if (tk == SearchStringLexer::STRING_LITERAL) {
+            if (isTag) {
+                searchTerms.pop_back();
+                tags.append(lex.yytext);
+                isTag = false;
+            } else {
+                searchTerms.append(lex.yytext);
+            }
+        }
+    }
+
+    setSearchStrings(searchTerms);
+    setFilterTags(tags);
+    updateFilter();
+}
+
 } // namespace Internal
 } // namespace QtSupport
diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h
index fc36970f0b0e3253431739ea66c11d97e6de68ff..cdac8c5abc9f8c126e9f9f1e80c277ba110b2dfd 100644
--- a/src/plugins/qtsupport/exampleslistmodel.h
+++ b/src/plugins/qtsupport/exampleslistmodel.h
@@ -38,6 +38,8 @@
 #include <QtCore/QXmlStreamReader>
 #include <QtGui/QSortFilterProxyModel>
 
+#include <qdebug.h>
+
 namespace QtSupport {
 namespace Internal {
 
@@ -105,39 +107,52 @@ class ExamplesListModelFilter : public QSortFilterProxyModel {
     Q_OBJECT
 public:
     Q_PROPERTY(bool showTutorialsOnly READ showTutorialsOnly WRITE setShowTutorialsOnly NOTIFY showTutorialsOnlyChanged)
-    Q_PROPERTY(QString filterTag READ filterTag WRITE setFilterTag NOTIFY filterTagChanged)
+    Q_PROPERTY(QStringList filterTags READ filterTags WRITE setFilterTags NOTIFY filterTagsChanged)
+    Q_PROPERTY(QStringList searchStrings READ searchStrings WRITE setSearchStrings NOTIFY searchStrings)
 
     explicit ExamplesListModelFilter(QObject *parent);
 
     bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
     bool showTutorialsOnly() {return m_showTutorialsOnly;}
+    QStringList filterTags() const { return m_filterTags; }
+    QStringList searchStrings() const { return m_searchString; }
 
-    QString filterTag() const
+public slots:
+    void setFilterTags(const QStringList& arg)
     {
-        return m_filterTag;
+        if (m_filterTags != arg) {
+            m_filterTags = arg;
+            emit filterTagsChanged(arg);
+        }
     }
+    void updateFilter();
 
-public slots:
-    void setFilterTag(const QString& arg)
+    void setSearchStrings(const QStringList& arg)
     {
-        if (m_filterTag != arg) {
-            m_filterTag = arg;
-            emit filterTagChanged(arg);
+        if (m_searchString != arg) {
+            m_searchString = arg;
+            emit searchStrings(arg);
+            updateFilter();
         }
     }
-    void updateFilter();
+
+    void parseSearchString(const QString& arg);
 
 signals:
     void showTutorialsOnlyChanged();
 
-    void filterTagChanged(const QString& arg);
+    void filterTagsChanged(const QStringList& arg);
+
+    void searchStrings(const QStringList& arg);
 
 private slots:
     void setShowTutorialsOnly(bool showTutorialsOnly);
 
 private:
     bool m_showTutorialsOnly;
-    QString m_filterTag;
+    QStringList m_filterTags;
+    QStringList m_searchString;
 };
 
 } // namespace Internal
diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp
index 85b40f286e21dab2c4418a6a890c1f1220d40f37..618a6731c31c450e16fba10009181636d2fa8f58 100644
--- a/src/plugins/welcome/welcomeplugin.cpp
+++ b/src/plugins/welcome/welcomeplugin.cpp
@@ -63,7 +63,7 @@
 #include <QtDeclarative/QDeclarativeEngine>
 #include <QtDeclarative/QDeclarativeNetworkAccessManagerFactory>
 
-enum { debug = 0 };
+enum { debug = 1 };
 
 using namespace ExtensionSystem;