diff --git a/requirements_py2.txt b/requirements_py2.txt
index 8dc6caa..d2ea5cf 100644
--- a/requirements_py2.txt
+++ b/requirements_py2.txt
@@ -28,3 +28,4 @@ pycrypto==2.6.1
 wsgiref==0.1.2
 simplejson==3.6.5
 importlib==1.0.3
+dateutils==2.4.2
diff --git a/requirements_py3.txt b/requirements_py3.txt
index 4504403..f2368ac 100644
--- a/requirements_py3.txt
+++ b/requirements_py3.txt
@@ -26,3 +26,4 @@ six==1.9.0
 speaklater==1.3
 pycrypto==2.6.1
 simplejson==3.6.5
+dateutils==2.4.2
diff --git a/web/config.py b/web/config.py
index 85388ad..5ee3410 100644
--- a/web/config.py
+++ b/web/config.py
@@ -138,7 +138,7 @@ MAX_SESSION_IDLE_TIME = 60
 
 # The schema version number for the configuration database
 # DO NOT CHANGE UNLESS YOU ARE A PGADMIN DEVELOPER!!
-SETTINGS_SCHEMA_VERSION = 7
+SETTINGS_SCHEMA_VERSION = 8
 
 # The default path to the SQLite database used to store user accounts and
 # settings. This default places the file in the same directory as this
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 38693d4..aa6c526 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -29,8 +29,11 @@ except:
 
 MODULE_NAME = 'browser'
 
+
 class BrowserModule(PgAdminModule):
 
+    LABEL = gettext('Browser')
+
     def get_own_stylesheets(self):
         stylesheets = []
         # Add browser stylesheets
@@ -168,20 +171,56 @@ class BrowserModule(PgAdminModule):
             scripts.extend(module.get_own_javascripts())
         return scripts
 
+    def register_preferences(self):
+        self.show_system_objects = self.preference.register(
+            'display', 'show_system_objects',
+            gettext("Show system objects"), 'boolean', False,
+            category_label=gettext('Display')
+            )
 
 blueprint = BrowserModule(MODULE_NAME, __name__)
 
+
 @six.add_metaclass(ABCMeta)
 class BrowserPluginModule(PgAdminModule):
     """
-    Base class for browser submodules.
+    Abstract base class for browser submodules.
+
+    It helps to define the node for each and every node comes under the browser
+    tree. It makes sure every module comes under browser will have prefix
+    '/browser', and sets the 'url_prefix', 'static_url_path', etc.
+
+    Also, creates some of the preferences to be used by the node.
     """
 
     browser_url_prefix = blueprint.url_prefix + '/'
+    SHOW_ON_BROWSER = True
 
     def __init__(self, import_name, **kwargs):
+        """
+        Construct a new 'BrowserPluginModule' object.
+
+        :param import_name: Name of the module
+        :param **kwargs:    Extra parameters passed to the base class
+                            pgAdminModule.
+
+        :return: returns nothing
+
+        It sets the url_prefix to based on the 'node_path'. And,
+        static_url_path to relative path to '/static'.
+
+        Every module extended from this will be identified as 'NODE-<type>'.
+
+        Also, create a preference 'show_node_<type>' to fetch whether it
+        can be shown in the browser or not. Also,  refer to the browser-preference.
+        """
         kwargs.setdefault("url_prefix", self.node_path)
         kwargs.setdefault("static_url_path", '/static')
+
+        self.browser_preference = None
+        self.pref_show_system_objects = None
+        self.pref_show_node = None
+
         super(BrowserPluginModule, self).__init__(
                                             "NODE-%s" % self.node_type,
                                             import_name,
@@ -196,6 +235,24 @@ class BrowserPluginModule(PgAdminModule):
         return []
 
     def get_own_javascripts(self):
+        """
+        Returns the list of javascripts information used by the module.
+
+        Each javascripts information must contain name, path of the script.
+
+        The name must be unique for each module, hence - in order to refer them
+        properly, we do use 'pgadmin.node.<type>' as norm.
+
+        That can also refer to when to load the script.
+
+        i.e.
+        We may not need to load the javascript of table node, when we're
+        not yet connected to a server, and no database is loaded. Hence - it
+        make sense to load them when a database is loaded.
+
+        We may also add 'deps', which also refers to the list of javascripts,
+        it may depends on.
+        """
         scripts = []
 
         scripts.extend([{
@@ -211,6 +268,27 @@ class BrowserPluginModule(PgAdminModule):
     def generate_browser_node(
             self, node_id, parent_id, label, icon, inode, node_type, **kwargs
             ):
+        """
+        Helper function to create a browser node for this particular subnode.
+
+        :param node_id:   Unique Id for each node
+        :param parent_id: Id of the parent.
+        :param label:     Label for the node
+        :param icon:      Icon for displaying along with this node on browser
+                          tree. Icon refers to a class name, it refers to.
+        :param inode:     True/False.
+                          Used by the browser tree node to check, if the
+                          current node will have children or not.
+        :param node_type: String to refer to the node type.
+        :param **kwargs:  A node can have extra information other than this
+                          data, which can be passed as key-value pair as
+                          argument here.
+                          i.e. A database, server node can have extra
+                          information like connected, or not.
+
+        Returns a dictionary object representing this node object for the
+        browser tree.
+        """
         obj = {
                 "id": "%s/%s" % (node_type, node_id),
                 "label": label,
@@ -269,12 +347,66 @@ class BrowserPluginModule(PgAdminModule):
 
     @property
     def node_path(self):
+        """
+        Defines the url path prefix for this submodule.
+        """
         return self.browser_url_prefix + self.node_type
 
     @property
     def javascripts(self):
+        """
+        Override the javascript of PgAdminModule, so that - we don't return
+        javascripts from the get_own_javascripts itself.
+        """
         return []
 
+    @property
+    def label(self):
+        """
+        Module label.
+        """
+        return self.LABEL
+
+    @property
+    def show_node(self):
+        """
+        A proper to check to show node for this module on the browser tree or not.
+
+        Relies on show_node preference object, otherwise on the SHOW_ON_BROWSER
+        default value.
+        """
+        if self.pref_show_node:
+            return self.pref_show_node.get()
+        else:
+            return self.SHOW_ON_BROWSER
+
+    @property
+    def show_system_objects(self):
+        """
+        Show/Hide the system objects in the database server.
+        """
+        if self.pref_show_system_objects:
+            return self.pref_show_system_objects.get()
+        else:
+            return False
+
+    def register_preferences(self):
+        """
+        Registers the preferences object for this module.
+
+        Sets the browser_preference, show_system_objects, show_node preference
+        objects for this submodule.
+        """
+        # Add the node informaton for browser, not in respective node preferences
+        self.browser_preference = blueprint.preference
+        self.pref_show_system_objects = blueprint.preference.preference(
+            'display', 'show_system_objects'
+            )
+        self.pref_show_node = self.browser_preference.preference(
+            'node', 'show_node_' + self.node_type,
+            self.label, 'boolean', self.SHOW_ON_BROWSER, category_label=gettext('Nodes')
+            )
+
 
 @blueprint.route("/")
 @login_required
diff --git a/web/pgadmin/browser/collection.py b/web/pgadmin/browser/collection.py
index c7d3fa7..3cbc977 100644
--- a/web/pgadmin/browser/collection.py
+++ b/web/pgadmin/browser/collection.py
@@ -14,6 +14,8 @@ from flask.ext.babel import gettext
 from pgadmin.utils import PgAdminModule
 from pgadmin.browser.utils import PGChildModule
 from pgadmin.browser import BrowserPluginModule
+from pgadmin.utils.preferences import Preferences
+
 
 @six.add_metaclass(ABCMeta)
 class CollectionNodeModule(PgAdminModule, PGChildModule):
@@ -21,6 +23,7 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
     Base class for collection node submodules.
     """
     browser_url_prefix = BrowserPluginModule.browser_url_prefix
+    SHOW_ON_BROWSER = True
 
     def __init__(self, import_name, **kwargs):
         kwargs.setdefault("url_prefix", self.node_path)
@@ -124,6 +127,10 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
         return self.COLLECTION_LABEL
 
     @property
+    def label(self):
+        return self.COLLECTION_LABEL
+
+    @property
     def collection_icon(self):
         """
         icon to be displayed for the browser collection node
@@ -173,3 +180,47 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
     @property
     def javascripts(self):
         return []
+
+    @property
+    def show_node(self):
+        """
+        Property to check whether to show the node for this module on the
+        browser tree or not.
+
+        Relies on show_node preference object, otherwise on the SHOW_ON_BROWSER
+        default value.
+        """
+        if self.pref_show_node:
+            return self.pref_show_node.get()
+        else:
+            return self.SHOW_ON_BROWSER
+
+    @property
+    def show_system_objects(self):
+        """
+        Show/Hide the system objects in the database server.
+        """
+        if self.pref_show_system_objects:
+            return self.pref_show_system_objects.get()
+        else:
+            return False
+
+    def register_preferences(self):
+        """
+        register_preferences
+        Register preferences for this module.
+
+        Keep the browser preference object to be used by overriden submodule,
+        along with that get two browser level preferences show_system_objects,
+        and show_node will be registered to used by the submodules.
+        """
+        # Add the node informaton for browser, not in respective node preferences
+        self.browser_preference = Preferences.module('browser')
+        self.pref_show_system_objects = self.browser_preference.preference(
+                'show_system_objects'
+                )
+        self.pref_show_node = self.browser_preference.register(
+                'node', 'show_node_' + self.node_type,
+                self.collection_label, 'node', self.SHOW_ON_BROWSER,
+                category_label=gettext('Nodes')
+                )
diff --git a/web/pgadmin/browser/server_groups/__init__.py b/web/pgadmin/browser/server_groups/__init__.py
index 08c0e67..dc9deb2 100644
--- a/web/pgadmin/browser/server_groups/__init__.py
+++ b/web/pgadmin/browser/server_groups/__init__.py
@@ -9,17 +9,15 @@
 """Defines views for management of server groups"""
 
 from abc import ABCMeta, abstractmethod
-import traceback
 import json
 from flask import request, render_template, make_response, jsonify
 from flask.ext.babel import gettext
-from flask.ext.security import current_user, login_required
-from pgadmin import current_blueprint
+from flask.ext.security import current_user
 from pgadmin.utils.ajax import make_json_response, \
     make_response as ajax_response
 from pgadmin.browser import BrowserPluginModule
 from pgadmin.utils.menu import MenuItem
-from pgadmin.settings.settings_model import db, ServerGroup
+from pgadmin.model import db, ServerGroup
 from pgadmin.browser.utils import NodeView
 import six
 
@@ -41,12 +39,30 @@ class ServerGroupModule(BrowserPluginModule):
 
     @property
     def node_type(self):
+        """
+        node_type
+        Node type for Server Group is server-group. It is defined by NODE_TYPE
+        static attribute of the class.
+        """
         return self.NODE_TYPE
 
     @property
     def script_load(self):
+        """
+        script_load
+        Load the server-group javascript module on loading of browser module.
+        """
         return None
 
+    def register_preferences(self):
+        """
+        register_preferences
+        Overrides the register_preferences PgAdminModule, because - we will not
+        register any preference for server-group (specially the show_node
+        preference.)
+        """
+        pass
+
 
 class ServerGroupMenuItem(MenuItem):
 
@@ -153,7 +169,6 @@ class ServerGroupView(NodeView):
         sg = ServerGroup.query.filter_by(
                 user_id=current_user.id,
                 id=gid).first()
-        data = {}
 
         if sg is None:
             return make_json_response(
@@ -181,7 +196,7 @@ class ServerGroupView(NodeView):
 
                 data[u'id'] = sg.id
                 data[u'name'] = sg.name
-                
+
                 return jsonify(
                         node=self.blueprint.generate_browser_node(
                             "%d" % (sg.id), None,
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index 4ca7387..f902fd8 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -8,25 +8,22 @@
 ##########################################################################
 
 import json
-from abc import ABCMeta, abstractproperty
 from flask import render_template, request, make_response, jsonify, \
         current_app, url_for
-from flask.ext.security import login_required, current_user
+from flask.ext.security import current_user
 from pgadmin.settings.settings_model import db, Server, ServerGroup, User
 from pgadmin.utils.menu import MenuItem
-from pgadmin.utils.ajax import make_json_response, \
-    make_response as ajax_response, internal_server_error, success_return, \
-    unauthorized, bad_request, precondition_required, forbidden
+from pgadmin.utils.ajax import make_json_response, bad_request, forbidden, \
+    make_response as ajax_response, internal_server_error, unauthorized
 from pgadmin.browser.utils import PGChildNodeView
 import traceback
 from flask.ext.babel import gettext
 import pgadmin.browser.server_groups as sg
 from pgadmin.utils.crypto import encrypt
-from pgadmin.browser import BrowserPluginModule
 from config import PG_DEFAULT_DRIVER
-import six
 from pgadmin.browser.server_groups.servers.types import ServerType
 
+
 def has_any(data, keys):
     """
     Checks any one of the keys present in the data given
@@ -46,6 +43,7 @@ def has_any(data, keys):
 
 class ServerModule(sg.ServerGroupPluginModule):
     NODE_TYPE = "server"
+    LABEL = gettext("Servers")
 
     @property
     def node_type(self):
@@ -146,6 +144,15 @@ class ServerModule(sg.ServerGroupPluginModule):
 
         super(ServerModule, self).register(app, options, first_registration)
 
+    # We do not have any preferences for server node.
+    def register_preferences(self):
+        """
+        register_preferences
+        Override it so that - it does not register the show_node preference for
+        server type.
+        """
+        pass
+
 class ServerMenuItem(MenuItem):
     def __init__(self, **kwargs):
         kwargs.setdefault("type", ServerModule.NODE_TYPE)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/__init__.py
index 03a5a02..56e2a10 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/__init__.py
@@ -25,7 +25,6 @@ from pgadmin.browser.server_groups.servers.databases.utils import \
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
 from functools import wraps
-import re
 
 
 class DatabaseModule(CollectionNodeModule):
@@ -42,7 +41,8 @@ class DatabaseModule(CollectionNodeModule):
         """
         Generate the collection node
         """
-        yield self.generate_browser_collection_node(sid)
+        if self.show_node:
+            yield self.generate_browser_collection_node(sid)
 
     @property
     def script_load(self):
@@ -633,7 +633,7 @@ class DatabaseView(PGChildNodeView):
         except Exception as e:
             current_app.logger.exception(e)
             return make_json_response(
-                    data="-- modified SQL",
+                    data=_("-- modified SQL"),
                     status=200
                     )
 
diff --git a/web/pgadmin/browser/server_groups/servers/roles/__init__.py b/web/pgadmin/browser/server_groups/servers/roles/__init__.py
index 798a6d3..23c5d8a 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/roles/__init__.py
@@ -10,8 +10,7 @@ from flask import render_template, request, jsonify, current_app
 from flask.ext.babel import gettext as _
 from pgadmin.utils.ajax import make_json_response, \
     make_response as ajax_response, precondition_required, \
-    internal_server_error, forbidden, \
-    not_implemented, success_return, gone
+    internal_server_error, forbidden, success_return, gone
 from pgadmin.browser.utils import PGChildNodeView
 from pgadmin.browser.collection import CollectionNodeModule
 import pgadmin.browser.server_groups as sg
@@ -37,8 +36,9 @@ class RoleModule(CollectionNodeModule):
         """
         Generate the collection node
         """
-
-        yield self.generate_browser_collection_node(sid)
+        if self.show_node:
+            yield self.generate_browser_collection_node(sid)
+        pass
 
     @property
     def node_inode(self):
@@ -480,7 +480,8 @@ rolmembership:{
                 if check_permission:
                     user = self.manager.user_info
 
-                    if not user['is_superuser'] and not user['can_create_role']:
+                    if not user['is_superuser'] and \
+                            not user['can_create_role']:
                         if (action != 'update' or
                                 'rid' in kwargs and kwargs['rid'] != -1 and
                                 user['id'] != kwargs['rid']):
diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py b/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py
index a1a380a..555f157 100644
--- a/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py
@@ -26,12 +26,6 @@ class TablespaceModule(CollectionNodeModule):
     NODE_TYPE = 'tablespace'
     COLLECTION_LABEL = gettext("Tablespaces")
 
-    def __init__(self, *args, **kwargs):
-        self.min_ver = None
-        self.max_ver = None
-
-        super(TablespaceModule, self).__init__(*args, **kwargs)
-
     def get_nodes(self, gid, sid):
         """
         Generate the collection node
diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py
index db44224..d7fd895 100644
--- a/web/pgadmin/browser/utils.py
+++ b/web/pgadmin/browser/utils.py
@@ -9,29 +9,14 @@
 
 """Browser helper utilities"""
 
-from abc import ABCMeta, abstractmethod
+from abc import abstractmethod
 import flask
 from flask.views import View, MethodViewType, with_metaclass
 from flask.ext.babel import gettext
 from flask import render_template, current_app
-import six
-
 from config import PG_DEFAULT_DRIVER
 from pgadmin.utils.ajax import make_json_response, precondition_required
 
-@six.add_metaclass(ABCMeta)
-class NodeAttr(object):
-    """
-    """
-
-    @abstractmethod
-    def validate(self, mode, value):
-        pass
-
-    @abstractmethod
-    def schema(self):
-        pass
-
 
 class PGChildModule(object):
     """
@@ -47,10 +32,6 @@ class PGChildModule(object):
     - Return True when it supports certain version.
       Uses the psycopg2 server connection manager as input for checking the
       compatibility of the current module.
-
-    * AddAttr(attr)
-    - This adds the attribute supported for specific version only. It takes
-      NodeAttr as input, and update max_ver, min_ver variables for this module.
     """
 
     def __init__(self, *args, **kwargs):
@@ -58,9 +39,12 @@ class PGChildModule(object):
         self.max_ver = 1000000000
         self.server_type = None
 
-        super(PGChildModule, self).__init__(*args, **kwargs)
+        super(PGChildModule, self).__init__()
 
     def BackendSupported(self, manager, **kwargs):
+        if hasattr(self, 'show_node'):
+            if not self.show_node:
+                return False
         sversion = getattr(manager, 'sversion', None)
         if (sversion is None or not isinstance(sversion, int)):
             return False
@@ -83,6 +67,7 @@ class PGChildModule(object):
     def get_nodes(self, sid=None, **kwargs):
         pass
 
+
 class NodeView(with_metaclass(MethodViewType, View)):
     """
     A PostgreSQL Object has so many operaions/functions apart from CRUD
diff --git a/web/pgadmin/model/__init__.py b/web/pgadmin/model/__init__.py
new file mode 100644
index 0000000..253bd67
--- /dev/null
+++ b/web/pgadmin/model/__init__.py
@@ -0,0 +1,150 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Defines the models for the configuration database.
+
+If any of the models are updated, you (yes, you, the developer) MUST do two
+things:
+
+1) Increment SETTINGS_SCHEMA_VERSION in config.py
+
+2) Modify setup.py to ensure that the appropriate changes are made to the
+   config database to upgrade it to the new version.
+"""
+
+from flask.ext.sqlalchemy import SQLAlchemy
+from flask.ext.security import UserMixin, RoleMixin
+
+db = SQLAlchemy()
+
+# Define models
+roles_users = db.Table(
+                'roles_users',
+                db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
+                db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
+                )
+
+
+class Version(db.Model):
+    """Version numbers for reference/upgrade purposes"""
+    __tablename__ = 'version'
+    name = db.Column(db.String(32), primary_key=True)
+    value = db.Column(db.Integer(), nullable=False)
+
+
+class Role(db.Model, RoleMixin):
+    """Define a security role"""
+    __tablename__ = 'role'
+    id = db.Column(db.Integer(), primary_key=True)
+    name = db.Column(db.String(128), unique=True, nullable=False)
+    description = db.Column(db.String(256), nullable=False)
+
+
+class User(db.Model, UserMixin):
+    """Define a user object"""
+    __tablename__ = 'user'
+    id = db.Column(db.Integer, primary_key=True)
+    email = db.Column(db.String(256), unique=True, nullable=False)
+    password = db.Column(db.String(256))
+    active = db.Column(db.Boolean(), nullable=False)
+    confirmed_at = db.Column(db.DateTime())
+    roles = db.relationship('Role', secondary=roles_users,
+                            backref=db.backref('users', lazy='dynamic'))
+
+
+class Setting(db.Model):
+    """Define a setting object"""
+    __tablename__ = 'setting'
+    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
+    setting = db.Column(db.String(256), primary_key=True)
+    value = db.Column(db.String(1024))
+
+
+class ServerGroup(db.Model):
+    """Define a server group for the treeview"""
+    __tablename__ = 'servergroup'
+    id = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
+
+    name = db.Column(db.String(128), nullable=False)
+    __table_args__ = (db.UniqueConstraint('user_id', 'name'),)
+
+
+class Server(db.Model):
+    """Define a registered Postgres server"""
+    __tablename__ = 'server'
+    id = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(
+            db.Integer,
+            db.ForeignKey('user.id'),
+            nullable=False
+            )
+    servergroup_id = db.Column(
+            db.Integer,
+            db.ForeignKey('servergroup.id'),
+            nullable=False
+            )
+    name = db.Column(db.String(128), nullable=False)
+    host = db.Column(db.String(128), nullable=False)
+    port = db.Column(
+            db.Integer(),
+            db.CheckConstraint('port >= 1024 AND port <= 65534'),
+            nullable=False)
+    maintenance_db = db.Column(db.String(64), nullable=False)
+    username = db.Column(db.String(64), nullable=False)
+    password = db.Column(db.String(64), nullable=True)
+    role = db.Column(db.String(64), nullable=True)
+    ssl_mode = db.Column(
+            db.String(16),
+            db.CheckConstraint(
+                "ssl_mode IN ('allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full')"
+                ),
+            nullable=False)
+    comment = db.Column(
+            db.String(1024),
+            nullable=True)
+
+class ModulePreference(db.Model):
+    """Define a preferences table for any modules."""
+    __tablename__ = 'module_preference'
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String(256), nullable=False)
+
+class PreferenceCategory(db.Model):
+    """Define a preferences category for each modules."""
+    __tablename__ = 'preference_category'
+    id = db.Column(db.Integer, primary_key=True)
+    mid = db.Column(
+        db.Integer,
+        db.ForeignKey('module_preference.id'),
+        nullable=False
+        )
+    name = db.Column(db.String(256), nullable=False)
+
+class Preferences(db.Model):
+    """Define a particular preference."""
+    __tablename__ = 'preferences'
+    id = db.Column(db.Integer, primary_key=True)
+    cid = db.Column(
+        db.Integer,
+        db.ForeignKey('preference_category.id'),
+        nullable=False
+        )
+    name = db.Column(db.String(1024), nullable=False)
+
+class UserPreference(db.Model):
+    """Define the preference for a particular user."""
+    __tablename__ = 'user_preferences'
+    pid = db.Column(
+        db.Integer, db.ForeignKey('preferences.id'), primary_key=True
+        )
+    uid = db.Column(
+        db.Integer, db.ForeignKey('user.id'), primary_key=True
+        )
+    value = db.Column(db.String(1024), nullable=False)
diff --git a/web/pgadmin/preferences/__init__.py b/web/pgadmin/preferences/__init__.py
new file mode 100644
index 0000000..a2aa7d0
--- /dev/null
+++ b/web/pgadmin/preferences/__init__.py
@@ -0,0 +1,130 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.ajax import success_return, \
+    make_response as ajax_response, internal_server_error
+
+from flask import render_template, url_for, Response, request
+from flask.ext.security import login_required
+from flask.ext.login import current_user
+from flask.ext.babel import gettext
+
+from pgadmin.utils.menu import MenuItem
+from pgadmin.utils.preferences import Preferences
+import simplejson as json
+
+
+MODULE_NAME = 'preferences'
+
+class PreferencesModule(PgAdminModule):
+    """
+    PreferenceModule represets the preferences of different modules to the
+    user in UI.
+
+    And, allows the user to modify (not add/remove) as per their requirement.
+    """
+
+    def get_own_javascripts(self):
+        return [{
+            'name': 'pgadmin.preferences',
+            'path': url_for('preferences.index') + 'preferences',
+            'when': None
+        }]
+
+    def get_own_stylesheets(self):
+        return [url_for('preferences.static', filename='css/preferences.css')]
+
+    def get_own_menuitems(self):
+        return {
+            'file_items': [
+                MenuItem(name='mnu_preferences',
+                         priority=999,
+                         module="pgAdmin.Preferences",
+                         callback='show',
+                         icon='fa fa-cog',
+                         label=gettext('Preferences'))
+            ]
+        }
+
+blueprint = PreferencesModule(MODULE_NAME, __name__)
+
+
+@blueprint.route("/")
+@login_required
+def index():
+    """Render the preferences dialog."""
+    return render_template(
+            MODULE_NAME + "/index.html",
+            username=current_user.email,
+            _=gettext
+            )
+
+
+@blueprint.route("/preferences.js")
+@login_required
+def script():
+    """render the required javascript"""
+    return Response(response=render_template("preferences/preferences.js", _=gettext),
+                    status=200,
+                    mimetype="application/javascript")
+
+
+@blueprint.route("/preferences", methods=["GET"])
+@login_required
+def preferences():
+    """Fetch all the preferences of pgAdmin IV."""
+
+    # Load Preferences
+    preferences = Preferences.preferences()
+    res = []
+
+    for m in preferences:
+        if len(m['categories']):
+            om = {
+                "id": m['id'],
+                "label": m['label'],
+                "inode": True,
+                "open": True,
+                "branch": []
+                }
+
+            for c in m['categories']:
+                oc = {
+                    "id": c['id'],
+                    "mid": m['id'],
+                    "label": c['label'],
+                    "inode": False,
+                    "open": False,
+                    "preferences": c['preferences']
+                    }
+
+                (om['branch']).append(oc)
+
+            res.append(om)
+
+    return ajax_response(
+            response=res,
+            status=200
+            )
+
+
+@blueprint.route("/preferences/<int:pid>", methods=["PUT"])
+@login_required
+def save(pid):
+    """
+    Save a specific preference.
+    """
+    data = request.form if request.form else json.loads(request.data.decode())
+
+    res, msg = Preferences.save(data['mid'], data['cid'], data['id'], data['value'])
+
+    if not res:
+        return internal_server_error(errormsg=msg)
+
+    return success_return()
diff --git a/web/pgadmin/preferences/static/css/preferences.css b/web/pgadmin/preferences/static/css/preferences.css
new file mode 100644
index 0000000..7946f90
--- /dev/null
+++ b/web/pgadmin/preferences/static/css/preferences.css
@@ -0,0 +1,40 @@
+.preferences_dialog {
+  height: 100%;
+  position: absolute;
+  top: 5px;
+  left: 0px;
+  bottom: 0px;
+  right: 0px;
+  padding-bottom: 30px;
+}
+
+.preferences_tree{
+  padding: 0px;
+  padding-top: 2px;
+  height: 100%;
+  overflow: auto;
+  border-right: 2px solid #999999;
+  background-image: #FAFAFA;
+}
+
+.preferences_content {
+  padding-top: 10px;
+  height: 100%;
+  overflow: auto;
+}
+
+.preferences_content .control-label, .preferences_content .pgadmin-controls {
+  min-width: 100px !important;
+}
+
+.pgadmin-preference-body {
+    min-width: 300px !important;
+    min-height: 400px !important;
+}
+
+@media (min-width: 768px) {
+  .pgadmin-preference-body {
+    min-width: 600px !important;
+    min-height: 480px !important;
+  }
+}
diff --git a/web/pgadmin/preferences/templates/preferences/index.html b/web/pgadmin/preferences/templates/preferences/index.html
new file mode 100644
index 0000000..a627858
--- /dev/null
+++ b/web/pgadmin/preferences/templates/preferences/index.html
@@ -0,0 +1,8 @@
+<div id="options_dialog">
+  <div id="options_tree" class="">
+          ACI TREE
+  </div>
+  <div id='options_content'>
+      Right hand side content
+  </div>
+</div>
\ No newline at end of file
diff --git a/web/pgadmin/preferences/templates/preferences/preferences.js b/web/pgadmin/preferences/templates/preferences/preferences.js
new file mode 100644
index 0000000..a8c7c4f
--- /dev/null
+++ b/web/pgadmin/preferences/templates/preferences/preferences.js
@@ -0,0 +1,374 @@
+define(
+  ['jquery', 'alertify', 'pgadmin', 'underscore', 'backform', 'pgadmin.backform'],
+
+  // This defines the Preference/Options Dialog for pgAdmin IV.
+  function($, alertify, pgAdmin, _, Backform) {
+    pgAdmin = pgAdmin || window.pgAdmin || {};
+
+    /*
+     * Hmm... this module is already been initialized, we can refer to the old
+     * object from here.
+     */
+    if (pgAdmin.Preferences)
+        return pgAdmin.Preferences;
+
+    pgAdmin.Preferences = {
+      init: function() {
+        if (this.initialized)
+          return;
+
+        this.initialized = true;
+
+        // Declare the Preferences dialog
+        alertify.dialog('preferencesDlg', function() {
+
+          var jTree,         // Variable to create the aci-tree
+              controls = [], // Keep tracking of all the backform controls
+                             // created by the dialog.
+              // Dialog containter
+              $container = $("<div class='preferences_dialog'></div>");
+
+
+          /*
+           * Preference Model
+           *
+           * This model will be used to keep tracking of the changes done for
+           * an individual option.
+           */
+          var PreferenceModel = Backbone.Model.extend({
+            idAttribute: 'id',
+            defaults: {
+              id: undefined,
+              value: undefined
+            }
+          });
+
+          /*
+           * Preferences Collection object.
+           *
+           * We will use only one collection object to keep track of all the
+           * preferences.
+           */
+          var preferences = this.preferences = new (Backbone.Collection.extend({
+            model: PreferenceModel,
+            url: "{{ url_for('preferences.preferences') }}",
+            updateAll: function() {
+              // We will send only the modified data to the server.
+              this.each(function(m) {
+                if (m.hasChanged()) {
+                  m.save({
+                    fail: function() {
+                    }
+                  });
+                }
+              });
+              return true;
+            }
+          }))(null);
+
+          /*
+           * Function: renderPreferencePanel
+           *
+           * Renders the preference panel in the content div based on the given
+           * preferences.
+           */
+          var renderPreferencePanel = function(prefs) {
+            /*
+             * Clear the existing html in the preferences content
+             */
+            var content = $container.find('.preferences_content');
+            content.empty();
+
+            /*
+             * We should clean up the existing controls.
+             */
+            if (controls) {
+              _.each(controls, function(c) {
+                c.remove();
+              });
+            }
+            controls = [];
+
+            /*
+             * We will create new set of controls and render it based on the
+             * list of preferences using the Backform Field, Control.
+             */
+            _.each(prefs, function(p) {
+
+              var m = preferences.get(p.id),
+                  f = new Backform.Field(_.extend({}, p, {id: 'value', name: 'value'})),
+                  cntr = new (f.get("control")) ({
+                    field: f,
+                    model: m
+                  });
+                  content.append(cntr.render().$el);
+
+                  // We will keep track of all the controls rendered at the
+                  // moment.
+                  controls.push(cntr);
+            });
+
+          };
+
+          /*
+           * Function: dialogContentCleanup
+           *
+           * Do the dialog container cleanup on openning.
+           */
+
+          var dialogContentCleanup = function() {
+              // Remove the existing preferences
+              if (!jTree)
+                return;
+
+              /*
+               * Remove the aci-tree (mainly to remove the jquery object of
+               * aciTree from the system for this container).
+               */
+              try {
+                jTreeApi = jTree.aciTree('destroy');
+              } catch(ex) {
+                // Sometimes - it fails to destroy the tree properly and throws
+                // exception.
+              }
+              jTree.off('acitree', treeEventHandler);
+
+              // We need to reset the data from the preferences too
+              preferences.reset();
+
+              /*
+               * Clean up the existing controls.
+               */
+              if (controls) {
+                _.each(controls, function(c) {
+                  c.remove();
+                });
+              }
+              controls = [];
+
+              // Remove all the objects now.
+              $container.empty();
+            },
+            /*
+             * Function: selectFirstCategory
+             *
+             * Whenever a user select a module instead of a category, we should
+             * select the first categroy of it.
+             */
+            selectFirstCategory = function(api, item) {
+              var  data = item ? api.itemData(item) : null;
+
+              if (data && data.preferences) {
+                  api.select(item);
+                  return;
+              }
+              item = api.first(item);
+              selectFirstCategory(api, item);
+            },
+            /*
+             * A map on how to create controls for each datatype in preferences
+             * dialog.
+             */
+            getControlMappedForType = function(p) {
+              switch(p.type) {
+                case 'boolean':
+                  p.options = {
+                      onText: '{{ _('True') }}',
+                      offText: '{{ _('False') }}',
+                      onColor: 'success',
+                      offColor: 'default',
+                      size: 'mini'
+                    };
+                  return 'switch';
+                case 'node':
+                    p.options = {
+                      onText: '{{ _('Show') }}',
+                      offText: '{{ _('Hide') }}',
+                      onColor: 'success',
+                      offColor: 'default',
+                      size: 'mini'
+                    };
+                    return 'switch';
+                case 'integer':
+                  return 'integer';
+                case 'numeric':
+                  return 'numeric';
+                case 'date':
+                  // TODO::
+                  // Datetime picker Control is missing at the moment, replace
+                  // once it has been implemented.
+                  return 'datepicker';
+                case 'datetime':
+                  return 'datepicker';
+                case 'options':
+                  var opts = [];
+                  // Convert the array to SelectControl understandable options.
+                  _.each(p.options, function(o) {
+                    opts.push({'label': o, 'value': o});
+                  });
+                  p.options = opts;
+                  return 'select2';
+                case 'multiline':
+                  return 'textarea';
+                case 'switch':
+                  return 'switch';
+                default:
+                    if (console && console.log) {
+                      // Warning for developer only.
+                       console.log(
+                         "Hmm.. We don't know how to render this type - ''" + type + "' of control."
+                       );
+                    }
+                  return 'input';
+              }
+            },
+            /*
+             * function: treeEventHandler
+             *
+             * It is basically a callback, which listens to aci-tree events,
+             * and act accordingly.
+             *
+             * + Selection of the node will existance of the preferences for
+             *   the selected tree-node, if not pass on to select the first
+             *   category under a module, else pass on to the render function.
+             *
+             * + When a new node is added in the tree, it will add the relavent
+             *   preferences in the preferences model collection, which will be
+             *   called during initialization itself.
+             *
+             *
+             */
+            treeEventHandler = function(event, api, item, eventName) {
+              // Look for selected item (if none supplied)!
+              item = item || api.selected();
+
+              // Event tree item has itemData
+              var d = item ? api.itemData(item) : null;
+
+              /*
+               * boolean (switch/checkbox), string, enum (combobox - enumvals),
+               * integer (min-max), font, color
+               */
+              switch (eventName) {
+                case "selected":
+                  if (!d)
+                    return true;
+
+                  if (d.preferences) {
+                    /*
+                     * Clear the existing html in the preferences content
+                     */
+                    renderPreferencePanel(d.preferences);
+
+                    return true;
+                  } else{
+                    selectFirstCategory(api, item);
+                  }
+                  break;
+                case 'added':
+                  if (!d)
+                    return true;
+
+                  // We will add the preferences in to the preferences data
+                  // collection.
+                  if (d.preferences && _.isArray(d.preferences)) {
+                    _.each(d.preferences, function(p) {
+                      preferences.add({
+                        'id': p.id, 'value': p.value, 'cid': d.id, 'mid': d.mid
+                      });
+                      /*
+                       * We don't know until now, how to render the control for
+                       * this preference.
+                       */
+                      if (!p.control) {
+                        p.control = getControlMappedForType(p);
+                      }
+                    });
+                  }
+                  d.sortable = false;
+                  break;
+                case 'loaded':
+                  // Let's select the first category from the prefrences.
+                  // We need to wait for sometime before all item gets loaded
+                  // properly.
+                  setTimeout(
+                    function() {
+                      selectFirstCategory(api, null);
+                    }, 300);
+                  break;
+              }
+              return true;
+          };
+
+          // Dialog property
+          return {
+            main: function() {
+
+              // Remove the existing content first.
+              dialogContentCleanup();
+
+              $container.append(
+                "<div class='col-xs-3 preferences_tree aciTree'></div>"
+              ).append(
+                "<div class='col-xs-9 preferences_content'>" +
+                " {{ _('Category is not selected.')|safe }}" +
+                "</div>"
+              );
+
+              // Create the aci-tree for listing the modules and categories of
+              // it.
+              jTree = $container.find('.preferences_tree');
+              jTree.on('acitree', treeEventHandler);
+
+              jTree.aciTree({
+                selectable: true,
+                expand: true,
+                ajax: {
+                  url: "{{ url_for('preferences.preferences') }}"
+                }
+              });
+
+              this.show();
+            },
+            setup:function(){
+              return {
+                buttons:[
+                  {
+                    text: "{{ _('OK') }}", key: 13, className: "btn btn-primary"
+                  },
+                  {
+                    text: "{{ _('Cancel') }}", className: "btn btn-danger"
+                  }
+                ],
+                focus: { element: 0 },
+                options: {
+                  padding: !1,
+                  overflow: !1,
+                  title: '{{ _('Preferences')|safe }}'
+                }
+              };
+            },
+            callback: function(closeEvent){
+              if (closeEvent.button.text == "{{ _('OK') }}"){
+                preferences.updateAll();
+              }
+            },
+            build: function() {
+              this.elements.content.appendChild($container.get(0));
+            },
+            hooks: {
+              onshow: function() {
+                $(this.elements.body).addClass('pgadmin-preference-body');
+              }
+            }
+          };
+        });
+
+      },
+      show: function() {
+        alertify.preferencesDlg(true).resizeTo('60%', '60%');
+      }
+    };
+
+    return pgAdmin.Preferences;
+  });
diff --git a/web/pgadmin/settings/__init__.py b/web/pgadmin/settings/__init__.py
index bf4c32c..a245aff 100644
--- a/web/pgadmin/settings/__init__.py
+++ b/web/pgadmin/settings/__init__.py
@@ -9,16 +9,13 @@
 
 """Utility functions for storing and retrieving user configuration settings."""
 
-from flask import current_app
 from flask.ext.login import current_user
-from flask.ext.sqlalchemy import SQLAlchemy
 
-from .settings_model import db, Setting
+from pgadmin.model import db, Setting
 import traceback
-from flask import Blueprint, Response, abort, request, render_template
+from flask import Response, request, render_template
 from flask.ext.security import login_required
 
-import config
 from pgadmin.utils.ajax import make_json_response
 from pgadmin.utils import PgAdminModule
 
@@ -59,7 +56,6 @@ def store(setting=None, value=None):
     """Store a configuration setting, or if this is a POST request and a
     count value is present, store multiple settings at once."""
     success = 1
-    errorcode = 0
     errormsg = ''
 
     try:
@@ -97,7 +93,6 @@ def get(setting=None, default=None):
         default = request.form['default']
 
     success = 1
-    errorcode = 0
     errormsg = ''
 
     try:
diff --git a/web/pgadmin/settings/settings_model.py b/web/pgadmin/settings/settings_model.py
deleted file mode 100644
index 4a13f95..0000000
--- a/web/pgadmin/settings/settings_model.py
+++ /dev/null
@@ -1,111 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2016, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Defines the models for the configuration database.
-
-If any of the models are updated, you (yes, you, the developer) MUST do two
-things:
-
-1) Increment SETTINGS_SCHEMA_VERSION in config.py
-
-2) Modify setup.py to ensure that the appropriate changes are made to the
-   config database to upgrade it to the new version.
-"""
-
-from flask.ext.sqlalchemy import SQLAlchemy
-from flask.ext.security import UserMixin, RoleMixin
-
-db = SQLAlchemy()
-
-# Define models
-roles_users = db.Table(
-                'roles_users',
-                db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
-                db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
-                )
-
-
-class Version(db.Model):
-    """Version numbers for reference/upgrade purposes"""
-    __tablename__ = 'version'
-    name = db.Column(db.String(32), primary_key=True)
-    value = db.Column(db.Integer(), nullable=False)
-
-
-class Role(db.Model, RoleMixin):
-    """Define a security role"""
-    __tablename__ = 'role'
-    id = db.Column(db.Integer(), primary_key=True)
-    name = db.Column(db.String(128), unique=True, nullable=False)
-    description = db.Column(db.String(256), nullable=False)
-
-
-class User(db.Model, UserMixin):
-    """Define a user object"""
-    __tablename__ = 'user'
-    id = db.Column(db.Integer, primary_key=True)
-    email = db.Column(db.String(256), unique=True, nullable=False)
-    password = db.Column(db.String(256))
-    active = db.Column(db.Boolean(), nullable=False)
-    confirmed_at = db.Column(db.DateTime())
-    roles = db.relationship('Role', secondary=roles_users,
-                            backref=db.backref('users', lazy='dynamic'))
-
-
-class Setting(db.Model):
-    """Define a setting object"""
-    __tablename__ = 'setting'
-    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
-    setting = db.Column(db.String(256), primary_key=True)
-    value = db.Column(db.String(1024))
-
-
-class ServerGroup(db.Model):
-    """Define a server group for the treeview"""
-    __tablename__ = 'servergroup'
-    id = db.Column(db.Integer, primary_key=True)
-    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
-
-    name = db.Column(db.String(128), nullable=False)
-    __table_args__ = (db.UniqueConstraint('user_id', 'name'),)
-
-
-class Server(db.Model):
-    """Define a registered Postgres server"""
-    __tablename__ = 'server'
-    id = db.Column(db.Integer, primary_key=True)
-    user_id = db.Column(
-            db.Integer,
-            db.ForeignKey('user.id'),
-            nullable=False
-            )
-    servergroup_id = db.Column(
-            db.Integer,
-            db.ForeignKey('servergroup.id'),
-            nullable=False
-            )
-    name = db.Column(db.String(128), nullable=False)
-    host = db.Column(db.String(128), nullable=False)
-    port = db.Column(
-            db.Integer(),
-            db.CheckConstraint('port >= 1024 AND port <= 65534'),
-            nullable=False)
-    maintenance_db = db.Column(db.String(64), nullable=False)
-    username = db.Column(db.String(64), nullable=False)
-    password = db.Column(db.String(64), nullable=True)
-    role = db.Column(db.String(64), nullable=True)
-    ssl_mode = db.Column(
-            db.String(16),
-            db.CheckConstraint(
-                "ssl_mode IN ('allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full')"
-                ),
-            nullable=False)
-    comment = db.Column(
-            db.String(1024),
-            nullable=True)
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index 4346156..226bd33 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -429,6 +429,7 @@
     /* Array of objects having attributes [label, fields] */
     schema: undefined,
     tagName: "form",
+    legend: true,
     className: function() {
       return 'col-sm-12 col-md-12 col-lg-12 col-xs-12';
     },
@@ -445,6 +446,7 @@
           o.cId = o.cId || _.uniqueId('pgC_');
           o.hId = o.hId || _.uniqueId('pgH_');
           o.disabled = o.disabled || false;
+          o.legend = opts.legend;
         });
         if (opts.tabPanelClassName && _.isFunction(opts.tabPanelClassName)) {
           this.tabPanelClassName = opts.tabPanelClassName;
@@ -545,8 +547,9 @@
     template: {
       'header': _.template([
         '<fieldset class="<%=fieldsetClass%>" <%=disabled ? "disabled" : ""%>>',
+        ' <% if (legend != false) { %>',
         '  <legend class="<%=legendClass%>" <%=collapse ? "data-toggle=\'collapse\'" : ""%> data-target="#<%=cId%>"><%=collapse ? "<span class=\'caret\'></span>" : "" %><%=label%></legend>',
-        '  ',
+        ' <% } %>',
         '</fieldset>'
       ].join("\n")),
       'content': _.template(
diff --git a/web/pgadmin/utils/__init__.py b/web/pgadmin/utils/__init__.py
index cfe8729..6d1eaa7 100644
--- a/web/pgadmin/utils/__init__.py
+++ b/web/pgadmin/utils/__init__.py
@@ -10,7 +10,7 @@
 from flask import Blueprint
 from collections import defaultdict
 from operator import attrgetter
-import sys
+from .preferences import Preferences
 
 
 class PgAdminModule(Blueprint):
@@ -26,8 +26,25 @@ class PgAdminModule(Blueprint):
         kwargs.setdefault('template_folder', 'templates')
         kwargs.setdefault('static_folder', 'static')
         self.submodules = []
+
         super(PgAdminModule, self).__init__(name, import_name, **kwargs)
 
+        def create_module_preference():
+            # Create preference for each module by default
+            if hasattr(self, 'LABEL'):
+                self.preference = Preferences(self.name, self.LABEL)
+            else:
+                self.preference = Preferences(self.name, None)
+
+            self.register_preferences()
+
+        # Create and register the module preference object and preferences for
+        # it just before the first request
+        self.before_app_first_request(create_module_preference)
+
+    def register_preferences(self):
+        pass
+
     def register(self, app, options, first_registration=False):
         """
         Override the default register function to automagically register
@@ -35,7 +52,9 @@ class PgAdminModule(Blueprint):
         """
         if first_registration:
             self.submodules = list(app.find_submodules(self.import_name))
+
         super(PgAdminModule, self).register(app, options, first_registration)
+
         for module in self.submodules:
             app.register_blueprint(module)
 
diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py
index 3badf3f..5a0bb0f 100644
--- a/web/pgadmin/utils/driver/psycopg2/__init__.py
+++ b/web/pgadmin/utils/driver/psycopg2/__init__.py
@@ -18,7 +18,7 @@ from flask.ext.babel import gettext
 from flask.ext.security import current_user
 
 from ..abstract import BaseDriver, BaseConnection
-from pgadmin.settings.settings_model import Server, User
+from pgadmin.model import Server, User
 from pgadmin.utils.crypto import decrypt
 import random
 
@@ -701,7 +701,7 @@ class Driver(BaseDriver):
 
         managers['pinged'] = datetime.datetime.now()
         if str(sid) not in managers:
-            from pgadmin.settings.settings_model import Server
+            from pgadmin.model import Server
             s = Server.query.filter_by(id=sid).first()
 
             managers[str(sid)] = ServerManager(s)
diff --git a/web/pgadmin/utils/preferences.py b/web/pgadmin/utils/preferences.py
new file mode 100644
index 0000000..e09feec
--- /dev/null
+++ b/web/pgadmin/utils/preferences.py
@@ -0,0 +1,528 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+from flask import current_app
+from flask.ext.security import current_user
+from pgadmin.model import db, Preferences as PrefTable, \
+    ModulePreference as ModulePrefTable, UserPreference as UserPrefTable, \
+    PreferenceCategory as PrefCategoryTbl
+from flask.ext.babel import gettext
+import dateutil.parser as dateutil_parser
+import decimal
+
+"""
+Utility classes to register a preference option with the system, which will be
+provided.
+"""
+
+
+class _Preference(object):
+    """
+    Internal class representing module, and categoy bound preference.
+    """
+
+    def __init__(
+            self, cid, name, label, _type, default, help_str=None, min_val=None,
+            max_val=None, options=None
+            ):
+        """
+        __init__
+        Constructor/Initializer for the internal _Preferene object.
+
+        It creates a new entry for this preference in configuration table based
+        on the name (if not exists), and keep the id of it for on demand value
+        fetching from the configuration table in later stage. Also, keeps track
+        of type of the preference/option, and other supporting parameters like
+        min, max, options, etc.
+
+        :param cid: configuration id
+        :param name: Name of the preference (must be unique for each
+                     configuration)
+        :param label: Display name of the options/preference
+        :param _type: Type for proper validation on value
+        :param default: Default value
+        :param help_str: Help string to be shown in preferences dialog.
+        :param min_val: minimum value
+        :param max_val: maximum value
+        :param options: options (Array of list objects)
+
+        :returns: nothing
+        """
+        self.cid = cid
+        self.name = name
+        self.default = default
+        self.label = label
+        self._type = _type
+        self.help_str = help_str
+        self.min_val = min_val
+        self.max_val = max_val
+        self.options = options
+
+        # Look into the configuration table to find out the id of the specific
+        # preference.
+        res = PrefTable.query.filter_by(
+            name=name
+            ).first()
+
+        if res is None:
+            # Couldn't find in the configuration table, we will create new
+            # entry for it.
+            res = PrefTable(name=self.name, cid=cid)
+            db.session.add(res)
+            db.session.commit()
+            res = PrefTable.query.filter_by(
+                name=name
+                ).first()
+
+        # Save this id for letter use.
+        self.pid = res.id
+
+    def get(self):
+        """
+        get
+        Fetch the value from the server for the current user from the
+        configuration table (if available), otherwise returns the default value
+        for it.
+
+        :returns: value for this preference.
+        """
+        res = UserPrefTable.query.filter_by(
+            pid=self.pid
+            ).filter_by(uid=current_user.id).first()
+
+        # Couldn't find any preference for this user, return default value.
+        if res is None:
+            return self.default
+
+        # The data stored in the configuration will be in string format, we
+        # need to convert them in proper format.
+        if self._type == 'boolean' or self._type == 'switch' or \
+                self._type == 'node':
+            return res.value == 'True'
+        if self._type == 'integer':
+            try:
+                return int(res.value)
+            except Exception as e:
+                current_app.logger.exeception(e)
+                return self.default
+        if self._type == 'numeric':
+            try:
+                return decimal.Decimal(res.value)
+            except Exception as e:
+                current_app.logger.exeception(e)
+                return self.default
+        if self._type == 'date' or self._type == 'datetime':
+            try:
+                return dateutil_parser.parse(res.value)
+            except Exception as e:
+                current_app.logger.exeception(e)
+                return self.default
+        if self._type == 'options':
+            if res.value in self.options:
+                return res.value
+            return self.default
+
+        return res.value
+
+    def set(self, value):
+        """
+        set
+        Set the value into the configuration table for this current user.
+
+        :param value: Value to be set
+
+        :returns: nothing.
+        """
+        # We can't store the values in the given format, we need to convert
+        # them in string first. We also need to validate the value type.
+        if self._type == 'boolean' or self._type == 'switch' or \
+                self._type == 'node':
+            if type(value) != bool:
+                return False, gettext("Invalid value for boolean type!")
+        elif self._type == 'integer':
+            if type(value) != int:
+                return False, gettext("Invalid value for integer type!")
+        elif self._type == 'numeric':
+            t = type(value)
+            if t != float and t != int and t != decimal.Decimal:
+                return False, gettext("Invalid value for numeric type!")
+        elif self._type == 'date':
+            try:
+                value = dateutil_parser.parse(value).date()
+            except Exception as e:
+                current_app.logger.exeception(e)
+                return False, gettext("Invalid value for date type!")
+        elif self._type == 'datetime':
+            try:
+                value = dateutil_parser.parse(value)
+            except Exception as e:
+                current_app.logger.exeception(e)
+                return False, gettext("Invalid value for datetime type!")
+        elif self._type == 'options':
+            if value not in self.options:
+                return False, gettext("Invalid value for options type!")
+
+        pref = UserPrefTable.query.filter_by(
+            pid=self.pid
+            ).filter_by(uid=current_user.id).first()
+
+        if pref is None:
+            pref = UserPrefTable(
+                uid=current_user.id, pid=self.pid, value=str(value)
+                )
+            db.session.add(pref)
+        else:
+            pref.value = str(value)
+        db.session.commit()
+
+        return True, None
+
+    def to_json(self):
+        """
+        to_json
+        Returns the JSON object representing this preferences.
+
+        :returns: the JSON representation for this preferences
+        """
+        res = {
+            'id': self.pid,
+            'cid': self.cid,
+            'name': self.name,
+            'label': self.label or self.name,
+            'type': self._type,
+            'help_str': self.help_str,
+            'min_val': self.min_val,
+            'max_val': self.max_val,
+            'options': self.options,
+            'value': self.get()
+            }
+        return res
+
+
+class Preferences(object):
+    """
+    class Preferences
+
+    It helps to manage all the preferences/options related to a specific
+    module.
+
+    It keeps track of all the preferences registered with it using this class
+    in the group of categories.
+
+    Also, create the required entries for each module, and categories in the
+    preferences tables (if required). If it is already present, it will refer
+    to the existing data from those tables.
+
+    class variables:
+    ---------------
+    modules:
+    Dictionary of all the modules, can be refered by its name.
+    Keeps track of all the modules in it, so that - only one object per module
+    gets created. If the same module refered by different object, the
+    categories dictionary within it will be shared between them to keep the
+    consistent data among all the object.
+
+    Instance Definitions:
+    -------- -----------
+    """
+    modules = dict()
+
+    def __init__(self, name, label=None):
+        """
+        __init__
+        Constructor/Initializer for the Preferences class.
+
+        :param name: Name of the module
+        :param label: Display name of the module, it will be displayed in the
+                      preferences dialog.
+
+        :returns nothing
+        """
+        self.name = name
+        self.label = label
+        self.categories = dict()
+
+        # Find the entry for this module in the configuration database.
+        module = ModulePrefTable.query.filter_by(name=name).first()
+
+        # Can't find the reference for it in the configuration database,
+        # create on for it.
+        if module is None:
+            module = ModulePrefTable(name=name)
+            db.session.add(module)
+            db.session.commit()
+            module = ModulePrefTable.query.filter_by(name=name).first()
+
+        self.mid = module.id
+
+        if name in Preferences.modules:
+            m = Preferences.modules
+            self.categories = m.categories
+        else:
+            Preferences.modules[name] = self
+
+    def to_json(self):
+        """
+        to_json
+        Converts the preference object to the JSON Format.
+
+        :returns: a JSON object contains information.
+        """
+        res = {
+            'id': self.mid,
+            'label': self.label or self.name,
+            'categories': []
+        }
+        for c in self.categories:
+            cat = self.categories[c]
+            interm = {
+                'id': cat['id'],
+                'label': cat['label'] or cat['name'],
+                'preferences': []
+                }
+
+            res['categories'].append(interm)
+
+            for p in cat['preferences']:
+                pref = (cat['preferences'][p]).to_json().copy()
+                pref.update({'mid': self.mid, 'cid': cat['id']})
+                interm['preferences'].append(pref)
+
+        return res
+
+    def __category(self, name, label):
+        """
+        __category
+
+        A private method to create/refer category for/of this module.
+
+        :param name: Name of the category
+        :param label: Display name of the category, it will be send to
+                      client/front end to list down in the preferences/options
+                      dialog.
+        :returns: A dictionary object reprenting this category.
+        """
+        if name in self.categories:
+            res = self.categories[name]
+            # Update the category label (if not yet defined)
+            res['label'] = res['label'] or label
+
+            return res
+
+        cat = PrefCategoryTbl.query.filter_by(
+            mid=self.mid
+            ).filter_by(name=name).first()
+
+        if cat is None:
+            cat = PrefCategoryTbl(name=name, mid=self.mid)
+            db.session.add(cat)
+            db.session.commit()
+            cat = PrefCategoryTbl.query.filter_by(
+                mid=self.mid
+                ).filter_by(name=name).first()
+
+        self.categories[name] = res = {
+            'id': cat.id,
+            'name': name,
+            'label': label,
+            'preferences': dict()
+            }
+
+        return res
+
+    def register(
+        self, category, name, label, _type, default, min_val=None,
+        max_val=None, options=None, help_str=None, category_label=None
+    ):
+        """
+        register
+        Register/Refer the particular preference in this module.
+
+        :param category: name of the category, in which this preference/option
+                         will be displayed.
+        :param name:     name of the preference/option
+        :param label:    Display name of the preference
+        :param _type:    [optional] Type of the options.
+                         It is an optional argument, only if this
+                         option/preference is registered earlier.
+        :param default:  [optional] Default value of the options
+                         It is an optional argument, only if this
+                         option/preference is registered earlier.
+        :param min_val:
+        :param max_val:
+        :param options:
+        :param help_str:
+        :param category_label:
+        """
+        cat = self.__category(category, category_label)
+        if name in cat['preferences']:
+            return (cat['preferences'])[name]
+
+        assert label is not None, "Label for a preference can not be none!"
+        assert _type is not None, "Type for a preference can not be none!"
+        assert _type in (
+            'boolean', 'integer', 'numeric', 'date', 'datetime',
+            'options', 'multiline', 'switch', 'node'
+            ), "Type can not be found in the defined list!"
+
+        (cat['preferences'])[name] = res = _Preference(
+            cat['id'], name, label, _type, default, help_str, min_val,
+            max_val, options
+            )
+
+        return res
+
+    def preference(self, name):
+        """
+        preference
+        Refer the particular preference in this module.
+
+        :param name:     name of the preference/option
+        """
+        for key in self.categories:
+            cat = self.categories[key]
+            if name in cat['preferences']:
+                return (cat['preferences'])[name]
+
+        assert False, """Couldn't find the preference in this preference!
+Did you forget to register it?"""
+
+    @classmethod
+    def preferences(cls):
+        """
+        preferences
+        Convert all the module preferences in the JSON format.
+
+        :returns: a list of the preferences for each of the modules.
+        """
+        res = []
+
+        for m in Preferences.modules:
+            res.append(Preferences.modules[m].to_json())
+
+        return res
+
+    @classmethod
+    def register_preference(
+            cls, module, category, name, label, _type, default, min_val=None,
+            max_val=None, options=None, help_str=None, module_label=None,
+            category_label=None
+            ):
+        """
+        register
+        Register/Refer a preference in the system for any module.
+
+        :param module:   Name of the module
+        :param category: Name of category
+        :param name:     Name of the option
+        :param label:    Label of the option, shown in the preferences dialog.
+        :param _type:    Type of the option.
+                         Allowed type of options are as below:
+                         boolean, integer, numeric, date, datetime,
+                         options, multiline, switch, node
+        :param default:  Default value for the preference/option
+        :param min_val:  Minimum value for integer, and numeric type
+        :param max_val:  Maximum value for integer, and numeric type
+        :param options:  Allowed list of options for 'option' type
+        :param help_str: Help string show for that preference/option.
+        :param module_label: Label for the module
+        :param category_label: Label for the category
+        """
+        m = None
+        if module in Preferences.modules:
+            m = Preferences.modules[module]
+            # Update the label (if not defined yet)
+            m.label = m.label or module_label
+        else:
+            m = Preferences(module, module_label)
+
+        return m.register(
+            category, name, label, _type, default, min_val, max_val,
+            options, help_str, category_label
+            )
+
+    @classmethod
+    def module(cls, name):
+        """
+        module (classmethod)
+        Get the module preferences object
+
+        :param name: Name of the module
+        :returns: a Preferences object representing for the module.
+        """
+        if name in Preferences.modules:
+            m = Preferences.modules[name]
+            # Update the label (if not defined yet)
+            if m.label is None:
+                m.label = name
+            return m
+        else:
+            m = Preferences(name, None)
+
+        return m
+
+    @classmethod
+    def save(cls, mid, cid, pid, value):
+        """
+        save
+        Update the value for the preference in the configuration database.
+
+        :param mid: Module ID
+        :param cid: Category ID
+        :param pid: Preference ID
+        :param value: Value for the options
+        """
+        # Find the entry for this module in the configuration database.
+        module = ModulePrefTable.query.filter_by(id=mid).first()
+
+        # Can't find the reference for it in the configuration database,
+        # create on for it.
+        if module is None:
+            return False, gettext("Couldn't find the specified module.")
+
+        m = cls.modules[module.name]
+
+        if m is None:
+            return False, gettext(
+                "Module '{0}' is no longer in use!"
+            ).format(module.name)
+
+        category = None
+
+        for c in m.categories:
+            cat = m.categories[c]
+            if cid == cat['id']:
+                category = cat
+                break
+
+        if category is None:
+            return False, gettext(
+                 "Module '{0}' does not have category with id '{1}'"
+            ).format(module.name, cid)
+
+        preference = None
+
+        for p in category['preferences']:
+            pref = (category['preferences'])[p]
+
+            if pref.pid == pid:
+                preference = pref
+                break
+
+        if preference is None:
+            return False, gettext(
+                 "Couldn't find the given preference!"
+            )
+
+        try:
+            pref.set(value)
+        except Exception as e:
+            return False, str(e)
+
+        return True, None
diff --git a/web/setup.py b/web/setup.py
index ae47ac3..5b407c1 100644
--- a/web/setup.py
+++ b/web/setup.py
@@ -17,10 +17,9 @@ import random
 import string
 
 from flask import Flask
-from flask.ext.sqlalchemy import SQLAlchemy
 from flask.ext.security import Security, SQLAlchemyUserDatastore
 from flask.ext.security.utils import encrypt_password
-from pgadmin.settings.settings_model import db, Role, User, Server, \
+from pgadmin.model import db, Role, User, Server, \
     ServerGroup, Version
 
 # Configuration settings
@@ -146,7 +145,7 @@ Exiting...""".format(version.value))
                 )
         if int(version.value) < 5:
             db.engine.execute('ALTER TABLE server ADD COLUMN role text(64)')
-        if int(version.value) == 6:
+        if int(version.value) < 6:
             db.engine.execute("ALTER TABLE server RENAME TO server_old")
             db.engine.execute("""
 CREATE TABLE server (
@@ -177,9 +176,46 @@ INSERT INTO server (
 FROM server_old""")
             db.engine.execute("DROP TABLE server_old")
 
-        # Finally, update the schema version
-        version.value = config.SETTINGS_SCHEMA_VERSION
-        db.session.merge(version)
+        if int(version.value) < 8:
+            app.logger.info(
+                "Creating the preferences tables..."
+                )
+            db.engine.execute("""
+CREATE TABLE module_preference(
+    id INTEGER PRIMARY KEY,
+    name VARCHAR(256) NOT NULL
+    )""")
+
+            db.engine.execute("""
+CREATE TABLE preference_category(
+    id INTEGER PRIMARY KEY,
+    mid INTEGER,
+    name VARCHAR(256) NOT NULL,
+
+    FOREIGN KEY(mid) REFERENCES module_preference(id)
+    )""")
+
+            db.engine.execute("""
+CREATE TABLE preferences (
+
+    id INTEGER PRIMARY KEY,
+    cid INTEGER NOT NULL,
+    name VARCHAR(256) NOT NULL,
+
+    FOREIGN KEY(cid) REFERENCES preference_category (id)
+    )""")
+
+            db.engine.execute("""
+CREATE TABLE user_preferences (
+
+    pid INTEGER,
+    uid INTEGER,
+    value VARCHAR(1024) NOT NULL,
+
+    PRIMARY KEY (pid, uid),
+    FOREIGN KEY(pid) REFERENCES preferences (pid),
+    FOREIGN KEY(uid) REFERENCES user (id)
+    )""")
 
     # Finally, update the schema version
     version.value = config.SETTINGS_SCHEMA_VERSION
@@ -190,7 +226,7 @@ FROM server_old""")
     # Done!
     app.logger.info(
         "The configuration database %s has been upgraded to version %d" %
-        (config.SQLITE_PATH, config.SETTINGS_SCHEMA_VERSION)
+            (config.SQLITE_PATH, config.SETTINGS_SCHEMA_VERSION)
         )
 
 ###############################################################################
@@ -222,8 +258,8 @@ if __name__ == '__main__':
     # Check if the database exists. If it does, tell the user and exit.
     if os.path.isfile(config.SQLITE_PATH):
         print("""
-The configuration database %s already exists.
-Entering upgrade mode...""".format(config.SQLITE_PATH))
+The configuration database '%s' already exists.
+Entering upgrade mode...""" % config.SQLITE_PATH)
 
         # Setup Flask-Security
         user_datastore = SQLAlchemyUserDatastore(db, User, Role)
@@ -238,12 +274,12 @@ Entering upgrade mode...""".format(config.SQLITE_PATH))
                 print("""
 The database schema version is %d, whilst the version required by the \
 software is %d.
-Exiting...""".format(version.value, config.SETTINGS_SCHEMA_VERSION))
+Exiting...""" % (version.value, config.SETTINGS_SCHEMA_VERSION))
                 sys.exit(1)
             elif int(version.value) == int(config.SETTINGS_SCHEMA_VERSION):
                 print("""
 The database schema version is %d as required.
-Exiting...""".format(version.value))
+Exiting...""" % (version.value))
                 sys.exit(1)
 
             print("NOTE: Upgrading database schema from version %d to %d." % (
@@ -252,6 +288,6 @@ Exiting...""".format(version.value))
             do_upgrade(app, user_datastore, security, version)
     else:
         print("""
-The configuration database - {0} does not exist.
+The configuration database - '{0}' does not exist.
 Entering initial setup mode...""".format(config.SQLITE_PATH))
         do_setup(app)
