diff --git a/core/API/Proxy.php b/core/API/Proxy.php
index bceac4556b7f5262adda56923b502276b061594a..f843bdb5fc42e5072a0f6f32f01fddb2f826ab0b 100644
--- a/core/API/Proxy.php
+++ b/core/API/Proxy.php
@@ -28,7 +28,7 @@ use ReflectionMethod;
  *
  * @package Piwik
  * @subpackage Piwik_API
- * @method \Piwik\API\Proxy getInstance()
+ * @static \Piwik\API\Proxy getInstance()
  */
 class Proxy extends Singleton
 {
@@ -265,6 +265,19 @@ class Proxy extends Singleton
         return str_replace(array('\\Piwik\\Plugins\\', '\\API'), '', $className);
     }
 
+    public function isExistingApiAction($pluginName, $apiAction)
+    {
+        $namespacedApiClassName = "\\Piwik\\Plugins\\$pluginName\\API";
+        $api = $namespacedApiClassName::getInstance();
+
+        return method_exists($api, $apiAction);
+    }
+
+    public function buildApiActionName($pluginName, $apiAction)
+    {
+        return sprintf("%s.%s", $pluginName, $apiAction);
+    }
+
     /**
      * Sets whether to hide '@ignore'd functions from method metadata or not.
      *
diff --git a/core/API/Request.php b/core/API/Request.php
index 93673bc1b1976b9c97ee516ff087fd3c86130fa0..219bcb2c2d42afcba07de86ed241bef790a20f3f 100644
--- a/core/API/Request.php
+++ b/core/API/Request.php
@@ -263,6 +263,21 @@ class Request
         return $GET;
     }
 
+    /**
+     * Returns URL for this report w/o any filter parameters.
+     *
+     * @param string $module
+     * @param string $action
+     * @param array $queryParams
+     *
+     * @return string
+     */
+    public static function getBaseReportUrl($module, $action, $queryParams = array())
+    {
+        $params = array_merge($queryParams, array('module' => $module, 'action' => $action));
+        return Request::getCurrentUrlWithoutGenericFilters($params);
+    }
+
     /**
      * Returns the current URL without generic filter query parameters.
      *
diff --git a/core/Common.php b/core/Common.php
index 8b5409469c8975719221283a69a3663763567bc8..2d7a95e0b6f04ad4a8b551cc4bb672d1a8316170 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -597,6 +597,19 @@ class Common
         return json_decode($json, $assoc);
     }
 
+    /**
+     * Returns the list of parent classes for the given class.
+     *
+     * @param  string    $klass   A class name.
+     * @return string[]  The list of parent classes in order from highest ancestor to the descended class.
+     */
+    public static function getClassLineage($klass)
+    {
+        $klasses = array_merge(array($klass), array_values(class_parents($klass, $autoload = false)));
+
+        return array_reverse($klasses);
+    }
+
     /*
      * DataFiles
      */
diff --git a/core/FrontController.php b/core/FrontController.php
index 0c43174fd78051c693e675dadb1469ff46876b63..f00e8772e9ea8648f97ff2e18afaf9ed5b3d208a 100644
--- a/core/FrontController.php
+++ b/core/FrontController.php
@@ -26,7 +26,7 @@ use Piwik\Session;
  *
  * @package Piwik
  * @subpackage FrontController
- * @method \Piwik\FrontController getInstance()
+ * @static \Piwik\FrontController getInstance()
  */
 class FrontController extends Singleton
 {
diff --git a/core/Plugin/API.php b/core/Plugin/API.php
index e10baf788878da70ea8ac5972543d98501006ad9..bb7e67cd7ec68bc549cb01c814f92c24a0f41c1f 100644
--- a/core/Plugin/API.php
+++ b/core/Plugin/API.php
@@ -15,4 +15,5 @@ use Piwik\Singleton;
 
 abstract class API extends Singleton
 {
+
 }
diff --git a/core/Plugin/Controller.php b/core/Plugin/Controller.php
index f16d4c694b0bbe26e77f461d9df7e3c7569b304f..b1be2080b1e954d187b945f68c0c3bba82a90cc1 100644
--- a/core/Plugin/Controller.php
+++ b/core/Plugin/Controller.php
@@ -32,7 +32,7 @@ use Piwik\SettingsPiwik;
 use Piwik\Site;
 use Piwik\Url;
 use Piwik\View;
-use Piwik\ViewDataTable;
+use Piwik\ViewDataTable as ViewDataTableBuilder;
 
 /**
  * Parent class of all plugins Controllers (located in /plugins/PluginName/Controller.php
@@ -179,9 +179,9 @@ abstract class Controller
      */
     protected function getLastUnitGraph($currentModuleName, $currentControllerAction, $apiMethod)
     {
-        $view = ViewDataTable::factory(
+        $view = ViewDataTableBuilder::factory(
             'graphEvolution', $apiMethod, $currentModuleName . '.' . $currentControllerAction, $forceDefault = true);
-        $view->show_goals = false;
+        $view->config->show_goals = false;
         return $view;
     }
 
@@ -222,13 +222,16 @@ abstract class Controller
 
         // initialize the graph and load the data
         $view = $this->getLastUnitGraph($currentModuleName, $currentControllerAction, $apiMethod);
-        $view->columns_to_display = $columnsToDisplay;
-        $view->visualization_properties->selectable_columns =
-            array_merge($view->visualization_properties->selectable_columns ? : array(), $selectableColumns);
-        $view->translations += $translations;
+        $view->config->columns_to_display = $columnsToDisplay;
+
+        if (property_exists($view->config, 'selectable_columns')) {
+            $view->config->selectable_columns = array_merge($view->config->selectable_columns ? : array(), $selectableColumns);
+        }
+
+        $view->config->translations += $translations;
 
         if ($reportDocumentation) {
-            $view->documentation = $reportDocumentation;
+            $view->config->documentation = $reportDocumentation;
         }
 
         return $view;
diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php
index b0e5e9153aea7b5a7ec28d436a3e80d9a377f43d..1b536f8d8cc8d26181054ba599f522983671fda4 100644
--- a/core/Plugin/Manager.php
+++ b/core/Plugin/Manager.php
@@ -25,7 +25,7 @@ require_once PIWIK_INCLUDE_PATH . '/core/EventDispatcher.php';
 /**
  * Plugin manager
  *
- * @method \Piwik\Plugin\Manager getInstance()
+ * @static \Piwik\Plugin\Manager getInstance()
  * @package Piwik
  * @subpackage Manager
  */
diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php
new file mode 100644
index 0000000000000000000000000000000000000000..933e4cdbe85c07ea2c96d35f1411ca6643829ee9
--- /dev/null
+++ b/core/Plugin/ViewDataTable.php
@@ -0,0 +1,481 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
+namespace Piwik\Plugin;
+
+use Piwik\API\Request;
+use Piwik\Common;
+use Piwik\DataTable;
+use Piwik\Date;
+use Piwik\Log;
+use Piwik\MetricsFormatter;
+use Piwik\Period;
+use Piwik\Period\Range;
+use Piwik\Piwik;
+use Piwik\Plugins\PrivacyManager\PrivacyManager;
+use Piwik\Site;
+use Piwik\View;
+use Piwik\View\ViewInterface;
+use Piwik\ViewDataTable\Config as VizConfig;
+use Piwik\ViewDataTable\Request as ViewDataTableRequest;
+use Piwik\ViewDataTable\RequestConfig as VizRequest;
+
+/**
+ * This class is used to load (from the API) and customize the output of a given DataTable.
+ * The main() method will create an object implementing ViewInterface
+ * You can customize the dataTable using the disable* methods.
+ *
+ * You can also customize the dataTable rendering using row metadata:
+ * - 'html_label_prefix': If this metadata is present on a row, it's contents will be prepended
+ *                        the label in the HTML output.
+ * - 'html_label_suffix': If this metadata is present on a row, it's contents will be appended
+ *                        after the label in the HTML output.
+ *
+ * Example:
+ * In the Controller of the plugin VisitorInterest
+ * <pre>
+ *    function getNumberOfVisitsPerVisitDuration( $fetch = false)
+ *  {
+ *        $view = ViewDataTable::factory( 'cloud' );
+ *        $view->init( $this->pluginName,  __FUNCTION__, 'VisitorInterest.getNumberOfVisitsPerVisitDuration' );
+ *        $view->setColumnsToDisplay( array('label','nb_visits') );
+ *        $view->disableSort();
+ *        $view->disableExcludeLowPopulation();
+ *        $view->disableOffsetInformation();
+ *
+ *        return $this->renderView($view, $fetch);
+ *    }
+ * </pre>
+ *
+ * @see factory() for all the available output (cloud tags, html table, pie chart, vertical bar chart)
+ * @package Piwik
+ * @subpackage ViewDataTable
+ *
+ * @api
+ */
+abstract class ViewDataTable implements ViewInterface
+{
+    const ID = '';
+    const CONFIGURE_FOOTER_ICONS_EVENT = 'Visualization.configureFooterIcons';
+
+    /**
+     * DataTable loaded from the API for this ViewDataTable.
+     *
+     * @var DataTable
+     */
+    protected $dataTable = null;
+
+    /**
+     * @var \Piwik\ViewDataTable\Config
+     */
+    public $config;
+
+    /**
+     * @var \Piwik\ViewDataTable\RequestConfig
+     */
+    public $requestConfig;
+
+    /**
+     * @var ViewDataTableRequest
+     */
+    protected $request;
+
+    /**
+     * Default constructor.
+     */
+    public function __construct($controllerAction, $apiMethodToRequestDataTable)
+    {
+        list($controllerName, $controllerAction) = explode('.', $controllerAction);
+
+        $this->requestConfig = static::getDefaultRequestConfig();
+        $this->config        = static::getDefaultConfig();
+        $this->config->subtable_controller_action = $controllerAction;
+        $this->config->setController($controllerName, $controllerAction);
+
+        $this->request = new ViewDataTableRequest($this->requestConfig);
+
+        $this->requestConfig->idSubtable = Common::getRequestVar('idSubtable', false, 'int');
+        $this->config->self_url          = Request::getBaseReportUrl($controllerName, $controllerAction);
+
+        $this->requestConfig->apiMethodToRequestDataTable = $apiMethodToRequestDataTable;
+
+        /**
+         * This event is triggered to gather the report display properties for each available report. If you define
+         * your own report, you want to subscribe to this event to define how your report shall be displayed in the
+         * Piwik UI.
+         *
+         * public function configureViewDataTable(ViewDataTable $view)
+         * {
+         *     switch ($view->requestConfig->apiMethodToRequestDataTable) {
+         *         case 'VisitTime.getVisitInformationPerServerTime':
+         *             $view->config->enable_sort = true;
+         *             $view->requestConfig->filter_limit = 10;
+         *             break;
+         *     }
+         * }
+         */
+        Piwik::postEvent('ViewDataTable.configure', array($this));
+
+        $this->config->show_footer_icons = (false == $this->requestConfig->idSubtable);
+
+        // the exclude low population threshold value is sometimes obtained by requesting data.
+        // to avoid issuing unecessary requests when display properties are determined by metadata,
+        // we allow it to be a closure.
+        if (isset($this->requestConfig->filter_excludelowpop_value)
+            && $this->requestConfig->filter_excludelowpop_value instanceof \Closure
+        ) {
+            $function = $this->requestConfig->filter_excludelowpop_value;
+            $this->requestConfig->filter_excludelowpop_value = $function();
+        }
+
+        $this->overrideViewPropertiesWithQueryParams();
+    }
+
+    public static function getDefaultConfig()
+    {
+        return new VizConfig();
+    }
+
+    public static function getDefaultRequestConfig()
+    {
+        return new VizRequest();
+    }
+
+    protected function loadDataTableFromAPI()
+    {
+        if (!is_null($this->dataTable)) {
+            // data table is already there
+            // this happens when setDataTable has been used
+            return $this->dataTable;
+        }
+
+        $this->dataTable = $this->request->loadDataTableFromAPI();
+
+        return $this->dataTable;
+    }
+
+    /**
+     * Returns the viewDataTable ID for this DataTable visualization. Derived classes
+     * should declare a const ID field with the viewDataTable ID.
+     *
+     * @throws \Exception
+     * @return string
+     */
+    public static function getViewDataTableId()
+    {
+        $id = static::ID;
+
+        if (empty($id)) {
+            $message = sprintf('ViewDataTable %s does not define an ID. Set the ID constant to fix this issue', get_called_class());
+            throw new \Exception($message);
+        }
+
+       return $id;
+    }
+
+    public function isViewDataTableId($viewDataTableId)
+    {
+        $myIds = static::getIdsWithInheritance(get_called_class());
+
+        return in_array($viewDataTableId, $myIds);
+    }
+
+    /**
+     * Returns the DataTable loaded from the API
+     *
+     * @return DataTable
+     * @throws \Exception if not yet defined
+     */
+    public function getDataTable()
+    {
+        if (is_null($this->dataTable)) {
+            throw new \Exception("The DataTable object has not yet been created");
+        }
+
+        return $this->dataTable;
+    }
+
+    /**
+     * To prevent calling an API multiple times, the DataTable can be set directly.
+     * It won't be loaded again from the API in this case
+     *
+     * @param $dataTable
+     * @return void $dataTable DataTable
+     */
+    public function setDataTable($dataTable)
+    {
+        $this->dataTable = $dataTable;
+    }
+
+    /**
+     * Returns the viewDataTable IDs of a visualization's class lineage.
+     *
+     * @see self::getVisualizationClassLineage
+     *
+     * @param string $klass The visualization class.
+     *
+     * @return array
+     */
+    public static function getIdsWithInheritance($klass)
+    {
+        $klasses = Common::getClassLineage($klass);
+
+        $result = array();
+        foreach ($klasses as $klass) {
+            if ('Piwik\\Plugin\\ViewDataTable' != $klass
+                && 'Piwik\\Plugin\\Visualization' != $klass) {
+                $result[] = $klass::getViewDataTableId();
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Checks that the API returned a normal DataTable (as opposed to DataTable\Map)
+     * @throws \Exception
+     * @return void
+     */
+    protected function checkStandardDataTable()
+    {
+        Piwik::checkObjectTypeIs($this->dataTable, array('\Piwik\DataTable'));
+    }
+
+    /**
+     * Convenience function. Calls main() & renders the view that gets built.
+     *
+     * @return string The result of rendering.
+     */
+    public function render()
+    {
+        $view = $this->buildView();
+        return $view->render();
+    }
+
+    abstract protected function buildView();
+
+    protected function getDefaultFooterIconsToShow()
+    {
+        $result = array();
+
+        // add normal view icons (eg, normal table, all columns, goals)
+        $normalViewIcons = array(
+            'class'   => 'tableAllColumnsSwitch',
+            'buttons' => array(),
+        );
+
+        if ($this->config->show_table) {
+            $normalViewIcons['buttons'][] = array(
+                'id'    => 'table',
+                'title' => Piwik::translate('General_DisplaySimpleTable'),
+                'icon'  => 'plugins/Zeitgeist/images/table.png',
+            );
+        }
+
+        if ($this->config->show_table_all_columns) {
+            $normalViewIcons['buttons'][] = array(
+                'id'    => 'tableAllColumns',
+                'title' => Piwik::translate('General_DisplayTableWithMoreMetrics'),
+                'icon'  => 'plugins/Zeitgeist/images/table_more.png'
+            );
+        }
+
+        if ($this->config->show_goals) {
+            if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
+                $icon = 'plugins/Zeitgeist/images/ecommerceOrder.gif';
+            } else {
+                $icon = 'plugins/Zeitgeist/images/goal.png';
+            }
+
+            $normalViewIcons['buttons'][] = array(
+                'id'    => 'tableGoals',
+                'title' => Piwik::translate('General_DisplayTableWithGoalMetrics'),
+                'icon'  => $icon
+            );
+        }
+
+        if ($this->config->show_ecommerce) {
+            $normalViewIcons['buttons'][] = array(
+                'id'    => 'ecommerceOrder',
+                'title' => Piwik::translate('General_EcommerceOrders'),
+                'icon'  => 'plugins/Zeitgeist/images/ecommerceOrder.gif',
+                'text'  => Piwik::translate('General_EcommerceOrders')
+            );
+
+            $normalViewIcons['buttons'][] = array(
+                'id'    => 'ecommerceAbandonedCart',
+                'title' => Piwik::translate('General_AbandonedCarts'),
+                'icon'  => 'plugins/Zeitgeist/images/ecommerceAbandonedCart.gif',
+                'text'  => Piwik::translate('General_AbandonedCarts')
+            );
+        }
+
+        if (!empty($normalViewIcons['buttons'])) {
+            $result[] = $normalViewIcons;
+        }
+
+        // add graph views
+        $graphViewIcons = array(
+            'class'   => 'tableGraphViews tableGraphCollapsed',
+            'buttons' => array(),
+        );
+
+        if ($this->config->show_all_views_icons) {
+            if ($this->config->show_bar_chart) {
+                $graphViewIcons['buttons'][] = array(
+                    'id'    => 'graphVerticalBar',
+                    'title' => Piwik::translate('General_VBarGraph'),
+                    'icon'  => 'plugins/Zeitgeist/images/chart_bar.png'
+                );
+            }
+
+            if ($this->config->show_pie_chart) {
+                $graphViewIcons['buttons'][] = array(
+                    'id'    => 'graphPie',
+                    'title' => Piwik::translate('General_Piechart'),
+                    'icon'  => 'plugins/Zeitgeist/images/chart_pie.png'
+                );
+            }
+
+            if ($this->config->show_tag_cloud) {
+                $graphViewIcons['buttons'][] = array(
+                    'id'    => 'cloud',
+                    'title' => Piwik::translate('General_TagCloud'),
+                    'icon'  => 'plugins/Zeitgeist/images/tagcloud.png'
+                );
+            }
+
+            if ($this->config->show_non_core_visualizations) {
+                $nonCoreVisualizations    = \Piwik\ViewDataTable::getNonCoreVisualizations();
+                $nonCoreVisualizationInfo = static::getVisualizationInfoFor($nonCoreVisualizations);
+
+                foreach ($nonCoreVisualizationInfo as $format => $info) {
+                    $graphViewIcons['buttons'][] = array(
+                        'id'    => $format,
+                        'title' => Piwik::translate($info['title']),
+                        'icon'  => $info['table_icon']
+                    );
+                }
+            }
+        }
+
+        if (!empty($graphViewIcons['buttons'])) {
+            $result[] = $graphViewIcons;
+        }
+
+        /**
+         * This event is called when determining the default set of footer icons to display
+         * below a report.
+         *
+         * Plugins can use this event to modify the default set of footer icons. You can
+         * add new icons or remove existing ones.
+         *
+         * $result must have the following format:
+         *
+         * ```
+         * array(
+         *     array( // footer icon group 1
+         *         'class' => 'footerIconGroup1CssClass',
+         *         'buttons' => array(
+         *             'id' => 'myid',
+         *             'title' => 'My Tooltip',
+         *             'icon' => 'path/to/my/icon.png'
+         *         )
+         *     ),
+         *     array( // footer icon group 2
+         *         'class' => 'footerIconGroup2CssClass',
+         *         'buttons' => array(...)
+         *     ),
+         *     ...
+         * )
+         * ```
+         */
+        Piwik::postEvent(self::CONFIGURE_FOOTER_ICONS_EVENT, array(&$result, $viewDataTable = $this));
+
+        return $result;
+    }
+
+    public function getDefaultDataTableCssClass()
+    {
+        return 'dataTableViz' . Piwik::getUnnamespacedClassName(get_class($this));
+    }
+
+    /**
+     * Returns an array mapping visualization IDs with information necessary for adding the
+     * visualizations to the footer of DataTable views.
+     *
+     * @param array $visualizations An array mapping visualization IDs w/ their associated classes.
+     * @return array
+     */
+    public static function getVisualizationInfoFor($visualizations)
+    {
+        $result = array();
+
+        foreach ($visualizations as $vizId => $vizClass) {
+            $result[$vizId] = array('table_icon' => $vizClass::FOOTER_ICON, 'title' => $vizClass::FOOTER_ICON_TITLE);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns the list of view properties that can be overriden by query parameters.
+     *
+     * @return array
+     */
+    public function getOverridableProperties()
+    {
+        return array_merge($this->config->overridableProperties, $this->requestConfig->overridableProperties);
+    }
+
+    private function overrideViewPropertiesWithQueryParams()
+    {
+        $properties = $this->getOverridableProperties();
+
+        foreach ($properties as $name) {
+            if (property_exists($this->requestConfig, $name)) {
+                $this->requestConfig->name = $this->getPropertyFromQueryParam($name, $this->requestConfig->$name);
+            } elseif (property_exists($this->config, $name)) {
+                $this->config->name  = $this->getPropertyFromQueryParam($name, $this->config->$name);
+            }
+        }
+
+        // handle special 'columns' query parameter
+        $columns = Common::getRequestVar('columns', false);
+
+        if (false !== $columns) {
+            $this->config->columns_to_display = Piwik::getArrayFromApiParameter($columns);
+            array_unshift($this->config->columns_to_display, 'label');
+        }
+    }
+
+    protected function getPropertyFromQueryParam($name, $defaultValue)
+    {
+        $type = is_numeric($defaultValue) ? 'int' : null;
+        return Common::getRequestVar($name, $defaultValue, $type);
+    }
+
+    public function isRequestingSingleDataTable()
+    {
+        $requestArray = $this->request->getRequestArray() + $_GET + $_POST;
+        $date   = Common::getRequestVar('date', null, 'string', $requestArray);
+        $period = Common::getRequestVar('period', null, 'string', $requestArray);
+        $idSite = Common::getRequestVar('idSite', null, 'string', $requestArray);
+
+        if (Period::isMultiplePeriod($date, $period)
+            || strpos($idSite, ',') !== false
+            || $idSite == 'all'
+        ) {
+            return false;
+        }
+
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php
new file mode 100644
index 0000000000000000000000000000000000000000..d57125b009159f5ddc22830b1f67b087aa4a37f4
--- /dev/null
+++ b/core/Plugin/Visualization.php
@@ -0,0 +1,463 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
+
+namespace Piwik\Plugin;
+
+use Piwik\Common;
+use Piwik\DataTable;
+use Piwik\Date;
+use Piwik\Log;
+use Piwik\Metrics;
+use Piwik\MetricsFormatter;
+use Piwik\NoAccessException;
+use Piwik\Option;
+use Piwik\Period;
+use Piwik\Period\Range;
+use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\PrivacyManager\PrivacyManager;
+use Piwik\Site;
+use Piwik\View;
+
+/**
+ * Base class for all DataTable visualizations. Different visualizations are used to
+ * handle different values of the viewDataTable query parameter. Each one will display
+ * DataTable data in a different way.
+ *
+ * TODO: must be more in depth
+ */
+class Visualization extends ViewDataTable
+{
+    const TEMPLATE_FILE = '';
+
+    private $templateVars = array();
+
+    final public function __construct($controllerAction, $apiMethodToRequestDataTable)
+    {
+        $templateFile = static::TEMPLATE_FILE;
+
+        if (empty($templateFile)) {
+            throw new \Exception('You have not defined a constant named TEMPLATE_FILE in your visualization class.');
+        }
+
+        parent::__construct($controllerAction, $apiMethodToRequestDataTable);
+    }
+
+    protected function init()
+    {
+        // do your init stuff here, do not overwrite constructor
+    }
+
+    protected function buildView()
+    {
+        $this->overrideSomeConfigPropertiesIfNeeded();
+
+        try {
+
+            $this->beforeLoadDataTable();
+
+            $this->loadDataTableFromAPI();
+            $this->postDataTableLoadedFromAPI();
+
+            $requestPropertiesAfterLoadDataTable = $this->requestConfig->getProperties();
+
+            $this->applyFilters();
+            $this->afterAllFilteresAreApplied();
+            $this->beforeRender();
+
+            $this->logMessageIfRequestPropertiesHaveChanged($requestPropertiesAfterLoadDataTable);
+
+        } catch (NoAccessException $e) {
+            throw $e;
+        } catch (\Exception $e) {
+            Log::warning("Failed to get data from API: " . $e->getMessage());
+
+            $loadingError = array('message' => $e->getMessage());
+        }
+
+        $view = new View("@CoreHome/_dataTable");
+
+        if (!empty($loadingError)) {
+            $view->error = $loadingError;
+        }
+
+        $view->assign($this->templateVars);
+        $view->visualization         = $this;
+        $view->visualizationTemplate = static::TEMPLATE_FILE;
+        $view->visualizationCssClass = $this->getDefaultDataTableCssClass();
+
+        if (null === $this->dataTable) {
+            $view->dataTable = null;
+        } else {
+            $view->dataTableHasNoData = !$this->isThereDataToDisplay();
+            $view->dataTable          = $this->dataTable;
+
+            // if it's likely that the report data for this data table has been purged,
+            // set whether we should display a message to that effect.
+            $view->showReportDataWasPurgedMessage = $this->hasReportBeenPurged();
+            $view->deleteReportsOlderThan         = Option::get('delete_reports_older_than');
+        }
+
+        $view->idSubtable  = $this->requestConfig->idSubtable;
+        $view->clientSideParameters = $this->getClientSideParametersToSet();
+        $view->clientSideProperties = $this->getClientSidePropertiesToSet();
+        $view->properties  = array_merge($this->requestConfig->getProperties(), $this->config->getProperties());
+        $view->footerIcons = $this->config->footer_icons;
+        $view->isWidget    = Common::getRequestVar('widget', 0, 'int');
+
+        return $view;
+    }
+
+    private function overrideSomeConfigPropertiesIfNeeded()
+    {
+        if (empty($this->config->footer_icons)) {
+            $this->config->footer_icons = $this->getDefaultFooterIconsToShow();
+        }
+
+        if (!\Piwik\Plugin\Manager::getInstance()->isPluginActivated('Goals')) {
+            $this->config->show_goals = false;
+        }
+    }
+
+    public function assignTemplateVar($vars, $value = null)
+    {
+        if (is_string($vars)) {
+            $this->templateVars[$vars] = $value;
+        } elseif (is_array($vars)) {
+            foreach ($vars as $key => $value) {
+                $this->templateVars[$key] = $value;
+            }
+        }
+    }
+
+    protected function isThereDataToDisplay()
+    {
+        return true;
+    }
+
+    /**
+     * Hook called after the dataTable has been loaded from the API
+     * Can be used to add, delete or modify the data freshly loaded
+     *
+     * @return bool
+     */
+    private function postDataTableLoadedFromAPI()
+    {
+        $columns = $this->dataTable->getColumns();
+        $hasNbVisits       = in_array('nb_visits', $columns);
+        $hasNbUniqVisitors = in_array('nb_uniq_visitors', $columns);
+
+        // default columns_to_display to label, nb_uniq_visitors/nb_visits if those columns exist in the
+        // dataset. otherwise, default to all columns in dataset.
+        if (empty($this->config->columns_to_display)) {
+            $this->config->setDefaultColumnsToDisplay($columns, $hasNbVisits, $hasNbUniqVisitors);
+        }
+
+        if (!empty($this->dataTable)) {
+            $this->removeEmptyColumnsFromDisplay();
+        }
+
+        if (empty($this->requestConfig->filter_sort_column)) {
+            $this->requestConfig->setDefaultSort($this->config->columns_to_display, $hasNbUniqVisitors);
+        }
+
+        // deal w/ table metadata
+        if ($this->dataTable instanceof DataTable) {
+            $this->config->metadata = $this->dataTable->getAllTableMetadata();
+
+            if (isset($this->config->metadata[DataTable::ARCHIVED_DATE_METADATA_NAME])) {
+                $this->config->report_last_updated_message = $this->makePrettyArchivedOnText();
+            }
+        }
+    }
+
+    private function applyFilters()
+    {
+        list($priorityFilters, $otherFilters) = $this->config->getFiltersToRun();
+
+        // First, filters that delete rows
+        foreach ($priorityFilters as $filter) {
+            $this->dataTable->filter($filter[0], $filter[1]);
+        }
+
+        $this->beforeGenericFiltersAreAppliedToLoadedDataTable();
+
+        if (!$this->config->areGenericFiltersDisabled()) {
+            $this->applyGenericFilters();
+        }
+
+        $this->afterGenericFiltersAreAppliedToLoadedDataTable();
+
+        // queue other filters so they can be applied later if queued filters are disabled
+        foreach ($otherFilters as $filter) {
+            $this->dataTable->queueFilter($filter[0], $filter[1]);
+        }
+
+        // Finally, apply datatable filters that were queued (should be 'presentation' filters that
+        // do not affect the number of rows)
+        if (!$this->config->areQueuedFiltersDisabled()) {
+            $this->dataTable->applyQueuedFilters();
+        }
+    }
+
+    private function removeEmptyColumnsFromDisplay()
+    {
+        if ($this->dataTable instanceof DataTable\Map) {
+            $emptyColumns = $this->dataTable->getMetadataIntersectArray(DataTable::EMPTY_COLUMNS_METADATA_NAME);
+        } else {
+            $emptyColumns = $this->dataTable->getMetadata(DataTable::EMPTY_COLUMNS_METADATA_NAME);
+        }
+
+        if (is_array($emptyColumns)) {
+            foreach ($emptyColumns as $emptyColumn) {
+                $key = array_search($emptyColumn, $this->config->columns_to_display);
+                if ($key !== false) {
+                    unset($this->config->columns_to_display[$key]);
+                }
+            }
+
+            $this->config->columns_to_display = array_values($this->config->columns_to_display);
+        }
+    }
+
+    /**
+     * Returns prettified and translated text that describes when a report was last updated.
+     *
+     * @return string
+     */
+    private function makePrettyArchivedOnText()
+    {
+        $dateText = $this->config->metadata[DataTable::ARCHIVED_DATE_METADATA_NAME];
+        $date     = Date::factory($dateText);
+        $today    = mktime(0, 0, 0);
+
+        if ($date->getTimestamp() > $today) {
+
+            $elapsedSeconds = time() - $date->getTimestamp();
+            $timeAgo        = MetricsFormatter::getPrettyTimeFromSeconds($elapsedSeconds);
+
+            return Piwik::translate('CoreHome_ReportGeneratedXAgo', $timeAgo);
+        }
+
+        $prettyDate = $date->getLocalized("%longYear%, %longMonth% %day%") . $date->toString('S');
+
+        return Piwik::translate('CoreHome_ReportGeneratedOn', $prettyDate);
+    }
+
+    /**
+     * Returns true if it is likely that the data for this report has been purged and if the
+     * user should be told about that.
+     *
+     * In order for this function to return true, the following must also be true:
+     * - The data table for this report must either be empty or not have been fetched.
+     * - The period of this report is not a multiple period.
+     * - The date of this report must be older than the delete_reports_older_than config option.
+     * @return bool
+     */
+    private function hasReportBeenPurged()
+    {
+        if (!\Piwik\Plugin\Manager::getInstance()->isPluginActivated('PrivacyManager')) {
+            return false;
+        }
+
+        return PrivacyManager::hasReportBeenPurged($this->dataTable);
+    }
+
+    /**
+     * Returns array of properties that should be visible to client side JavaScript. The data
+     * will be available in the data-props HTML attribute of the .dataTable div.
+     *
+     * @return array Maps property names w/ property values.
+     */
+    private function getClientSidePropertiesToSet()
+    {
+        $result = array();
+
+        foreach ($this->config->clientSideProperties as $name) {
+            if (property_exists($this->requestConfig, $name)) {
+                $result[$name] = $this->getIntIfValueIsBool($this->requestConfig->$name);
+            } else if (property_exists($this->config, $name)) {
+                $result[$name] = $this->getIntIfValueIsBool($this->config->$name);
+            }
+        }
+
+        return $result;
+    }
+
+    private function getIntIfValueIsBool($value)
+    {
+        return is_bool($value) ? (int)$value : $value;
+    }
+
+    /**
+     * This functions reads the customization values for the DataTable and returns an array (name,value) to be printed in Javascript.
+     * This array defines things such as:
+     * - name of the module & action to call to request data for this table
+     * - optional filters information, eg. filter_limit and filter_offset
+     * - etc.
+     *
+     * The values are loaded:
+     * - from the generic filters that are applied by default @see Piwik_API_DataTableGenericFilter.php::getGenericFiltersInformation()
+     * - from the values already available in the GET array
+     * - from the values set using methods from this class (eg. setSearchPattern(), setLimit(), etc.)
+     *
+     * @return array eg. array('show_offset_information' => 0, 'show_...
+     */
+    protected function getClientSideParametersToSet()
+    {
+        // build javascript variables to set
+        $javascriptVariablesToSet = array();
+
+        foreach ($this->config->custom_parameters as $name => $value) {
+            $javascriptVariablesToSet[$name] = $value;
+        }
+
+        foreach ($_GET as $name => $value) {
+            try {
+                $requestValue = Common::getRequestVar($name);
+            } catch (\Exception $e) {
+                $requestValue = '';
+            }
+            $javascriptVariablesToSet[$name] = $requestValue;
+        }
+
+        foreach ($this->requestConfig->clientSideParameters as $name) {
+            if (isset($javascriptVariablesToSet[$name])) {
+                continue;
+            }
+
+            $valueToConvert = false;
+
+            if (property_exists($this->requestConfig, $name)) {
+                $valueToConvert = $this->requestConfig->$name;
+            } else if (property_exists($this->config, $name)) {
+                $valueToConvert = $this->config->$name;
+            }
+
+            if (false !== $valueToConvert) {
+                $javascriptVariablesToSet[$name] = $this->getIntIfValueIsBool($valueToConvert);
+            }
+        }
+
+        if ($this->dataTable instanceof DataTable) {
+            // we override the filter_sort_column with the column used for sorting,
+            // which can be different from the one specified (eg. if the column doesn't exist)
+            $javascriptVariablesToSet['filter_sort_column'] = $this->dataTable->getSortedByColumnName();
+            // datatable can return "2" but we want to write "nb_visits" in the js
+            if (isset(Metrics::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']])) {
+                $javascriptVariablesToSet['filter_sort_column'] = Metrics::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']];
+            }
+        }
+
+        $javascriptVariablesToSet['module'] = $this->config->controllerName;
+        $javascriptVariablesToSet['action'] = $this->config->controllerAction;
+        if (!isset($javascriptVariablesToSet['viewDataTable'])) {
+            $javascriptVariablesToSet['viewDataTable'] = static::getViewDataTableId();
+        }
+
+        if ($this->dataTable &&
+            // Set doesn't have the method
+            !($this->dataTable instanceof DataTable\Map)
+            && empty($javascriptVariablesToSet['totalRows'])
+        ) {
+            $javascriptVariablesToSet['totalRows'] = $this->dataTable->getRowsCountBeforeLimitFilter();
+        }
+
+        $deleteFromJavascriptVariables = array(
+            'filter_excludelowpop',
+            'filter_excludelowpop_value',
+        );
+        foreach ($deleteFromJavascriptVariables as $name) {
+            if (isset($javascriptVariablesToSet[$name])) {
+                unset($javascriptVariablesToSet[$name]);
+            }
+        }
+
+        $rawSegment = \Piwik\API\Request::getRawSegmentFromRequest();
+        if (!empty($rawSegment)) {
+            $javascriptVariablesToSet['segment'] = $rawSegment;
+        }
+
+        return $javascriptVariablesToSet;
+    }
+
+    public function beforeRender()
+    {
+        // make sure config properties have a specific value because it can be changed by a report or by request params
+        // like $this->config->showFooterColumns = true;
+    }
+
+    public function beforeLoadDataTable()
+    {
+        // change request
+        // like defining $this->requestConfig->filter_column
+    }
+
+    public function beforeGenericFiltersAreAppliedToLoadedDataTable()
+    {
+
+    }
+
+    public function afterGenericFiltersAreAppliedToLoadedDataTable()
+    {
+
+    }
+
+    public function afterAllFilteresAreApplied()
+    {
+        // filter and format requested data here
+        // $dataTable ...
+
+        // $this->generator = new GeneratorFoo($dataTable);
+    }
+
+    /**
+     * Second, generic filters (Sort, Limit, Replace Column Names, etc.)
+     */
+    private function applyGenericFilters()
+    {
+        $requestArray = $this->request->getRequestArray();
+        $request      = \Piwik\API\Request::getRequestArrayFromString($requestArray);
+
+        if (false === $this->config->enable_sort) {
+            $request['filter_sort_column'] = '';
+            $request['filter_sort_order']  = '';
+        }
+
+        $genericFilter = new \Piwik\API\DataTableGenericFilter($request);
+        $genericFilter->filter($this->dataTable);
+    }
+
+    private function logMessageIfRequestPropertiesHaveChanged(array $requestPropertiesBefore)
+    {
+        $requestProperties = $this->requestConfig->getProperties();
+
+        $diff = array_diff_assoc($requestProperties, $requestPropertiesBefore);
+
+        if (empty($diff)) {
+            return;
+        }
+
+        $details = array(
+            'changedProperties' => $diff,
+            'apiMethod'         => $this->requestConfig->apiMethodToRequestDataTable,
+            'controller'        => $this->config->controllerName . '.' . $this->config->controllerAction,
+            'viewDataTable'     => static::getViewDataTableId()
+        );
+
+        $message = 'Some ViewDataTable::requestConfig properties have changed after requesting the data table. '
+                 . 'That means the changed values had probably no effect. For instance in beforeRender() hook. '
+                 . 'Probably a bug? Details:'
+                 . print_r($details, 1);
+
+        Log::warning($message);
+    }
+}
\ No newline at end of file
diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php
index 9ca220201c0fcf72f93003cf487e7c45a465f187..473be55c92657999f1411c7166e74eda115612e2 100644
--- a/core/ViewDataTable.php
+++ b/core/ViewDataTable.php
@@ -10,15 +10,10 @@
  */
 namespace Piwik;
 
+use Piwik\API\Proxy;
 use Piwik\API\Request;
-use Piwik\DataTable;
-use Piwik\Period;
-use Piwik\Period\Range;
 use Piwik\Plugins\API\API;
-use Piwik\ViewDataTable\Visualization;
-use Piwik\ViewDataTable\VisualizationPropertiesProxy;
-use Piwik\Visualization\Config as VizConfig;
-use Piwik\Visualization\Request as VizRequest;
+use Piwik\Plugin\Visualization;
 
 /**
  * This class is used to load (from the API) and customize the output of a given DataTable.
@@ -55,185 +50,13 @@ use Piwik\Visualization\Request as VizRequest;
  */
 class ViewDataTable
 {
-    const CONFIGURE_VIEW_EVENT = 'Visualization.initView';
-    const CONFIGURE_FOOTER_ICONS_EVENT = 'Visualization.configureFooterIcons';
 
     /**
-     * The class name of the visualization to use.
-     *
-     * @var string|null
-     */
-    private $visualizationClass;
-
-    /**
-     * Cache for getAllReportDisplayProperties result.
+     * Cache for getDefaultViewTypeForReports result.
      *
      * @var array
      */
-    public static $reportPropertiesCache = null;
-
-    /**
-     * If the current dataTable refers to a subDataTable (eg. keywordsBySearchEngineId for id=X) this variable is set to the Id
-     *
-     * @var bool|int
-     */
-    protected $idSubtable = false;
-
-    /**
-     * DataTable loaded from the API for this ViewDataTable.
-     *
-     * @var DataTable
-     */
-    protected $dataTable = null;
-
-    /**
-     * @see init()
-     * @var string
-     */
-    protected $currentControllerAction;
-
-    /**
-     * @see init()
-     * @var string
-     */
-    protected $currentControllerName;
-
-    /**
-     * @var null|\Piwik\Visualization\Config
-     */
-    protected $vizConfig;
-
-    /**
-     * @var null|\Piwik\Visualization\Request
-     */
-    protected $vizRequest;
-
-    /**
-     * Default constructor.
-     */
-    public function __construct($currentControllerAction,
-                                $apiMethodToRequestDataTable,
-                                $viewProperties = array(),
-                                $visualizationId = null)
-    {
-        if (class_exists($visualizationId)
-            && is_subclass_of($visualizationId, "Piwik\\ViewDataTable\\Visualization")
-        ) {
-            $visualizationClass = $visualizationId;
-        } else {
-            $visualizationClass = $visualizationId ? Visualization::getClassFromId($visualizationId) : null;
-        }
-
-        $this->visualizationClass = $visualizationClass;
-
-        list($currentControllerName, $currentControllerAction) = explode('.', $currentControllerAction);
-        $this->currentControllerName = $currentControllerName;
-        $this->currentControllerAction = $currentControllerAction;
-
-        $this->vizRequest = new VizRequest();
-        $this->vizConfig  = new VizConfig();
-        $this->vizConfig->visualization_properties = new VisualizationPropertiesProxy($visualizationClass);
-        $this->vizConfig->subtable_controller_action = $currentControllerAction;
-
-        $this->setDefaultProperties();
-        $this->setViewProperties($viewProperties);
-
-        $this->idSubtable = Common::getRequestVar('idSubtable', false, 'int');
-
-        $this->vizConfig->show_footer_icons            = ($this->idSubtable == false);
-        $this->vizRequest->apiMethodToRequestDataTable = $apiMethodToRequestDataTable;
-
-        $this->vizConfig->report_id = $currentControllerName . '.' . $currentControllerAction;
-        $this->vizConfig->self_url  = $this->getBaseReportUrl($currentControllerName, $currentControllerAction);
-
-        // the exclude low population threshold value is sometimes obtained by requesting data.
-        // to avoid issuing unecessary requests when display properties are determined by metadata,
-        // we allow it to be a closure.
-        if (isset($this->vizRequest->filter_excludelowpop_value)
-            && $this->vizRequest->filter_excludelowpop_value instanceof \Closure
-        ) {
-            $function = $this->vizRequest->filter_excludelowpop_value;
-            $this->vizRequest->filter_excludelowpop_value = $function();
-        }
-
-        $this->overrideViewPropertiesWithQueryParams();
-
-        $this->loadDocumentation();
-    }
-
-    /**
-     * Returns the API method that will be called to obatin the report data.
-     *
-     * @return string e.g. 'Actions.getPageUrls'
-     */
-    public function getReportApiMethod()
-    {
-        return $this->vizRequest->apiMethodToRequestDataTable;
-    }
-
-    /**
-     * Returns the view's associated visualization class name.
-     *
-     * @return string
-     */
-    public function getVisualizationClass()
-    {
-        return $this->visualizationClass;
-    }
-
-    /**
-     * Gets a view property by reference.
-     *
-     * @param string $name A valid view property name. @see Properties for all
-     *                     valid view properties.
-     * @return mixed
-     * @throws \Exception if the property name is invalid.
-     */
-    public function &__get($name)
-    {
-        if (property_exists($this->vizRequest, $name)) {
-            return $this->vizRequest->$name;
-        } elseif (property_exists($this->vizConfig, $name)) {
-            return $this->vizConfig->$name;
-        }
-    }
-
-    /**
-     * Sets a view property.
-     *
-     * @param string $name A valid view property name. @see Properties for all
-     *                     valid view properties.
-     * @param mixed $value
-     * @return mixed Returns $value.
-     * @throws \Exception if the property name is invalid.
-     */
-    public function __set($name, $value)
-    {
-        if (property_exists($this->vizRequest, $name)) {
-            return $this->vizRequest->$name = $value;
-        } elseif (property_exists($this->vizConfig, $name)) {
-            return $this->vizConfig->$name = $value;
-        }
-    }
-
-    /**
-     * Hack to allow property access in Twig (w/ property name checking).
-     */
-    public function __call($name, $arguments)
-    {
-        return $this->$name;
-    }
-
-    /**
-     * Unique string ID that defines the format of the dataTable, eg. "pieChart", "table", etc.
-     *
-     * @return string
-     */
-    public function getViewDataTableId()
-    {
-        $klass = $this->visualizationClass;
-        return $klass::getViewDataTableId($this);
-    }
+    private static $defaultViewTypes = null;
 
     /**
      * Returns a Piwik_ViewDataTable_* object.
@@ -247,762 +70,96 @@ class ViewDataTable
      * @param string|bool $controllerAction
      * @param bool $forceDefault
      *
-     * @return ViewDataTable
-     */
-    static public function factory($defaultType = null, $apiAction = false, $controllerAction = false, $forceDefault = false)
-    {
-        if ($controllerAction === false) {
-            $controllerAction = $apiAction;
-        }
-
-        $defaultProperties = self::getDefaultPropertiesForReport($apiAction);
-        if (!empty($defaultProperties['default_view_type'])
-            && !$forceDefault
-        ) {
-            $defaultType = $defaultProperties['default_view_type'];
-        }
-
-        $type = Common::getRequestVar('viewDataTable', $defaultType ? : 'table', 'string');
-
-        if ($type == 'sparkline') {
-            $result = new ViewDataTable\Sparkline($controllerAction, $apiAction, $defaultProperties);
-        } else {
-            $result = new ViewDataTable($controllerAction, $apiAction, $defaultProperties, $type);
-        }
-
-        return $result;
-    }
-
-    /**
-     * Returns the list of view properties that should be sent with the HTML response
-     * as JSON. These properties are visible to the UI JavaScript, but are not passed
-     * with every request.
-     *
-     * @return array
-     */
-    public function getClientSideConfigProperties()
-    {
-        return $this->getPropertyNameListWithMetaProperty(VizConfig::$clientSideProperties, __FUNCTION__);
-    }
-
-    /**
-     * Returns the list of view properties that should be sent with the HTML response
-     * and resent by the UI JavaScript in every subsequent AJAX request.
-     *
-     * @return array
-     */
-    public function getClientSideRequestParameters()
-    {
-        return $this->getPropertyNameListWithMetaProperty(VizRequest::$clientSideParameters, __FUNCTION__);
-    }
-
-    /**
-     * Returns the list of view properties that can be overriden by query parameters.
-     *
-     * @return array
-     */
-    public function getOverridableProperties()
-    {
-        $params = array_merge(VizConfig::$overridableProperties, VizRequest::$overridableProperties);
-
-        return $this->getPropertyNameListWithMetaProperty($params, __FUNCTION__);
-    }
-
-    public function getCurrentControllerAction()
-    {
-        return $this->currentControllerAction;
-    }
-
-    public function getCurrentControllerName()
-    {
-        return $this->currentControllerName;
-    }
-
-    /**
-     * Returns the DataTable loaded from the API
-     *
-     * @return DataTable
-     * @throws \Exception if not yet defined
-     */
-    public function getDataTable()
-    {
-        if (is_null($this->dataTable)) {
-            throw new \Exception("The DataTable object has not yet been created");
-        }
-        return $this->dataTable;
-    }
-
-    /**
-     * To prevent calling an API multiple times, the DataTable can be set directly.
-     * It won't be loaded again from the API in this case
-     *
-     * @param $dataTable
-     * @return void $dataTable DataTable
-     */
-    public function setDataTable($dataTable)
-    {
-        $this->dataTable = $dataTable;
-    }
-
-    /**
-     * Returns the defaut view properties for a report, if any.
-     *
-     * Plugins can associate callbacks with the Visualization.getReportDisplayProperties
-     * event to set the default properties of reports.
-     *
-     * @param string $apiAction
-     * @return array
-     */
-    private static function getDefaultPropertiesForReport($apiAction)
-    {
-        $reportDisplayProperties = self::getAllReportDisplayProperties();
-        return isset($reportDisplayProperties[$apiAction]) ? $reportDisplayProperties[$apiAction] : array();
-    }
-
-    /**
-     * Returns the list of display properties for all available reports.
-     *
-     * @return array
-     */
-    private static function getAllReportDisplayProperties()
-    {
-        if (self::$reportPropertiesCache === null) {
-            self::$reportPropertiesCache = array();
-            /**
-             * This event is triggered to gather the report display properties for each available report. If you define
-             * your own report, you want to subscribe to this event to define how your report shall be displayed in the
-             * Piwik UI.
-             *
-             * Example:
-             * ```
-             * public function getReportDisplayProperties(&$properties)
-             * {
-             *     $properties['Provider.getProvider'] = array(
-             *         'translations' => array('label' => Piwik::translate('Provider_ColumnProvider')),
-             *         'filter_limit' => 5
-             *     )
-             * }
-             * ```
-             */
-            Piwik::postEvent('Visualization.getReportDisplayProperties', array(&self::$reportPropertiesCache));
-        }
-
-        return self::$reportPropertiesCache;
-    }
-
-    /**
-     * Sets a view property by name. This function handles special view properties
-     * like 'translations' & 'related_reports' that store arrays.
-     *
-     * @param string $name
-     * @param mixed $value For array properties, $value can be a comma separated string.
-     * @throws \Exception
-     */
-    private function setViewProperty($name, $value)
-    {
-        if (isset($this->vizRequest->$name)
-            && is_array($this->vizRequest->$name)
-            && is_string($value)
-        ) {
-            $value = Piwik::getArrayFromApiParameter($value);
-        }
-
-        if (isset($this->vizConfig->$name)
-            && is_array($this->vizConfig->$name)
-            && is_string($value)
-        ) {
-            $value = Piwik::getArrayFromApiParameter($value);
-        }
-
-        if ($name == 'translations'
-            || $name == 'filters'
-        ) {
-            $this->vizConfig->$name = array_merge($this->vizConfig->$name, $value);
-        } else if ($name == 'related_reports') { // TODO: should process after (in overrideViewProperties)
-            $this->addRelatedReports($value);
-        } else if ($name == 'visualization_properties') {
-            $this->setVisualizationPropertiesFromMetadata($value);
-        } elseif (property_exists($this->vizRequest, $name)) {
-            $this->vizRequest->$name = $value;
-        } else if (property_exists($this->vizConfig, $name)) {
-            $this->vizConfig->$name = $value;
-        } else {
-            $report = $this->currentControllerName . '.' . $this->currentControllerAction;
-            throw new \Exception("Invalid view property '$name' specified in view property metadata for '$report'.");
-        }
-    }
-
-    /**
-     * Sets visualization properties using data in a visualization's default property values
-     * array.
-     */
-    private function setVisualizationPropertiesFromMetadata($properties)
-    {
-        if ($this->visualizationClass === null) {
-            return null;
-        }
-
-        if (!is_array($properties)) {
-            return null;
-        }
-
-        $visualizationIds = Visualization::getVisualizationIdsWithInheritance($this->visualizationClass);
-        foreach ($visualizationIds as $visualizationId) {
-            if (empty($properties[$visualizationId])) {
-                continue;
-            }
-
-            foreach ($properties[$visualizationId] as $key => $value) {
-                if (property_exists($this->vizRequest, $key)) {
-                    $this->vizRequest->$key = $value;
-                } elseif (property_exists($this->vizConfig, $key)) {
-                    $this->vizConfig->$key = $value;
-                } else {
-                    $this->vizConfig->visualization_properties->$key = $value;
-                }
-            }
-        }
-    }
-
-    /**
-     * Function called by the ViewDataTable objects in order to fetch data from the API.
-     * The function init() must have been called before, so that the object knows which API module and action to call.
-     * It builds the API request string and uses Request to call the API.
-     * The requested DataTable object is stored in $this->dataTable.
-     */
-    protected function loadDataTableFromAPI()
-    {
-        if (!is_null($this->dataTable)) {
-            // data table is already there
-            // this happens when setDataTable has been used
-            return;
-        }
-
-        // we build the request (URL) to call the API
-        $requestArray = $this->getRequestArray();
-
-        // we make the request to the API
-        $request = new Request($requestArray);
-
-        // and get the DataTable structure
-        $dataTable = $request->process();
-
-        $this->dataTable = $dataTable;
-    }
-
-    /**
-     * Checks that the API returned a normal DataTable (as opposed to DataTable\Map)
      * @throws \Exception
-     * @return void
-     */
-    protected function checkStandardDataTable()
-    {
-        Piwik::checkObjectTypeIs($this->dataTable, array('\Piwik\DataTable'));
-    }
-
-    private function getFiltersToRun()
-    {
-        $priorityFilters = array();
-        $presentationFilters = array();
-
-        foreach ($this->vizConfig->filters as $filterInfo) {
-            if ($filterInfo instanceof \Closure) {
-                $nameOrClosure = $filterInfo;
-                $parameters = array();
-                $priority = false;
-            } else {
-                @list($nameOrClosure, $parameters, $priority) = $filterInfo;
-            }
-
-            if ($nameOrClosure instanceof \Closure) {
-                $parameters[] = $this;
-            }
-
-            if ($priority) {
-                $priorityFilters[] = array($nameOrClosure, $parameters);
-            } else {
-                $presentationFilters[] = array($nameOrClosure, $parameters);
-            }
-        }
-
-        return array($priorityFilters, $presentationFilters);
-    }
-
-    /**
-     * Hook called after the dataTable has been loaded from the API
-     * Can be used to add, delete or modify the data freshly loaded
-     *
-     * @return bool
-     */
-    protected function postDataTableLoadedFromAPI(Visualization $visualization)
-    {
-        $columns = $this->dataTable->getColumns();
-        $haveNbVisits = in_array('nb_visits', $columns);
-        $haveNbUniqVisitors = in_array('nb_uniq_visitors', $columns);
-
-        // default columns_to_display to label, nb_uniq_visitors/nb_visits if those columns exist in the
-        // dataset. otherwise, default to all columns in dataset.
-        if (empty($this->vizConfig->columns_to_display)) {
-            if ($haveNbVisits
-                || $haveNbUniqVisitors
-            ) {
-                $columnsToDisplay = array('label');
-
-                // if unique visitors data is available, show it, otherwise just visits
-                if ($haveNbUniqVisitors) {
-                    $columnsToDisplay[] = 'nb_uniq_visitors';
-                } else {
-                    $columnsToDisplay[] = 'nb_visits';
-                }
-            } else {
-                $columnsToDisplay = $columns;
-            }
-
-            $this->vizConfig->columns_to_display = array_filter($columnsToDisplay);
-        }
-
-        $this->removeEmptyColumnsFromDisplay();
-
-        // default sort order to visits/visitors data
-        if (empty($this->vizRequest->filter_sort_column)) {
-            if ($haveNbUniqVisitors
-                && in_array('nb_uniq_visitors', $this->vizConfig->columns_to_display)
-            ) {
-                $this->vizRequest->filter_sort_column = 'nb_uniq_visitors';
-            } else {
-                $this->vizRequest->filter_sort_column = 'nb_visits';
-            }
-            $this->vizRequest->filter_sort_order = 'desc';
-        }
-
-        // deal w/ table metadata
-        if ($this->dataTable instanceof DataTable) {
-            $this->vizConfig->metadata = $this->dataTable->getAllTableMetadata();
-
-            if (isset($this->vizConfig->metadata[DataTable::ARCHIVED_DATE_METADATA_NAME])) {
-                $this->vizConfig->metadata[DataTable::ARCHIVED_DATE_METADATA_NAME] =
-                    $this->makePrettyArchivedOnText();
-            }
-        }
-
-        list($priorityFilters, $otherFilters) = $this->getFiltersToRun();
-
-        // First, filters that delete rows
-        foreach ($priorityFilters as $filter) {
-            $this->dataTable->filter($filter[0], $filter[1]);
-        }
-
-        $visualization->beforeGenericFiltersAreAppliedToLoadedDataTable($this->dataTable, $this->vizConfig, $this->vizRequest);
-
-        if (!$this->areGenericFiltersDisabled()) {
-            // Second, generic filters (Sort, Limit, Replace Column Names, etc.)
-            $requestArray = $this->getRequestArray();
-            $request = Request::getRequestArrayFromString($requestArray);
-
-            if ($this->vizConfig->enable_sort === false) {
-                $request['filter_sort_column'] = $request['filter_sort_order'] = '';
-            }
-
-            $genericFilter = new \Piwik\API\DataTableGenericFilter($request);
-            $genericFilter->filter($this->dataTable);
-        }
-
-        // queue other filters so they can be applied later if queued filters are disabled
-        foreach ($otherFilters as $filter) {
-            $this->dataTable->queueFilter($filter[0], $filter[1]);
-        }
-
-        // Finally, apply datatable filters that were queued (should be 'presentation' filters that
-        // do not affect the number of rows)
-        if (!$this->areQueuedFiltersDisabled()) {
-
-            $this->dataTable->applyQueuedFilters();
-        }
-
-        $visualization->afterGenericFiltersAreAppliedToLoadedDataTable($this->dataTable, $this->vizConfig, $this->vizRequest);
-
-        return true;
-    }
-
-    /**
-     * Returns true if generic filters have been disabled, false if otherwise.
-     *
-     * @return bool
+     * @return \Piwik\Plugin\ViewDataTable|\Piwik\Plugin\Visualization|\Piwik\Plugins\CoreVisualizations\Visualizations\Sparkline;
      */
-    private function areGenericFiltersDisabled()
+    public static function factory($defaultType = null, $apiAction = false, $controllerAction = false, $forceDefault = false)
     {
-        // if disable_generic_filters query param is set to '1', generic filters are disabled
-        if (Common::getRequestVar('disable_generic_filters', '0', 'string') == 1) {
-            return true;
-        }
-
-        // if $this->disableGenericFilters() was called, generic filters are disabled
-        if (isset($this->vizConfig->disable_generic_filters)
-            && $this->vizConfig->disable_generic_filters === true
-        ) {
-            return true;
+        if (false === $controllerAction) {
+            $controllerAction = $apiAction;
         }
 
-        return false;
-    }
-
-    /**
-     * Returns true if queued filters have been disabled, false if otherwise.
-     *
-     * @return bool
-     */
-    private function areQueuedFiltersDisabled()
-    {
-        return isset($this->vizConfig->disable_queued_filters) && $this->vizConfig->disable_queued_filters;
-    }
-
-    /**
-     * Returns prettified and translated text that describes when a report was last updated.
-     *
-     * @return string
-     */
-    private function makePrettyArchivedOnText()
-    {
-        $dateText = $this->vizConfig->metadata[DataTable::ARCHIVED_DATE_METADATA_NAME];
-        $date = Date::factory($dateText);
-        $today = mktime(0, 0, 0);
-        if ($date->getTimestamp() > $today) {
-            $elapsedSeconds = time() - $date->getTimestamp();
-            $timeAgo = MetricsFormatter::getPrettyTimeFromSeconds($elapsedSeconds);
+        $defaultViewType = self::getDefaultViewTypeForReport($apiAction);
 
-            return Piwik::translate('CoreHome_ReportGeneratedXAgo', $timeAgo);
+        if (!$forceDefault && !empty($defaultViewType)) {
+            $defaultType = $defaultViewType;
         }
 
-        $prettyDate = $date->getLocalized("%longYear%, %longMonth% %day%") . $date->toString('S');
-        return Piwik::translate('CoreHome_ReportGeneratedOn', $prettyDate);
-    }
-
-    /**
-     * @return string URL to call the API, eg. "method=Referrers.getKeywords&period=day&date=yesterday"...
-     */
-    public function getRequestArray()
-    {
-        // we prepare the array to give to the API Request
-        // we setup the method and format variable
-        // - we request the method to call to get this specific DataTable
-        // - the format = original specifies that we want to get the original DataTable structure itself, not rendered
-        $requestArray = array(
-            'method'                  => $this->vizRequest->apiMethodToRequestDataTable,
-            'format'                  => 'original',
-            'disable_generic_filters' => Common::getRequestVar('disable_generic_filters', 1, 'int'),
-        );
+        $type = Common::getRequestVar('viewDataTable', $defaultType ? : 'table', 'string');
 
-        $toSetEventually = array(
-            'filter_limit',
-            'keep_summary_row',
-            'filter_sort_column',
-            'filter_sort_order',
-            'filter_excludelowpop',
-            'filter_excludelowpop_value',
-            'filter_column',
-            'filter_pattern',
-        );
+        $visualizations = static::getAvailableVisualizations();
 
-        foreach ($toSetEventually as $varToSet) {
-            $value = $this->getDefaultOrCurrent($varToSet);
-            if (false !== $value) {
-                $requestArray[$varToSet] = $value;
-            }
+        if (array_key_exists($type, $visualizations)) {
+            return new $visualizations[$type]($controllerAction, $apiAction);
         }
 
-        $segment = Request::getRawSegmentFromRequest();
-        if (!empty($segment)) {
-            $requestArray['segment'] = $segment;
+        if (class_exists($type)) {
+            return new $type($controllerAction, $apiAction);
         }
 
-        if (self::shouldLoadExpanded()) {
-            $requestArray['expanded'] = 1;
-        }
-
-        $requestArray = array_merge($requestArray, $this->vizRequest->request_parameters_to_modify);
-
-        if (!empty($requestArray['filter_limit'])
-            && $requestArray['filter_limit'] === 0
-        ) {
-            unset($requestArray['filter_limit']);
-        }
-
-        return $requestArray;
+        throw new \Exception(sprintf('Visuzalization type %s not found', $type));
     }
 
     /**
-     * This functions reads the customization values for the DataTable and returns an array (name,value) to be printed in Javascript.
-     * This array defines things such as:
-     * - name of the module & action to call to request data for this table
-     * - optional filters information, eg. filter_limit and filter_offset
-     * - etc.
-     *
-     * The values are loaded:
-     * - from the generic filters that are applied by default @see Piwik_API_DataTableGenericFilter.php::getGenericFiltersInformation()
-     * - from the values already available in the GET array
-     * - from the values set using methods from this class (eg. setSearchPattern(), setLimit(), etc.)
+     * Returns all registered visualization classes. Uses the 'Visualization.getAvailable'
+     * event to retrieve visualizations.
      *
-     * @return array eg. array('show_offset_information' => 0, 'show_...
+     * @return array Array mapping visualization IDs with their associated visualization classes.
+     * @throws \Exception If a visualization class does not exist or if a duplicate visualization ID
+     *                   is found.
+     * @return array
      */
-    protected function getClientSideParametersToSet()
+    public static function getAvailableVisualizations()
     {
-        // build javascript variables to set
-        $javascriptVariablesToSet = array();
-
-        foreach ($this->vizConfig->custom_parameters as $name => $value) {
-            $javascriptVariablesToSet[$name] = $value;
-        }
-
-        foreach ($_GET as $name => $value) {
-            try {
-                $requestValue = Common::getRequestVar($name);
-            } catch (\Exception $e) {
-                $requestValue = '';
-            }
-            $javascriptVariablesToSet[$name] = $requestValue;
-        }
+        /** @var string[] $visualizations */
+        $visualizations = array();
 
-        foreach ($this->getClientSideRequestParameters() as $name) {
-            if (isset($javascriptVariablesToSet[$name])) {
-                continue;
-            }
+        /**
+         * This event is used to gather all available DataTable visualizations. Callbacks should add visualization
+         * class names to the incoming array.
+         */
+        Piwik::postEvent('Visualization.addVisualizations', array(&$visualizations));
 
-            $valueToConvert = false;
-            if (property_exists($this->vizRequest, $name)) {
-                $valueToConvert = $this->vizRequest->$name;
-            } else if (property_exists($this->vizConfig, $name)) {
-                $valueToConvert = $this->vizConfig->$name;
-            } else if (VisualizationPropertiesProxy::isValidVisualizationProperty($this->visualizationClass, $name)) {
-                $valueToConvert = $this->vizConfig->visualization_properties->$name;
-            }
+        $result = array();
 
-            if (false !== $valueToConvert) {
-                $javascriptVariablesToSet[$name] = $this->convertForJson($valueToConvert);
+        foreach ($visualizations as $viz) {
+            if (!class_exists($viz)) {
+                throw new \Exception("Invalid visualization class '$viz' found in Visualization.getAvailableVisualizations.");
             }
-        }
 
-        if ($this->dataTable instanceof DataTable) {
-            // we override the filter_sort_column with the column used for sorting,
-            // which can be different from the one specified (eg. if the column doesn't exist)
-            $javascriptVariablesToSet['filter_sort_column'] = $this->dataTable->getSortedByColumnName();
-            // datatable can return "2" but we want to write "nb_visits" in the js
-            if (isset(Metrics::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']])) {
-                $javascriptVariablesToSet['filter_sort_column'] = Metrics::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']];
+            if (!is_subclass_of($viz, '\\Piwik\\Plugin\\ViewDataTable')) {
+                throw new \Exception("Visualization class '$viz' does not extend Plugin/ViewDataTable");
             }
-        }
-
-        $javascriptVariablesToSet['module'] = $this->currentControllerName;
-        $javascriptVariablesToSet['action'] = $this->currentControllerAction;
-        if (!isset($javascriptVariablesToSet['viewDataTable'])) {
-            $javascriptVariablesToSet['viewDataTable'] = $this->getViewDataTableId();
-        }
 
-        if ($this->dataTable &&
-            // Set doesn't have the method
-            !($this->dataTable instanceof DataTable\Map)
-            && empty($javascriptVariablesToSet['totalRows'])
-        ) {
-            $javascriptVariablesToSet['totalRows'] = $this->dataTable->getRowsCountBeforeLimitFilter();
-        }
+            $vizId = $viz::getViewDataTableId();
 
-        $deleteFromJavascriptVariables = array(
-            'filter_excludelowpop',
-            'filter_excludelowpop_value',
-        );
-        foreach ($deleteFromJavascriptVariables as $name) {
-            if (isset($javascriptVariablesToSet[$name])) {
-                unset($javascriptVariablesToSet[$name]);
+            if (isset($result[$vizId])) {
+                throw new \Exception("Visualization ID '$vizId' is already in use!");
             }
-        }
-
-        $rawSegment = Request::getRawSegmentFromRequest();
-        if (!empty($rawSegment)) {
-            $javascriptVariablesToSet['segment'] = $rawSegment;
-        }
 
-        return $javascriptVariablesToSet;
-    }
-
-    /**
-     * Returns array of properties that should be visible to client side JavaScript. The data
-     * will be available in the data-props HTML attribute of the .dataTable div.
-     *
-     * @return array Maps property names w/ property values.
-     */
-    private function getClientSidePropertiesToSet()
-    {
-        $result = array();
-        
-        foreach ($this->getClientSideConfigProperties() as $name) {
-            if (property_exists($this->vizRequest, $name)) {
-                $result[$name] = $this->convertForJson($this->vizRequest->$name);
-            } else if (property_exists($this->vizConfig, $name)) {
-                $result[$name] = $this->convertForJson($this->vizConfig->$name);
-            } else if (VisualizationPropertiesProxy::isValidVisualizationProperty($this->visualizationClass, $name)) {
-                $result[$name] = $this->convertForJson($this->vizConfig->visualization_properties->$name);
-            }
+            $result[$vizId] = $viz;
         }
 
         return $result;
     }
 
     /**
-     * Returns, for a given parameter, the value of this parameter in the REQUEST array.
-     * If not set, returns the default value for this parameter @see getDefault()
-     *
-     * @param string $nameVar
-     * @return string|mixed Value of this parameter
-     */
-    protected function getDefaultOrCurrent($nameVar)
-    {
-        if (isset($_GET[$nameVar])) {
-            return Common::sanitizeInputValue($_GET[$nameVar]);
-        }
-        $default = $this->getDefault($nameVar);
-        return $default;
-    }
-
-    /**
-     * Returns the default value for a given parameter.
-     * For example, these default values can be set using the disable* methods.
-     *
-     * @param string $nameVar
-     * @return mixed
-     */
-    protected function getDefault($nameVar)
-    {
-        if (isset($this->vizRequest->$nameVar)) {
-            return $this->vizRequest->$nameVar;
-        }
-        if (isset($this->vizConfig->$nameVar)) {
-            return $this->vizConfig->$nameVar;
-        }
-
-        return false;
-    }
-
-    /** Load documentation from the API */
-    private function loadDocumentation()
-    {
-        $this->vizConfig->metrics_documentation = array();
-
-        $report = API::getInstance()->getMetadata(0, $this->currentControllerName, $this->currentControllerAction);
-        $report = $report[0];
-
-        if (isset($report['metricsDocumentation'])) {
-            $this->vizConfig->metrics_documentation = $report['metricsDocumentation'];
-        }
-
-        if (isset($report['documentation'])) {
-            $this->vizConfig->documentation = $report['documentation'];
-        }
-    }
-
-    private function removeEmptyColumnsFromDisplay()
-    {
-        if (empty($this->dataTable)) {
-            return;
-        }
-        if ($this->dataTable instanceof DataTable\Map) {
-            $emptyColumns = $this->dataTable->getMetadataIntersectArray(DataTable::EMPTY_COLUMNS_METADATA_NAME);
-        } else {
-            $emptyColumns = $this->dataTable->getMetadata(DataTable::EMPTY_COLUMNS_METADATA_NAME);
-        }
-        if (is_array($emptyColumns)) {
-            foreach ($emptyColumns as $emptyColumn) {
-                $key = array_search($emptyColumn, $this->vizConfig->columns_to_display);
-                if ($key !== false) {
-                    unset($this->vizConfig->columns_to_display[$key]);
-                }
-            }
-            $this->vizConfig->columns_to_display = array_values($this->vizConfig->columns_to_display);
-        }
-    }
-
-    private function addRelatedReport($module, $action, $title, $queryParams = array())
-    {
-        // don't add the related report if it references this report
-        if ($this->currentControllerName == $module && $this->currentControllerAction == $action) {
-            return;
-        }
-
-        $url = $this->getBaseReportUrl($module, $action, $queryParams);
-        $this->vizConfig->related_reports[$url] = $title;
-    }
-
-    private function addRelatedReports($relatedReports)
-    {
-        foreach ($relatedReports as $report => $title) {
-            list($module, $action) = explode('.', $report);
-            $this->addRelatedReport($module, $action, $title);
-        }
-    }
-
-    /**
-     * Returns true if it is likely that the data for this report has been purged and if the
-     * user should be told about that.
+     * Returns all available visualizations that are not part of the CoreVisualizations plugin.
      *
-     * In order for this function to return true, the following must also be true:
-     * - The data table for this report must either be empty or not have been fetched.
-     * - The period of this report is not a multiple period.
-     * - The date of this report must be older than the delete_reports_older_than config option.
-     * @return bool
+     * @return array Array mapping visualization IDs with their associated visualization classes.
      */
-    public function hasReportBeenPurged()
+    public static function getNonCoreVisualizations()
     {
-        $strPeriod = Common::getRequestVar('period', false);
-        $strDate = Common::getRequestVar('date', false);
-
-        if ($strPeriod !== false
-            && $strDate !== false
-            && (is_null($this->dataTable)
-                || (!empty($this->dataTable) && $this->dataTable->getRowsCount() == 0))
-        ) {
-            // if range, only look at the first date
-            if ($strPeriod == 'range') {
-                $idSite = Common::getRequestVar('idSite', '');
-                if (intval($idSite) != 0) {
-                    $site = new Site($idSite);
-                    $timezone = $site->getTimezone();
-                } else {
-                    $timezone = 'UTC';
-                }
-
-                $period = new Range('range', $strDate, $timezone);
-                $reportDate = $period->getDateStart();
-            } // if a multiple period, this function is irrelevant
-            else if (Period::isMultiplePeriod($strDate, $strPeriod)) {
-                return false;
-            } // otherwise, use the date as given
-            else {
-                $reportDate = Date::factory($strDate);
-            }
-
-            $reportYear = $reportDate->toString('Y');
-            $reportMonth = $reportDate->toString('m');
+        $result = array();
 
-            if (\Piwik\Plugin\Manager::getInstance()->isPluginActivated('PrivacyManager')
-                && Plugins\PrivacyManager\PrivacyManager::shouldReportBePurged($reportYear, $reportMonth)
-            ) {
-                return true;
+        foreach (static::getAvailableVisualizations() as $vizId => $vizClass) {
+            if (false === strpos($vizClass, 'Piwik\\Plugins\\CoreVisualizations')
+                && false === strpos($vizClass, 'Piwik\\Plugins\\Goals\\Visualizations\\Goals')) {
+                $result[$vizId] = $vizClass;
             }
         }
 
-        return false;
-    }
-
-    /**
-     * Returns URL for this report w/o any filter parameters.
-     *
-     * @param string $module
-     * @param string $action
-     * @param array $queryParams
-     * @return string
-     */
-    private function getBaseReportUrl($module, $action, $queryParams = array())
-    {
-        $params = array_merge($queryParams, array('module' => $module, 'action' => $action));
-        return Request::getCurrentUrlWithoutGenericFilters($params);
+        return $result;
     }
 
     /**
@@ -1014,15 +171,19 @@ class ViewDataTable
      * @throws \Exception
      * @return string|null See $fetch.
      */
-    static public function renderReport($pluginName, $apiAction, $fetch = true)
+    public static function renderReport($pluginName, $apiAction, $fetch = true)
     {
-        $namespacedApiClassName = "\\Piwik\\Plugins\\$pluginName\\API";
-        if (!method_exists($namespacedApiClassName::getInstance(), $apiAction)) {
-            throw new \Exception("$namespacedApiClassName Invalid action name '$apiAction' for '$pluginName' plugin.");
+        /** @var Proxy $apiProxy */
+        $apiProxy = Proxy::getInstance();
+
+        if (!$apiProxy->isExistingApiAction($pluginName, $apiAction)) {
+            throw new \Exception("Invalid action name '$apiAction' for '$pluginName' plugin.");
         }
 
-        $view = self::factory(null, $pluginName . '.' . $apiAction);
-        $rendered = $view->render();
+        $apiAction = $apiProxy->buildApiActionName($pluginName, $apiAction);
+
+        $view      = static::factory(null, $apiAction);
+        $rendered  = $view->render();
 
         if ($fetch) {
             return $rendered;
@@ -1032,323 +193,41 @@ class ViewDataTable
     }
 
     /**
-     * Convenience function. Calls main() & renders the view that gets built.
-     *
-     * @return string The result of rendering.
+     * Returns the default viewDataTable ID to use when determining which visualization to use.
      */
-    public function render()
+    private static function getDefaultViewTypeForReport($apiAction)
     {
-        $view = $this->buildView();
-        return $view->render();
+        $defaultViewTypes = self::getDefaultViewTypeForReports();
+        return isset($defaultViewTypes[$apiAction]) ? $defaultViewTypes[$apiAction] : false;
     }
 
     /**
-     * Returns whether the DataTable result will have to be expanded for the
-     * current request before rendering.
-     *
-     * @return bool
+     * Returns a list of default viewDataTables ID to use when determining which visualization to use for multiple
+     * reports.
      */
-    public static function shouldLoadExpanded()
+    private static function getDefaultViewTypeForReports()
     {
-        // if filter_column_recursive & filter_pattern_recursive are supplied, and flat isn't supplied
-        // we have to load all the child subtables.
-        return Common::getRequestVar('filter_column_recursive', false) !== false
-        && Common::getRequestVar('filter_pattern_recursive', false) !== false
-        && Common::getRequestVar('flat', false) === false;
-    }
-
-    protected function overrideViewProperties()
-    {
-        if (!\Piwik\Plugin\Manager::getInstance()->isPluginActivated('Goals')) {
-            $this->vizConfig->show_goals = false;
-        }
-
-        if (empty($this->vizConfig->footer_icons)) {
-            $this->vizConfig->footer_icons = $this->getDefaultFooterIconsToShow();
-        }
-    }
-
-    protected function buildView()
-    {
-        /** @var Visualization $visualization */
-        $visualization = new $this->visualizationClass($this);
-
-        try {
-
-            $visualization->configureVisualization($this->vizConfig);
-
+        if (null === self::$defaultViewTypes) {
+            self::$defaultViewTypes = array();
             /**
-             * This event is called after a visualization has been configured. Plugins can use this event to
-             * override view properties for individual reports or visualizations.
+             * This event is triggered to gather the default view types for each available report. By default a table
+             * is used. If you define your own report, you may want to subscribe to this event to define another
+             * Visualization that should be used by default to display your report. For instance a Pie, a Bar or a
+             * Cloud.
              *
-             * Themes can use this event to make sure reports look nice with their themes. Plugins
-             * that provide new visualizations can use this event to make sure certain reports
-             * are configured differently when viewed with the new visualization.
+             * Example:
+             * ```
+             * public function getDefaultViewTypeForReports(&$defaultViewTypes)
+             * {
+             *     $defaultViewTypes['Referrers.getSocials']       = HtmlTable::ID;
+             *     $defaultViewTypes['Referrers.getUrlsForSocial'] = Pie::ID;
+             *     )
+             * }
+             * ```
              */
-            Piwik::postEvent(self::CONFIGURE_VIEW_EVENT, array($viewDataTable = $this));
-
-            $this->overrideViewProperties();
-            $visualization->beforeLoadDataTable($this->vizRequest, $this->vizConfig);
-
-            $this->loadDataTableFromAPI();
-            $this->postDataTableLoadedFromAPI($visualization);
-
-            $visualization->afterAllFilteresAreApplied($this->dataTable, $this->vizConfig, $this->vizRequest);
-
-        } catch (NoAccessException $e) {
-            throw $e;
-        } catch (\Exception $e) {
-            Log::warning("Failed to get data from API: " . $e->getMessage());
-
-            $loadingError = array('message' => $e->getMessage());
-        }
-
-        $view = new View("@CoreHome/_dataTable");
-
-        if (!empty($loadingError)) {
-            $view->error = $loadingError;
-        }
-
-        $view->visualization = $visualization;
-        $view->visualizationCssClass = $this->getDefaultDataTableCssClass();
-
-        if (null === $this->dataTable) {
-            $view->dataTable = null;
-        } else {
-            // TODO: this hook seems inappropriate. should be able to find data that is requested for (by site/date) and check if that
-            //       has data.
-            if (method_exists($visualization, 'isThereDataToDisplay')) {
-                $view->dataTableHasNoData = !$visualization->isThereDataToDisplay($this->dataTable, $this);
-            }
-
-            $view->dataTable = $this->dataTable;
-
-            // if it's likely that the report data for this data table has been purged,
-            // set whether we should display a message to that effect.
-            $view->showReportDataWasPurgedMessage = $this->hasReportBeenPurged();
-            $view->deleteReportsOlderThan = Option::get('delete_reports_older_than');
-        }
-        $view->idSubtable = $this->idSubtable;
-        $view->clientSideParameters = $this->getClientSideParametersToSet();
-        $view->clientSideProperties = $this->getClientSidePropertiesToSet();
-        $view->properties = array_merge($this->vizRequest->getProperties(), $this->vizConfig->getProperties());
-        $view->footerIcons = $this->vizConfig->footer_icons;
-        $view->isWidget = Common::getRequestVar('widget', 0, 'int');
-
-        return $view;
-    }
-
-    private function getDefaultFooterIconsToShow()
-    {
-        $result = array();
-
-        // add normal view icons (eg, normal table, all columns, goals)
-        $normalViewIcons = array(
-            'class'   => 'tableAllColumnsSwitch',
-            'buttons' => array(),
-        );
-
-        if ($this->show_table) {
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'table',
-                'title' => Piwik::translate('General_DisplaySimpleTable'),
-                'icon'  => 'plugins/Zeitgeist/images/table.png',
-            );
-        }
-
-        if ($this->show_table_all_columns) {
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'tableAllColumns',
-                'title' => Piwik::translate('General_DisplayTableWithMoreMetrics'),
-                'icon'  => 'plugins/Zeitgeist/images/table_more.png'
-            );
-        }
-
-        if ($this->show_goals) {
-            if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
-                $icon = 'plugins/Zeitgeist/images/ecommerceOrder.gif';
-            } else {
-                $icon = 'plugins/Zeitgeist/images/goal.png';
-            }
-
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'tableGoals',
-                'title' => Piwik::translate('General_DisplayTableWithGoalMetrics'),
-                'icon'  => $icon
-            );
-        }
-
-        if ($this->show_ecommerce) {
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'ecommerceOrder',
-                'title' => Piwik::translate('General_EcommerceOrders'),
-                'icon'  => 'plugins/Zeitgeist/images/ecommerceOrder.gif',
-                'text'  => Piwik::translate('General_EcommerceOrders')
-            );
-
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'ecommerceAbandonedCart',
-                'title' => Piwik::translate('General_AbandonedCarts'),
-                'icon'  => 'plugins/Zeitgeist/images/ecommerceAbandonedCart.gif',
-                'text'  => Piwik::translate('General_AbandonedCarts')
-            );
-        }
-
-        if (!empty($normalViewIcons['buttons'])) {
-            $result[] = $normalViewIcons;
-        }
-
-        // add graph views
-        $graphViewIcons = array(
-            'class'   => 'tableGraphViews tableGraphCollapsed',
-            'buttons' => array(),
-        );
-
-        if ($this->show_all_views_icons) {
-            if ($this->show_bar_chart) {
-                $graphViewIcons['buttons'][] = array(
-                    'id'    => 'graphVerticalBar',
-                    'title' => Piwik::translate('General_VBarGraph'),
-                    'icon'  => 'plugins/Zeitgeist/images/chart_bar.png'
-                );
-            }
-
-            if ($this->show_pie_chart) {
-                $graphViewIcons['buttons'][] = array(
-                    'id'    => 'graphPie',
-                    'title' => Piwik::translate('General_Piechart'),
-                    'icon'  => 'plugins/Zeitgeist/images/chart_pie.png'
-                );
-            }
-
-            if ($this->show_tag_cloud) {
-                $graphViewIcons['buttons'][] = array(
-                    'id'    => 'cloud',
-                    'title' => Piwik::translate('General_TagCloud'),
-                    'icon'  => 'plugins/Zeitgeist/images/tagcloud.png'
-                );
-            }
-
-            if ($this->show_non_core_visualizations) {
-                $nonCoreVisualizations = Visualization::getNonCoreVisualizations();
-                $nonCoreVisualizationInfo = Visualization::getVisualizationInfoFor($nonCoreVisualizations);
-
-                foreach ($nonCoreVisualizationInfo as $format => $info) {
-                    $graphViewIcons['buttons'][] = array(
-                        'id'    => $format,
-                        'title' => Piwik::translate($info['title']),
-                        'icon'  => $info['table_icon']
-                    );
-                }
-            }
-        }
-
-        if (!empty($graphViewIcons['buttons'])) {
-            $result[] = $graphViewIcons;
-        }
-
-        /**
-         * This event is called when determining the default set of footer icons to display
-         * below a report.
-         *
-         * Plugins can use this event to modify the default set of footer icons. You can
-         * add new icons or remove existing ones.
-         *
-         * $result must have the following format:
-         *
-         * ```
-         * array(
-         *     array( // footer icon group 1
-         *         'class' => 'footerIconGroup1CssClass',
-         *         'buttons' => array(
-         *             'id' => 'myid',
-         *             'title' => 'My Tooltip',
-         *             'icon' => 'path/to/my/icon.png'
-         *         )
-         *     ),
-         *     array( // footer icon group 2
-         *         'class' => 'footerIconGroup2CssClass',
-         *         'buttons' => array(...)
-         *     ),
-         *     ...
-         * )
-         * ```
-         */
-        Piwik::postEvent(self::CONFIGURE_FOOTER_ICONS_EVENT, array(&$result, $viewDataTable = $this));
-
-        return $result;
-    }
-
-    public function getDefaultDataTableCssClass()
-    {
-        return 'dataTableViz' . Piwik::getUnnamespacedClassName($this->visualizationClass);
-    }
-
-    private function setViewProperties($values)
-    {
-        foreach ($values as $name => $value) {
-            $this->setViewProperty($name, $value);
+            Piwik::postEvent('Visualization.getDefaultViewTypeForReports', array(&self::$defaultViewTypes));
         }
-    }
-
-    private function setDefaultProperties()
-    {
-        // set core default properties
-        $this->setViewProperties($this->vizRequest->getProperties());
-        $this->setViewProperties($this->vizConfig->getProperties());
 
-        // set visualization default properties
-        if ($this->visualizationClass === null) {
-            return;
-        }
-
-        $visualizationClass = $this->visualizationClass;
-        $this->setViewProperties($visualizationClass::getDefaultPropertyValues());
-    }
-
-    private function convertForJson($value)
-    {
-        return is_bool($value) ? (int)$value : $value;
-    }
-
-    private function overrideViewPropertiesWithQueryParams()
-    {
-        $properties = $this->getOverridableProperties();
-        foreach ($properties as $name) {
-            if (property_exists($this->vizRequest, $name)) {
-                $this->vizRequest->name = $this->getPropertyFromQueryParam($name, $this->vizRequest->$name);
-            } elseif (property_exists($this->vizConfig, $name)) {
-                $this->vizConfig->name  = $this->getPropertyFromQueryParam($name, $this->vizConfig->$name);
-            } else if (VisualizationPropertiesProxy::isValidVisualizationProperty($this->visualizationClass, $name)) {
-                $default = $this->vizConfig->visualization_properties->$name;
-
-                $this->vizConfig->visualization_properties->$name = $this->getPropertyFromQueryParam($name, $default);
-            }
-        }
-
-        // handle special 'columns' query parameter
-        $columns = Common::getRequestVar('columns', false);
-        if ($columns !== false) {
-            $this->columns_to_display = Piwik::getArrayFromApiParameter($columns);
-            array_unshift($this->columns_to_display, 'label');
-        }
-    }
-
-    private function getPropertyFromQueryParam($name, $defaultValue)
-    {
-        $type = is_numeric($defaultValue) ? 'int' : null;
-        return Common::getRequestVar($name, $defaultValue, $type);
-    }
-
-    /**
-     * Helper function for getCliendSiteProperties/getClientSideParameters/etc.
-     */
-    private function getPropertyNameListWithMetaProperty($propertyNames, $getPropertiesFunctionName)
-    {
-        if ($this->visualizationClass) {
-            $klass = $this->visualizationClass;
-            $propertyNames = array_merge($propertyNames, $klass::$getPropertiesFunctionName());
-        }
-        return $propertyNames;
+        return self::$defaultViewTypes;
     }
-}
+}
\ No newline at end of file
diff --git a/core/Visualization/Config.php b/core/ViewDataTable/Config.php
similarity index 73%
rename from core/Visualization/Config.php
rename to core/ViewDataTable/Config.php
index 6e6499144292aa59007dc88db8dadfbed65e9bf7..fdf467a39b1c6894bbe0be6a70a4e0816ca6b888 100644
--- a/core/Visualization/Config.php
+++ b/core/ViewDataTable/Config.php
@@ -9,8 +9,12 @@
  * @package Piwik
  */
 
-namespace Piwik\Visualization;
+namespace Piwik\ViewDataTable;
+use Piwik\API\Request as ApiRequest;
+use Piwik\Common;
 use Piwik\Metrics;
+use Piwik\Piwik;
+use Piwik\Plugins\API\API;
 
 /**
  * Renders a sparkline image given a PHP data array.
@@ -24,19 +28,15 @@ class Config
 
     /**
      * The list of ViewDataTable properties that are 'Client Side Properties'.
-     *
-     * @see Piwik\ViewDataTable\Visualization::getClientSideProperties
      */
-    public static $clientSideProperties = array(
+    public $clientSideProperties = array(
         'show_limit_control'
     );
 
     /**
      * The list of ViewDataTable properties that can be overriden by query parameters.
-     *
-     * @see Piwik\ViewDataTable\Visualization::getOverridableProperties
      */
-    public static $overridableProperties = array(
+    public $overridableProperties = array(
         'show_goals',
         'disable_generic_filters',
         'disable_queued_filters',
@@ -66,16 +66,6 @@ class Config
         'show_non_core_visualizations'
     );
 
-    /**
-     * The default viewDataTable ID to use when determining which visualization to use.
-     * This property is only valid for reports whose properties are determined by the
-     * Visualization.getReportDisplayProperties event. When manually creating ViewDataTables,
-     * setting this property will have no effect.
-     *
-     * Default value: 'table'
-     */
-    public $default_view_type = 'table';
-
     /**
      * Controls what footer icons are displayed on the bottom left of the DataTable view.
      * The value of this property must be an array of footer icon groups. Footer icon groups
@@ -209,8 +199,6 @@ class Config
      * change to the clicked report and the list will change so the original report can be
      * navigated back to.
      *
-     * @see also self::TITLE. Both must be set if associating related reports.
-     *
      * Default value: array()
      */
     public $related_reports = array();
@@ -219,7 +207,7 @@ class Config
      * The report title. Used with related reports so report headings can be changed when switching
      * reports.
      *
-     * @see also self::RELATED_REPORTS. This must be set if related reports are added.
+     * This must be set if related reports are added.
      *
      * Default value: ''
      */
@@ -354,19 +342,10 @@ class Config
      * from a Related Report will go to a different URL. Can be used to load an entire page instead
      * of a single report when going back to the original report.
      *
-     * @see also self::RELATED_REPORTS
-     *
      * Default value: The URL used to request the report without generic filters.
      */
     public $self_url = '';
 
-    /**
-     * Special property that holds the properties for DataTable Visualizations.
-     *
-     * @var \Piwik\ViewDataTable\VisualizationPropertiesProxy
-     */
-    public $visualization_properties = array();
-
     /**
      * CSS class to use in the output HTML div. This is added in addition to the visualization CSS
      * class.
@@ -386,8 +365,6 @@ class Config
     /**
      * If true, searching through the DataTable will search through all subtables.
      *
-     * @see also self::FILTER_PATTERN
-     *
      * Default value: false
      */
     public $search_recursive = false;
@@ -435,8 +412,6 @@ class Config
      *
      * TODO: pagination/offset is only valid for HtmlTables... should only display for those visualizations.
      *
-     * @see self::SHOW_OFFSET_INFORMATION
-     *
      * Default value: true
      */
     public $show_pagination_control = true;
@@ -444,8 +419,6 @@ class Config
     /**
      * Controls whether offset information (ie, '5-10 of 20') is shown under the datatable.
      *
-     * @see self::SHOW_PAGINATION_CONTROL
-     *
      * Default value: true
      */
     public $show_offset_information = true;
@@ -471,9 +444,13 @@ class Config
      */
     public $show_non_core_visualizations = true;
 
+    public $report_last_updated_message = false;
     public $metadata  = array();
     public $report_id = '';
 
+    public $controllerName;
+    public $controllerAction;
+
     public function __construct()
     {
         $this->export_limit = \Piwik\Config::getInstance()->General['API_datatable_default_limit'];
@@ -483,57 +460,153 @@ class Config
         );
     }
 
+    public function setController($controllerName, $controllerAction)
+    {
+        $this->controllerName   = $controllerName;
+        $this->controllerAction = $controllerAction;
+        $this->report_id        = $controllerName . '.' . $controllerAction;
+
+        $this->loadDocumentation();
+    }
+
+    /** Load documentation from the API */
+    private function loadDocumentation()
+    {
+        $this->metrics_documentation = array();
+
+        $report = API::getInstance()->getMetadata(0, $this->controllerName, $this->controllerAction);
+        $report = $report[0];
+
+        if (isset($report['metricsDocumentation'])) {
+            $this->metrics_documentation = $report['metricsDocumentation'];
+        }
+
+        if (isset($report['documentation'])) {
+            $this->documentation = $report['documentation'];
+        }
+    }
+
+    public function addPropertiesThatShouldBeAvailableClientSide(array $propertyNames)
+    {
+        foreach ($propertyNames as $propertyName) {
+            $this->clientSideProperties[] = $propertyName;
+        }
+    }
+
+    public function addPropertiesThatCanBeOverwrittenByQueryParams(array $propertyNames)
+    {
+        foreach ($propertyNames as $propertyName) {
+            $this->overridableProperties[] = $propertyName;
+        }
+    }
+
     public function getProperties()
     {
-        return array(
-            'show_non_core_visualizations' => $this->show_non_core_visualizations,
-            'export_limit' => $this->export_limit,
-            'hide_annotations_view' => $this->hide_annotations_view,
-            'show_offset_information' => $this->show_offset_information,
-            'show_pagination_control' => $this->show_pagination_control,
-            'subtable_controller_action' => $this->subtable_controller_action,
-            'filters' => $this->filters,
-            'show_export_as_image_icon' => $this->show_export_as_image_icon,
-            'y_axis_unit' => $this->y_axis_unit,
-            'search_recursive' => $this->search_recursive,
-            'datatable_js_type' => $this->datatable_js_type,
-            'datatable_css_class' => $this->datatable_css_class,
-            'visualization_properties' => $this->visualization_properties,
-            'self_url' => $this->self_url,
-            'tooltip_metadata_name' => $this->tooltip_metadata_name,
-            'metrics_documentation' => $this->metrics_documentation,
-            'show_footer_message' => $this->show_footer_message,
-            'show_ecommerce' => $this->show_ecommerce,
-            'show_export_as_rss_feed' => $this->show_export_as_rss_feed,
-            'show_tag_cloud' => $this->show_tag_cloud,
-            'show_pie_chart' => $this->show_pie_chart,
-            'show_bar_chart' => $this->show_bar_chart,
-            'enable_sort' => $this->enable_sort,
-            'show_search' => $this->show_search,
-            'show_limit_control' => $this->show_limit_control,
-            'disable_queued_filters' => $this->disable_queued_filters,
-            'disable_generic_filters' => $this->disable_generic_filters,
-            'custom_parameters' => $this->custom_parameters,
-            'documentation' => $this->documentation,
-            'show_related_reports' => $this->show_related_reports,
-            'title' => $this->title,
-            'related_reports' => $this->related_reports,
-            'show_active_view_icon' => $this->show_active_view_icon,
-            'show_all_views_icons' => $this->show_all_views_icons,
-            'columns_to_display' => $this->columns_to_display,
-            'show_footer_icons' => $this->show_footer_icons,
-            'show_footer' => $this->show_footer,
-            'show_table_all_columns' => $this->show_table_all_columns,
-            'show_table' => $this->show_table,
-            'show_flatten_table' => $this->show_flatten_table,
-            'show_exclude_low_population' => $this->show_exclude_low_population,
-            'translations' => $this->translations,
-            'show_goals' => $this->show_goals,
-            'show_visualization_only' => $this->show_visualization_only,
-            'footer_icons' => $this->footer_icons,
-            'default_view_type' => $this->default_view_type,
-            'metadata' => $this->metadata,
-            'report_id' => $this->report_id
-        );
+        return get_object_vars($this);
     }
+
+    /**
+     * Returns true if queued filters have been disabled, false if otherwise.
+     *
+     * @return bool
+     */
+    public function areQueuedFiltersDisabled()
+    {
+        return isset($this->disable_queued_filters) && $this->disable_queued_filters;
+    }
+
+    /**
+     * Returns true if generic filters have been disabled, false if otherwise.
+     *
+     * @return bool
+     */
+    public function areGenericFiltersDisabled()
+    {
+        // if disable_generic_filters query param is set to '1', generic filters are disabled
+        if (Common::getRequestVar('disable_generic_filters', '0', 'string') == 1) {
+            return true;
+        }
+
+        if (isset($this->disable_generic_filters) && true === $this->disable_generic_filters) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public function setDefaultColumnsToDisplay($columns, $hasNbVisits, $hasNbUniqVisitors)
+    {
+        if ($hasNbVisits || $hasNbUniqVisitors) {
+            $columnsToDisplay = array('label');
+
+            // if unique visitors data is available, show it, otherwise just visits
+            if ($hasNbUniqVisitors) {
+                $columnsToDisplay[] = 'nb_uniq_visitors';
+            } else {
+                $columnsToDisplay[] = 'nb_visits';
+            }
+        } else {
+            $columnsToDisplay = $columns;
+        }
+
+        $this->columns_to_display = array_filter($columnsToDisplay);
+    }
+
+    public function getFiltersToRun()
+    {
+        $priorityFilters     = array();
+        $presentationFilters = array();
+
+        foreach ($this->filters as $filterInfo) {
+            if ($filterInfo instanceof \Closure) {
+                $nameOrClosure = $filterInfo;
+                $parameters    = array();
+                $priority      = false;
+            } else {
+                @list($nameOrClosure, $parameters, $priority) = $filterInfo;
+            }
+
+            if ($priority) {
+                $priorityFilters[] = array($nameOrClosure, $parameters);
+            } else {
+                $presentationFilters[] = array($nameOrClosure, $parameters);
+            }
+        }
+
+        return array($priorityFilters, $presentationFilters);
+    }
+
+    public function addRelatedReport($relatedReport, $title, $queryParams = array())
+    {
+        list($module, $action) = explode('.', $relatedReport);
+
+        // don't add the related report if it references this report
+        if ($this->controllerName == $module && $this->controllerAction == $action) {
+            return;
+        }
+
+        $url = ApiRequest::getBaseReportUrl($module, $action, $queryParams);
+
+        $this->related_reports[$url] = $title;
+    }
+
+    public function addRelatedReports($relatedReports)
+    {
+        foreach ($relatedReports as $report => $title) {
+            $this->addRelatedReport($report, $title);
+        }
+    }
+
+    public function addTranslation($key, $translation)
+    {
+        $this->translations[$key] = $translation;
+    }
+
+    public function addTranslations($translations)
+    {
+        foreach ($translations as $key => $translation) {
+            $this->addTranslation($key, $translation);
+        }
+    }
+
 }
diff --git a/core/ViewDataTable/Graph.php b/core/ViewDataTable/Graph.php
deleted file mode 100644
index 00404f5c055830540856d0012010805ddfb8243b..0000000000000000000000000000000000000000
--- a/core/ViewDataTable/Graph.php
+++ /dev/null
@@ -1,243 +0,0 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- * @category Piwik
- * @package Piwik
- */
-namespace Piwik\ViewDataTable;
-
-use Piwik\DataTable\Row;
-use Piwik\DataTable;
-use Piwik\DataTable\DataTableInterface;
-use Piwik\Piwik;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
-
-/**
- * This is an abstract visualization that should be the base of any 'graph' visualization.
- * This class defines certain visualization properties that are specific to all graph types.
- * Derived visualizations can decide for themselves whether they should support individual
- * properties.
- */
-abstract class Graph extends Visualization
-{
-    const ID = 'graph';
-
-    /**
-     * Whether the series picker should allow picking more than one series or not.
-     *
-     * Default value: true
-     */
-    const ALLOW_MULTI_SELECT_SERIES_PICKER = 'allow_multi_select_series_picker';
-
-    /**
-     * The maximum number of rows to render. All other rows will be aggregated in an 'Others' row.
-     *
-     * Default value: false (no limit)
-     */
-    const MAX_GRAPH_ELEMENTS = 'max_graph_elements';
-
-    /**
-     * Array property that contains the names of columns that can be selected in the Series Picker.
-     *
-     * Default value: false
-     */
-    const SELECTABLE_COLUMNS = 'selectable_columns';
-
-    /**
-     * Contains the column (if any) of the values used in the Row Picker.
-     *
-     * @see self::ROWS_TO_DISPLAY
-     *
-     * Default value: false
-     */
-    const ROW_PICKER_VALUE_COLUMN = 'row_picker_match_rows_by';
-
-    /**
-     * Contains the list of values identifying rows that should be displayed as separate series.
-     * The values are of a specific column determined by the row_picker_match_rows_by column.
-     *
-     * @see self::ROW_PICKER_VALUE_COLUMN
-     *
-     * Default value: false
-     */
-    const ROWS_TO_DISPLAY = 'rows_to_display';
-
-    /**
-     * Contains the list of values available for the Row Picker. Currently set to be all visible
-     * rows, if the row_picker_match_rows_by property is set.
-     *
-     * @see self::ROW_PICKER_VALUE_COLUMN
-     */
-    const SELECTABLE_ROWS = 'selectable_rows';
-
-    /**
-     * Controls whether all ticks & labels are shown on a graph's x-axis or just some.
-     *
-     * Default value: false
-     */
-    const SHOW_ALL_TICKS = 'show_all_ticks';
-
-    /**
-     * If true, a row with totals of each DataTable column is added.
-     *
-     * Default value: false
-     */
-    const ADD_TOTAL_ROW = 'add_total_row';
-
-    /**
-     * Controls whether the Series Picker is shown or not. The Series Picker allows users to
-     * choose between displaying data of different columns.
-     *
-     * Default value: true
-     */
-    const SHOW_SERIES_PICKER = 'show_series_picker';
-
-    /**
-     * Controls whether the percentage of the total is displayed as a tooltip when hovering over
-     * data points.
-     *
-     * NOTE: Sometimes this percentage is meaningless (when the total of the column values is
-     * not the total number of elements in the set). In this case the tooltip should not be
-     * displayed.
-     *
-     * Default value: true
-     */
-    const DISPLAY_PERCENTAGE_IN_TOOLTIP = 'display_percentage_in_tooltip';
-
-    public static $clientSideConfigProperties = array(
-        'show_series_picker',
-        'allow_multi_select_series_picker',
-        'selectable_columns',
-        'selectable_rows',
-        'display_percentage_in_tooltip'
-    );
-
-    public static $clientSideRequestParameters = array(
-        'columns'
-    );
-
-    public static $overridableProperties = array(
-        'show_all_ticks',
-        'show_series_picker'
-    );
-
-    public $selectableRows = array();
-
-    public function configureVisualization(Config $properties)
-    {
-        if ($properties->show_goals) {
-            $properties->translations['nb_conversions'] = Piwik::translate('Goals_ColumnConversions');
-            $properties->translations['revenue'] = Piwik::translate('General_TotalRevenue');
-        }
-    }
-
-    public static function getDefaultPropertyValues()
-    {
-        return array(
-            'show_limit_control'       => false,
-            'visualization_properties' => array(
-                'graph' => array(
-                    'add_total_row'                    => false,
-                    'show_all_ticks'                   => false,
-                    'allow_multi_select_series_picker' => true,
-                    'max_graph_elements'               => false,
-                    'selectable_columns'               => false,
-                    'show_series_picker'               => true,
-                    'display_percentage_in_tooltip'    => true,
-                    'row_picker_match_rows_by'         => false,
-                    'rows_to_display'                  => false,
-                    'selectable_rows'                  => false
-                )
-            )
-        );
-    }
-
-    /**
-     * Defaults the selectable_columns property if it has not been set and then transforms
-     * it into something the SeriesPicker JavaScript class can use.
-     */
-    public function afterAllFilteresAreApplied(DataTableInterface $dataTable, Config $properties, Request $request)
-    {
-        $properties->visualization_properties->selectable_rows = array_values($this->selectableRows);
-
-        $selectableColumns = $properties->visualization_properties->selectable_columns;
-
-        // set default selectable columns, if none specified
-        if ($selectableColumns === false) {
-            $selectableColumns = array('nb_visits', 'nb_actions');
-
-            if (in_array('nb_uniq_visitors', $dataTable->getColumns())) {
-                $selectableColumns[] = 'nb_uniq_visitors';
-            }
-        }
-
-        if ($properties->show_goals) {
-            $goalMetrics = array('nb_conversions', 'revenue');
-            $selectableColumns = array_merge($selectableColumns, $goalMetrics);
-        }
-
-        $transformed = array();
-        foreach ($selectableColumns as $column) {
-            $transformed[] = array(
-                'column'      => $column,
-                'translation' => @$properties->translations[$column],
-                'displayed'   => in_array($column, $properties->columns_to_display)
-            );
-        }
-        $properties->visualization_properties->selectable_columns = $transformed;
-    }
-
-    /**
-     * Determines what rows are selectable and stores them in the selectable_rows property in
-     * a format the SeriesPicker JavaScript class can use.
-     */
-    public function beforeLoadDataTable(Request $request, Config $properties)
-    {
-        // TODO: this should not be required here. filter_limit should not be a view property, instead HtmlTable should use 'limit' or something,
-        //       and manually set request_parameters_to_modify['filter_limit'] based on that. (same for filter_offset).
-        $request->request_parameters_to_modify['filter_limit'] = false;
-
-        if ($properties->visualization_properties->max_graph_elements) {
-            $request->request_parameters_to_modify['filter_truncate'] = $properties->visualization_properties->max_graph_elements - 1;
-        }
-
-        if ($properties->visualization_properties->row_picker_match_rows_by === false) {
-            return;
-        }
-    }
-
-    public function beforeGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
-    {
-        // collect all selectable rows
-        $self = $this;
-
-        $dataTable->filter(function ($dataTable) use ($self, $properties) {
-            foreach ($dataTable->getRows() as $row) {
-                $rowLabel = $row->getColumn('label');
-                if ($rowLabel === false) {
-                    continue;
-                }
-
-                // determine whether row is visible
-                $isVisible = true;
-                if ($properties->visualization_properties->row_picker_match_rows_by == 'label') {
-                    $isVisible = in_array($rowLabel, $properties->visualization_properties->rows_to_display);
-                }
-
-                // build config
-                if (!isset($self->selectableRows[$rowLabel])) {
-                    $self->selectableRows[$rowLabel] = array(
-                        'label'     => $rowLabel,
-                        'matcher'   => $rowLabel,
-                        'displayed' => $isVisible
-                    );
-                }
-            }
-        });
-    }
-}
\ No newline at end of file
diff --git a/core/ViewDataTable/Request.php b/core/ViewDataTable/Request.php
new file mode 100644
index 0000000000000000000000000000000000000000..9cd5d933d4560a3c4ade8c002fb0eb3136ad6023
--- /dev/null
+++ b/core/ViewDataTable/Request.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
+
+namespace Piwik\ViewDataTable;
+
+use Piwik\API\Request as ApiRequest;
+use Piwik\Common;
+use Piwik\DataTable;
+use Piwik\Date;
+use Piwik\Metrics;
+use Piwik\MetricsFormatter;
+use Piwik\Period;
+use Piwik\Piwik;
+
+class Request
+{
+    /**
+     * @var null|\Piwik\ViewDataTable\RequestConfig
+     */
+    public $requestConfig;
+
+    public function __construct($requestConfig)
+    {
+        $this->requestConfig = $requestConfig;
+    }
+
+    /**
+     * Function called by the ViewDataTable objects in order to fetch data from the API.
+     * The function init() must have been called before, so that the object knows which API module and action to call.
+     * It builds the API request string and uses Request to call the API.
+     * The requested DataTable object is stored in $this->dataTable.
+     */
+    public function loadDataTableFromAPI()
+    {
+        // we build the request (URL) to call the API
+        $requestArray = $this->getRequestArray();
+
+        // we make the request to the API
+        $request = new ApiRequest($requestArray);
+
+        // and get the DataTable structure
+        $dataTable = $request->process();
+
+        return $dataTable;
+    }
+
+    /**
+     * @return array  URL to call the API, eg. "method=Referrers.getKeywords&period=day&date=yesterday"...
+     */
+    public function getRequestArray()
+    {
+        // we prepare the array to give to the API Request
+        // we setup the method and format variable
+        // - we request the method to call to get this specific DataTable
+        // - the format = original specifies that we want to get the original DataTable structure itself, not rendered
+        $requestArray = array(
+            'method'                  => $this->requestConfig->apiMethodToRequestDataTable,
+            'format'                  => 'original',
+            'disable_generic_filters' => Common::getRequestVar('disable_generic_filters', 1, 'int')
+        );
+
+        $toSetEventually = array(
+            'filter_limit',
+            'keep_summary_row',
+            'filter_sort_column',
+            'filter_sort_order',
+            'filter_excludelowpop',
+            'filter_excludelowpop_value',
+            'filter_column',
+            'filter_pattern',
+        );
+
+        foreach ($toSetEventually as $varToSet) {
+            $value = $this->getDefaultOrCurrent($varToSet);
+            if (false !== $value) {
+                $requestArray[$varToSet] = $value;
+            }
+        }
+
+        $segment = ApiRequest::getRawSegmentFromRequest();
+        if (!empty($segment)) {
+            $requestArray['segment'] = $segment;
+        }
+
+        if (self::shouldLoadExpanded()) {
+            $requestArray['expanded'] = 1;
+        }
+
+        $requestArray = array_merge($requestArray, $this->requestConfig->request_parameters_to_modify);
+
+        if (!empty($requestArray['filter_limit'])
+            && $requestArray['filter_limit'] === 0
+        ) {
+            unset($requestArray['filter_limit']);
+        }
+
+        return $requestArray;
+    }
+
+    /**
+     * Returns, for a given parameter, the value of this parameter in the REQUEST array.
+     * If not set, returns the default value for this parameter @see getDefault()
+     *
+     * @param string $nameVar
+     * @return string|mixed Value of this parameter
+     */
+    protected function getDefaultOrCurrent($nameVar)
+    {
+        if (isset($_GET[$nameVar])) {
+            return Common::sanitizeInputValue($_GET[$nameVar]);
+        }
+        $default = $this->getDefault($nameVar);
+        return $default;
+    }
+
+    /**
+     * Returns the default value for a given parameter.
+     * For example, these default values can be set using the disable* methods.
+     *
+     * @param string $nameVar
+     * @return mixed
+     */
+    protected function getDefault($nameVar)
+    {
+        if (isset($this->requestConfig->$nameVar)) {
+            return $this->requestConfig->$nameVar;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns whether the DataTable result will have to be expanded for the
+     * current request before rendering.
+     *
+     * @return bool
+     */
+    public static function shouldLoadExpanded()
+    {
+        // TODO this is not the right class for this
+
+        // if filter_column_recursive & filter_pattern_recursive are supplied, and flat isn't supplied
+        // we have to load all the child subtables.
+        return Common::getRequestVar('filter_column_recursive', false) !== false
+                && Common::getRequestVar('filter_pattern_recursive', false) !== false
+                && Common::getRequestVar('flat', false) === false;
+    }
+
+}
\ No newline at end of file
diff --git a/core/Visualization/Request.php b/core/ViewDataTable/RequestConfig.php
similarity index 64%
rename from core/Visualization/Request.php
rename to core/ViewDataTable/RequestConfig.php
index 959658e619646a3a3a2f0056696e07af929305e5..c92b0a3ef70aaca3b139214eb0f0a48bdf3cb562 100644
--- a/core/Visualization/Request.php
+++ b/core/ViewDataTable/RequestConfig.php
@@ -9,7 +9,7 @@
  * @package Piwik
  */
 
-namespace Piwik\Visualization;
+namespace Piwik\ViewDataTable;
 
 /**
  * Renders a sparkline image given a PHP data array.
@@ -18,15 +18,13 @@ namespace Piwik\Visualization;
  * @package Piwik
  * @subpackage Piwik_Visualization
  */
-class Request
+class RequestConfig
 {
 
     /**
      * The list of ViewDataTable properties that are 'Client Side Parameters'.
-     *
-     * @see Piwik\ViewDataTable\Visualization::getClientSideParameters
      */
-    public static $clientSideParameters = array(
+    public $clientSideParameters = array(
         'filter_excludelowpop',
         'filter_excludelowpop_value',
         'filter_pattern',
@@ -36,10 +34,8 @@ class Request
 
     /**
      * The list of ViewDataTable properties that can be overriden by query parameters.
-     *
-     * @see Piwik\ViewDataTable\Visualization::getOverridableProperties
      */
-    public static $overridableProperties = array(
+    public $overridableProperties = array(
         'filter_sort_column',
         'filter_sort_order',
         'filter_limit',
@@ -47,7 +43,7 @@ class Request
         'filter_pattern',
         'filter_column',
         'filter_excludelowpop',
-        'filter_excludelowpop_value',
+        'filter_excludelowpop_value'
     );
 
     /**
@@ -63,8 +59,6 @@ class Request
      * Controls the sort order. Either 'asc' or 'desc'.
      *
      * Default value: 'desc'
-     *
-     * @see self::SORTED_COLUMN
      */
     public $filter_sort_order = 'desc';
 
@@ -72,8 +66,6 @@ class Request
      * The number of items to truncate the data set to before rendering the DataTable view.
      *
      * Default value: false
-     *
-     * @see self::OFFSET
      */
     public $filter_limit = false;
 
@@ -81,8 +73,6 @@ class Request
      * The number of items from the start of the data set that should be ignored.
      *
      * Default value: 0
-     *
-     * @see self::LIMIT
      */
     public $filter_offset = 0;
 
@@ -107,8 +97,6 @@ class Request
     /**
      * Stores the column name to filter when filtering out rows with low values.
      *
-     * @see also self::EXCLUDE_LOW_POPULATION_VALUE
-     *
      * Default value: false
      */
     public $filter_excludelowpop = false;
@@ -116,8 +104,6 @@ class Request
     /**
      * Stores the value considered 'low' when filtering out rows w/ low values.
      *
-     * @see also self::EXCLUDE_LOW_POPULATION_COLUMN
-     *
      * Default value: false
      * @var \Closure|string
      */
@@ -135,19 +121,56 @@ class Request
 
     public $apiMethodToRequestDataTable = '';
 
+    /**
+     * If the current dataTable refers to a subDataTable (eg. keywordsBySearchEngineId for id=X) this variable is set to the Id
+     *
+     * @var bool|int
+     */
+    public $idSubtable = false;
+
     public function getProperties()
     {
-        return array(
-            'filter_excludelowpop_value' => $this->filter_excludelowpop_value,
-            'filter_excludelowpop' => $this->filter_excludelowpop,
-            'filter_column' => $this->filter_column,
-            'filter_pattern' => $this->filter_pattern,
-            'filter_offset' => $this->filter_offset,
-            'filter_limit' => $this->filter_limit,
-            'filter_sort_order' => $this->filter_sort_order,
-            'filter_sort_column' => $this->filter_sort_column,
-            'request_parameters_to_modify' => $this->request_parameters_to_modify,
-            'apiMethodToRequestDataTable' => $this->apiMethodToRequestDataTable
-        );
+        return get_object_vars($this);
     }
+
+    public function addPropertiesThatShouldBeAvailableClientSide(array $propertyNames)
+    {
+        foreach ($propertyNames as $propertyName) {
+            $this->clientSideParameters[] = $propertyName;
+        }
+    }
+
+    public function addPropertiesThatCanBeOverwrittenByQueryParams(array $propertyNames)
+    {
+        foreach ($propertyNames as $propertyName) {
+            $this->overridableProperties[] = $propertyName;
+        }
+    }
+
+    public function setDefaultSort($columnsToDisplay, $hasNbUniqVisitors)
+    {
+        // default sort order to visits/visitors data
+        if ($hasNbUniqVisitors && in_array('nb_uniq_visitors', $columnsToDisplay)) {
+            $this->filter_sort_column = 'nb_uniq_visitors';
+        } else {
+            $this->filter_sort_column = 'nb_visits';
+        }
+
+        $this->filter_sort_order = 'desc';
+    }
+
+    public function getApiModuleToRequest()
+    {
+        list($module, $method) = explode('.', $this->apiMethodToRequestDataTable);
+
+        return $module;
+    }
+
+    public function getApiMethodToRequest()
+    {
+        list($module, $method) = explode('.', $this->apiMethodToRequestDataTable);
+
+        return $method;
+    }
+
 }
diff --git a/core/ViewDataTable/Visualization.php b/core/ViewDataTable/Visualization.php
deleted file mode 100644
index 3af056bd0d58af6205468cd4ad32b4c0d9e9fe9e..0000000000000000000000000000000000000000
--- a/core/ViewDataTable/Visualization.php
+++ /dev/null
@@ -1,310 +0,0 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- * @category Piwik
- * @package Piwik
- */
-
-namespace Piwik\ViewDataTable;
-
-use Piwik\DataTable;
-use Piwik\DataTable\DataTableInterface;
-use Piwik\Piwik;
-use Piwik\View;
-use Piwik\ViewDataTable;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
-
-/**
- * Base class for all DataTable visualizations. Different visualizations are used to
- * handle different values of the viewDataTable query parameter. Each one will display
- * DataTable data in a different way.
- *
- * TODO: must be more in depth
- */
-abstract class Visualization extends View
-{
-    const GET_AVAILABLE_EVENT = 'Visualization.addVisualizations';
-    const TEMPLATE_FILE = '';
-
-    /**
-     * The view data table
-     * @var ViewDataTable
-     */
-    protected $viewDataTable;
-
-    final public function __construct($view)
-    {
-        $templateFile = static::TEMPLATE_FILE;
-
-        if (empty($templateFile)) {
-            throw new \Exception('You have not defined a constant named TEMPLATE_FILE in your visualization class.');
-        }
-
-        parent::__construct($templateFile);
-
-        $this->viewDataTable = $view;
-        $this->init();
-    }
-
-    protected function init()
-    {
-        // do your init stuff here, do not overwrite constructor
-        // maybe setting my view properties $this->vizTitle
-    }
-
-    public function configureVisualization(Config $properties)
-    {
-        // our stuff goes in here
-        // like $properties->showFooterColumns = true;
-    }
-
-    public function beforeLoadDataTable(Request $request, Config $properties)
-    {
-        // change request --> $requestProperties...
-        // like defining filter_column
-        // $requestProperties->filterColumn = 54;
-        // $requestProperties->setFilterColumn();
-    }
-
-    public function beforeGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
-    {
-
-    }
-
-    public function afterGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
-    {
-
-    }
-
-    public function afterAllFilteresAreApplied(DataTableInterface $dataTable, Config $properties, Request $request)
-    {
-        // filter and format requested data here
-        // $dataTable ...
-
-        // $this->generator = new GeneratorFoo($dataTable);
-    }
-
-    /**
-     * Default implementation of getDefaultPropertyValues static function.
-     *
-     * @return array
-     */
-    public static function getDefaultPropertyValues()
-    {
-        return array();
-    }
-
-    /**
-     * Returns the array of view properties that a DataTable visualization will require
-     * to be both visible to client side JavaScript, and passed along as query parameters
-     * in every AJAX request.
-     *
-     * Derived Visualizations can specify client side parameters by declaring
-     * a static $clientSideParameters field that contains a list of view property
-     * names.
-     *
-     * @return array
-     */
-    public static function getClientSideRequestParameters()
-    {
-        return self::getPropertyNameListWithMetaProperty('clientSideRequestParameters');
-    }
-
-    /**
-     * Returns an array of view property names that a DataTable visualization will
-     * require to be visible to client side JavaScript. Unlike 'client side parameters',
-     * these will not be passed with AJAX requests as query parameters.
-     *
-     * Derived Visualizations can specify client side properties by declaring
-     * a static $clientSideProperties field that contains a list of view property
-     * names.
-     *
-     * @return array
-     */
-    public static function getClientSideConfigProperties()
-    {
-        return self::getPropertyNameListWithMetaProperty('clientSideConfigProperties');
-    }
-
-    /**
-     * Returns an array of view property names that can be overriden by query parameters.
-     * If a query parameter is sent with the same name as a view property, the view
-     * property will be set to the value of the query parameter.
-     *
-     * Derived Visualizations can specify overridable properties by declaring
-     * a static $overridableProperties field that contains a list of view property
-     * names.
-     */
-    public static function getOverridableProperties()
-    {
-        return self::getPropertyNameListWithMetaProperty('overridableProperties');
-    }
-
-    /**
-     * Returns the viewDataTable ID for this DataTable visualization. Derived classes
-     * should declare a const ID field with the viewDataTable ID.
-     *
-     * @return string
-     */
-    public static function getViewDataTableId()
-    {
-        if (defined('static::ID')) {
-            return static::ID;
-        } else {
-            return get_called_class();
-        }
-    }
-
-    /**
-     * Returns the list of parents for a Visualization class excluding the
-     * Visualization class and above.
-     *
-     * @param string $klass The class name of the Visualization.
-     * @return Visualization[]  The list of parent classes in order from highest
-     *                                   ancestor to the descended class.
-     */
-    public static function getVisualizationClassLineage($klass)
-    {
-        $klasses = array_merge(array($klass), array_values(class_parents($klass, $autoload = false)));
-
-        $idx = array_search('Piwik\\ViewDataTable\\Visualization', $klasses);
-        if ($idx !== false) {
-            $klasses = array_slice($klasses, 0, $idx);
-        }
-
-        return array_reverse($klasses);
-    }
-
-    /**
-     * Returns the viewDataTable IDs of a visualization's class lineage.
-     *
-     * @see self::getVisualizationClassLineage
-     *
-     * @param string $klass The visualization class.
-     *
-     * @return array
-     */
-    public static function getVisualizationIdsWithInheritance($klass)
-    {
-        $klasses = self::getVisualizationClassLineage($klass);
-
-        $result = array();
-        foreach ($klasses as $klass) {
-            $result[] = $klass::getViewDataTableId();
-        }
-        return $result;
-    }
-
-    /**
-     * Returns all registered visualization classes. Uses the 'Visualization.getAvailable'
-     * event to retrieve visualizations.
-     *
-     * @return array Array mapping visualization IDs with their associated visualization classes.
-     * @throws \Exception If a visualization class does not exist or if a duplicate visualization ID
-     *                   is found.
-     */
-    public static function getAvailableVisualizations()
-    {
-        /** @var self[] $visualizations */
-        $visualizations = array();
-
-        /**
-         * This event is used to gather all available DataTable visualizations. Callbacks should add visualization
-         * class names to the incoming array.
-         */
-        Piwik::postEvent(self::GET_AVAILABLE_EVENT, array(&$visualizations));
-
-        $result = array();
-        foreach ($visualizations as $viz) {
-            if (!class_exists($viz)) {
-                throw new \Exception(
-                    "Invalid visualization class '$viz' found in Visualization.getAvailableVisualizations.");
-            }
-
-            if (is_subclass_of($viz, __CLASS__)) {
-                $vizId = $viz::getViewDataTableId();
-                if (isset($result[$vizId])) {
-                    throw new \Exception("Visualization ID '$vizId' is already in use!");
-                }
-
-                $result[$vizId] = $viz;
-            }
-        }
-        return $result;
-    }
-
-    /**
-     * Returns all available visualizations that are not part of the CoreVisualizations plugin.
-     *
-     * @return array Array mapping visualization IDs with their associated visualization classes.
-     */
-    public static function getNonCoreVisualizations()
-    {
-        $result = array();
-        foreach (self::getAvailableVisualizations() as $vizId => $vizClass) {
-            if (strpos($vizClass, 'Piwik\\Plugins\\CoreVisualizations') === false) {
-                $result[$vizId] = $vizClass;
-            }
-        }
-        return $result;
-    }
-
-    /**
-     * Returns an array mapping visualization IDs with information necessary for adding the
-     * visualizations to the footer of DataTable views.
-     *
-     * @param array $visualizations An array mapping visualization IDs w/ their associated classes.
-     * @return array
-     */
-    public static function getVisualizationInfoFor($visualizations)
-    {
-        $result = array();
-        foreach ($visualizations as $vizId => $vizClass) {
-            $result[$vizId] = array('table_icon' => $vizClass::FOOTER_ICON, 'title' => $vizClass::FOOTER_ICON_TITLE);
-        }
-        return $result;
-    }
-
-    /**
-     * Returns the visualization class by it's viewDataTable ID.
-     *
-     * @param string $id The visualization ID.
-     * @return string The visualization class name. If $id is not a valid ID, the HtmlTable visualization
-     *                is returned.
-     */
-    public static function getClassFromId($id)
-    {
-        $visualizationClasses = self::getAvailableVisualizations();
-        if (!isset($visualizationClasses[$id])) {
-            return $visualizationClasses['table'];
-        }
-        return $visualizationClasses[$id];
-    }
-
-    /**
-     * Helper function that merges the static field values of every class in this
-     * classes inheritance hierarchy. Uses late-static binding.
-     */
-    private static function getPropertyNameListWithMetaProperty($staticFieldName)
-    {
-        if (isset(static::$$staticFieldName)) {
-            $result = array();
-
-            $lineage = static::getVisualizationClassLineage(get_called_class());
-            foreach ($lineage as $klass) {
-                if (isset($klass::$$staticFieldName)) {
-                    $result = array_merge($result, $klass::$$staticFieldName);
-                }
-            }
-
-            return array_unique($result);
-        } else {
-            return array();
-        }
-    }
-}
\ No newline at end of file
diff --git a/core/ViewDataTable/VisualizationPropertiesProxy.php b/core/ViewDataTable/VisualizationPropertiesProxy.php
deleted file mode 100644
index b100cd5c9298f592c95d99e083e6d9e46372e33f..0000000000000000000000000000000000000000
--- a/core/ViewDataTable/VisualizationPropertiesProxy.php
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- * @category Piwik
- * @package Piwik
- */
-
-namespace Piwik\ViewDataTable;
-
-
-/**
- * Proxy object used to get/set visualization properties. Used to check that property
- * names are valid.
- */
-class VisualizationPropertiesProxy
-{
-    /**
-     * The visualization class name.
-     *
-     * @var string
-     */
-    private $visualizationClass;
-
-    /**
-     * Stores visualization properties.
-     *
-     * @var array
-     */
-    private $visualizationProperties = array();
-
-    /**
-     * Constructor.
-     *
-     * @param string $visualizationClass The visualization class to get/set properties of.
-     */
-    public function __construct($visualizationClass)
-    {
-        $this->visualizationClass = $visualizationClass;
-    }
-
-    /**
-     * Hack to allow property access in Twig (w/ property name checking).
-     */
-    public function __call($name, $arguments)
-    {
-        return $this->$name;
-    }
-
-    /**
-     * Gets a reference to a visualization property.
-     *
-     * @param string $name A valid property name for the current visualization.
-     * @return mixed
-     * @throws \Exception if the property name is invalid.
-     */
-    public function &__get($name)
-    {
-        if ($this->visualizationClass !== null) {
-            static::checkValidVisualizationProperty($this->visualizationClass, $name);
-        }
-
-        return $this->visualizationProperties[$name];
-    }
-
-    /**
-     * Sets a visualization property.
-     *
-     * @param string $name A valid property name for the current visualization.
-     * @param mixed $value
-     * @return mixed Returns $value.
-     * @throws \Exception if the property name is invalid.
-     */
-    public function __set($name, $value)
-    {
-        if ($this->visualizationClass !== null) {
-            static::checkValidVisualizationProperty($this->visualizationClass, $name);
-        }
-
-        return $this->visualizationProperties[$name] = $value;
-    }
-
-    /**
-     * Checks if a property is a valid visualization property for the given visualization class,
-     * and if not, throws an exception.
-     *
-     * @param string $visualizationClass
-     * @param string $name The property name.
-     * @throws \Exception
-     */
-    public static function checkValidVisualizationProperty($visualizationClass, $name)
-    {
-        if (!self::isValidVisualizationProperty($visualizationClass, $name)) {
-            throw new \Exception("Invalid Visualization display property '$name' for '$visualizationClass'.");
-        }
-    }
-    /**
-     * Returns true if $name is a valid visualization property for the given visualization class.
-     */
-    public static function isValidVisualizationProperty($visualizationClass, $name)
-    {
-        $properties = self::getVisualizationProperties($visualizationClass);
-        return isset($properties[$name]);
-    }
-
-    /**
-     * Returns the set of all valid properties for the given visualization class. The result is an
-     * array with property names as keys. Values of the array are undefined.
-     *
-     * @param string $visualizationClass
-     *
-     * @return array
-     */
-    public static function getVisualizationProperties($visualizationClass)
-    {
-        static $propertiesCache = array();
-
-        if ($visualizationClass === null) {
-            return array();
-        }
-
-        if (!isset($propertiesCache[$visualizationClass])) {
-            $properties = self::getFlippedClassConstantMap($visualizationClass);
-
-            $parentClass = get_parent_class($visualizationClass);
-            if ($parentClass != 'Piwik\\ViewDataTable\\Visualization') {
-                $properties += self::getVisualizationProperties($parentClass);
-            }
-
-            $propertiesCache[$visualizationClass] = $properties;
-        }
-
-        return $propertiesCache[$visualizationClass];
-    }
-
-    private static function getFlippedClassConstantMap($klass)
-    {
-        $klass = new \ReflectionClass($klass);
-        $constants = $klass->getConstants();
-
-        unset($constants['ID']);
-        unset($constants['FOOTER_ICON']);
-        unset($constants['FOOTER_ICON_TITLE']);
-
-        foreach ($constants as $name => $value) {
-            if (!is_string($value)) {
-                unset($constants[$name]);
-            }
-        }
-
-        return array_flip($constants);
-    }
-
-    /**
-     * Sets a visualization property, but only if the visualization is an instance of a
-     * certain class.
-     *
-     * @param string $forClass The visualization class to check for.
-     * @param string $name A valid property name for the current visualization.
-     * @param mixed $value
-     * @return mixed Returns $value.
-     * @throws \Exception if the property name is invalid.
-     */
-    public function setForVisualization($forClass, $name, $value)
-    {
-        if ($forClass == $this->visualizationClass
-            || is_subclass_of($this->visualizationClass, $forClass)
-        ) {
-            return $this->__set($name, $value);
-        }
-    }
-}
\ No newline at end of file
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index b2fb9e9583b6883cae7ec602c665f234b67a0aca..84bae607b7d54a41378424459a360518878576ff 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -17,11 +17,13 @@ use Piwik\Db;
 use Piwik\Menu\MenuMain;
 use Piwik\MetricsFormatter;
 use Piwik\Piwik;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
 use Piwik\SegmentExpression;
 use Piwik\Site;
 use Piwik\Tracker\Action;
-use Piwik\ViewDataTable;
+use Piwik\ViewDataTable\Request as ViewDataTableRequest;
 use Piwik\WidgetsList;
+use \Piwik\Plugin\ViewDataTable;
 
 /**
  * Actions plugin
@@ -56,15 +58,15 @@ class Actions extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenus',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
-            'AssetManager.getStylesheetFiles'          => 'getStylesheetFiles',
-            'AssetManager.getJavaScriptFiles'          => 'getJsFiles'
+            'ArchiveProcessor.Day.compute'    => 'archiveDay',
+            'ArchiveProcessor.Period.compute' => 'archivePeriod',
+            'WidgetsList.addWidgets'          => 'addWidgets',
+            'Menu.Reporting.addItems'         => 'addMenus',
+            'API.getReportMetadata'           => 'getReportMetadata',
+            'API.getSegmentsMetadata'         => 'getSegmentsMetadata',
+            'ViewDataTable.configure'         => 'configureViewDataTable',
+            'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
+            'AssetManager.getJavaScriptFiles' => 'getJsFiles'
         );
         return $hooks;
     }
@@ -643,51 +645,93 @@ class Actions extends \Piwik\Plugin
         }
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['Actions.getPageUrls'] = $this->getDisplayPropertiesForPageUrls();
-        $properties['Actions.getEntryPageUrls'] = $this->getDisplayPropertiesForEntryPageUrls();
-        $properties['Actions.getExitPageUrls'] = $this->getDisplayPropertiesForExitPageUrls();
-        $properties['Actions.getSiteSearchKeywords'] = $this->getDisplayPropertiesForSiteSearchKeywords();
-        $properties['Actions.getSiteSearchNoResultKeywords'] = $this->getDisplayPropertiesForSiteSearchNoResultKeywords();
-        $properties['Actions.getSiteSearchCategories'] = $this->getDisplayPropertiesForSiteSearchCategories();
-        $properties['Actions.getPageUrlsFollowingSiteSearch'] = $this->getDisplayPropertiesForGetPageUrlsOrTitlesFollowingSiteSearch(false);
-        $properties['Actions.getPageTitlesFollowingSiteSearch'] = $this->getDisplayPropertiesForGetPageUrlsOrTitlesFollowingSiteSearch(true);
-        $properties['Actions.getPageTitles'] = $this->getDisplayPropertiesForGetPageTitles();
-        $properties['Actions.getEntryPageTitles'] = $this->getDisplayPropertiesForGetEntryPageTitles();
-        $properties['Actions.getExitPageTitles'] = $this->getDisplayPropertiesForGetExitPageTitles();
-        $properties['Actions.getDownloads'] = $this->getDisplayPropertiesForGetDownloads();
-        $properties['Actions.getOutlinks'] = $this->getDisplayPropertiesForGetOutlinks();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'Actions.getPageUrls':
+                $this->configureViewForPageUrls($view);
+                break;
+            case 'Actions.getEntryPageUrls':
+                $this->configureViewForEntryPageUrls($view);
+                break;
+            case 'Actions.getExitPageUrls':
+                $this->configureViewForExitPageUrls($view);
+                break;
+            case 'Actions.getSiteSearchKeywords':
+                $this->configureViewForSiteSearchKeywords($view);
+                break;
+            case 'Actions.getSiteSearchNoResultKeywords':
+                $this->configureViewForSiteSearchNoResultKeywords($view);
+                break;
+            case 'Actions.getSiteSearchCategories':
+                $this->configureViewForSiteSearchCategories($view);
+                break;
+            case 'Actions.getPageUrlsFollowingSiteSearch':
+                $this->configureViewForGetPageUrlsOrTitlesFollowingSiteSearch($view, false);
+                break;
+            case 'Actions.getPageTitlesFollowingSiteSearch':
+                $this->configureViewForGetPageUrlsOrTitlesFollowingSiteSearch($view, true);
+                break;
+            case 'Actions.getPageTitles':
+                $this->configureViewForGetPageTitles($view);
+                break;
+            case 'Actions.getEntryPageTitles':
+                $this->configureViewForGetEntryPageTitles($view);
+                break;
+            case 'Actions.getExitPageTitles':
+                $this->configureViewForGetExitPageTitles($view);
+                break;
+            case 'Actions.getDownloads':
+                $this->configureViewForGetDownloads($view);
+                break;
+            case 'Actions.getOutlinks':
+                $this->configureViewForGetOutlinks($view);
+                break;
+        }
+
+        if ($this->pluginName == $view->requestConfig->getApiModuleToRequest()) {
+            if ($view->isRequestingSingleDataTable()) {
+                // make sure custom visualizations are shown on actions reports
+                $view->config->show_all_views_icons = true;
+                $view->config->show_bar_chart = false;
+                $view->config->show_pie_chart = false;
+                $view->config->show_tag_cloud = false;
+            }
+        }
     }
 
-    private function addBaseDisplayProperties(&$result)
+    private function addBaseDisplayProperties(ViewDataTable $view)
     {
-        $result['datatable_js_type'] = 'ActionsDataTable';
-        $result['visualization_properties']['table']['show_embedded_subtable'] = true;
-        $result['search_recursive'] = true;
-        $result['show_all_views_icons'] = false;
-        $result['show_table_all_columns'] = false;
-        $result['filter_limit'] = self::ACTIONS_REPORT_ROWS_DISPLAY;
+        $view->config->datatable_js_type      = 'ActionsDataTable';
+        $view->config->search_recursive       = true;
+        $view->config->show_table_all_columns = false;
+        $view->requestConfig->filter_limit    = self::ACTIONS_REPORT_ROWS_DISPLAY;
+        $view->config->show_all_views_icons   = false;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->show_embedded_subtable = true;
+        }
 
         // if the flat parameter is not provided, make sure it is set to 0 in the URL,
         // so users can see that they can set it to 1 (see #3365)
-        $result['custom_parameters'] = array('flat' => 0);
+        $view->config->custom_parameters = array('flat' => 0);
 
-        if (ViewDataTable::shouldLoadExpanded()) {
-            $result['visualization_properties']['table']['show_expanded'] = true;
+        if (ViewDataTableRequest::shouldLoadExpanded()) {
 
-            $result['filters'][] = function ($dataTable) {
+            if ($view->isViewDataTableId(HtmlTable::ID)) {
+                $view->config->show_expanded = true;
+            }
+
+            $view->config->filters[] = function ($dataTable) {
                 Actions::setDataTableRowLevels($dataTable);
             };
         }
 
-        $result['filters'][] = function ($dataTable, $view) {
-            if ($view->getViewDataTableId() == 'table') {
-                $view->datatable_css_class = 'dataTableActions';
+        $view->config->filters[] = function ($dataTable) use ($view) {
+            if ($view->isViewDataTableId(HtmlTable::ID)) {
+                $view->config->datatable_css_class = 'dataTableActions';
             }
         };
-
-        return $result;
     }
 
     /**
@@ -706,11 +750,11 @@ class Actions extends \Piwik\Plugin
         }
     }
 
-    private function addExcludeLowPopDisplayProperties(&$result)
+    private function addExcludeLowPopDisplayProperties(ViewDataTable $view)
     {
         if (Common::getRequestVar('enable_filter_excludelowpop', '0', 'string') != '0') {
-            $result['filter_excludelowpop'] = 'nb_hits';
-            $result['filter_excludelowpop_value'] = function () {
+            $view->requestConfig->filter_excludelowpop = 'nb_hits';
+            $view->requestConfig->filter_excludelowpop_value = function () {
                 // computing minimum value to exclude (2 percent of the total number of actions)
                 $visitsInfo = \Piwik\Plugins\VisitsSummary\Controller::getVisitsSummary()->getFirstRow();
                 $nbActions = $visitsInfo->getColumn('nb_actions');
@@ -723,27 +767,26 @@ class Actions extends \Piwik\Plugin
         }
     }
 
-    private function addPageDisplayProperties(&$result)
+    private function addPageDisplayProperties(ViewDataTable $view)
     {
-        // add common translations
-        $result['translations'] += array(
+        $view->config->addTranslations(array(
             'nb_hits'             => Piwik::translate('General_ColumnPageviews'),
             'nb_visits'           => Piwik::translate('General_ColumnUniquePageviews'),
             'avg_time_on_page'    => Piwik::translate('General_ColumnAverageTimeOnPage'),
             'bounce_rate'         => Piwik::translate('General_ColumnBounceRate'),
             'exit_rate'           => Piwik::translate('General_ColumnExitRate'),
             'avg_time_generation' => Piwik::translate('General_ColumnAverageGenerationTime'),
-        );
+        ));
 
         // prettify avg_time_on_page column
         $getPrettyTimeFromSeconds = '\Piwik\MetricsFormatter::getPrettyTimeFromSeconds';
-        $result['filters'][] = array('ColumnCallbackReplace', array('avg_time_on_page', $getPrettyTimeFromSeconds));
+        $view->config->filters[] = array('ColumnCallbackReplace', array('avg_time_on_page', $getPrettyTimeFromSeconds));
 
         // prettify avg_time_generation column
         $avgTimeCallback = function ($time) {
             return $time ? MetricsFormatter::getPrettyTimeFromSeconds($time, true, true, false) : "-";
         };
-        $result['filters'][] = array('ColumnCallbackReplace', array('avg_time_generation', $avgTimeCallback));
+        $view->config->filters[] = array('ColumnCallbackReplace', array('avg_time_generation', $avgTimeCallback));
 
         // add avg_generation_time tooltip
         $tooltipCallback = function ($hits, $min, $max) {
@@ -758,7 +801,7 @@ class Actions extends \Piwik\Plugin
                                                                             MetricsFormatter::getPrettyTimeFromSeconds($max)
                                                                        ));
         };
-        $result['filters'][] = array('ColumnCallbackAddMetadata',
+        $view->config->filters[] = array('ColumnCallbackAddMetadata',
                                      array(
                                          array('nb_hits_with_time_generation', 'min_time_generation', 'max_time_generation'),
                                          'avg_time_generation_tooltip',
@@ -766,135 +809,117 @@ class Actions extends \Piwik\Plugin
                                      )
         );
 
-        $this->addExcludeLowPopDisplayProperties($result);
+        $this->addExcludeLowPopDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForPageUrls()
+    public function configureViewForPageUrls(ViewDataTable $view)
     {
-        $result = array(
-            'translations'       => array('label' => Piwik::translate('Actions_ColumnPageURL')),
-            'columns_to_display' => array('label', 'nb_hits', 'nb_visits', 'bounce_rate',
-                                          'avg_time_on_page', 'exit_rate', 'avg_time_generation'),
-        );
+        $view->config->addTranslation('label', Piwik::translate('Actions_ColumnPageURL'));
+        $view->config->columns_to_display = array('label', 'nb_hits', 'nb_visits', 'bounce_rate',
+                                                  'avg_time_on_page', 'exit_rate', 'avg_time_generation');
 
-        $this->addPageDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
-
-        return $result;
+        $this->addPageDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForEntryPageUrls()
+    public function configureViewForEntryPageUrls(ViewDataTable $view)
     {
         // link to the page, not just the report, but only if not a widget
-        $widget = Common::getRequestVar('widget', false);
-        $reportUrl = Request::getCurrentUrlWithoutGenericFilters(array(
-                                                                      'module' => 'Actions',
-                                                                      'action' => $widget === false ? 'indexEntryPageUrls' : 'getEntryPageUrls'
-                                                                 ));
-
-        $result = array(
-            'translations'       => array('label'              => Piwik::translate('Actions_ColumnEntryPageURL'),
-                                          'entry_bounce_count' => Piwik::translate('General_ColumnBounces'),
-                                          'entry_nb_visits'    => Piwik::translate('General_ColumnEntrances')),
-            'columns_to_display' => array('label', 'entry_nb_visits', 'entry_bounce_count', 'bounce_rate'),
-            'filter_sort_column' => 'entry_nb_visits',
-            'filter_sort_order'  => 'desc',
-            'title'              => Piwik::translate('Actions_SubmenuPagesEntry'),
-            'related_reports'    => array(
-                'Actions.getEntryPageTitles' => Piwik::translate('Actions_EntryPageTitles')
-            ),
-            'self_url'           => $reportUrl
+        $widget    = Common::getRequestVar('widget', false);
+
+        $view->config->self_url = Request::getCurrentUrlWithoutGenericFilters(array(
+            'module' => 'Actions',
+            'action' => $widget === false ? 'indexEntryPageUrls' : 'getEntryPageUrls'
+        ));
+
+        $view->config->addTranslations(array(
+            'label'              => Piwik::translate('Actions_ColumnEntryPageURL'),
+            'entry_bounce_count' => Piwik::translate('General_ColumnBounces'),
+            'entry_nb_visits'    => Piwik::translate('General_ColumnEntrances'))
         );
 
-        $this->addPageDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
+        $view->config->title = Piwik::translate('Actions_SubmenuPagesEntry');
+        $view->config->addRelatedReport('Actions.getEntryPageTitles', Piwik::translate('Actions_EntryPageTitles'));
+        $view->config->columns_to_display = array('label', 'entry_nb_visits', 'entry_bounce_count', 'bounce_rate');
+        $view->requestConfig->filter_sort_column = 'entry_nb_visits';
+        $view->requestConfig->filter_sort_order  = 'desc';
 
-        return $result;
+        $this->addPageDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForExitPageUrls()
+    public function configureViewForExitPageUrls(ViewDataTable $view)
     {
         // link to the page, not just the report, but only if not a widget
-        $widget = Common::getRequestVar('widget', false);
-        $reportUrl = Request::getCurrentUrlWithoutGenericFilters(array(
-                                                                      'module' => 'Actions',
-                                                                      'action' => $widget === false ? 'indexExitPageUrls' : 'getExitPageUrls'
-                                                                 ));
-
-        $result = array(
-            'translations'       => array('label'          => Piwik::translate('Actions_ColumnExitPageURL'),
-                                          'exit_nb_visits' => Piwik::translate('General_ColumnExits')),
-            'columns_to_display' => array('label', 'exit_nb_visits', 'nb_visits', 'exit_rate'),
-            'filter_sort_column' => 'exit_nb_visits',
-            'filter_sort_order'  => 'desc',
-            'title'              => Piwik::translate('Actions_SubmenuPagesExit'),
-            'related_reports'    => array(
-                'Actions.getExitPageTitles' => Piwik::translate('Actions_ExitPageTitles')
-            ),
-            'self_url'           => $reportUrl,
+        $widget    = Common::getRequestVar('widget', false);
+
+        $view->config->self_url = Request::getCurrentUrlWithoutGenericFilters(array(
+            'module' => 'Actions',
+            'action' => $widget === false ? 'indexExitPageUrls' : 'getExitPageUrls'
+        ));
+
+        $view->config->addTranslations(array(
+                'label'          => Piwik::translate('Actions_ColumnExitPageURL'),
+                'exit_nb_visits' => Piwik::translate('General_ColumnExits'))
         );
 
-        $this->addPageDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
+        $view->config->title = Piwik::translate('Actions_SubmenuPagesExit');
+        $view->config->addRelatedReport('Actions.getExitPageTitles', Piwik::translate('Actions_ExitPageTitles'));
 
-        return $result;
+        $view->config->columns_to_display        = array('label', 'exit_nb_visits', 'nb_visits', 'exit_rate');
+        $view->requestConfig->filter_sort_column = 'exit_nb_visits';
+        $view->requestConfig->filter_sort_order  = 'desc';
+
+        $this->addPageDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    private function addSiteSearchDisplayProperties(&$result)
+    private function addSiteSearchDisplayProperties(ViewDataTable $view)
     {
-        $result['translations'] += array(
+        $view->config->addTranslations(array(
             'nb_visits'           => Piwik::translate('Actions_ColumnSearches'),
             'exit_rate'           => str_replace("% ", "%&nbsp;", Piwik::translate('Actions_ColumnSearchExits')),
             'nb_pages_per_search' => Piwik::translate('Actions_ColumnPagesPerSearch')
-        );
-        $result['show_bar_chart'] = false;
-        $result['show_table_all_columns'] = false;
+        ));
+
+        $view->config->show_bar_chart         = false;
+        $view->config->show_table_all_columns = false;
     }
 
-    public function getDisplayPropertiesForSiteSearchKeywords()
+    public function configureViewForSiteSearchKeywords(ViewDataTable $view)
     {
-        $result = array(
-            'translations'       => array('label' => Piwik::translate('General_ColumnKeyword')),
-            'columns_to_display' => array('label', 'nb_visits', 'nb_pages_per_search', 'exit_rate'),
-        );
+        $view->config->addTranslation('label', Piwik::translate('General_ColumnKeyword'));
+        $view->config->columns_to_display = array('label', 'nb_visits', 'nb_pages_per_search', 'exit_rate');
 
-        $this->addSiteSearchDisplayProperties($result);
-
-        return $result;
+        $this->addSiteSearchDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForSiteSearchNoResultKeywords()
+    public function configureViewForSiteSearchNoResultKeywords(ViewDataTable $view)
     {
-        $result = array(
-            'translations'       => array('label', Piwik::translate('Actions_ColumnNoResultKeyword')),
-            'columns_to_display' => array('label', 'nb_visits', 'exit_rate')
-        );
-
-        $this->addSiteSearchDisplayProperties($result);
+        $view->config->addTranslation('label', Piwik::translate('Actions_ColumnNoResultKeyword'));
+        $view->config->columns_to_display = array('label', 'nb_visits', 'exit_rate');
 
-        return $result;
+        $this->addSiteSearchDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForSiteSearchCategories()
+    public function configureViewForSiteSearchCategories(ViewDataTable $view)
     {
-        return array(
-            'translations'             => array(
-                'label'               => Piwik::translate('Actions_ColumnSearchCategory'),
-                'nb_visits'           => Piwik::translate('Actions_ColumnSearches'),
-                'nb_pages_per_search' => Piwik::translate('Actions_ColumnPagesPerSearch')
-            ),
-            'columns_to_display'       => array('label', 'nb_visits', 'nb_pages_per_search'),
-            'show_table_all_columns'   => false,
-            'show_bar_chart'           => false,
-            'visualization_properties' => array(
-                'table' => array(
-                    'disable_row_evolution' => false,
-                )
-            )
-        );
+        $view->config->addTranslations(array(
+            'label'               => Piwik::translate('Actions_ColumnSearchCategory'),
+            'nb_visits'           => Piwik::translate('Actions_ColumnSearches'),
+            'nb_pages_per_search' => Piwik::translate('Actions_ColumnPagesPerSearch')
+        ));
+
+        $view->config->columns_to_display     = array('label', 'nb_visits', 'nb_pages_per_search');
+        $view->config->show_table_all_columns = false;
+        $view->config->show_bar_chart         = false;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_row_evolution = false;
+        }
     }
 
-    public function getDisplayPropertiesForGetPageUrlsOrTitlesFollowingSiteSearch($isTitle)
+    public function configureViewForGetPageUrlsOrTitlesFollowingSiteSearch(ViewDataTable $view, $isTitle)
     {
         $title = $isTitle ? Piwik::translate('Actions_WidgetPageTitlesFollowingSearch')
             : Piwik::translate('Actions_WidgetPageUrlsFollowingSearch');
@@ -904,135 +929,118 @@ class Actions extends \Piwik\Plugin
             'Actions.getPageUrlsFollowingSiteSearch'   => Piwik::translate('Actions_WidgetPageUrlsFollowingSearch'),
         );
 
-        $result = array(
-            'translations'                => array(
-                'label'                    => Piwik::translate('General_ColumnDestinationPage'),
-                'nb_hits_following_search' => Piwik::translate('General_ColumnViewedAfterSearch'),
-                'nb_hits'                  => Piwik::translate('General_ColumnTotalPageviews')
-            ),
-            'columns_to_display'          => array('label', 'nb_hits_following_search', 'nb_hits'),
-            'filter_sort_column'          => 'nb_hits_following_search',
-            'filter_sort_order'           => 'desc',
-            'show_exclude_low_population' => false,
-            'title'                       => $title,
-            'related_reports'             => $relatedReports
-        );
-
-        $this->addExcludeLowPopDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
-
-        return $result;
+        $view->config->addRelatedReports($relatedReports);
+        $view->config->addTranslations(array(
+            'label'                    => Piwik::translate('General_ColumnDestinationPage'),
+            'nb_hits_following_search' => Piwik::translate('General_ColumnViewedAfterSearch'),
+            'nb_hits'                  => Piwik::translate('General_ColumnTotalPageviews')
+        ));
+
+        $view->config->title = $title;
+        $view->config->columns_to_display          = array('label', 'nb_hits_following_search', 'nb_hits');
+        $view->config->show_exclude_low_population = false;
+        $view->requestConfig->filter_sort_column = 'nb_hits_following_search';
+        $view->requestConfig->filter_sort_order  = 'desc';
+
+        $this->addExcludeLowPopDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForGetPageTitles()
+    public function configureViewForGetPageTitles(ViewDataTable $view)
     {
         // link to the page, not just the report, but only if not a widget
         $widget = Common::getRequestVar('widget', false);
-        $reportUrl = Request::getCurrentUrlWithoutGenericFilters(array(
-                                                                      'module' => 'Actions',
-                                                                      'action' => $widget === false ? 'indexPageTitles' : 'getPageTitles'
-                                                                 ));
-
-        $result = array(
-            'translations'       => array('label' => Piwik::translate('Actions_ColumnPageName')),
-            'columns_to_display' => array('label', 'nb_hits', 'nb_visits', 'bounce_rate',
-                                          'avg_time_on_page', 'exit_rate', 'avg_time_generation'),
-            'title'              => Piwik::translate('Actions_SubmenuPageTitles'),
-            'related_reports'    => array(
-                'Actions.getEntryPageTitles' => Piwik::translate('Actions_EntryPageTitles'),
-                'Actions.getExitPageTitles'  => Piwik::translate('Actions_ExitPageTitles'),
-            ),
-            'self_url'           => $reportUrl
-        );
 
-        $this->addPageDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
+        $view->config->self_url = Request::getCurrentUrlWithoutGenericFilters(array(
+            'module' => 'Actions',
+            'action' => $widget === false ? 'indexPageTitles' : 'getPageTitles'
+        ));
+
+        $view->config->title = Piwik::translate('Actions_SubmenuPageTitles');
+        $view->config->addRelatedReports(array(
+            'Actions.getEntryPageTitles' => Piwik::translate('Actions_EntryPageTitles'),
+            'Actions.getExitPageTitles'  => Piwik::translate('Actions_ExitPageTitles'),
+        ));
 
-        return $result;
+        $view->config->addTranslation('label', Piwik::translate('Actions_ColumnPageName'));
+        $view->config->columns_to_display = array('label', 'nb_hits', 'nb_visits', 'bounce_rate',
+                                                  'avg_time_on_page', 'exit_rate', 'avg_time_generation');
+
+        $this->addPageDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForGetEntryPageTitles()
+    public function configureViewForGetEntryPageTitles(ViewDataTable $view)
     {
         $entryPageUrlAction =
             Common::getRequestVar('widget', false) === false ? 'indexEntryPageUrls' : 'getEntryPageUrls';
 
-        $result = array(
-            'translations'       => array(
-                'label'              => Piwik::translate('Actions_ColumnEntryPageTitle'),
-                'entry_bounce_count' => Piwik::translate('General_ColumnBounces'),
-                'entry_nb_visits'    => Piwik::translate('General_ColumnEntrances'),
-            ),
-            'columns_to_display' => array('label', 'entry_nb_visits', 'entry_bounce_count', 'bounce_rate'),
-            'title'              => Piwik::translate('Actions_EntryPageTitles'),
-            'related_reports'    => array(
-                'Actions.getPageTitles'       => Piwik::translate('Actions_SubmenuPageTitles'),
-                "Actions.$entryPageUrlAction" => Piwik::translate('Actions_SubmenuPagesEntry')
-            ),
-            'filter_sort_column' => 'entry_nb_visits'
-        );
+        $view->config->addTranslations(array(
+            'label'              => Piwik::translate('Actions_ColumnEntryPageTitle'),
+            'entry_bounce_count' => Piwik::translate('General_ColumnBounces'),
+            'entry_nb_visits'    => Piwik::translate('General_ColumnEntrances'),
+        ));
+        $view->config->addRelatedReports(array(
+            'Actions.getPageTitles'       => Piwik::translate('Actions_SubmenuPageTitles'),
+            "Actions.$entryPageUrlAction" => Piwik::translate('Actions_SubmenuPagesEntry')
+        ));
+
+        $view->config->columns_to_display = array('label', 'entry_nb_visits', 'entry_bounce_count', 'bounce_rate');
+        $view->config->title = Piwik::translate('Actions_EntryPageTitles');
 
-        $this->addPageDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
+        $view->requestConfig->filter_sort_column = 'entry_nb_visits';
 
-        return $result;
+        $this->addPageDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForGetExitPageTitles()
+    public function configureViewForGetExitPageTitles(ViewDataTable $view)
     {
         $exitPageUrlAction =
             Common::getRequestVar('widget', false) === false ? 'indexExitPageUrls' : 'getExitPageUrls';
 
-        $result = array(
-            'translations'       => array(
-                'label'          => Piwik::translate('Actions_ColumnExitPageTitle'),
-                'exit_nb_visits' => Piwik::translate('General_ColumnExits'),
-            ),
-            'columns_to_display' => array('label', 'exit_nb_visits', 'nb_visits', 'exit_rate'),
-            'title'              => Piwik::translate('Actions_ExitPageTitles'),
-            'related_reports'    => array(
-                'Actions.getPageTitles'      => Piwik::translate('Actions_SubmenuPageTitles'),
-                "Actions.$exitPageUrlAction" => Piwik::translate('Actions_SubmenuPagesExit'),
-            ),
-        );
+        $view->config->addTranslations(array(
+            'label'          => Piwik::translate('Actions_ColumnExitPageTitle'),
+            'exit_nb_visits' => Piwik::translate('General_ColumnExits'),
+        ));
+        $view->config->addRelatedReports(array(
+            'Actions.getPageTitles'      => Piwik::translate('Actions_SubmenuPageTitles'),
+            "Actions.$exitPageUrlAction" => Piwik::translate('Actions_SubmenuPagesExit'),
+        ));
 
-        $this->addPageDisplayProperties($result);
-        $this->addBaseDisplayProperties($result);
+        $view->config->title = Piwik::translate('Actions_ExitPageTitles');
+        $view->config->columns_to_display = array('label', 'exit_nb_visits', 'nb_visits', 'exit_rate');
 
-        return $result;
+        $this->addPageDisplayProperties($view);
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForGetDownloads()
+    public function configureViewForGetDownloads(ViewDataTable $view)
     {
-        $result = array(
-            'translations'                => array(
-                'label'     => Piwik::translate('Actions_ColumnDownloadURL'),
-                'nb_visits' => Piwik::translate('Actions_ColumnUniqueDownloads'),
-                'nb_hits'   => Piwik::translate('General_Downloads'),
-            ),
-            'columns_to_display'          => array('label', 'nb_visits', 'nb_hits'),
-            'show_exclude_low_population' => false
-        );
+        $view->config->addTranslations(array(
+            'label'     => Piwik::translate('Actions_ColumnDownloadURL'),
+            'nb_visits' => Piwik::translate('Actions_ColumnUniqueDownloads'),
+            'nb_hits'   => Piwik::translate('General_Downloads'),
+        ));
 
-        $this->addBaseDisplayProperties($result);
+        $view->config->columns_to_display = array('label', 'nb_visits', 'nb_hits');
+        $view->config->show_exclude_low_population = false;
 
-        return $result;
+        $this->addBaseDisplayProperties($view);
     }
 
-    public function getDisplayPropertiesForGetOutlinks()
+    public function configureViewForGetOutlinks(ViewDataTable $view)
     {
-        $result = array(
-            'translations'                => array(
-                'label'     => Piwik::translate('Actions_ColumnClickedURL'),
-                'nb_visits' => Piwik::translate('Actions_ColumnUniqueClicks'),
-                'nb_hits'   => Piwik::translate('Actions_ColumnClicks'),
-            ),
-            'columns_to_display'          => array('label', 'nb_visits', 'nb_hits'),
-            'show_exclude_low_population' => false
-        );
+        $view->config->addTranslations(array(
+            'label'     => Piwik::translate('Actions_ColumnClickedURL'),
+            'nb_visits' => Piwik::translate('Actions_ColumnUniqueClicks'),
+            'nb_hits'   => Piwik::translate('Actions_ColumnClicks'),
+        ));
 
-        $this->addBaseDisplayProperties($result);
+        $view->config->columns_to_display          = array('label', 'nb_visits', 'nb_hits');
+        $view->config->show_exclude_low_population = false;
 
-        return $result;
+        $this->addBaseDisplayProperties($view);
     }
 }
 
diff --git a/plugins/CoreHome/DataTableRowAction/RowEvolution.php b/plugins/CoreHome/DataTableRowAction/RowEvolution.php
index f7a730e56d83ce18edce36b4a84ebe303198104e..11039ca5a7b2c7984ce96b78c8b1542cce762641 100644
--- a/plugins/CoreHome/DataTableRowAction/RowEvolution.php
+++ b/plugins/CoreHome/DataTableRowAction/RowEvolution.php
@@ -194,22 +194,22 @@ class RowEvolution
         $view->setDataTable($this->dataTable);
 
         if (!empty($this->graphMetrics)) { // In row Evolution popover, this is empty
-            $view->columns_to_display = array_keys($metrics ? : $this->graphMetrics);
+            $view->config->columns_to_display = array_keys($metrics ? : $this->graphMetrics);
         }
 
-        $view->show_goals = false;
-        $view->show_all_views_icons = false;
-        $view->show_active_view_icon = false;
-        $view->show_related_reports = false;
-        $view->show_footer_message = false;
-        $view->visualization_properties->show_series_picker = false;
+        $view->config->show_goals = false;
+        $view->config->show_all_views_icons  = false;
+        $view->config->show_active_view_icon = false;
+        $view->config->show_related_reports  = false;
+        $view->config->show_series_picker    = false;
+        $view->config->show_footer_message   = false;
 
         foreach ($this->availableMetrics as $metric => $metadata) {
-            $view->translations[$metric] = $metadata['name'];
+            $view->config->translations[$metric] = $metadata['name'];
         }
 
-        $view->visualization_properties->external_series_toggle = 'RowEvolutionSeriesToggle';
-        $view->visualization_properties->external_series_toggle_show_all = $this->initiallyShowAllMetrics;
+        $view->config->external_series_toggle = 'RowEvolutionSeriesToggle';
+        $view->config->external_series_toggle_show_all = $this->initiallyShowAllMetrics;
 
         return $view;
     }
diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js
index 4dc2e59cee55c2b357ff9313cbc981dc6add2d4f..e570bc976c8a5168192bef27022fda906ad25089 100644
--- a/plugins/CoreHome/javascripts/dataTable.js
+++ b/plugins/CoreHome/javascripts/dataTable.js
@@ -504,7 +504,7 @@ $.extend(DataTable.prototype, UIControl.prototype, {
                 var totalRows = Number(self.param.totalRows);
                 var offsetEndDisp = offsetEnd;
 
-                if (self.props.keep_summary_row == 1) --totalRows;
+                if (self.param.keep_summary_row == 1) --totalRows;
 
                 if (offsetEnd > totalRows) offsetEndDisp = totalRows;
 
@@ -522,7 +522,7 @@ $.extend(DataTable.prototype, UIControl.prototype, {
                 var offsetEnd = Number(self.param.filter_offset)
                     + Number(self.param.filter_limit);
                 var totalRows = Number(self.param.totalRows);
-                if (self.props.keep_summary_row == 1) --totalRows;
+                if (self.param.keep_summary_row == 1) --totalRows;
                 if (offsetEnd < totalRows) {
                     $(this).css('display', 'inline');
                 }
diff --git a/plugins/CoreHome/templates/_dataTable.twig b/plugins/CoreHome/templates/_dataTable.twig
index 56a4564d042910877bf49cb69e46d9478a4d22d3..54ed0b757bbb2fa743b4bd97dcdae58515d2fd8f 100644
--- a/plugins/CoreHome/templates/_dataTable.twig
+++ b/plugins/CoreHome/templates/_dataTable.twig
@@ -1,5 +1,5 @@
 {% if properties.show_visualization_only %}
-    {% include visualization.getTemplateFile() with visualization.getTemplateVars() %}
+    {% include visualizationTemplate %}
 {%- else -%}
 
 {% set summaryRowId = constant('Piwik\\DataTable::ID_SUMMARY_ROW') %}{# ID_SUMMARY_ROW #}
@@ -11,7 +11,7 @@
      data-params="{% if clientSideParameters is empty %}{}{% else %}{{ clientSideParameters|json_encode }}{% endif %}">
     <div class="reportDocumentation">
         {% if properties.documentation|default is not empty %}<p>{{ properties.documentation|raw }}</p>{% endif %}
-        {% if properties.metadata.archived_date is defined %}<span class='helpDate'>{{ properties.metadata.archived_date }}</span>{% endif %}
+        {% if properties.report_last_updated_message is defined %}<span class='helpDate'>{{ properties.report_last_updated_message }}</span>{% endif %}
     </div>
     <div class="dataTableWrapper">
         {% if error is defined %}
@@ -26,7 +26,7 @@
                 {% endif %}
                 </div>
             {% else %}
-                {% include visualization.getTemplateFile() with visualization.getTemplateVars() %}
+                {% include visualizationTemplate %}
             {% endif %}
 
             {% if properties.show_footer %}
diff --git a/plugins/CorePluginsAdmin/Controller.php b/plugins/CorePluginsAdmin/Controller.php
index 6b12dbec523fc953e5fc494f8517493411a1fc73..33a97d27b092b9ad241fa8ccbb0541a92ed82d34 100644
--- a/plugins/CorePluginsAdmin/Controller.php
+++ b/plugins/CorePluginsAdmin/Controller.php
@@ -192,7 +192,7 @@ class Controller extends Plugin\ControllerAdmin
     {
         Piwik::checkUserIsSuperUser();
 
-        $activated = Common::getRequestVar('activated', false, 'integer', $_GET);
+        $activated  = Common::getRequestVar('activated', false, 'integer', $_GET);
         $pluginName = Common::getRequestVar('pluginName', '', 'string');
 
         $view = $this->configureView('@CorePluginsAdmin/' . $template);
diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php
index 06db725f513fbb36660916c6b29aa7b25ea2b165..bab6c3f6d6f8c97d544b74b5470d8bc9601f25d8 100644
--- a/plugins/CoreVisualizations/CoreVisualizations.php
+++ b/plugins/CoreVisualizations/CoreVisualizations.php
@@ -37,9 +37,9 @@ class CoreVisualizations extends \Piwik\Plugin
 
     public function getAvailableDataTableVisualizations(&$visualizations)
     {
+        $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\Sparkline';
         $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable';
         $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable\\AllColumns';
-        $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable\\Goals';
         $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\Cloud';
         $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Pie';
         $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Bar';
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator.php b/plugins/CoreVisualizations/JqplotDataGenerator.php
index cc6022f83c7df32c789ca81f4e9d16afdd678f1c..fdc23c93c58ae1e6f3dabafb124c781a57a72ac6 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator.php
@@ -86,7 +86,7 @@ class JqplotDataGenerator
         if ($dataTable->getRowsCount() > 0) {
             // if addTotalRow was called in GenerateGraphHTML, add a row containing totals of
             // different metrics
-            if ($this->properties['visualization_properties']->add_total_row) {
+            if ($this->properties['add_total_row']) {
                 $dataTable->queueFilter('AddSummaryRow', array(0, Piwik::translate('General_Total'), null, false));
             }
 
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php b/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php
index 0f1361b83af99181177eab7460c80c7ce61f2c2d..51ab4e017dd65ccf93e7a803f04e1cfba1326690 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php
@@ -29,8 +29,8 @@ class Chart
 
     public function setAxisXLabels($xLabels)
     {
-        $xSteps = $this->properties['visualization_properties']->x_axis_step_size;
-        $showAllTicks = $this->properties['visualization_properties']->show_all_ticks;
+        $xSteps = $this->properties['x_axis_step_size'];
+        $showAllTicks = $this->properties['show_all_ticks'];
 
         $this->axes['xaxis']['labels'] = array_values($xLabels);
 
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
index 8fbf5e7e783afd3df81e07ddbe110afe06ff373a..7ef36c902fd5cde58db73958458bdd8e975adabb 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
@@ -47,7 +47,7 @@ class Evolution extends JqplotDataGenerator
         $units = $this->getUnitsForColumnsToDisplay();
 
         // if rows to display are not specified, default to all rows (TODO: perhaps this should be done elsewhere?)
-        $rowsToDisplay = $this->properties['visualization_properties']->rows_to_display
+        $rowsToDisplay = $this->properties['rows_to_display']
             ? : array_unique($dataTable->getColumn('label'))
                 ? : array(false) // make sure that a series is plotted even if there is no data
         ;
diff --git a/plugins/CoreVisualizations/Visualizations/Cloud.php b/plugins/CoreVisualizations/Visualizations/Cloud.php
index 8785ee6f1d230a208be68eddfffc7a19779660b9..8e23f5f7bcd8205256b5efe7f9adac827549f278 100644
--- a/plugins/CoreVisualizations/Visualizations/Cloud.php
+++ b/plugins/CoreVisualizations/Visualizations/Cloud.php
@@ -12,12 +12,10 @@ namespace Piwik\Plugins\CoreVisualizations\Visualizations;
 
 use Piwik\Common;
 use Piwik\DataTable;
-use Piwik\DataTable\DataTableInterface;
 use Piwik\Log;
 use Piwik\View;
-use Piwik\ViewDataTable\Visualization;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
+use Piwik\Plugin\Visualization;
+use Piwik\ViewDataTable\Config;
 
 /**
  * Generates a tag cloud from a given data array.
@@ -25,6 +23,8 @@ use Piwik\Visualization\Request;
  *
  * Inspired from Derek Harvey (www.derekharvey.co.uk)
  *
+ * @property Cloud\Config $config
+ *
  * @package Piwik
  * @subpackage Piwik_Visualization
  */
@@ -33,34 +33,36 @@ class Cloud extends Visualization
     const ID = 'cloud';
     const TEMPLATE_FILE = "@CoreVisualizations/_dataTableViz_tagCloud.twig";
 
-    /**
-     * Whether to display the logo assocatied with a DataTable row (stored as 'logo' row metadata)
-     * instead of the label in Tag Clouds.
-     *
-     * Default value: false
-     */
-    const DISPLAY_LOGO_INSTEAD_OF_LABEL = 'display_logo_instead_of_label';
-
     /** Used by integration tests to make sure output is consistent. */
     public static $debugDisableShuffle = false;
-
-    public static $overridableProperties = array('display_logo_instead_of_label');
+    public $truncatingLimit = 50;
 
     protected $wordsArray = array();
-    public $truncatingLimit = 50;
 
-    public function afterAllFilteresAreApplied(DataTableInterface $dataTable, Config $properties, Request $request)
+    public static function getDefaultConfig()
+    {
+        return new Cloud\Config();
+    }
+
+    public function beforeRender()
     {
-        if ($dataTable->getRowsCount() == 0) {
+        $this->config->show_exclude_low_population = false;
+        $this->config->show_offset_information     = false;
+        $this->config->show_limit_control          = false;
+    }
+
+    public function afterAllFilteresAreApplied()
+    {
+        if ($this->dataTable->getRowsCount() == 0) {
             return;
         }
 
-        $columnToDisplay = isset($properties->columns_to_display[1]) ? $properties->columns_to_display[1] : 'nb_visits';
+        $columnToDisplay = isset($this->config->columns_to_display[1]) ? $this->config->columns_to_display[1] : 'nb_visits';
+        $labelMetadata   = array();
 
-        $labelMetadata = array();
-        foreach ($dataTable->getRows() as $row) {
+        foreach ($this->dataTable->getRows() as $row) {
             $logo = false;
-            if ($properties->visualization_properties->display_logo_instead_of_label) {
+            if ($this->config->display_logo_instead_of_label) {
                 $logo = $row->getMetadata('logo');
             }
 
@@ -73,31 +75,14 @@ class Cloud extends Visualization
 
             $this->addWord($label, $row->getColumn($columnToDisplay));
         }
+
         $cloudValues = $this->getCloudValues();
         foreach ($cloudValues as &$value) {
             $value['logoWidth'] = round(max(16, $value['percent']));
         }
 
-        $this->labelMetadata = $labelMetadata;
-        $this->cloudValues   = $cloudValues;
-    }
-
-    public function configureVisualization(Config $properties)
-    {
-        $properties->show_exclude_low_population = false;
-        $properties->show_offset_information     = false;
-        $properties->show_limit_control          = false;
-    }
-
-    public static function getDefaultPropertyValues()
-    {
-        return array(
-            'visualization_properties'    => array(
-                'cloud' => array(
-                    'display_logo_instead_of_label' => false,
-                )
-            )
-        );
+        $this->assignTemplateVar('labelMetadata', $labelMetadata);
+        $this->assignTemplateVar('cloudValues', $cloudValues);
     }
 
     /**
@@ -118,25 +103,19 @@ class Cloud extends Visualization
     public function getCloudValues()
     {
         $this->shuffleCloud();
-        $return = array();
+
         if (empty($this->wordsArray)) {
             return array();
         }
+
+        $return   = array();
         $maxValue = max($this->wordsArray);
+
         foreach ($this->wordsArray as $word => $popularity) {
-            $wordTruncated = $word;
-            if (Common::mb_strlen($word) > $this->truncatingLimit) {
-                $wordTruncated = Common::mb_substr($word, 0, $this->truncatingLimit - 3) . '...';
-            }
 
-            // case hideFutureHoursWhenToday=1 shows hours with no visits
-            if ($maxValue == 0) {
-                $percent = 0;
-            } else {
-                $percent = ($popularity / $maxValue) * 100;
-            }
-            // CSS style value
-            $sizeRange = $this->getClassFromPercent($percent);
+            $wordTruncated = $this->truncateWordIfNeeded($word);
+            $percent       = $this->getPercentage($popularity, $maxValue);
+            $sizeRange     = $this->getClassFromPercent($percent);
 
             $return[$word] = array(
                 'word'          => $word,
@@ -146,6 +125,7 @@ class Cloud extends Visualization
                 'percent'       => $percent,
             );
         }
+
         return $return;
     }
 
@@ -163,10 +143,14 @@ class Cloud extends Visualization
         shuffle($keys);
 
         if (count($keys) && is_array($keys)) {
+
             $tmpArray = $this->wordsArray;
+
             $this->wordsArray = array();
-            foreach ($keys as $key => $value)
+            foreach ($keys as $key => $value) {
                 $this->wordsArray[$value] = $tmpArray[$value];
+            }
+
         }
     }
 
@@ -187,4 +171,29 @@ class Cloud extends Visualization
         }
         return 0;
     }
+
+    /**
+     * @param $word
+     * @return string
+     */
+    private function truncateWordIfNeeded($word)
+    {
+        if (Common::mb_strlen($word) > $this->truncatingLimit) {
+            return Common::mb_substr($word, 0, $this->truncatingLimit - 3) . '...';
+        }
+
+        return $word;
+    }
+
+    private function getPercentage($popularity, $maxValue)
+    {
+        // case hideFutureHoursWhenToday=1 shows hours with no visits
+        if ($maxValue == 0) {
+            return 0;
+        }
+
+        $percent = ($popularity / $maxValue) * 100;
+
+        return $percent;
+    }
 }
diff --git a/plugins/CoreVisualizations/Visualizations/Cloud/Config.php b/plugins/CoreVisualizations/Visualizations/Cloud/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..eda61f937d0f409ea6a18a696d232d9eb1227362
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/Cloud/Config.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package CoreVisualizations
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
+
+use Piwik\ViewDataTable\Config as VisualizationConfig;
+
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class Config extends VisualizationConfig
+{
+
+    /**
+     * Whether to display the logo assocatied with a DataTable row (stored as 'logo' row metadata)
+     * instead of the label in Tag Clouds.
+     *
+     * Default value: false
+     */
+    public $display_logo_instead_of_label = false;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->addPropertiesThatCanBeOverwrittenByQueryParams(array('display_logo_instead_of_label'));
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/Graph.php b/plugins/CoreVisualizations/Visualizations/Graph.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d6a47b323eed756a35fb586f16dc75742fce820
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/Graph.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
+namespace Piwik\Plugins\CoreVisualizations\Visualizations;
+
+use Piwik\DataTable\Row;
+use Piwik\DataTable;
+use Piwik\Piwik;
+use Piwik\Plugin\Visualization;
+
+/**
+ * This is an abstract visualization that should be the base of any 'graph' visualization.
+ * This class defines certain visualization properties that are specific to all graph types.
+ * Derived visualizations can decide for themselves whether they should support individual
+ * properties.
+ *
+ * @property Graph\Config $config
+ */
+abstract class Graph extends Visualization
+{
+    const ID = 'graph';
+
+    public $selectableRows = array();
+
+    public static function getDefaultConfig()
+    {
+        return new Graph\Config();
+    }
+
+    public static function getDefaultRequestConfig()
+    {
+        $config = parent::getDefaultRequestConfig();
+        $config->addPropertiesThatShouldBeAvailableClientSide(array('columns'));
+
+        return $config;
+    }
+
+    public function beforeRender()
+    {
+        if ($this->config->show_goals) {
+            $this->config->translations['nb_conversions'] = Piwik::translate('Goals_ColumnConversions');
+            $this->config->translations['revenue'] = Piwik::translate('General_TotalRevenue');
+        }
+    }
+
+    public function beforeLoadDataTable()
+    {
+        // TODO: this should not be required here. filter_limit should not be a view property, instead HtmlTable should use 'limit' or something,
+        //       and manually set request_parameters_to_modify['filter_limit'] based on that. (same for filter_offset).
+        $this->requestConfig->request_parameters_to_modify['filter_limit'] = false;
+
+        if ($this->config->max_graph_elements) {
+            $this->requestConfig->request_parameters_to_modify['filter_truncate'] = $this->config->max_graph_elements - 1;
+        }
+    }
+
+    /**
+     * Determines what rows are selectable and stores them in the selectable_rows property in
+     * a format the SeriesPicker JavaScript class can use.
+     */
+    public function beforeGenericFiltersAreAppliedToLoadedDataTable()
+    {
+        if ($this->config->row_picker_match_rows_by === false) {
+            return;
+        }
+
+        // collect all selectable rows
+        $self = $this;
+
+        $this->dataTable->filter(function ($dataTable) use ($self) {
+            /** @var DataTable $dataTable */
+
+            foreach ($dataTable->getRows() as $row) {
+                $rowLabel = $row->getColumn('label');
+
+                if (false === $rowLabel) {
+                    continue;
+                }
+
+                // determine whether row is visible
+                $isVisible = true;
+                if ('label' == $self->config->row_picker_match_rows_by) {
+                    $isVisible = in_array($rowLabel, $self->config->rows_to_display);
+                }
+
+                // build config
+                if (!isset($self->selectableRows[$rowLabel])) {
+                    $self->selectableRows[$rowLabel] = array(
+                        'label'     => $rowLabel,
+                        'matcher'   => $rowLabel,
+                        'displayed' => $isVisible
+                    );
+                }
+            }
+        });
+    }
+
+    /**
+     * Defaults the selectable_columns property if it has not been set and then transforms
+     * it into something the SeriesPicker JavaScript class can use.
+     */
+    public function afterAllFilteresAreApplied()
+    {
+        $this->config->selectable_rows = array_values($this->selectableRows);
+
+        $selectableColumns = $this->config->selectable_columns;
+
+        // set default selectable columns, if none specified
+        if (false === $selectableColumns) {
+            $selectableColumns = array('nb_visits', 'nb_actions');
+
+            if (in_array('nb_uniq_visitors', $this->dataTable->getColumns())) {
+                $selectableColumns[] = 'nb_uniq_visitors';
+            }
+        }
+
+        if ($this->config->show_goals) {
+            $goalMetrics       = array('nb_conversions', 'revenue');
+            $selectableColumns = array_merge($selectableColumns, $goalMetrics);
+        }
+
+        $transformed = array();
+        foreach ($selectableColumns as $column) {
+            $transformed[] = array(
+                'column'      => $column,
+                'translation' => @$this->config->translations[$column],
+                'displayed'   => in_array($column, $this->config->columns_to_display)
+            );
+        }
+
+        $this->config->selectable_columns = $transformed;
+    }
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/Graph/Config.php b/plugins/CoreVisualizations/Visualizations/Graph/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..ada068b39ac81178343c3c3719db8db032c3fb7b
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/Graph/Config.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package CoreVisualizations
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+
+use Piwik\ViewDataTable\Config as VisualizationConfig;
+
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class Config extends VisualizationConfig
+{
+
+    /**
+     * Whether the series picker should allow picking more than one series or not.
+     *
+     * Default value: true
+     */
+    public $allow_multi_select_series_picker = true;
+
+    /**
+     * The maximum number of rows to render. All other rows will be aggregated in an 'Others' row.
+     *
+     * Default value: false (no limit)
+     */
+    public $max_graph_elements = false;
+
+    /**
+     * Array property that contains the names of columns that can be selected in the Series Picker.
+     *
+     * Default value: false
+     */
+    public $selectable_columns = false;
+
+    /**
+     * Contains the column (if any) of the values used in the Row Picker.
+     *
+     * @see self::ROWS_TO_DISPLAY
+     *
+     * Default value: false
+     */
+    public $row_picker_match_rows_by = false;
+
+    /**
+     * Contains the list of values identifying rows that should be displayed as separate series.
+     * The values are of a specific column determined by the row_picker_match_rows_by column.
+     *
+     * @see self::ROW_PICKER_VALUE_COLUMN
+     *
+     * Default value: false
+     */
+    public $rows_to_display = false;
+
+    /**
+     * Contains the list of values available for the Row Picker. Currently set to be all visible
+     * rows, if the row_picker_match_rows_by property is set.
+     *
+     * @see self::ROW_PICKER_VALUE_COLUMN
+     */
+    public $selectable_rows = 'selectable_rows';
+
+    /**
+     * Controls whether all ticks & labels are shown on a graph's x-axis or just some.
+     *
+     * Default value: false
+     */
+    public $show_all_ticks = false;
+
+    /**
+     * If true, a row with totals of each DataTable column is added.
+     *
+     * Default value: false
+     */
+    public $add_total_row = false;
+
+    /**
+     * Controls whether the Series Picker is shown or not. The Series Picker allows users to
+     * choose between displaying data of different columns.
+     *
+     * Default value: true
+     */
+    public $show_series_picker = true;
+
+    /**
+     * Controls whether the percentage of the total is displayed as a tooltip when hovering over
+     * data points.
+     *
+     * NOTE: Sometimes this percentage is meaningless (when the total of the column values is
+     * not the total number of elements in the set). In this case the tooltip should not be
+     * displayed.
+     *
+     * Default value: true
+     */
+    public $display_percentage_in_tooltip = true;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->show_limit_control = false;
+
+        $this->addPropertiesThatShouldBeAvailableClientSide(array(
+            'show_series_picker',
+            'allow_multi_select_series_picker',
+            'selectable_columns',
+            'selectable_rows',
+            'display_percentage_in_tooltip'
+        ));
+
+        $this->addPropertiesThatCanBeOverwrittenByQueryParams(array(
+            'show_all_ticks',
+            'show_series_picker'
+        ));
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
index bc7704812699d83fe3827d3e85b4bd163f917750..87b297921eb20f19fdd617eaf6439b312c206ccd 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
@@ -11,180 +11,41 @@
 namespace Piwik\Plugins\CoreVisualizations\Visualizations;
 
 use Piwik\Common;
-use Piwik\Config;
 use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal;
 use Piwik\MetricsFormatter;
 use Piwik\Piwik;
 use Piwik\Plugins\Goals\API as APIGoals;
 use Piwik\Site;
 use Piwik\View;
-use Piwik\ViewDataTable\Visualization;
-use Piwik\Visualization\Config as VizConfig;
-
-require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php';
-require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php';
+use Piwik\Plugin\Visualization;
 
 /**
  * DataTable visualization that shows DataTable data in an HTML table.
+ *
+ * @property HtmlTable\Config $config
  */
 class HtmlTable extends Visualization
 {
     const ID = 'table';
-
     const TEMPLATE_FILE = "@CoreVisualizations/_dataTableViz_htmlTable.twig";
 
-    /**
-     * If this property is set to true, subtables will be shown as embedded in the original table.
-     * If false, subtables will be shown as whole tables between rows.
-     *
-     * Default value: false
-     */
-    const SHOW_EMBEDDED_SUBTABLE = 'show_embedded_subtable';
-
-    /**
-     * Controls whether the entire DataTable should be rendered (including subtables) or just one
-     * specific table in the tree.
-     *
-     * Default value: false
-     */
-    const SHOW_EXPANDED = 'show_expanded';
-
-    /**
-     * When showing an expanded datatable, this property controls whether rows with subtables are
-     * replaced with their subtables, or if they are shown alongside their subtables.
-     *
-     * Default value: false
-     */
-    const REPLACE_ROW_WITH_SUBTABLE = 'replace_row_with_subtable';
-
-    /**
-     * Controls whether any DataTable Row Action icons are shown. If true, no icons are shown.
-     *
-     * @see also self::DISABLE_ROW_EVOLUTION
-     *
-     * Default value: false
-     */
-    const DISABLE_ROW_ACTIONS = 'disable_row_actions';
-
-    /**
-     * Controls whether the row evolution DataTable Row Action icon is shown or not.
-     *
-     * @see also self::DISABLE_ROW_ACTIONS
-     *
-     * Default value: false
-     */
-    const DISABLE_ROW_EVOLUTION = 'disable_row_evolution';
-
-    /**
-     * If true, the 'label', 'nb_visits', 'nb_uniq_visitors' (if present), 'nb_actions',
-     * 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate' and 'conversion_rate' (if
-     * goals view is not allowed) are displayed.
-     *
-     * Default value: false
-     */
-    const SHOW_EXTRA_COLUMNS = 'show_extra_columns';
-
-    /**
-     * If true, conversions for each existing goal will be displayed for the visits in
-     * each row.
-     *
-     * Default value: false
-     */
-    const SHOW_GOALS_COLUMNS = 'show_goals_columns';
-
-    /**
-     * If true, subtables will not be loaded when rows are clicked, but only if the
-     * 'show_goals_columns' property is also true.
-     *
-     * @see also self::SHOW_GOALS_COLUMNS
-     *
-     * Default value: false
-     */
-    const DISABLE_SUBTABLE_IN_GOALS_VIEW = 'disable_subtable_when_show_goals';
-
-    /**
-     * Controls whether the summary row is displayed on every page of the datatable view or not.
-     * If false, the summary row will be treated as the last row of the dataset and will only visible
-     * when viewing the last rows.
-     *
-     * Default value: false
-     */
-    const KEEP_SUMMARY_ROW = 'keep_summary_row';
-
-    /**
-     * If true, the summary row will be colored differently than all other DataTable rows.
-     *
-     * @see also self::KEEP_SUMMARY_ROW
-     *
-     * Default value: false
-     */
-    const HIGHLIGHT_SUMMARY_ROW = 'highlight_summary_row';
-
-    static public $clientSideRequestParameters = array(
-        'search_recursive',
-        'filter_limit',
-        'filter_offset',
-        'filter_sort_column',
-        'filter_sort_order',
-    );
-
-    static public $clientSideConfigProperties = array(
-        'show_extra_columns',
-        'show_goals_columns',
-        'disable_row_evolution',
-        'disable_row_actions',
-        'enable_sort',
-        'keep_summary_row',
-        'subtable_controller_action',
-    );
-
-    public static $overridableProperties = array(
-        'show_expanded',
-        'disable_row_actions',
-        'disable_row_evolution',
-        'show_extra_columns',
-        'show_goals_columns',
-        'disable_subtable_when_show_goals',
-        'keep_summary_row',
-        'highlight_summary_row',
-    );
+    public static function getDefaultConfig()
+    {
+        return new HtmlTable\Config();
+    }
 
-    public function configureVisualization(VizConfig $properties)
+    public static function getDefaultRequestConfig()
     {
-        if (Common::getRequestVar('idSubtable', false)
-            && $properties->visualization_properties->show_embedded_subtable
-        ) {
-            $properties->show_visualization_only = true;
-        }
+        return new HtmlTable\RequestConfig();
     }
 
-    public static function getDefaultPropertyValues()
+    public function beforeRender()
     {
-        $defaults = array(
-            'enable_sort'              => true,
-            'datatable_js_type'        => 'DataTable',
-            'filter_limit'             => Config::getInstance()->General['datatable_default_limit'],
-            'visualization_properties' => array(
-                'table' => array(
-                    'disable_row_evolution'            => false,
-                    'disable_row_actions'              => false,
-                    'show_extra_columns'               => false,
-                    'show_goals_columns'               => false,
-                    'disable_subtable_when_show_goals' => false,
-                    'keep_summary_row'                 => false,
-                    'highlight_summary_row'            => false,
-                    'show_expanded'                    => false,
-                    'show_embedded_subtable'           => false
-                ),
-            ),
-        );
+        if ($this->requestConfig->idSubtable
+            && $this->config->show_embedded_subtable) {
 
-        if (Common::getRequestVar('enable_filter_excludelowpop', false) == '1') {
-            $defaults['filter_excludelowpop'] = 'nb_visits';
-            $defaults['filter_excludelowpop_value'] = false;
+            $this->config->show_visualization_only = true;
         }
-
-        return $defaults;
     }
 
 }
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
index 04d50f3d8be96e393b2b57c2aa8bb3f745379b54..4a8a51c55e925ae73066fcb5e7cc363cb0ae475f 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
@@ -11,9 +11,7 @@
 
 namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
 
-use Piwik\DataTable\DataTableInterface;
 use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-use Piwik\Visualization\Config;
 use Piwik\Common;
 use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal;
 use Piwik\MetricsFormatter;
@@ -21,8 +19,6 @@ use Piwik\Piwik;
 use Piwik\Plugins\Goals\API as APIGoals;
 use Piwik\Site;
 use Piwik\View;
-use Piwik\ViewDataTable\Visualization;
-use Piwik\Visualization\Request;
 
 /**
  * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
@@ -31,21 +27,22 @@ class AllColumns extends HtmlTable
 {
     const ID = 'tableAllColumns';
 
-    public function configureVisualization(Config $properties)
+    public function beforeRender()
     {
-        $properties->visualization_properties->show_extra_columns = true;
+        $this->config->show_extra_columns  = true;
+        $this->config->datatable_css_class = 'dataTableVizAllColumns';
+        $this->config->show_exclude_low_population = true;
 
-        $properties->show_exclude_low_population = true;
-        $properties->datatable_css_class = 'dataTableVizAllColumns';
-
-        parent::configureVisualization($properties);
+        parent::beforeRender();
     }
 
-    public function beforeGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function beforeGenericFiltersAreAppliedToLoadedDataTable()
     {
-        $dataTable->filter('AddColumnsProcessedMetrics');
+        $this->dataTable->filter('AddColumnsProcessedMetrics');
+
+        $properties = $this->config;
 
-        $dataTable->filter(function ($dataTable) use ($properties) {
+        $this->dataTable->filter(function ($dataTable) use ($properties) {
             $columnsToDisplay = array('label', 'nb_visits');
 
             if (in_array('nb_uniq_visitors', $dataTable->getColumns())) {
@@ -66,9 +63,10 @@ class AllColumns extends HtmlTable
         });
     }
 
-    public function afterGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function afterGenericFiltersAreAppliedToLoadedDataTable()
     {
         $prettifyTime = array('\Piwik\MetricsFormatter', 'getPrettyTimeFromSeconds');
-        $dataTable->filter('ColumnCallbackReplace', array('avg_time_on_site', $prettifyTime));
+
+        $this->dataTable->filter('ColumnCallbackReplace', array('avg_time_on_site', $prettifyTime));
     }
 }
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/Config.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..10a72cc1523ac8e2e127b14f926f586ef8c9847b
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/Config.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package CoreVisualizations
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+
+use Piwik\Common;
+use Piwik\ViewDataTable\Config as VisualizationConfig;
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class Config extends VisualizationConfig
+{
+
+    /**
+     * If this property is set to true, subtables will be shown as embedded in the original table.
+     * If false, subtables will be shown as whole tables between rows.
+     *
+     * Default value: false
+     */
+    public $show_embedded_subtable = false;
+
+    /**
+     * Controls whether the entire DataTable should be rendered (including subtables) or just one
+     * specific table in the tree.
+     *
+     * Default value: false
+     */
+    public $show_expanded = false;
+
+    /**
+     * When showing an expanded datatable, this property controls whether rows with subtables are
+     * replaced with their subtables, or if they are shown alongside their subtables.
+     *
+     * Default value: false
+     */
+    public $replace_row_with_subtable = false;
+
+    /**
+     * Controls whether any DataTable Row Action icons are shown. If true, no icons are shown.
+     *
+     * Default value: false
+     */
+    public $disable_row_actions = false;
+
+    /**
+     * Controls whether the row evolution DataTable Row Action icon is shown or not.
+     *
+     * Default value: false
+     */
+    public $disable_row_evolution = false;
+
+    /**
+     * If true, the 'label', 'nb_visits', 'nb_uniq_visitors' (if present), 'nb_actions',
+     * 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate' and 'conversion_rate' (if
+     * goals view is not allowed) are displayed.
+     *
+     * Default value: false
+     */
+    public $show_extra_columns = false;
+
+    /**
+     * If true, conversions for each existing goal will be displayed for the visits in
+     * each row.
+     *
+     * Default value: false
+     */
+    public $show_goals_columns = false;
+
+    /**
+     * If true, subtables will not be loaded when rows are clicked, but only if the
+     * 'show_goals_columns' property is also true.
+     *
+     * Default value: false
+     */
+    public $disable_subtable_when_show_goals = false;
+
+    /**
+     * If true, the summary row will be colored differently than all other DataTable rows.
+     *
+     * Default value: false
+     */
+    public $highlight_summary_row = false;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->enable_sort       = true;
+        $this->datatable_js_type = 'DataTable';
+
+        $this->addPropertiesThatShouldBeAvailableClientSide(array(
+            'show_extra_columns',
+            'show_goals_columns',
+            'disable_row_evolution',
+            'disable_row_actions',
+            'enable_sort',
+            'keep_summary_row',
+            'subtable_controller_action',
+        ));
+
+        $this->addPropertiesThatCanBeOverwrittenByQueryParams(array(
+            'show_expanded',
+            'disable_row_actions',
+            'disable_row_evolution',
+            'show_extra_columns',
+            'show_goals_columns',
+            'disable_subtable_when_show_goals',
+            'keep_summary_row',
+            'highlight_summary_row',
+        ));
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..5fc97a398d788b62fd9604ac495d53d5b711b308
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/RequestConfig.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package CoreVisualizations
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+
+use Piwik\Common;
+use Piwik\ViewDataTable\RequestConfig as VisualizationRequestConfig;
+use Piwik\Config as PiwikConfig;
+
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class RequestConfig extends VisualizationRequestConfig
+{
+
+    /**
+     * Controls whether the summary row is displayed on every page of the datatable view or not.
+     * If false, the summary row will be treated as the last row of the dataset and will only visible
+     * when viewing the last rows.
+     *
+     * Default value: false
+     */
+    public $keep_summary_row = false;
+
+    public function __construct()
+    {
+        $this->filter_limit = PiwikConfig::getInstance()->General['datatable_default_limit'];
+
+        if (Common::getRequestVar('enable_filter_excludelowpop', false) == '1') {
+            $this->filter_excludelowpop       = 'nb_visits';
+            $this->filter_excludelowpop_value = false;
+        }
+
+        $this->addPropertiesThatShouldBeAvailableClientSide(array(
+            'search_recursive',
+            'filter_limit',
+            'filter_offset',
+            'filter_sort_column',
+            'filter_sort_order',
+            'keep_summary_row'
+        ));
+
+        $this->addPropertiesThatCanBeOverwrittenByQueryParams(array(
+            'keep_summary_row',
+        ));
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
index 9e4550326481bde5ef759af6c83247ba45a8debb..b3ca71dfe91f864f09f41f3d5d69edd4ce760cb4 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
@@ -14,82 +14,35 @@ namespace Piwik\Plugins\CoreVisualizations\Visualizations;
 use Piwik\DataTable;
 use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator;
 use Piwik\View;
-use Piwik\ViewDataTable\Graph;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
 
 /**
  * DataTable visualization that displays DataTable data in a JQPlot graph.
  * TODO: should merge all this logic w/ jqplotdatagenerator & 'Chart' visualizations.
+ *
+ * @property JqplotGraph\Config $config
  */
-class JqplotGraph extends Graph
+abstract class JqplotGraph extends Graph
 {
     const ID = 'jqplot_graph';
     const TEMPLATE_FILE = '@CoreVisualizations/_dataTableViz_jqplotGraph.twig';
 
-    /**
-     * The name of the JavaScript class to use as this graph's external series toggle. The class
-     * must be a subclass of JQPlotExternalSeriesToggle.
-     *
-     * @see self::EXTERNAL_SERIES_TOGGLE_SHOW_ALL
-     *
-     * Default value: false
-     */
-    const EXTERNAL_SERIES_TOGGLE = 'external_series_toggle';
-
-    /**
-     * Whether the graph should show all loaded series upon initial display.
-     *
-     * @see self::EXTERNAL_SERIES_TOGGLE
-     *
-     * Default value: false
-     */
-    const EXTERNAL_SERIES_TOGGLE_SHOW_ALL = 'external_series_toggle_show_all';
-
-    /**
-     * The number of x-axis ticks for each x-axis label.
-     *
-     * Default: 2
-     */
-    const X_AXIS_STEP_SIZE = 'x_axis_step_size';
-
-    public static $clientSideConfigProperties = array(
-        'external_series_toggle',
-        'external_series_toggle_show_all'
-    );
-
-    public static $overridableProperties = array('x_axis_step_size');
-
-    /**
-     * Returns an array mapping property names with default values for this visualization.
-     *
-     * @return array
-     */
-    public static function getDefaultPropertyValues()
+    public static function getDefaultConfig()
     {
-        $result = parent::getDefaultPropertyValues();
-        return array_merge_recursive($result, array(
-                                                   'show_offset_information'     => false,
-                                                   'show_pagination_control'     => false,
-                                                   'show_exclude_low_population' => false,
-                                                   'show_search'                 => false,
-                                                   'show_export_as_image_icon'   => true,
-                                                   'y_axis_unit'                 => '',
-                                                   'visualization_properties'    => array(
-                                                       'jqplot_graph' => array(
-                                                           'external_series_toggle'          => false,
-                                                           'external_series_toggle_show_all' => false,
-                                                           'x_axis_step_size'                => 2
-                                                       )
-                                                   )
-                                              ));
+        return new JqplotGraph\Config();
     }
 
     public function getGraphData($dataTable, $properties)
     {
         $dataGenerator = $this->makeDataGenerator($properties);
+
         return $dataGenerator->generate($dataTable);
     }
+
+    /**
+     * @param $properties
+     * @return JqplotDataGenerator
+     */
+    abstract protected function makeDataGenerator($properties);
 }
 
 require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php';
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php
index bb364e5f761d9c171e740ea101ebdea8be520ce4..7973da33be059b55b958ebd042bac266e9f174f7 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php
@@ -13,7 +13,6 @@ namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
 
 use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator;
 use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
-use Piwik\Visualization\Config;
 
 /**
  * Visualization that renders HTML for a Bar graph using jqPlot.
@@ -22,18 +21,19 @@ class Bar extends JqplotGraph
 {
     const ID = 'graphVerticalBar';
 
-    public function configureVisualization(Config $properties)
+    public function beforeRender()
     {
-        parent::configureVisualization($properties);
+        parent::beforeRender();
 
-        $properties->datatable_js_type = 'JqplotBarGraphDataTable';
+        $this->config->datatable_js_type = 'JqplotBarGraphDataTable';
     }
 
-    public static function getDefaultPropertyValues()
+    public static function getDefaultConfig()
     {
-        $result = parent::getDefaultPropertyValues();
-        $result['visualization_properties']['graph']['max_graph_elements'] = 6;
-        return $result;
+        $config = new Config();
+        $config->max_graph_elements = 6;
+
+        return $config;
     }
 
     protected function makeDataGenerator($properties)
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Config.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..25dc9f38426ac7bfb33fca103c327ddf27a0f5bb
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Config.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package CoreVisualizations
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
+
+use Piwik\Plugins\CoreVisualizations\Visualizations\Graph\Config as GraphConfig;
+
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class Config extends GraphConfig
+{
+    /**
+     * The name of the JavaScript class to use as this graph's external series toggle. The class
+     * must be a subclass of JQPlotExternalSeriesToggle.
+     *
+     * @see self::EXTERNAL_SERIES_TOGGLE_SHOW_ALL
+     *
+     * Default value: false
+     */
+    public $external_series_toggle = false;
+
+    /**
+     * Whether the graph should show all loaded series upon initial display.
+     *
+     * @see self::EXTERNAL_SERIES_TOGGLE
+     *
+     * Default value: false
+     */
+    public $external_series_toggle_show_all = false;
+
+    /**
+     * The number of x-axis ticks for each x-axis label.
+     *
+     * Default: 2
+     */
+    public $x_axis_step_size = 2;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->show_exclude_low_population = false;
+        $this->show_offset_information     = false;
+        $this->show_pagination_control     = false;
+        $this->show_exclude_low_population = false;
+        $this->show_search                 = false;
+        $this->show_export_as_image_icon   = true;
+        $this->y_axis_unit                 = '';
+
+        $this->addPropertiesThatShouldBeAvailableClientSide(array(
+            'external_series_toggle',
+            'external_series_toggle_show_all'
+        ));
+
+        $this->addPropertiesThatCanBeOverwrittenByQueryParams(array('x_axis_step_size'));
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php
index 75f07864270cb937e847ec218651317f93e95c70..921ed01e5db586bf6df432d4c141afe13796ce45 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php
@@ -13,78 +13,59 @@ namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
 
 use Piwik\Common;
 use Piwik\DataTable;
-use Piwik\DataTable\DataTableInterface;
 use Piwik\Period\Range;
 use Piwik\Plugin\Controller;
 use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator;
 use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
 use Piwik\Site;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
 
 /**
  * Visualization that renders HTML for a line graph using jqPlot.
+ *
+ * @property Evolution\Config $config
  */
 class Evolution extends JqplotGraph
 {
     const ID = 'graphEvolution';
     const SERIES_COLOR_COUNT = 8;
 
-    /**
-     * Whether to show a line graph or a bar graph.
-     *
-     * Default value: true
-     */
-    const SHOW_LINE_GRAPH = 'show_line_graph';
-
-    public static $clientSideConfigProperties = array('show_line_graph');
-
-    public static $overridableProperties = array('show_line_graph');
-
-    public function configureVisualization(Config $properties)
+    public static function getDefaultConfig()
     {
-        $this->calculateEvolutionDateRange($properties);
+        return new Evolution\Config();
+    }
 
-        parent::configureVisualization($properties);
+    public function beforeRender()
+    {
+        parent::beforeRender();
 
-        $properties->datatable_js_type = 'JqplotEvolutionGraphDataTable';
+        $this->config->datatable_js_type = 'JqplotEvolutionGraphDataTable';
     }
 
-    public function beforeLoadDataTable(Request $request, Config $properties)
+    public function beforeLoadDataTable()
     {
-        parent::beforeLoadDataTable($request, $properties);
+        $this->calculateEvolutionDateRange();
+
+        parent::beforeLoadDataTable();
 
         // period will be overridden when 'range' is requested in the UI
         // but the graph will display for each day of the range.
         // Default 'range' behavior is to return the 'sum' for the range
         if (Common::getRequestVar('period', false) == 'range') {
-            $request->request_parameters_to_modify['period'] = 'day';
+            $this->requestConfig->request_parameters_to_modify['period'] = 'day';
         }
     }
 
-    public function afterAllFilteresAreApplied(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function afterAllFilteresAreApplied()
     {
-        parent::afterAllFilteresAreApplied($dataTable, $properties, $request);
+        parent::afterAllFilteresAreApplied();
 
-        if ($properties->visualization_properties->x_axis_step_size === false) {
+        if (false === $this->config->x_axis_step_size) {
+            $rowCount = $this->dataTable->getRowsCount();
 
-            $size = $this->getDefaultXAxisStepSize($dataTable->getRowsCount());
-            $properties->visualization_properties->x_axis_step_size = $size;
+            $this->config->x_axis_step_size = $this->getDefaultXAxisStepSize($rowCount);
         }
     }
 
-    public static function getDefaultPropertyValues()
-    {
-        $result = parent::getDefaultPropertyValues();
-        $result['show_all_views_icons'] = false;
-        $result['show_table'] = false;
-        $result['show_table_all_columns'] = false;
-        $result['hide_annotations_view'] = false;
-        $result['visualization_properties']['jqplot_graph']['x_axis_step_size'] = false;
-        $result['visualization_properties']['graphEvolution']['show_line_graph'] = true;
-        return $result;
-    }
-
     protected function makeDataGenerator($properties)
     {
         return JqplotDataGenerator::factory('evolution', $properties);
@@ -94,29 +75,34 @@ class Evolution extends JqplotGraph
      * Based on the period, date and evolution_{$period}_last_n query parameters,
      * calculates the date range this evolution chart will display data for.
      */
-    private function calculateEvolutionDateRange(Config $properties)
+    private function calculateEvolutionDateRange()
     {
-        $view = $this->viewDataTable;
         $period = Common::getRequestVar('period');
 
         $defaultLastN = self::getDefaultLastN($period);
         $originalDate = Common::getRequestVar('date', 'last' . $defaultLastN, 'string');
 
-        if ($period != 'range') { // show evolution limit if the period is not a range
-            $properties->show_limit_control = true;
+        if ('range' != $period) { // show evolution limit if the period is not a range
+            $this->config->show_limit_control = true;
 
             // set the evolution_{$period}_last_n query param
-            if (Range::parseDateRange($originalDate)) { // if a multiple period
+            if (Range::parseDateRange($originalDate)) {
+                // if a multiple period
+
                 // overwrite last_n param using the date range
                 $oPeriod = new Range($period, $originalDate);
-                $lastN = count($oPeriod->getSubperiods());
-            } else { // if not a multiple period
+                $lastN   = count($oPeriod->getSubperiods());
+
+            } else {
+
+                // if not a multiple period
                 list($newDate, $lastN) = self::getDateRangeAndLastN($period, $originalDate, $defaultLastN);
-                $view->request_parameters_to_modify['date'] = $newDate;
-                $properties->custom_parameters['dateUsedInGraph'] = $newDate;
+                $this->requestConfig->request_parameters_to_modify['date'] = $newDate;
+                $this->config->custom_parameters['dateUsedInGraph'] = $newDate;
             }
+
             $lastNParamName = self::getLastNParamName($period);
-            $properties->custom_parameters[$lastNParamName] = $lastN;
+            $this->config->custom_parameters[$lastNParamName] = $lastN;
         }
     }
 
@@ -188,6 +174,7 @@ class Evolution extends JqplotGraph
         }
 
         $periodLabel = Common::getRequestVar('period');
+
         switch ($periodLabel) {
             case 'day':
             case 'range':
@@ -208,6 +195,7 @@ class Evolution extends JqplotGraph
         }
 
         $paddedCount = $countGraphElements + 2; // pad count so last label won't be cut off
+
         return ceil($paddedCount / $steps);
     }
 }
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution/Config.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..7d3ac54bcc110b77f549a42d87bed43e5d6cfccf
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution/Config.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package CoreVisualizations
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Config as JqplotGraphConfig;
+
+/**
+ * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
+ */
+class Config extends JqplotGraphConfig
+{
+    /**
+     * Whether to show a line graph or a bar graph.
+     *
+     * Default value: true
+     */
+    public $show_line_graph = true;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->show_all_views_icons   = false;
+        $this->show_table             = false;
+        $this->show_table_all_columns = false;
+        $this->hide_annotations_view  = false;
+        $this->x_axis_step_size       = false;
+        $this->show_line_graph        = true;
+
+        $this->addPropertiesThatShouldBeAvailableClientSide(array('show_line_graph'));
+        $this->addPropertiesThatCanBeOverwrittenByQueryParams(array('show_line_graph'));
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php
index e6db071c9ff9787b64ca372cb69b79657572a7c1..5411979ab541c5c35c07e1831e7565d33e6e4c54 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php
@@ -11,11 +11,8 @@
 
 namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
 
-use Piwik\DataTable\DataTableInterface;
 use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator;
 use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
 
 /**
  * Visualization that renders HTML for a Pie graph using jqPlot.
@@ -24,33 +21,34 @@ class Pie extends JqplotGraph
 {
     const ID = 'graphPie';
 
-    public function configureVisualization(Config $properties)
+    public static function getDefaultConfig()
     {
-        parent::configureVisualization($properties);
+        $config = new Config();
+        $config->max_graph_elements = 6;
+        $config->allow_multi_select_series_picker = false;
 
-        $properties->visualization_properties->show_all_ticks = true;
-        $properties->datatable_js_type = 'JqplotPieGraphDataTable';
+        return $config;
     }
 
-    public function afterAllFilteresAreApplied(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function beforeRender()
     {
-        parent::afterAllFilteresAreApplied($dataTable, $properties, $request);
+        parent::beforeRender();
 
-        $metricColumn = reset($properties->columns_to_display);
+        $this->config->show_all_ticks = true;
+        $this->config->datatable_js_type = 'JqplotPieGraphDataTable';
+    }
+
+    public function afterAllFilteresAreApplied()
+    {
+        parent::afterAllFilteresAreApplied();
+
+        $metricColumn = reset($this->config->columns_to_display);
 
         if ($metricColumn == 'label') {
-            $metricColumn = next($properties->columns_to_display);
+            $metricColumn = next($this->config->columns_to_display);
         }
 
-        $properties->columns_to_display = array($metricColumn ? : 'nb_visits');
-    }
-
-    public static function getDefaultPropertyValues()
-    {
-        $result = parent::getDefaultPropertyValues();
-        $result['visualization_properties']['graph']['max_graph_elements'] = 6;
-        $result['visualization_properties']['graph']['allow_multi_select_series_picker'] = false;
-        return $result;
+        $this->config->columns_to_display = array($metricColumn ? : 'nb_visits');
     }
 
     protected function makeDataGenerator($properties)
diff --git a/core/ViewDataTable/Sparkline.php b/plugins/CoreVisualizations/Visualizations/Sparkline.php
similarity index 90%
rename from core/ViewDataTable/Sparkline.php
rename to plugins/CoreVisualizations/Visualizations/Sparkline.php
index 5197c8b671686add9dc0815998e70ccaf72cf2d7..338dcb611ddeb1a3c6a1401645a1d011324a62c2 100644
--- a/core/ViewDataTable/Sparkline.php
+++ b/plugins/CoreVisualizations/Visualizations/Sparkline.php
@@ -8,12 +8,12 @@
  * @category Piwik
  * @package Piwik
  */
-namespace Piwik\ViewDataTable;
+namespace Piwik\Plugins\CoreVisualizations\Visualizations;
 
 use Exception;
 use Piwik\Common;
 use Piwik\DataTable;
-use Piwik\ViewDataTable;
+use Piwik\Plugin\ViewDataTable;
 
 /**
  * Reads the requested DataTable from the API and prepare data for the Sparkline view.
@@ -23,15 +23,7 @@ use Piwik\ViewDataTable;
  */
 class Sparkline extends ViewDataTable
 {
-    /**
-     * Returns dataTable id for view
-     *
-     * @return string
-     */
-    public function getViewDataTableId()
-    {
-        return 'sparkline';
-    }
+    const ID = 'sparkline';
 
     /**
      * @see ViewDataTable::main()
@@ -44,7 +36,9 @@ class Sparkline extends ViewDataTable
         if ($period == 'range') {
             $_GET['period'] = 'day';
         }
+
         $this->loadDataTableFromAPI();
+
         // then revert the hack for potentially subsequent getRequestVar
         $_GET['period'] = $period;
 
@@ -81,14 +75,19 @@ class Sparkline extends ViewDataTable
     protected function getValuesFromDataTableMap($dataTableMap, $columnToPlot)
     {
         $dataTableMap->applyQueuedFilters();
+
         $values = array();
+
         foreach ($dataTableMap->getDataTables() as $table) {
+
             if ($table->getRowsCount() > 1) {
                 throw new Exception("Expecting only one row per DataTable");
             }
-            $value = 0;
+
+            $value   = 0;
             $onlyRow = $table->getFirstRow();
-            if ($onlyRow !== false) {
+
+            if (false !== $onlyRow) {
                 if (!empty($columnToPlot)) {
                     $value = $onlyRow->getColumn($columnToPlot);
                 } // if not specified, we load by default the first column found
@@ -98,29 +97,36 @@ class Sparkline extends ViewDataTable
                     $value = current($columns);
                 }
             }
+
             $values[] = $value;
         }
+
         return $values;
     }
 
     protected function getValuesFromDataTable($dataTable)
     {
-        $columns = $this->vizConfig->columns_to_display;
+        $columns = $this->config->columns_to_display;
+
         $columnToPlot = false;
+
         if (!empty($columns)) {
             $columnToPlot = reset($columns);
             if ($columnToPlot == 'label') {
                 $columnToPlot = next($columns);
             }
         }
-        $values = false;
+
         // a Set is returned when using the normal code path to request data from Archives, in all core plugins
         // however plugins can also return simple datatable, hence why the sparkline can accept both data types
         if ($this->dataTable instanceof DataTable\Map) {
             $values = $this->getValuesFromDataTableMap($dataTable, $columnToPlot);
         } elseif ($this->dataTable instanceof DataTable) {
             $values = $this->dataTable->getColumn($columnToPlot);
+        } else {
+            $values = false;
         }
+
         return $values;
     }
 }
diff --git a/plugins/CoreVisualizations/templates/_dataTableViz_htmlTable.twig b/plugins/CoreVisualizations/templates/_dataTableViz_htmlTable.twig
index f18a7afa99c09f75fce0eae127ee8c5e9cf10d58..a0f868288174e2d3022e795a21ce82983c0b48de 100644
--- a/plugins/CoreVisualizations/templates/_dataTableViz_htmlTable.twig
+++ b/plugins/CoreVisualizations/templates/_dataTableViz_htmlTable.twig
@@ -1,6 +1,6 @@
-{%- set subtablesAreDisabled = properties.visualization_properties.show_goals_columns|default(false)
-                           and properties.visualization_properties.disable_subtable_when_show_goals|default(false) -%}
-{%- set showingEmbeddedSubtable = properties.visualization_properties.show_embedded_subtable is not empty
+{%- set subtablesAreDisabled = properties.show_goals_columns|default(false)
+                           and properties.disable_subtable_when_show_goals|default(false) -%}
+{%- set showingEmbeddedSubtable = properties.show_embedded_subtable is not empty
                               and idSubtable|default(false) -%}
 {% if error is defined %}
     {{ error.message }}
@@ -18,13 +18,13 @@
         {% else %}
             {%- for rowId, row in dataTable.getRows() -%}
                 {%- set rowHasSubtable = not subtablesAreDisabled and row.getIdSubDataTable() and properties.subtable_controller_action is not null -%}
-                {%- set shouldHighlightRow = rowId == constant('Piwik\\DataTable::ID_SUMMARY_ROW') and properties.visualization_properties.highlight_summary_row -%}
+                {%- set shouldHighlightRow = rowId == constant('Piwik\\DataTable::ID_SUMMARY_ROW') and properties.highlight_summary_row -%}
 
                 {# display this row if it doesn't have a subtable or if we don't replace the row with the subtable #}
                 {%- set showRow = subtablesAreDisabled
                                or not rowHasSubtable
-                               or not properties.visualization_properties.show_expanded|default(false)
-                               or not properties.visualization_properties.replace_row_with_subtable|default(false) -%}
+                               or not properties.show_expanded|default(false)
+                               or not properties.replace_row_with_subtable|default(false) -%}
 
                 {% if showRow %}
                 <tr {% if rowHasSubtable %}id="{{ row.getIdSubDataTable() }}"{% endif %}
@@ -36,9 +36,9 @@
                     {% endfor %}
                 </tr>
                 {% endif %}
-                
+
                 {# display subtable if present and showing expanded datatable #}
-                {% if properties.visualization_properties.show_expanded|default(false) and rowHasSubtable %}
+                {% if properties.show_expanded|default(false) and rowHasSubtable %}
                     {% include "@CoreVisualizations/_dataTableViz_htmlTable.twig" with {'dataTable': row.getSubtable(), 'idSubtable': row.getIdSubDataTable()} %}
                 {% endif %}
             {%- endfor -%}
diff --git a/plugins/CustomVariables/CustomVariables.php b/plugins/CustomVariables/CustomVariables.php
index 763ee09634bbf4fe3880f0bd852b774364dd9cc5..63c85655e31ce6ffa8ebc3fc0f1303a43db797fb 100644
--- a/plugins/CustomVariables/CustomVariables.php
+++ b/plugins/CustomVariables/CustomVariables.php
@@ -13,6 +13,7 @@ namespace Piwik\Plugins\CustomVariables;
 use Piwik\ArchiveProcessor;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
 use Piwik\Tracker;
 use Piwik\WidgetsList;
 
@@ -34,14 +35,14 @@ class CustomVariables extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenus',
-            'Goals.getReportsWithGoalMetrics'          => 'getReportsWithGoalMetrics',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'    => 'archiveDay',
+            'ArchiveProcessor.Period.compute' => 'archivePeriod',
+            'WidgetsList.addWidgets'          => 'addWidgets',
+            'Menu.Reporting.addItems'         => 'addMenus',
+            'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
+            'API.getReportMetadata'           => 'getReportMetadata',
+            'API.getSegmentsMetadata'         => 'getSegmentsMetadata',
+            'ViewDataTable.configure'         => 'configureViewDataTable',
         );
         return $hooks;
     }
@@ -152,39 +153,40 @@ class CustomVariables extends \Piwik\Plugin
         }
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['CustomVariables.getCustomVariables'] = $this->getDisplayPropertiesForGetCustomVariables();
-        $properties['CustomVariables.getCustomVariablesValuesFromNameId'] =
-            $this->getDisplayPropertiesForGetCustomVariablesValuesFromNameId();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'CustomVariables.getCustomVariables':
+                $this->configureViewForGetCustomVariables($view);
+                break;
+            case 'CustomVariables.getCustomVariablesValuesFromNameId':
+                $this->configureViewForGetCustomVariablesValuesFromNameId($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetCustomVariables()
+    private function configureViewForGetCustomVariables(ViewDataTable $view)
     {
         $footerMessage = Piwik::translate('CustomVariables_TrackingHelp',
             array('<a target="_blank" href="http://piwik.org/docs/custom-variables/">', '</a>'));
 
-        return array(
-            'columns_to_display'         => array('label', 'nb_actions', 'nb_visits'),
-            'filter_sort_column'         => 'nb_actions',
-            'filter_sort_order'          => 'desc',
-            'show_goals'                 => true,
-            'subtable_controller_action' => 'getCustomVariablesValuesFromNameId',
-            'translations'               => array('label' => Piwik::translate('CustomVariables_ColumnCustomVariableName')),
-            'show_footer_message'        => $footerMessage
-        );
+        $view->config->columns_to_display = array('label', 'nb_actions', 'nb_visits');
+        $view->config->show_goals = true;
+        $view->config->subtable_controller_action = 'getCustomVariablesValuesFromNameId';
+        $view->config->show_footer_message = $footerMessage;
+        $view->config->addTranslation('label', Piwik::translate('CustomVariables_ColumnCustomVariableName'));
+        $view->requestConfig->filter_sort_column = 'nb_actions';
+        $view->requestConfig->filter_sort_order  = 'desc';
     }
 
-    private function getDisplayPropertiesForGetCustomVariablesValuesFromNameId()
+    private function configureViewForGetCustomVariablesValuesFromNameId(ViewDataTable $view)
     {
-        return array(
-            'columns_to_display'          => array('label', 'nb_actions', 'nb_visits'),
-            'filter_sort_column'          => 'nb_actions',
-            'filter_sort_order'           => 'desc',
-            'show_goals'                  => true,
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('CustomVariables_ColumnCustomVariableValue'))
-        );
+        $view->config->columns_to_display = array('label', 'nb_actions', 'nb_visits');
+        $view->config->show_goals  = true;
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('CustomVariables_ColumnCustomVariableValue'));
+        $view->requestConfig->filter_sort_column = 'nb_actions';
+        $view->requestConfig->filter_sort_order  = 'desc';
     }
 }
diff --git a/plugins/DBStats/DBStats.php b/plugins/DBStats/DBStats.php
index be12d261fa856f28b5e32b07ab752ff8224f9e3f..52535defdacb6c846fe8c01b8acb56f2e5ae2136 100644
--- a/plugins/DBStats/DBStats.php
+++ b/plugins/DBStats/DBStats.php
@@ -16,8 +16,12 @@ use Piwik\Date;
 use Piwik\Menu\MenuAdmin;
 use Piwik\Option;
 use Piwik\Piwik;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
 use Piwik\ScheduledTask;
 use Piwik\ScheduledTime\Weekly;
+use \Piwik\Plugin\ViewDataTable;
 
 /**
  *
@@ -33,10 +37,11 @@ class DBStats extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         return array(
-            'AssetManager.getStylesheetFiles'          => 'getStylesheetFiles',
-            'Menu.Admin.addItems'                      => 'addMenu',
-            'TaskScheduler.getScheduledTasks'          => 'getScheduledTasks',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'AssetManager.getStylesheetFiles'            => 'getStylesheetFiles',
+            'Menu.Admin.addItems'                        => 'addMenu',
+            'TaskScheduler.getScheduledTasks'            => 'getScheduledTasks',
+            'ViewDataTable.configure'                    => 'configureViewDataTable',
+            'Visualization.getDefaultViewTypeForReports' => 'getDefaultViewTypeForReports'
         );
     }
 
@@ -88,28 +93,63 @@ class DBStats extends \Piwik\Plugin
         return Option::get(self::TIME_OF_LAST_TASK_RUN_OPTION);
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function getDefaultViewTypeForReports(&$defaultViewTypes)
     {
-        $properties['DBStats.getDatabaseUsageSummary'] = $this->getDisplayPropertiesForGetDatabaseUsageSummary();
-        $properties['DBStats.getTrackerDataSummary'] = $this->getDisplayPropertiesForGetTrackerDataSummary();
-        $properties['DBStats.getMetricDataSummary'] = $this->getDisplayPropertiesForGetMetricDataSummary();
-        $properties['DBStats.getMetricDataSummaryByYear'] = $this->getDisplayPropertiesForGetMetricDataSummaryByYear();
-        $properties['DBStats.getReportDataSummary'] = $this->getDisplayPropertiesForGetReportDataSummary();
-        $properties['DBStats.getReportDataSummaryByYear'] = $this->getDisplayPropertiesForGetReportDataSummaryByYear();
-        $properties['DBStats.getIndividualReportsSummary'] = $this->getDisplayPropertiesForGetIndividualReportsSummary();
-        $properties['DBStats.getIndividualMetricsSummary'] = $this->getDisplayPropertiesForGetIndividualMetricsSummary();
-        $properties['DBStats.getAdminDataSummary'] = $this->getDisplayPropertiesForGetAdminDataSummary();
+        $defaultViewTypes['DBStats.getDatabaseUsageSummary']     = Pie::ID;
+        $defaultViewTypes['DBStats.getTrackerDataSummary']       = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getMetricDataSummary']        = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getMetricDataSummaryByYear']  = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getReportDataSummary']        = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getReportDataSummaryByYear']  = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getIndividualReportsSummary'] = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getIndividualMetricsSummary'] = HtmlTable::ID;
+        $defaultViewTypes['DBStats.getAdminDataSummary']         = HtmlTable::ID;
     }
 
-    private function getDisplayPropertiesForGetDatabaseUsageSummary()
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $result = array('default_view_type' => 'graphPie');
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result, $addTotalSizeColumn = true, $addPercentColumn = true);
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'DBStats.getDatabaseUsageSummar':
+                $this->configureViewForGetDatabaseUsageSummary($view);
+                break;
+            case 'DBStats.getTrackerDataSummary':
+                $this->configureViewForGetTrackerDataSummary($view);
+                break;
+            case 'DBStats.getMetricDataSummary':
+                $this->configureViewForGetMetricDataSummary($view);
+                break;
+            case 'DBStats.getMetricDataSummaryByYear':
+                $this->configureViewForGetMetricDataSummaryByYear($view);
+                break;
+            case 'DBStats.getReportDataSummary':
+                $this->configureViewForGetReportDataSummary($view);
+                break;
+            case 'DBStats.getReportDataSummaryByYear':
+                $this->configureViewForGetReportDataSummaryByYear($view);
+                break;
+            case 'DBStats.getIndividualReportsSummary':
+                $this->configureViewForGetIndividualReportsSummary($view);
+                break;
+            case 'DBStats.getIndividualMetricsSummary':
+                $this->configureViewForGetIndividualMetricsSummary($view);
+                break;
+            case 'DBStats.getAdminDataSummary':
+                $this->configureViewForGetAdminDataSummary($view);
+                break;
+        }
+    }
+
+    private function configureViewForGetDatabaseUsageSummary(ViewDataTable $view)
+    {
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view, $addTotalSizeColumn = true, $addPercentColumn = true);
 
-        $result['show_offset_information'] = false;
-        $result['show_pagination_control'] = false;
-        $result['visualization_properties']['graph']['show_all_ticks'] = true;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->show_all_ticks = true;
+        }
 
         // translate the labels themselves
         $valueToTranslationStr = array(
@@ -125,143 +165,122 @@ class DBStats extends \Piwik\Plugin
                 : $value;
         };
 
-        $result['filters'][] = array('ColumnCallbackReplace', array('label', $translateSummaryLabel), $isPriority = true);
-
-        return $result;
+        $view->config->filters[] = array('ColumnCallbackReplace', array('label', $translateSummaryLabel), $isPriority = true);
     }
 
-    private function getDisplayPropertiesForGetTrackerDataSummary()
+    private function configureViewForGetTrackerDataSummary(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result);
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view);
 
-        $result['filter_sort_order'] = 'asc';
-        $result['show_offset_information'] = false;
-        $result['show_pagination_control'] = false;
-
-        return $result;
+        $view->requestConfig->filter_sort_order = 'asc';
+        $view->config->show_offset_information  = false;
+        $view->config->show_pagination_control  = false;
     }
 
-    private function getDisplayPropertiesForGetMetricDataSummary()
+    private function configureViewForGetMetricDataSummary(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result);
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view);
 
-        $result['title'] = Piwik::translate('DBStats_MetricTables');
-        $result['related_reports'] = array(
+        $view->config->title = Piwik::translate('DBStats_MetricTables');
+        $view->config->addRelatedReports(array(
             'DBStats.getMetricDataSummaryByYear' => Piwik::translate('DBStats_MetricDataByYear')
-        );
-
-        return $result;
+        ));
     }
 
-    private function getDisplayPropertiesForGetMetricDataSummaryByYear()
+    private function configureViewForGetMetricDataSummaryByYear(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result);
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view);
 
-        $result['translations']['label'] = Piwik::translate('CoreHome_PeriodYear');
-        $result['title'] = Piwik::translate('DBStats_MetricDataByYear');
-        $result['related_reports'] = array(
+        $view->config->title = Piwik::translate('DBStats_MetricDataByYear');
+        $view->config->addTranslation('label', Piwik::translate('CoreHome_PeriodYear'));
+        $view->config->addRelatedReports(array(
             'DBStats.getMetricDataSummary' => Piwik::translate('DBStats_MetricTables')
-        );
-
-        return $result;
+        ));
     }
 
-    private function getDisplayPropertiesForGetReportDataSummary()
+    private function configureViewForGetReportDataSummary(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result);
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view);
 
-        $result['title'] = Piwik::translate('DBStats_ReportTables');
-        $result['related_reports'] = array(
+        $view->config->title = Piwik::translate('DBStats_ReportTables');
+        $view->config->addRelatedReports(array(
             'DBStats.getReportDataSummaryByYear' => Piwik::translate('DBStats_ReportDataByYear')
-        );
-
-        return $result;
+        ));
     }
 
-    private function getDisplayPropertiesForGetReportDataSummaryByYear()
+    private function configureViewForGetReportDataSummaryByYear(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result);
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view);
 
-        $result['translations']['label'] = Piwik::translate('CoreHome_PeriodYear');
-        $result['title'] = Piwik::translate('DBStats_ReportDataByYear');
-        $result['related_reports'] = array(
+        $view->config->title = Piwik::translate('DBStats_ReportDataByYear');
+        $view->config->addTranslation('label', Piwik::translate('CoreHome_PeriodYear'));
+        $view->config->addRelatedReports(array(
             'DBStats.getReportDataSummary' => Piwik::translate('DBStats_ReportTables')
-        );
-
-        return $result;
+        ));
     }
 
-    private function getDisplayPropertiesForGetIndividualReportsSummary()
+    private function configureViewForGetIndividualReportsSummary(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $viewDataTable = $this->addPresentationFilters($result, $addTotalSizeColumn = false, $addPercentColumn = false,
-            $sizeColumns = array('estimated_size'));
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view, $addTotalSizeColumn = false, $addPercentColumn = false,
+                                     $sizeColumns = array('estimated_size'));
 
-        $result['filter_sort_order'] = 'asc';
-        $result['translations']['label'] = Piwik::translate('General_Report');
+        $view->requestConfig->filter_sort_order = 'asc';
+        $view->config->addTranslation('label', Piwik::translate('General_Report'));
 
         // this report table has some extra columns that shouldn't be shown
-        if ($viewDataTable == 'table') {
-            $result['columns_to_display'] = array('label', 'row_count', 'estimated_size');
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->columns_to_display = array('label', 'row_count', 'estimated_size');
         }
 
-        $this->setIndividualSummaryFooterMessage($result);
-
-        return $result;
+        $this->setIndividualSummaryFooterMessage($view);
     }
 
-    private function getDisplayPropertiesForGetIndividualMetricsSummary()
+    private function configureViewForGetIndividualMetricsSummary(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result, $addTotalSizeColumn = false, $addPercentColumn = false,
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view, $addTotalSizeColumn = false, $addPercentColumn = false,
             $sizeColumns = array('estimated_size'));
 
-        $result['filter_sort_order'] = 'asc';
-        $result['translations']['label'] = Piwik::translate('General_Metric');
+        $view->requestConfig->filter_sort_order = 'asc';
+        $view->config->addTranslation('label', Piwik::translate('General_Metric'));
 
-        $this->setIndividualSummaryFooterMessage($result);
-
-        return $result;
+        $this->setIndividualSummaryFooterMessage($view);
     }
 
-    private function getDisplayPropertiesForGetAdminDataSummary()
+    private function configureViewForGetAdminDataSummary(ViewDataTable $view)
     {
-        $result = array();
-        $this->addBaseDisplayProperties($result);
-        $this->addPresentationFilters($result);
-
-        $result['filter_sort_order'] = 'asc';
-        $result['show_offset_information'] = false;
-        $result['show_pagination_control'] = false;
+        $this->addBaseDisplayProperties($view);
+        $this->addPresentationFilters($view);
 
-        return $result;
+        $view->requestConfig->filter_sort_order = 'asc';
+        $view->config->show_offset_information  = false;
+        $view->config->show_pagination_control  = false;
     }
 
-    private function addBaseDisplayProperties(&$properties)
+    private function addBaseDisplayProperties(ViewDataTable $view)
     {
-        $properties['filter_sort_column'] = 'label';
-        $properties['filter_sort_order'] = 'desc';
-        $properties['filter_limit'] = 25;
-        $properties['show_search'] = false;
-        $properties['show_exclude_low_population'] = false;
-        $properties['show_tag_cloud'] = false;
-        $properties['show_table_all_columns'] = false;
-        $properties['visualization_properties']['table']['keep_summary_row'] = true;
-        $properties['visualization_properties']['table']['disable_row_evolution'] = true;
-        $properties['visualization_properties']['table']['highlight_summary_row'] = true;
-        $properties['translations'] = array(
+        $view->requestConfig->filter_sort_column   = 'label';
+        $view->requestConfig->filter_sort_order    = 'desc';
+        $view->requestConfig->filter_limit         = 25;
+
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_table_all_columns      = false;
+        $view->config->show_tag_cloud = false;
+        $view->config->show_search    = false;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->keep_summary_row      = true;
+            $view->config->disable_row_evolution = true;
+            $view->config->highlight_summary_row = true;
+        }
+
+        $view->config->addTranslations(array(
             'label'          => Piwik::translate('DBStats_Table'),
             'year'           => Piwik::translate('CoreHome_PeriodYear'),
             'data_size'      => Piwik::translate('DBStats_DataSize'),
@@ -270,10 +289,10 @@ class DBStats extends \Piwik\Plugin
             'row_count'      => Piwik::translate('DBStats_RowCount'),
             'percent_total'  => '%&nbsp;' . Piwik::translate('DBStats_DBSize'),
             'estimated_size' => Piwik::translate('DBStats_EstimatedSize')
-        );
+        ));
     }
 
-    private function addPresentationFilters(&$properties, $addTotalSizeColumn = true, $addPercentColumn = false,
+    private function addPresentationFilters(ViewDataTable $view, $addTotalSizeColumn = true, $addPercentColumn = false,
                                             $sizeColumns = array('data_size', 'index_size'))
     {
         // add total_size column
@@ -282,7 +301,7 @@ class DBStats extends \Piwik\Plugin
                 return $dataSize + $indexSize;
             };
 
-            $properties['filters'][] = array('ColumnCallbackAddColumn',
+            $view->config->filters[] = array('ColumnCallbackAddColumn',
                                              array(array('data_size', 'index_size'), 'total_size', $getTotalTableSize), $isPriority = true);
 
             $sizeColumns[] = 'total_size';
@@ -290,78 +309,74 @@ class DBStats extends \Piwik\Plugin
 
         $runPrettySizeFilterBeforeGeneric = false;
 
-        $viewDataTable = empty($properties['default_view_type']) ? 'table' : $properties['default_view_type'];
-        $viewDataTable = Common::getRequestVar('viewDataTable', $viewDataTable);
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
 
-        if ($viewDataTable == 'table') {
             // add summary row only if displaying a table
-            $properties['filters'][] = array(
+            $view->config->filters[] = array(
                 'AddSummaryRow', array(0, Piwik::translate('General_Total'), 'label', false), $isPriority = true);
 
             // add percentage column if desired
             if ($addPercentColumn
                 && $addTotalSizeColumn
             ) {
-                $properties['filters'][] = array('ColumnCallbackAddColumnPercentage',
+                $view->config->filters[] = array('ColumnCallbackAddColumnPercentage',
                                                  array('percent_total', 'total_size', 'total_size', $quotientPrecision = 0,
                                                        $shouldSkipRows = false, $getDivisorFromSummaryRow = true),
                                                  $isPriority = true
                 );
 
-                $properties['filter_sort_column'] = 'percent_total';
+                $view->requestConfig->filter_sort_column = 'percent_total';
             }
-        } else if (strpos($viewDataTable, 'graph') === 0) {
+
+        } else if ($view->isViewDataTableId(Graph::ID)) {
             if ($addTotalSizeColumn) {
-                $properties['columns_to_display'] = array('label', 'total_size');
+                $view->config->columns_to_display = array('label', 'total_size');
 
                 // when displaying a graph, we force sizes to be shown as the same unit so axis labels
                 // will be readable. NOTE: The unit should depend on the smallest value of the data table,
                 // however there's no way to know this information, short of creating a custom filter. For
                 // now, just assume KB.
                 $fixedMemoryUnit = 'K';
-                $properties['y_axis_unit'] = ' K';
-
-                $properties['filter_sort_column'] = 'total_size';
-                $properties['filter_sort_order'] = 'desc';
+                $view->config->y_axis_unit = ' K';
+                $view->requestConfig->filter_sort_column = 'total_size';
+                $view->requestConfig->filter_sort_order  = 'desc';
 
                 $runPrettySizeFilterBeforeGeneric = true;
             } else {
-                $properties['columns_to_display'] = array('label', 'row_count');
-                $properties['y_axis_unit'] = ' ' . Piwik::translate('General_Rows');
+                $view->config->columns_to_display = array('label', 'row_count');
+                $view->config->y_axis_unit        = ' ' . Piwik::translate('General_Rows');
 
-                $properties['filter_sort_column'] = 'row_count';
-                $properties['filter_sort_order'] = 'desc';
+                $view->requestConfig->filter_sort_column = 'row_count';
+                $view->requestConfig->filter_sort_order  = 'desc';
             }
         }
 
         $getPrettySize = array('\Piwik\MetricsFormatter', 'getPrettySizeFromBytes');
-        $params = !isset($fixedMemoryUnit) ? array() : array($fixedMemoryUnit);
-        $properties['filters'][] = array(
-            'ColumnCallbackReplace', array($sizeColumns, $getPrettySize, $params), $runPrettySizeFilterBeforeGeneric);
+        $params        = !isset($fixedMemoryUnit) ? array() : array($fixedMemoryUnit);
+
+        $view->config->filters[] = array('ColumnCallbackReplace', array($sizeColumns, $getPrettySize, $params), $runPrettySizeFilterBeforeGeneric);
 
         // jqPlot will display &nbsp; as, well, '&nbsp;', so don't replace the spaces when rendering as a graph
-        if ($viewDataTable == 'table') {
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
             $replaceSpaces = function ($value) {
                 return str_replace(' ', '&nbsp;', $value);
             };
 
-            $properties['filters'][] = array('ColumnCallbackReplace', array($sizeColumns, $replaceSpaces));
+            $view->config->filters[] = array('ColumnCallbackReplace', array($sizeColumns, $replaceSpaces));
         }
 
         $getPrettyNumber = array('\Piwik\MetricsFormatter', 'getPrettyNumber');
-        $properties['filters'][] = array('ColumnCallbackReplace', array('row_count', $getPrettyNumber));
-
-        return $viewDataTable;
+        $view->config->filters[] = array('ColumnCallbackReplace', array('row_count', $getPrettyNumber));
     }
 
     /**
      * Sets the footer message for the Individual...Summary reports.
      */
-    private function setIndividualSummaryFooterMessage($result)
+    private function setIndividualSummaryFooterMessage(ViewDataTable $view)
     {
         $lastGenerated = self::getDateOfLastCachingRun();
         if ($lastGenerated !== false) {
-            $result['show_footer_message'] = Piwik::translate('Mobile_LastUpdated', $lastGenerated);
+            $view->config->show_footer_message = Piwik::translate('Mobile_LastUpdated', $lastGenerated);
         }
     }
 }
diff --git a/plugins/DevicesDetection/DevicesDetection.php b/plugins/DevicesDetection/DevicesDetection.php
index 1fdbb01613c099f2492dfce3b77ddc304bcbc43c..0fb275341e7cdf75cc79de14c73eeb789b67f694 100644
--- a/plugins/DevicesDetection/DevicesDetection.php
+++ b/plugins/DevicesDetection/DevicesDetection.php
@@ -19,6 +19,7 @@ use Piwik\Config;
 use Piwik\Db;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
 use Piwik\WidgetsList;
 use UserAgentParserEnhanced;
 
@@ -90,14 +91,14 @@ class DevicesDetection extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         return array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'Tracker.newVisitorInformation'            => 'parseMobileVisitData',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'    => 'archiveDay',
+            'ArchiveProcessor.Period.compute' => 'archivePeriod',
+            'Menu.Reporting.addItems'         => 'addMenu',
+            'Tracker.newVisitorInformation'   => 'parseMobileVisitData',
+            'WidgetsList.addWidgets'          => 'addWidgets',
+            'API.getReportMetadata'           => 'getReportMetadata',
+            'API.getSegmentsMetadata'         => 'getSegmentsMetadata',
+            'ViewDataTable.configure'         => 'configureViewDataTable',
         );
     }
 
@@ -293,85 +294,87 @@ class DevicesDetection extends \Piwik\Plugin
         MenuMain::getInstance()->add('General_Visitors', 'DevicesDetection_submenu', array('module' => 'DevicesDetection', 'action' => 'index'));
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['DevicesDetection.getType'] = $this->getDisplayPropertiesForGetType();
-        $properties['DevicesDetection.getBrand'] = $this->getDisplayPropertiesForGetBrand();
-        $properties['DevicesDetection.getModel'] = $this->getDisplayPropertiesForGetModel();
-        $properties['DevicesDetection.getOsFamilies'] = $this->getDisplayPropertiesForGetOsFamilies();
-        $properties['DevicesDetection.getOsVersions'] = $this->getDisplayPropertiesForGetOsVersions();
-        $properties['DevicesDetection.getBrowserFamilies'] = $this->getDisplayPropertiesForGetBrowserFamilies();
-        $properties['DevicesDetection.getBrowserVersions'] = $this->getDisplayPropertiesForGetBrowserVersions();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'DevicesDetection.getType':
+                $this->configureViewForGetType($view);
+                break;
+            case 'DevicesDetection.getBrand':
+                $this->configureViewForGetBrand($view);
+                break;
+            case 'DevicesDetection.getModel':
+                $this->configureViewForGetModel($view);
+                break;
+            case 'DevicesDetection.getOsFamilies':
+                $this->configureViewForGetOsFamilies($view);
+                break;
+            case 'DevicesDetection.getOsVersions':
+                $this->configureViewForGetOsVersions($view);
+                break;
+            case 'DevicesDetection.getBrowserFamilies':
+                $this->configureViewForGetBrowserFamilies($view);
+                break;
+            case 'DevicesDetection.getBrowserVersions':
+                $this->configureViewForGetBrowserVersions($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetType()
+    private function configureViewForGetType(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelTypes"))
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelTypes"));
     }
 
-    private function getDisplayPropertiesForGetBrand()
+    private function configureViewForGetBrand(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelBrands"))
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelBrands"));
     }
 
-    private function getDisplayPropertiesForGetModel()
+    private function configureViewForGetModel(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelModels"))
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelModels"));
     }
 
-    private function getDisplayPropertiesForGetOsFamilies()
+    private function configureViewForGetOsFamilies(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelSystemFamily")),
-            'title'                       => Piwik::translate('DevicesDetection_OperatingSystemFamilies'),
-            'related_reports'             => $this->getOsRelatedReports()
-        );
+        $view->config->title = Piwik::translate('DevicesDetection_OperatingSystemFamilies');
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelSystemFamily"));
+        $view->config->addRelatedReports($this->getOsRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetOsVersions()
+    private function configureViewForGetOsVersions(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelSystemVersion")),
-            'title'                       => Piwik::translate('DevicesDetection_OperatingSystemVersions'),
-            'related_reports'             => $this->getOsRelatedReports()
-        );
+        $view->config->title = Piwik::translate('DevicesDetection_OperatingSystemVersions');
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelSystemVersion"));
+        $view->config->addRelatedReports($this->getOsRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetBrowserFamilies()
+    private function configureViewForGetBrowserFamilies(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelBrowserFamily")),
-            'title'                       => Piwik::translate('DevicesDetection_BrowsersFamily'),
-            'related_reports'             => $this->getBrowserRelatedReports()
-        );
+        $view->config->title = Piwik::translate('DevicesDetection_BrowsersFamily');
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelBrowserFamily"));
+        $view->config->addRelatedReports($this->getBrowserRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetBrowserVersions()
+    private function configureViewForGetBrowserVersions(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate("DevicesDetection_dataTableLabelBrowserVersion")),
-            'related_reports'             => $this->getBrowserRelatedReports()
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate("DevicesDetection_dataTableLabelBrowserVersion"));
+        $view->config->addRelatedReports($this->getBrowserRelatedReports());
     }
 
     private function getOsRelatedReports()
diff --git a/plugins/ExampleUI/Controller.php b/plugins/ExampleUI/Controller.php
index f4dd86c6fb6f150c504e7f754be186bea856e179..46d2627a3c51f863a0f377baa148c80d6bf224e3 100644
--- a/plugins/ExampleUI/Controller.php
+++ b/plugins/ExampleUI/Controller.php
@@ -52,7 +52,7 @@ class Controller extends \Piwik\Plugin\Controller
 
         $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
             $selectableColumns = array('server1', 'server2'), 'My documentation', 'ExampleUI.getTemperaturesEvolution');
-        $view->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_column = 'label';
 
         return $this->renderView($view, $fetch);
     }
@@ -62,11 +62,11 @@ class Controller extends \Piwik\Plugin\Controller
         $view = ViewDataTable::factory(
             'graphVerticalBar', 'ExampleUI.getTemperatures', $controllerAction = 'ExampleUI.barGraph');
 
-        $view->y_axis_unit = '°C';
-        $view->show_footer = false;
-        $view->translations['value'] = "Temperature";
-        $view->visualization_properties->selectable_columns = array("value");
-        $view->visualization_properties->max_graph_elements = 24;
+        $view->config->y_axis_unit = '°C';
+        $view->config->show_footer = false;
+        $view->config->translations['value'] = "Temperature";
+        $view->config->selectable_columns = array("value");
+        $view->config->max_graph_elements = 24;
 
         echo $view->render();
     }
@@ -76,11 +76,11 @@ class Controller extends \Piwik\Plugin\Controller
         $view = ViewDataTable::factory(
             'graphPie', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.pieGraph');
 
-        $view->columns_to_display = array('value');
-        $view->translations['value'] = "times the diameter of Earth";
-        $view->show_footer_icons = false;
-        $view->visualization_properties->selectable_columns = array("value");
-        $view->visualization_properties->max_graph_elements = 10;
+        $view->config->columns_to_display = array('value');
+        $view->config->translations['value'] = "times the diameter of Earth";
+        $view->config->show_footer_icons = false;
+        $view->config->selectable_columns = array("value");
+        $view->config->max_graph_elements = 10;
 
         echo $view->render();
     }
@@ -103,9 +103,9 @@ class Controller extends \Piwik\Plugin\Controller
         $view = ViewDataTable::factory(
             'cloud', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.echoSimpleTagClouds');
 
-        $view->columns_to_display = array('label', 'value');
-        $view->translations['value'] = "times the diameter of Earth";
-        $view->show_footer = false;
+        $view->config->columns_to_display = array('label', 'value');
+        $view->config->translations['value'] = "times the diameter of Earth";
+        $view->config->show_footer = false;
 
         echo $view->render();
     }
@@ -115,13 +115,9 @@ class Controller extends \Piwik\Plugin\Controller
         $view = ViewDataTable::factory(
             'cloud', 'ExampleUI.getPlanetRatiosWithLogos', $controllerAction = 'ExampleUI.echoAdvancedTagClouds');
 
-        $view->visualization_properties->setForVisualization(
-            'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\Cloud',
-            'display_logo_instead_of_label',
-            true
-        );
-        $view->columns_to_display = array('label', 'value');
-        $view->translations['value'] = "times the diameter of Earth";
+        $view->config->display_logo_instead_of_label = true;
+        $view->config->columns_to_display = array('label', 'value');
+        $view->config->translations['value'] = "times the diameter of Earth";
 
         echo $view->render();
     }
@@ -142,7 +138,7 @@ class Controller extends \Piwik\Plugin\Controller
 
         $serverRequested = Common::getRequestVar('server', false);
         if (false !== $serverRequested) {
-            $view->columns_to_display = array($serverRequested);
+            $view->config->columns_to_display = array($serverRequested);
         }
 
         echo $view->render();
diff --git a/plugins/ExampleUI/CustomDataTable.php b/plugins/ExampleUI/CustomDataTable.php
index bfda92a70422808dd50e8c42cf2b8a5fd66c2ebd..3f8b780a81692abbd6b812fe3bd0128a06c580a6 100644
--- a/plugins/ExampleUI/CustomDataTable.php
+++ b/plugins/ExampleUI/CustomDataTable.php
@@ -20,24 +20,17 @@ class CustomDataTable
     {
         $view = ViewDataTable::factory('table', $apiAction, $controllerAction);
 
-        $view->translations['value'] = $value;
-        $view->translations['label'] = $label;
-        $view->filter_sort_column = 'label';
-        $view->filter_sort_order = 'asc';
-        $view->filter_limit = 24;
-        $view->y_axis_unit = '°C'; // useful if the user requests the bar graph
-        $view->show_exclude_low_population = false;
-        $view->show_table_all_columns = false;
-        $view->visualization_properties->setForVisualization(
-            'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable',
-            'disable_row_evolution',
-            true
-        );
-        $view->visualization_properties->setForVisualization(
-            'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph',
-            'max_graph_elements',
-            24
-        );
+        $view->config->translations['value'] = $value;
+        $view->config->translations['label'] = $label;
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order = 'asc';
+        $view->requestConfig->filter_limit = 24;
+        $view->config->columns_to_display = array('label', 'value');
+        $view->config->y_axis_unit = '°C'; // useful if the user requests the bar graph
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_table_all_columns = false;
+        $view->config->disable_row_evolution = true;
+        $view->config->max_graph_elements = 24;
 
         return $view->render();
     }
diff --git a/plugins/ExampleVisualization/SimpleTable.php b/plugins/ExampleVisualization/SimpleTable.php
index abd5c8aff2030d7fecbfd93bcbbadde64ada3807..6b70c1fdc5ddfa1f14315c7b01cff7fe8a186bdd 100644
--- a/plugins/ExampleVisualization/SimpleTable.php
+++ b/plugins/ExampleVisualization/SimpleTable.php
@@ -12,58 +12,52 @@
 namespace Piwik\Plugins\ExampleVisualization;
 
 use Piwik\DataTable;
-use Piwik\DataTable\DataTableInterface;
-use Piwik\ViewDataTable\Visualization;
-use Piwik\Visualization\Config;
-use Piwik\Visualization\Request;
+use Piwik\Plugin\Visualization;
 
 /**
  * SimpleTable Visualization.
  */
 class SimpleTable extends Visualization
 {
+    const ID = 'simpleTable';
     const TEMPLATE_FILE     = '@ExampleVisualization/simpleTable.twig';
     const FOOTER_ICON_TITLE = 'Simple Table';
     const FOOTER_ICON       = 'plugins/ExampleVisualization/images/table.png';
 
-    /**
-     * You do not have to implement the init method. It is just an example how to assign view variables.
-     */
-    public function init()
-    {
-        $this->vizTitle = 'MyAwesomeTitle';
-    }
-
-    public function configureVisualization(Config $properties)
-    {
-        // Configure how your visualization should look like, for instance you can disable search
-        // $properties->show_search = false
-    }
-
-    public function beforeLoadDataTable(Request $request, Config $properties)
+    public function beforeLoadDataTable()
     {
         // Here you can change the request that is sent to the API, for instance
-        // $properties->filter_sort_order = 'desc';
+        // $this->requestConfig->filter_sort_order = 'desc';
     }
 
-    public function beforeGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function beforeGenericFiltersAreAppliedToLoadedDataTable()
     {
         // this hook is executed before generic filters like "filter_limit" and "filter_offset" are applied
         // Usage:
-        // $dateTable->filter($nameOrClosure);
+        // $this->dateTable->filter($nameOrClosure);
     }
 
-    public function afterGenericFiltersAreAppliedToLoadedDataTable(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function afterGenericFiltersAreAppliedToLoadedDataTable()
     {
         // this hook is executed after generic filters like "filter_limit" and "filter_offset" are applied
         // Usage:
-        // $dateTable->filter($nameOrClosure, $parameters);
+        // $this->dateTable->filter($nameOrClosure, $parameters);
     }
 
-    public function afterAllFilteresAreApplied(DataTableInterface $dataTable, Config $properties, Request $request)
+    public function afterAllFilteresAreApplied()
     {
         // this hook is executed after the data table is loaded and after all filteres are applied.
         // format your data here that you want to pass to the view
-        // $this->myCustomViewVariable = $dataTable->getRows();
+
+        $this->assignTemplateVar('vizTitle', 'MyAwesomeTitle');
+    }
+
+    public function beforeRender()
+    {
+        // Configure how your visualization should look like, for instance you can disable search
+        // By defining the config properties shortly before rendering you make sure the config properties have a certain
+        // value because they could be changed by a report or by request parameters ($_GET / $_POST) before.
+        // $this->config->show_search = false
     }
+
 }
\ No newline at end of file
diff --git a/plugins/ExampleVisualization/templates/simpleTable.twig b/plugins/ExampleVisualization/templates/simpleTable.twig
index 6cb0fdadd86492106163f9803c83dafca094b594..6b0748711d2216436d68faa5cda83aace5a303cf 100644
--- a/plugins/ExampleVisualization/templates/simpleTable.twig
+++ b/plugins/ExampleVisualization/templates/simpleTable.twig
@@ -4,7 +4,7 @@
     <table class="dataTable">
         <thead>
             <tr>
-                {% for name,value in dataTable.getFirstRow.getColumns %}
+                {% for name in properties.columns_to_display %}
                     {% if name in properties.translations|keys %}
                         <th>{{ properties.translations[name]|translate }}</th>
                     {% else %}
@@ -16,8 +16,8 @@
         <tbody>
             {% for tableRow in dataTable.getRows %}
             <tr>
-                {% for column in tableRow.getColumns %}
-                    <td>{{ column|truncate(50)|raw }}</td>
+                {% for column in properties.columns_to_display %}
+                    <td>{{ tableRow.getColumn(column)|default('-')|truncate(50)|raw }}</td>
                 {% endfor %}
             </tr>
             {% endfor %}
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
index 752edf55804f855d82176db6d7e35c3c31a4d855..87ea5ed1582a2e1cd9cae9033d24ef89f0986ea2 100644
--- a/plugins/Goals/Controller.php
+++ b/plugins/Goals/Controller.php
@@ -255,7 +255,7 @@ class Controller extends \Piwik\Plugin\Controller
             $idGoal = Common::getRequestVar('idGoal', false, 'string');
         }
         $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.get');
-        $view->request_parameters_to_modify['idGoal'] = $idGoal;
+        $view->requestConfig->request_parameters_to_modify['idGoal'] = $idGoal;
 
         $nameToLabel = $this->goalColumnNameToLabel;
         if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
@@ -287,13 +287,13 @@ class Controller extends \Piwik\Plugin\Controller
                 $goalName = $this->goals[$idGoal]['name'];
                 $columnTranslation = "$columnTranslation (" . Piwik::translate('Goals_GoalX', "$goalName") . ")";
             }
-            $view->translations[$columnName] = $columnTranslation;
+            $view->config->translations[$columnName] = $columnTranslation;
         }
-        $view->columns_to_display = $columns;
-        $view->visualization_properties->selectable_columns = $selectableColumns;
+        $view->config->columns_to_display = $columns;
+        $view->config->selectable_columns = $selectableColumns;
 
         $langString = $idGoal ? 'Goals_SingleGoalOverviewDocumentation' : 'Goals_GoalsOverviewDocumentation';
-        $view->documentation = Piwik::translate($langString, '<br />');
+        $view->config->documentation = Piwik::translate($langString, '<br />');
 
         return $this->renderView($view, $fetch);
     }
diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php
index 1d60a52966fddb8cd818672ca0e6241abc09b405..31db9f742e00a63003c4aca4c2fa29bfc545c592 100644
--- a/plugins/Goals/Goals.php
+++ b/plugins/Goals/Goals.php
@@ -16,6 +16,7 @@ use Piwik\Common;
 use Piwik\Db;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
 use Piwik\Site;
 use Piwik\Tracker\GoalManager;
 use Piwik\Translate;
@@ -88,23 +89,29 @@ class Goals extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'AssetManager.getJavaScriptFiles'          => 'getJsFiles',
-            'AssetManager.getStylesheetFiles'          => 'getStylesheetFiles',
-            'Site.getSiteAttributes'                   => 'fetchGoalsFromDb',
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'API.getReportMetadata.end'                => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenus',
-            'SitesManager.deleteSite.end'              => 'deleteSiteGoals',
-            'Goals.getReportsWithGoalMetrics'          => 'getActualReportsWithGoalMetrics',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
-            'Translate.getClientSideTranslationKeys'   => 'getClientSideTranslationKeys'
+            'AssetManager.getJavaScriptFiles'        => 'getJsFiles',
+            'AssetManager.getStylesheetFiles'        => 'getStylesheetFiles',
+            'Site.getSiteAttributes'                 => 'fetchGoalsFromDb',
+            'ArchiveProcessor.Day.compute'           => 'archiveDay',
+            'ArchiveProcessor.Period.compute'        => 'archivePeriod',
+            'API.getReportMetadata.end'              => 'getReportMetadata',
+            'API.getSegmentsMetadata'                => 'getSegmentsMetadata',
+            'WidgetsList.addWidgets'                 => 'addWidgets',
+            'Menu.Reporting.addItems'                => 'addMenus',
+            'SitesManager.deleteSite.end'            => 'deleteSiteGoals',
+            'Goals.getReportsWithGoalMetrics'        => 'getActualReportsWithGoalMetrics',
+            'ViewDataTable.configure'                => 'configureViewDataTable',
+            'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+            'Visualization.addVisualizations'        => 'getAvailableDataTableVisualizations'
         );
         return $hooks;
     }
 
+    public function getAvailableDataTableVisualizations(&$visualizations)
+    {
+        $visualizations[] = 'Piwik\\Plugins\\Goals\\Visualizations\\Goals';
+    }
+
     /**
      * Delete goals recorded for this site
      */
@@ -518,71 +525,83 @@ class Goals extends \Piwik\Plugin
         }
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['Goals.getItemsSku'] = $this->getDisplayPropertiesForGetItemsSku();
-        $properties['Goals.getItemsName'] = $this->getDisplayPropertiesForGetItemsName();
-        $properties['Goals.getItemsCategory'] = $this->getDisplayPropertiesForGetItemsCategory();
-        $properties['Goals.getVisitsUntilConversion'] = $this->getDisplayPropertiesForGetVisitsUntilConversion();
-        $properties['Goals.getDaysToConversion'] = $this->getDisplayPropertiesForGetDaysToConversion();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'Goals.getItemsSku':
+                $this->configureViewForGetItemsSku($view);
+                break;
+            case 'Goals.getItemsName':
+                $this->configureViewForGetItemsName($view);
+                break;
+            case 'Goals.getItemsCategory':
+                $this->configureViewForGetItemsCategory($view);
+                break;
+            case 'Goals.getVisitsUntilConversion':
+                $this->configureViewForGetVisitsUntilConversion($view);
+                break;
+            case 'Goals.getDaysToConversion':
+                $this->configureViewForGetDaysToConversion($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetItemsSku()
+    private function configureViewForGetItemsSku(ViewDataTable $view)
     {
-        return $this->getDisplayPropertiesForItemsReport(Piwik::translate('Goals_ProductSKU'));
+        return $this->configureViewForItemsReport($view, Piwik::translate('Goals_ProductSKU'));
     }
 
-    private function getDisplayPropertiesForGetItemsName()
+    private function configureViewForGetItemsName(ViewDataTable $view)
     {
-        return $this->getDisplayPropertiesForItemsReport(Piwik::translate('Goals_ProductName'));
+        return $this->configureViewForItemsReport($view, Piwik::translate('Goals_ProductName'));
     }
 
-    private function getDisplayPropertiesForGetItemsCategory()
+    private function configureViewForGetItemsCategory(ViewDataTable $view)
     {
-        return $this->getDisplayPropertiesForItemsReport(Piwik::translate('Goals_ProductCategory'));
+        return $this->configureViewForItemsReport($view, Piwik::translate('Goals_ProductCategory'));
     }
 
-    private function getDisplayPropertiesForGetVisitsUntilConversion()
+    private function configureViewForGetVisitsUntilConversion(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'show_table_all_columns'      => false,
-            'columns_to_display'          => array('label', 'nb_conversions'),
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'translations'                => array(
-                'label'          => Piwik::translate('Goals_VisitsUntilConv'),
-                'nb_conversions' => Piwik::translate('Goals_ColumnConversions'),
-            ),
-            'filter_limit'                => count(Archiver::$visitCountRanges),
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_all_views_icons'        => false
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_table_all_columns  = false;
+        $view->config->columns_to_display      = array('label', 'nb_conversions');
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_all_views_icons    = false;
+
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order  = 'asc';
+        $view->requestConfig->filter_limit       = count(Archiver::$visitCountRanges);
+
+        $view->config->addTranslations(array(
+            'label'          => Piwik::translate('Goals_VisitsUntilConv'),
+            'nb_conversions' => Piwik::translate('Goals_ColumnConversions'),
+        ));
     }
 
-    private function getDisplayPropertiesForGetDaysToConversion()
+    private function configureViewForGetDaysToConversion(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'show_table_all_columns'      => false,
-            'columns_to_display'          => array('label', 'nb_conversions'),
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'translations'                => array(
-                'label'          => Piwik::translate('Goals_DaysToConv'),
-                'nb_conversions' => Piwik::translate('Goals_ColumnConversions'),
-            ),
-            'filter_limit'                => count(Archiver::$daysToConvRanges),
-            'show_all_views_icons'        => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_table_all_columns  = false;
+        $view->config->show_all_views_icons    = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->columns_to_display      = array('label', 'nb_conversions');
+
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order  = 'asc';
+        $view->requestConfig->filter_limit       = count(Archiver::$daysToConvRanges);
+
+        $view->config->addTranslations(array(
+            'label'          => Piwik::translate('Goals_DaysToConv'),
+            'nb_conversions' => Piwik::translate('Goals_ColumnConversions'),
+        ));
     }
 
-    private function getDisplayPropertiesForItemsReport($label)
+    private function configureViewForItemsReport(ViewDataTable $view, $label)
     {
         $idSite = Common::getRequestVar('idSite');
 
@@ -590,18 +609,17 @@ class Goals extends \Piwik\Plugin
         $prettifyMoneyColumns = array(
             'ColumnCallbackReplace', array($moneyColumns, '\Piwik\MetricsFormatter::getPrettyMoney', array($idSite)));
 
-        $result = array(
-            'show_ecommerce'              => true,
-            'show_all_views_icons'        => false,
-            'show_table'                  => false,
-            'show_exclude_low_population' => false,
-            'show_table_all_columns'      => false,
-            'filter_limit'                => 10,
-            'translations'                => array('label' => $label),
-            'filter_sort_column'          => 'revenue',
-            'filter_sort_order'           => 'desc',
-            'filters'                     => array($prettifyMoneyColumns)
-        );
+        $view->config->show_ecommerce = true;
+        $view->config->show_table     = false;
+        $view->config->show_all_views_icons        = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_table_all_columns      = false;
+        $view->config->addTranslation('label', $label);
+        $view->config->filters[] = $prettifyMoneyColumns;
+
+        $view->requestConfig->filter_limit       = 10;
+        $view->requestConfig->filter_sort_column = 'revenue';
+        $view->requestConfig->filter_sort_order  = 'desc';
 
         // set columns/translations which differ based on viewDataTable TODO: shouldn't have to do this check... amount of reports should be dynamic, but metadata should be static
         $columns = Goals::getProductReportColumns();
@@ -615,15 +633,17 @@ class Goals extends \Piwik\Plugin
             unset($columns['orders']);
             unset($columns['conversion_rate']);
 
-            $result['request_parameters_to_modify'] = array('abandonedCarts' => '1');
+            $view->requestConfig->request_parameters_to_modify['abandonedCarts'] = '1';
         }
 
-        $result['translations'] = array_merge(array('label' => $label), $columns);
-        $result['columns_to_display'] = array_keys($result['translations']);
+        $translations = array_merge(array('label' => $label), $columns);
+
+        $view->config->addTranslations($translations);
+        $view->config->columns_to_display = array_keys($translations);
 
         // set metrics documentation in normal ecommerce report
         if (!$abandonedCart) {
-            $result['metrics_documentation'] = array(
+            $view->config->metrics_documentation = array(
                 'revenue'         => Piwik::translate('Goals_ColumnRevenueDocumentation',
                     Piwik::translate('Goals_DocumentationRevenueGeneratedByProductSales')),
                 'quantity'        => Piwik::translate('Goals_ColumnQuantityDocumentation', $label),
@@ -635,10 +655,8 @@ class Goals extends \Piwik\Plugin
             );
         }
 
-        $result['custom_parameters']['viewDataTable'] =
+        $view->config->custom_parameters['viewDataTable'] =
             $abandonedCart ? Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART : Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER;
-
-        return $result;
     }
 
 
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php b/plugins/Goals/Visualizations/Goals.php
similarity index 66%
rename from plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php
rename to plugins/Goals/Visualizations/Goals.php
index 71aec3fe2fd2b7775f7bdd9a9a83fffa222f0621..7835d8afb15cf7dcb3d0cbf8fe6a6d2205f831da 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php
+++ b/plugins/Goals/Visualizations/Goals.php
@@ -9,18 +9,16 @@
  * @package CoreVisualizations
  */
 
-namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+namespace Piwik\Plugins\Goals\Visualizations;
 
 use Piwik\Piwik;
 use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-use Piwik\Visualization\Config;
 use Piwik\Common;
 use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal;
 use Piwik\MetricsFormatter;
 use Piwik\Plugins\Goals\API as APIGoals;
 use Piwik\Site;
 use Piwik\View;
-use Piwik\ViewDataTable\Visualization;
 
 /**
  * DataTable Visualization that derives from HtmlTable and sets show_goals_columns to true.
@@ -29,63 +27,69 @@ class Goals extends HtmlTable
 {
     const ID = 'tableGoals';
 
-    public function configureVisualization(Config $properties)
+    public function beforeLoadDataTable()
     {
-        $properties->visualization_properties->show_goals_columns = true;
+        parent::beforeLoadDataTable();
 
-        $properties->datatable_css_class = 'dataTableVizGoals';
-        $properties->show_exclude_low_population = true;
-        $properties->show_goals = true;
+        if (!$this->config->disable_subtable_when_show_goals) {
+            $this->config->subtable_controller_action = null;
+        }
+
+        $this->setShowGoalsColumnsProperties();
+    }
 
-        $properties->translations += array(
+    public function beforeRender()
+    {
+        $this->config->show_goals = true;
+        $this->config->show_goals_columns  = true;
+        $this->config->datatable_css_class = 'dataTableVizGoals';
+        $this->config->show_exclude_low_population = true;
+
+        $this->config->translations += array(
             'nb_conversions'    => Piwik::translate('Goals_ColumnConversions'),
             'conversion_rate'   => Piwik::translate('General_ColumnConversionRate'),
             'revenue'           => Piwik::translate('General_ColumnRevenue'),
             'revenue_per_visit' => Piwik::translate('General_ColumnValuePerVisit'),
         );
-        $properties->metrics_documentation['nb_visits'] = Piwik::translate('Goals_ColumnVisits');
 
-        if (Common::getRequestVar('documentationForGoalsPage', 0, 'int') == 1) { // TODO: should not use query parameter
-            $properties->documentation = Piwik::translate('Goals_ConversionByTypeReportDocumentation',
-                array('<br />', '<br />', '<a href="http://piwik.org/docs/tracking-goals-web-analytics/" target="_blank">', '</a>'));
-        }
+        $this->config->metrics_documentation['nb_visits'] = Piwik::translate('Goals_ColumnVisits');
 
-        if (!$properties->visualization_properties->disable_subtable_when_show_goals) {
-            $properties->subtable_controller_action = null;
+        if (1 == Common::getRequestVar('documentationForGoalsPage', 0, 'int')) {
+            // TODO: should not use query parameter
+            $this->config->documentation = Piwik::translate('Goals_ConversionByTypeReportDocumentation',
+                array('<br />', '<br />', '<a href="http://piwik.org/docs/tracking-goals-web-analytics/" target="_blank">', '</a>'));
         }
 
-        $this->setShowGoalsColumnsProperties();
-
-        parent::configureVisualization($properties);
+        parent::beforeRender();
     }
 
     private function setShowGoalsColumnsProperties()
     {
-        $view = $this->viewDataTable;
-
         // set view properties based on goal requested
         $idSite = Common::getRequestVar('idSite', null, 'int');
         $idGoal = Common::getRequestVar('idGoal', AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW, 'string');
-        if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
-            $this->setPropertiesForEcommerceView($view);
-        } else if ($idGoal == AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE) {
-            $this->setPropertiesForGoals($view, $idSite, 'all');
-        } else if ($idGoal == AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW) {
-            $this->setPropertiesForGoalsOverview($view, $idSite);
+
+        if (Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER == $idGoal) {
+            $this->setPropertiesForEcommerceView();
+        } else if (AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE == $idGoal) {
+            $this->setPropertiesForGoals($idSite, 'all');
+        } else if (AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW == $idGoal) {
+            $this->setPropertiesForGoalsOverview($idSite);
         } else {
-            $this->setPropertiesForGoals($view, $idSite, array($idGoal));
+            $this->setPropertiesForGoals($idSite, array($idGoal));
         }
 
         // add goals columns
-        $view->filters[] = array('AddColumnsProcessedMetricsGoal', array($ignore = true, $idGoal), $priority = true);
+        $this->config->filters[] = array('AddColumnsProcessedMetricsGoal', array($ignore = true, $idGoal), $priority = true);
 
         // prettify columns
         $setRatePercent = function ($rate, $thang = false) {
             return $rate == 0 ? "0%" : $rate;
         };
-        foreach ($view->columns_to_display as $columnName) {
-            if (strpos($columnName, 'conversion_rate') !== false) {
-                $view->filters[] = array('ColumnCallbackReplace', array($columnName, $setRatePercent));
+
+        foreach ($this->config->columns_to_display as $columnName) {
+            if (false !== strpos($columnName, 'conversion_rate')) {
+                $this->config->filters[] = array('ColumnCallbackReplace', array($columnName, $setRatePercent));
             }
         }
 
@@ -93,9 +97,9 @@ class Goals extends HtmlTable
             return MetricsFormatter::getPrettyMoney(sprintf("%.1f", $value), $idSite);
         };
 
-        foreach ($view->columns_to_display as $columnName) {
+        foreach ($this->config->columns_to_display as $columnName) {
             if ($this->isRevenueColumn($columnName)) {
-                $view->filters[] = array('ColumnCallbackReplace', array($columnName, $formatPercent));
+                $this->config->filters[] = array('ColumnCallbackReplace', array($columnName, $formatPercent));
             }
         }
 
@@ -103,25 +107,26 @@ class Goals extends HtmlTable
         $identityFunction = function ($value) {
             return $value;
         };
-        foreach ($view->columns_to_display as $columnName) {
+
+        foreach ($this->config->columns_to_display as $columnName) {
             if (!$this->isRevenueColumn($columnName)) {
-                $view->filters[] = array('ColumnCallbackReplace', array($columnName, $identityFunction));
+                $this->config->filters[] = array('ColumnCallbackReplace', array($columnName, $identityFunction));
             }
         }
     }
 
-    private function setPropertiesForEcommerceView($view)
+    private function setPropertiesForEcommerceView()
     {
-        $view->filter_sort_column = 'goal_ecommerceOrder_revenue';
-        $view->filter_sort_order = 'desc';
+        $this->requestConfig->filter_sort_column = 'goal_ecommerceOrder_revenue';
+        $this->requestConfig->filter_sort_order = 'desc';
 
-        $view->columns_to_display = array(
+        $this->config->columns_to_display = array(
             'label', 'nb_visits', 'goal_ecommerceOrder_nb_conversions', 'goal_ecommerceOrder_revenue',
             'goal_ecommerceOrder_conversion_rate', 'goal_ecommerceOrder_avg_order_revenue', 'goal_ecommerceOrder_items',
             'goal_ecommerceOrder_revenue_per_visit'
         );
 
-        $view->translations += array(
+        $this->config->translations += array(
             'goal_ecommerceOrder_conversion_rate'   => Piwik::translate('Goals_ConversionRate', Piwik::translate('Goals_EcommerceOrder')),
             'goal_ecommerceOrder_nb_conversions'    => Piwik::translate('General_EcommerceOrders'),
             'goal_ecommerceOrder_revenue'           => Piwik::translate('General_TotalRevenue'),
@@ -131,7 +136,7 @@ class Goals extends HtmlTable
         );
 
         $goalName = Piwik::translate('General_EcommerceOrders');
-        $view->metrics_documentation += array(
+        $this->config->metrics_documentation += array(
             'goal_ecommerceOrder_conversion_rate'   => Piwik::translate('Goals_ColumnConversionRateDocumentation', $goalName),
             'goal_ecommerceOrder_nb_conversions'    => Piwik::translate('Goals_ColumnConversionsDocumentation', $goalName),
             'goal_ecommerceOrder_revenue'           => Piwik::translate('Goals_ColumnRevenueDocumentation', $goalName),
@@ -142,40 +147,40 @@ class Goals extends HtmlTable
         );
     }
 
-    private function setPropertiesForGoalsOverview($view, $idSite)
+    private function setPropertiesForGoalsOverview($idSite)
     {
         $allGoals = $this->getGoals($idSite);
 
         // set view properties
-        $view->columns_to_display = array('label', 'nb_visits');
+        $this->config->columns_to_display = array('label', 'nb_visits');
 
         foreach ($allGoals as $goal) {
-            $column = "goal_{$goal['idgoal']}_conversion_rate";
+            $column        = "goal_{$goal['idgoal']}_conversion_rate";
+            $documentation = Piwik::translate('Goals_ColumnConversionRateDocumentation', $goal['quoted_name'] ? : $goal['name']);
 
-            $view->columns_to_display[] = $column;
-            $view->translations[$column] = Piwik::translate('Goals_ConversionRate', $goal['name']);
-            $view->metrics_documentation[$column]
-                = Piwik::translate('Goals_ColumnConversionRateDocumentation', $goal['quoted_name'] ? : $goal['name']);
+            $this->config->columns_to_display[]  = $column;
+            $this->config->translations[$column] = Piwik::translate('Goals_ConversionRate', $goal['name']);
+            $this->config->metrics_documentation[$column] = $documentation;
         }
 
-        $view->columns_to_display[] = 'revenue_per_visit';
-        $view->metrics_documentation['revenue_per_visit'] =
+        $this->config->columns_to_display[] = 'revenue_per_visit';
+        $this->config->metrics_documentation['revenue_per_visit'] =
             Piwik::translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik::translate('Goals_EcommerceAndGoalsMenu'));
     }
 
-    private function setPropertiesForGoals($view, $idSite, $idGoals)
+    private function setPropertiesForGoals($idSite, $idGoals)
     {
         $allGoals = $this->getGoals($idSite);
 
-        if ($idGoals == 'all') {
+        if ('all' == $idGoals) {
             $idGoals = array_keys($allGoals);
         } else {
             // only sort by a goal's conversions if not showing all goals (for FULL_REPORT)
-            $view->filter_sort_column = 'goal_' . reset($idGoals) . '_nb_conversions';
-            $view->filter_sort_order = 'desc';
+            $this->requestConfig->filter_sort_column = 'goal_' . reset($idGoals) . '_nb_conversions';
+            $this->requestConfig->filter_sort_order  = 'desc';
         }
 
-        $view->columns_to_display = array('label', 'nb_visits');
+        $this->config->columns_to_display = array('label', 'nb_visits');
 
         $goalColumnTemplates = array(
             'goal_%s_nb_conversions',
@@ -188,8 +193,7 @@ class Goals extends HtmlTable
         // ie, goal_0_nb_conversions, goal_1_nb_conversions, etc.)
         foreach ($goalColumnTemplates as $idx => $columnTemplate) {
             foreach ($idGoals as $idGoal) {
-                $column = sprintf($columnTemplate, $idGoal);
-                $view->columns_to_display[] = $column;
+                $this->config->columns_to_display[] = sprintf($columnTemplate, $idGoal);
             }
         }
 
@@ -198,7 +202,7 @@ class Goals extends HtmlTable
             $goalName = $allGoals[$idGoal]['name'];
             $quotedGoalName = $allGoals[$idGoal]['quoted_name'] ? : $goalName;
 
-            $view->translations += array(
+            $this->config->translations += array(
                 'goal_' . $idGoal . '_nb_conversions'    => Piwik::translate('Goals_Conversions', $goalName),
                 'goal_' . $idGoal . '_conversion_rate'   => Piwik::translate('Goals_ConversionRate', $goalName),
                 'goal_' . $idGoal . '_revenue'           =>
@@ -207,7 +211,7 @@ class Goals extends HtmlTable
                 Piwik::translate('%s ' . Piwik::translate('General_ColumnValuePerVisit'), $goalName),
             );
 
-            $view->metrics_documentation += array(
+            $this->config->metrics_documentation += array(
                 'goal_' . $idGoal . '_nb_conversions'    => Piwik::translate('Goals_ColumnConversionsDocumentation', $quotedGoalName),
                 'goal_' . $idGoal . '_conversion_rate'   => Piwik::translate('Goals_ColumnConversionRateDocumentation', $quotedGoalName),
                 'goal_' . $idGoal . '_revenue'           => Piwik::translate('Goals_ColumnRevenueDocumentation', $quotedGoalName),
@@ -216,7 +220,7 @@ class Goals extends HtmlTable
             );
         }
 
-        $view->columns_to_display[] = 'revenue_per_visit';
+        $this->config->columns_to_display[] = 'revenue_per_visit';
     }
 
     private function getGoals($idSite)
@@ -236,6 +240,7 @@ class Goals extends HtmlTable
 
         // add the site's goals (and escape all goal names)
         $siteGoals = APIGoals::getInstance()->getGoals($idSite);
+
         foreach ($siteGoals as &$goal) {
             $goal['name'] = Common::sanitizeInputValue($goal['name']);
 
diff --git a/plugins/Live/Live.php b/plugins/Live/Live.php
index f309877ce00bfdc5e02f6dbfdf40fff85bdb8c56..53e735114e7711f854510de8a2ad4a904b2f9953 100644
--- a/plugins/Live/Live.php
+++ b/plugins/Live/Live.php
@@ -14,6 +14,8 @@ namespace Piwik\Plugins\Live;
 use Piwik\Common;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
 use Piwik\WidgetsList;
 
 /**
@@ -29,12 +31,13 @@ class Live extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         return array(
-            'AssetManager.getJavaScriptFiles'          => 'getJsFiles',
-            'AssetManager.getStylesheetFiles'          => 'getStylesheetFiles',
-            'WidgetsList.addWidgets'                   => 'addWidget',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
-            'Translate.getClientSideTranslationKeys'   => 'getClientSideTranslationKeys',
+            'AssetManager.getJavaScriptFiles'            => 'getJsFiles',
+            'AssetManager.getStylesheetFiles'            => 'getStylesheetFiles',
+            'WidgetsList.addWidgets'                     => 'addWidget',
+            'Menu.Reporting.addItems'                    => 'addMenu',
+            'ViewDataTable.configure'                    => 'configureViewDataTable',
+            'Translate.getClientSideTranslationKeys'     => 'getClientSideTranslationKeys',
+            'Visualization.getDefaultViewTypeForReports' => 'getDefaultViewTypeForReports'
         );
     }
 
@@ -73,51 +76,59 @@ class Live extends \Piwik\Plugin
         $translationKeys[] = "Live_PageRefreshed";
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['Live.getLastVisitsDetails'] = $this->getDisplayPropertiesForGetLastVisitsDetails();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'Live.getLastVisitsDetails':
+                $this->configureViewForGetLastVisitsDetails($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetLastVisitsDetails()
+    public function getDefaultViewTypeForReports(&$defaultViewTypes)
     {
-        return array(
-            'default_view_type'           => 'Piwik\\Plugins\\Live\\VisitorLog',
-            'disable_generic_filters'     => true,
-            'enable_sort'                 => false,
-            'filter_sort_column'          => 'idVisit',
-            'filter_sort_order'           => 'asc',
-            'show_search'                 => false,
-            'filter_limit'                => 20,
-            'show_offset_information'     => false,
-            'show_exclude_low_population' => false,
-            'show_all_views_icons'        => false,
-            'show_table_all_columns'      => false,
-            'show_export_as_rss_feed'     => false,
-            'documentation'               => Piwik::translate('Live_VisitorLogDocumentation', array('<br />', '<br />')),
-            'custom_parameters'           => array(
-                // set a very high row count so that the next link in the footer of the data table is always shown
-                'totalRows'         => 10000000,
-
-                'filterEcommerce'   => Common::getRequestVar('filterEcommerce', 0, 'int'),
-                'pageUrlNotDefined' => Piwik::translate('General_NotDefined', Piwik::translate('Actions_ColumnPageURL'))
-            ),
-            'footer_icons'                => array(
-                array(
-                    'class'   => 'tableAllColumnsSwitch',
-                    'buttons' => array(
-                        array(
-                            'id'    => 'Piwik\\Plugins\\Live\\VisitorLog',
-                            'title' => Piwik::translate('Live_LinkVisitorLog'),
-                            'icon'  => 'plugins/Zeitgeist/images/table.png'
-                        )
+        $defaultViewTypes['Live.getLastVisitsDetails'] = VisitorLog::ID;
+    }
+
+    private function configureViewForGetLastVisitsDetails(ViewDataTable $view)
+    {
+        $view->config->disable_generic_filters = true;
+        $view->config->enable_sort = false;
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_offset_information     = false;
+        $view->config->show_all_views_icons        = false;
+        $view->config->show_table_all_columns      = false;
+        $view->config->show_export_as_rss_feed     = false;
+
+        $view->requestConfig->filter_sort_column = 'idVisit';
+        $view->requestConfig->filter_sort_order  = 'asc';
+        $view->requestConfig->filter_limit       = 20;
+
+        $view->config->documentation = Piwik::translate('Live_VisitorLogDocumentation', array('<br />', '<br />'));
+        $view->config->custom_parameters = array(
+            // set a very high row count so that the next link in the footer of the data table is always shown
+            'totalRows'         => 10000000,
+
+            'filterEcommerce'   => Common::getRequestVar('filterEcommerce', 0, 'int'),
+            'pageUrlNotDefined' => Piwik::translate('General_NotDefined', Piwik::translate('Actions_ColumnPageURL'))
+        );
+
+        $view->config->footer_icons = array(
+            array(
+                'class'   => 'tableAllColumnsSwitch',
+                'buttons' => array(
+                    array(
+                        'id'    => 'Piwik\\Plugins\\Live\\VisitorLog',
+                        'title' => Piwik::translate('Live_LinkVisitorLog'),
+                        'icon'  => 'plugins/Zeitgeist/images/table.png'
                     )
                 )
-            ),
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_row_actions' => true,
-                )
             )
         );
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_row_actions = true;
+        }
     }
 }
\ No newline at end of file
diff --git a/plugins/Live/VisitorLog.php b/plugins/Live/VisitorLog.php
index 88b7260bbe9eb8f3fd22ba1c635423a50b139754..4fd5ffd5aa9d4d1d81e5b1f855f277c38e5eff5e 100644
--- a/plugins/Live/VisitorLog.php
+++ b/plugins/Live/VisitorLog.php
@@ -11,28 +11,31 @@
 namespace Piwik\Plugins\Live;
 
 use Piwik\View;
-use Piwik\ViewDataTable\Visualization;
-use Piwik\Visualization\Config;
+use Piwik\Plugin\Visualization;
 
 /**
  * A special DataTable visualization for the Live.getLastVisitsDetails API method.
  */
 class VisitorLog extends Visualization
 {
+    const ID = 'Piwik\\Plugins\\Live\\VisitorLog';
     const TEMPLATE_FILE = "@Live/_dataTableViz_visitorLog.twig";
 
-    static public $clientSideRequestParameters = array(
-        'filter_limit',
-        'filter_offset',
-        'filter_sort_column',
-        'filter_sort_order',
-    );
+    public function beforeLoadDataTable()
+    {
+        $this->requestConfig->addPropertiesThatShouldBeAvailableClientSide(array(
+            'filter_limit',
+            'filter_offset',
+            'filter_sort_column',
+            'filter_sort_order',
+        ));
+    }
 
     /**
      * Configure visualization.
      */
-    public function configureVisualization(Config $properties)
+    public function beforeRender()
     {
-        $properties->datatable_js_type = 'VisitorLog';
+        $this->config->datatable_js_type = 'VisitorLog';
     }
 }
\ No newline at end of file
diff --git a/plugins/PrivacyManager/PrivacyManager.php b/plugins/PrivacyManager/PrivacyManager.php
index 5b4126a768229b0203c8fbc8ded852de18b5fb01..b647eaa6e5e6eea8a52512d0626167a569a438be 100644
--- a/plugins/PrivacyManager/PrivacyManager.php
+++ b/plugins/PrivacyManager/PrivacyManager.php
@@ -17,12 +17,16 @@ use Piwik\Date;
 use Piwik\Db;
 use Piwik\Menu\MenuAdmin;
 use Piwik\Metrics;
+use Piwik\DataTable\DataTableInterface;
 
 use Piwik\Option;
+use Piwik\Period\Range;
+use Piwik\Period;
 use Piwik\Piwik;
 use Piwik\Plugins\Goals\Archiver;
 use Piwik\ScheduledTask;
 use Piwik\ScheduledTime\Daily;
+use Piwik\Site;
 use Piwik\Tracker\GoalManager;
 
 /**
@@ -36,7 +40,6 @@ require_once PIWIK_INCLUDE_PATH . '/plugins/PrivacyManager/LogDataPurger.php';
 require_once PIWIK_INCLUDE_PATH . '/plugins/PrivacyManager/ReportsPurger.php';
 
 /**
- *
  * @package PrivacyManager
  */
 class PrivacyManager extends \Piwik\Plugin
@@ -63,6 +66,63 @@ class PrivacyManager extends \Piwik\Plugin
         'delete_reports_keep_segment_reports'  => 0,
     );
 
+    /**
+     * Returns true if it is likely that the data for this report has been purged and if the
+     * user should be told about that.
+     *
+     * In order for this function to return true, the following must also be true:
+     * - The data table for this report must either be empty or not have been fetched.
+     * - The period of this report is not a multiple period.
+     * - The date of this report must be older than the delete_reports_older_than config option.
+     * @param  DataTableInterface $dataTable
+     * @return bool
+     */
+    public static function hasReportBeenPurged($dataTable)
+    {
+        $strPeriod = Common::getRequestVar('period', false);
+        $strDate   = Common::getRequestVar('date', false);
+
+        if (false !== $strPeriod
+            && false !== $strDate
+            && (is_null($dataTable)
+                || (!empty($dataTable) && $dataTable->getRowsCount() == 0))
+        ) {
+            // if range, only look at the first date
+            if ($strPeriod == 'range') {
+
+                $idSite = Common::getRequestVar('idSite', '');
+
+                if (intval($idSite) != 0) {
+                    $site     = new Site($idSite);
+                    $timezone = $site->getTimezone();
+                } else {
+                    $timezone = 'UTC';
+                }
+
+                $period     = new Range('range', $strDate, $timezone);
+                $reportDate = $period->getDateStart();
+
+            } elseif (Period::isMultiplePeriod($strDate, $strPeriod)) {
+
+                // if a multiple period, this function is irrelevant
+                return false;
+
+            }  else {
+                // otherwise, use the date as given
+                $reportDate = Date::factory($strDate);
+            }
+
+            $reportYear = $reportDate->toString('Y');
+            $reportMonth = $reportDate->toString('m');
+
+            if (static::shouldReportBePurged($reportYear, $reportMonth)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * @see Piwik_Plugin::getListHooksRegistered
      */
diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php
index 41dc2e6fffd9c664f2f8cf76a4e89f339d66c377..8537b8527fb070eec18e92e2db96e81e86ded10b 100644
--- a/plugins/Provider/Provider.php
+++ b/plugins/Provider/Provider.php
@@ -19,6 +19,7 @@ use Piwik\FrontController;
 use Piwik\IP;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
 use Piwik\WidgetsList;
 
 /**
@@ -33,14 +34,14 @@ class Provider extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'Tracker.newVisitorInformation'            => 'logProviderInfo',
-            'WidgetsList.addWidgets'                   => 'addWidget',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'    => 'archiveDay',
+            'ArchiveProcessor.Period.compute' => 'archivePeriod',
+            'Tracker.newVisitorInformation'   => 'logProviderInfo',
+            'WidgetsList.addWidgets'          => 'addWidget',
+            'Menu.Reporting.addItems'         => 'addMenu',
+            'API.getReportMetadata'           => 'getReportMetadata',
+            'API.getSegmentsMetadata'         => 'getSegmentsMetadata',
+            'ViewDataTable.configure'         => 'configureViewDataTable',
         );
         return $hooks;
     }
@@ -235,16 +236,18 @@ class Provider extends \Piwik\Plugin
         }
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['Provider.getProvider'] = $this->getDisplayPropertiesForGetProvider();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'Provider.getProvider':
+                $this->configureViewForGetProvider($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetProvider()
+    private function configureViewForGetProvider(ViewDataTable $view)
     {
-        return array(
-            'translations' => array('label' => Piwik::translate('Provider_ColumnProvider')),
-            'filter_limit' => 5
-        );
+        $view->requestConfig->filter_limit = 5;
+        $view->config->addTranslation('label', Piwik::translate('Provider_ColumnProvider'));
     }
 }
diff --git a/plugins/Referrers/Controller.php b/plugins/Referrers/Controller.php
index 2c4cfd5fb9f5094c6b9dd14bba81c7c30cc78f73..bf15aa9f74848b4302117119423d27dc66d62f9b 100644
--- a/plugins/Referrers/Controller.php
+++ b/plugins/Referrers/Controller.php
@@ -265,7 +265,7 @@ class Controller extends \Piwik\Plugin\Controller
     {
         $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Referrers.getReferrerType');
 
-        $view->visualization_properties->add_total_row = true;
+        $view->config->add_total_row = true;
 
         // configure displayed columns
         if (empty($columns)) {
@@ -273,7 +273,7 @@ class Controller extends \Piwik\Plugin\Controller
             $columns = Piwik::getArrayFromApiParameter($columns);
         }
         $columns = !is_array($columns) ? array($columns) : $columns;
-        $view->columns_to_display = $columns;
+        $view->config->columns_to_display = $columns;
 
         // configure selectable columns
         if (Common::getRequestVar('period', false) == 'day') {
@@ -281,7 +281,7 @@ class Controller extends \Piwik\Plugin\Controller
         } else {
             $selectable = array('nb_visits', 'nb_actions');
         }
-        $view->visualization_properties->selectable_columns = $selectable;
+        $view->config->selectable_columns = $selectable;
 
         // configure displayed rows
         $visibleRows = Common::getRequestVar('rows', false);
@@ -290,7 +290,7 @@ class Controller extends \Piwik\Plugin\Controller
             $visibleRows = Piwik::getArrayFromApiParameter($visibleRows);
 
             // typeReferrer is redundant if rows are defined, so make sure it's not used
-            $view->custom_parameters['typeReferrer'] = false;
+            $view->config->custom_parameters['typeReferrer'] = false;
         } else {
             // use $typeReferrer as default
             if ($typeReferrer === false) {
@@ -299,12 +299,12 @@ class Controller extends \Piwik\Plugin\Controller
             $label = self::getTranslatedReferrerTypeLabel($typeReferrer);
             $total = Piwik::translate('General_Total');
             $visibleRows = array($label, $total);
-            $view->request_parameters_to_modify['rows'] = $label . ',' . $total;
+            $view->requestConfig->request_parameters_to_modify['rows'] = $label . ',' . $total;
         }
-        $view->visualization_properties->row_picker_match_rows_by = 'label';
-        $view->visualization_properties->rows_to_display = $visibleRows;
+        $view->config->row_picker_match_rows_by = 'label';
+        $view->config->rows_to_display = $visibleRows;
 
-        $view->documentation = Piwik::translate('Referrers_EvolutionDocumentation') . '<br />'
+        $view->config->documentation = Piwik::translate('Referrers_EvolutionDocumentation') . '<br />'
             . Piwik::translate('General_BrokenDownReportDocumentation') . '<br />'
             . Piwik::translate('Referrers_EvolutionDocumentationMoreInfo', '&quot;'
                 . Piwik::translate('Referrers_DetailsByReferrerType') . '&quot;');
@@ -315,32 +315,32 @@ class Controller extends \Piwik\Plugin\Controller
     public function getLastDistinctSearchEnginesGraph($fetch = false)
     {
         $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctSearchEngines");
-        $view->translations['Referrers_distinctSearchEngines'] = ucfirst(Piwik::translate('Referrers_DistinctSearchEngines'));
-        $view->columns_to_display = array('Referrers_distinctSearchEngines');
+        $view->config->translations['Referrers_distinctSearchEngines'] = ucfirst(Piwik::translate('Referrers_DistinctSearchEngines'));
+        $view->config->columns_to_display = array('Referrers_distinctSearchEngines');
         return $this->renderView($view, $fetch);
     }
 
     public function getLastDistinctKeywordsGraph($fetch = false)
     {
         $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctKeywords");
-        $view->translations['Referrers_distinctKeywords'] = ucfirst(Piwik::translate('Referrers_DistinctKeywords'));
-        $view->columns_to_display = array('Referrers_distinctKeywords');
+        $view->config->translations['Referrers_distinctKeywords'] = ucfirst(Piwik::translate('Referrers_DistinctKeywords'));
+        $view->config->columns_to_display = array('Referrers_distinctKeywords');
         return $this->renderView($view, $fetch);
     }
 
     public function getLastDistinctWebsitesGraph($fetch = false)
     {
         $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctWebsites");
-        $view->translations['Referrers_distinctWebsites'] = ucfirst(Piwik::translate('Referrers_DistinctWebsites'));
-        $view->columns_to_display = array('Referrers_distinctWebsites');
+        $view->config->translations['Referrers_distinctWebsites'] = ucfirst(Piwik::translate('Referrers_DistinctWebsites'));
+        $view->config->columns_to_display = array('Referrers_distinctWebsites');
         return $this->renderView($view, $fetch);
     }
 
     public function getLastDistinctCampaignsGraph($fetch = false)
     {
         $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctCampaigns");
-        $view->translations['Referrers_distinctCampaigns'] = ucfirst(Piwik::translate('Referrers_DistinctCampaigns'));
-        $view->columns_to_display = array('Referrers_distinctCampaigns');
+        $view->config->translations['Referrers_distinctCampaigns'] = ucfirst(Piwik::translate('Referrers_DistinctCampaigns'));
+        $view->config->columns_to_display = array('Referrers_distinctCampaigns');
         return $this->renderView($view, $fetch);
     }
 
diff --git a/plugins/Referrers/Referrers.php b/plugins/Referrers/Referrers.php
index e2714706ebe29124ad4a3d260ff764c561de718c..099c0b10758b8ef6f92c2e3602657546b353b6e8 100644
--- a/plugins/Referrers/Referrers.php
+++ b/plugins/Referrers/Referrers.php
@@ -14,6 +14,10 @@ use Piwik\ArchiveProcessor;
 use Piwik\Common;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable\AllColumns;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
 use Piwik\SettingsPiwik;
 use Piwik\WidgetsList;
 
@@ -33,14 +37,15 @@ class Referrers extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenus',
-            'Goals.getReportsWithGoalMetrics'          => 'getReportsWithGoalMetrics',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'               => 'archiveDay',
+            'ArchiveProcessor.Period.compute'            => 'archivePeriod',
+            'WidgetsList.addWidgets'                     => 'addWidgets',
+            'Menu.Reporting.addItems'                    => 'addMenus',
+            'Goals.getReportsWithGoalMetrics'            => 'getReportsWithGoalMetrics',
+            'API.getReportMetadata'                      => 'getReportMetadata',
+            'API.getSegmentsMetadata'                    => 'getSegmentsMetadata',
+            'ViewDataTable.configure'                    => 'configureViewDataTable',
+            'Visualization.getDefaultViewTypeForReports' => 'getDefaultViewTypeForReports'
         );
         return $hooks;
     }
@@ -295,26 +300,59 @@ class Referrers extends \Piwik\Plugin
         }
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function getDefaultViewTypeForReports(&$defaultViewTypes)
     {
-        $properties['Referrers.getReferrerType'] = $this->getDisplayPropertiesForGetReferrerType();
-        $properties['Referrers.getAll'] = $this->getDisplayPropertiesForGetAll();
-        $properties['Referrers.getKeywords'] = $this->getDisplayPropertiesForGetKeywords();
-        $properties['Referrers.getSearchEnginesFromKeywordId'] = $this->getDisplayPropertiesForGetSearchEnginesFromKeywordId();
-        $properties['Referrers.getSearchEngines'] = $this->getDisplayPropertiesForGetSearchEngines();
-        $properties['Referrers.getKeywordsFromSearchEngineId'] = $this->getDisplayPropertiesForGetKeywordsFromSearchEngineId();
-        $properties['Referrers.getWebsites'] = $this->getDisplayPropertiesForGetWebsites();
-        $properties['Referrers.getSocials'] = $this->getDisplayPropertiesForGetSocials();
-        $properties['Referrers.getUrlsForSocial'] = $this->getDisplayPropertiesForGetUrlsForSocial();
-        $properties['Referrers.getCampaigns'] = $this->getDisplayPropertiesForGetCampaigns();
-        $properties['Referrers.getKeywordsFromCampaignId'] = $this->getDisplayPropertiesForGetKeywordsFromCampaignId();
-        $properties['Referrers.getUrlsFromWebsiteId'] = $this->getDisplayPropertiesForGetUrlsFromWebsiteId();
+        $defaultViewTypes['Referrers.getReferrerType'] = AllColumns::ID;
+        $defaultViewTypes['Referrers.getSocials']      = Pie::ID;
     }
 
-    private function getDisplayPropertiesForGetReferrerType()
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $idSubtable = Common::getRequestVar('idSubtable', false);
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'Referrers.getReferrerType':
+                $this->configureViewForGetReferrerType($view);
+                break;
+            case 'Referrers.getAll':
+                $this->configureViewForGetAll($view);
+                break;
+            case 'Referrers.getKeywords':
+                $this->configureViewForGetKeywords($view);
+                break;
+            case 'Referrers.getSearchEnginesFromKeywordId':
+                $this->configureViewForGetSearchEnginesFromKeywordId($view);
+                break;
+            case 'Referrers.getSearchEngines':
+                $this->configureViewForGetSearchEngines($view);
+                break;
+            case 'Referrers.getKeywordsFromSearchEngineId':
+                $this->configureViewForGetKeywordsFromSearchEngineId($view);
+                break;
+            case 'Referrers.getWebsites':
+                $this->configureViewForGetWebsites($view);
+                break;
+            case 'Referrers.getSocials':
+                $this->configureViewForGetSocials($view);
+                break;
+            case 'Referrers.getUrlsForSocial':
+                $this->configureViewForGetUrlsForSocial($view);
+                break;
+            case 'Referrers.getCampaigns':
+                $this->configureViewForGetCampaigns($view);
+                break;
+            case 'Referrers.getKeywordsFromCampaignId':
+                $this->configureViewForGetKeywordsFromCampaignId($view);
+                break;
+            case 'Referrers.getUrlsFromWebsiteId':
+                $this->configureViewForGetUrlsFromWebsiteId($view);
+                break;
+        }
+    }
+
+    private function configureViewForGetReferrerType(ViewDataTable $view)
+    {
+        $idSubtable       = Common::getRequestVar('idSubtable', false);
         $labelColumnTitle = Piwik::translate('Referrers_Type');
+
         switch ($idSubtable) {
             case Common::REFERRER_TYPE_SEARCH_ENGINE:
                 $labelColumnTitle = Piwik::translate('Referrers_ColumnSearchEngine');
@@ -329,182 +367,154 @@ class Referrers extends \Piwik\Plugin
                 break;
         }
 
-        return array(
-            'default_view_type'           => 'tableAllColumns',
-            'show_search'                 => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 10,
-            'translations'                => array('label' => $labelColumnTitle),
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_subtable_when_show_goals' => true,
-                )
-            ),
-        );
+        $view->config->show_search = false;
+        $view->config->show_goals  = true;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', $labelColumnTitle);
+
+        $view->requestConfig->filter_limit = 10;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_subtable_when_show_goals = true;
+        }
     }
 
-    private function getDisplayPropertiesForGetAll()
+    private function configureViewForGetAll(ViewDataTable $view)
     {
         $setGetAllHtmlPrefix = array($this, 'setGetAllHtmlPrefix');
-        return array(
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('Referrers_Referrer')),
-            'show_goals'                  => true,
-            'filter_limit'                => 20,
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_row_actions' => true
-                )
-            ),
-            'filters'                     => array(
-                array('MetadataCallbackAddMetadata', array('referer_type', 'html_label_prefix', $setGetAllHtmlPrefix))
-            )
-        );
+
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_goals = true;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_Referrer'));
+
+        $view->requestConfig->filter_limit = 20;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_row_actions = true;
+        }
+
+        $view->config->filters[] = array('MetadataCallbackAddMetadata', array('referer_type', 'html_label_prefix', $setGetAllHtmlPrefix));
     }
 
-    private function getDisplayPropertiesForGetKeywords()
+    private function configureViewForGetKeywords(ViewDataTable $view)
     {
-        return array(
-            'subtable_controller_action'  => 'getSearchEnginesFromKeywordId',
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('General_ColumnKeyword')),
-            'show_goals'                  => true,
-            'filter_limit'                => 25,
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_subtable_when_show_goals' => true,
-                )
-            ),
-        );
+        $view->config->subtable_controller_action  = 'getSearchEnginesFromKeywordId';
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('General_ColumnKeyword'));
+        $view->config->show_goals = true;
+
+        $view->requestConfig->filter_limit = 25;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_subtable_when_show_goals = true;
+        }
     }
 
-    private function getDisplayPropertiesForGetSearchEnginesFromKeywordId()
+    private function configureViewForGetSearchEnginesFromKeywordId(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnSearchEngine'))
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnSearchEngine'));
     }
 
-    private function getDisplayPropertiesForGetSearchEngines()
+    private function configureViewForGetSearchEngines(ViewDataTable $view)
     {
-        return array(
-            'subtable_controller_action'  => 'getKeywordsFromSearchEngineId',
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 25,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnSearchEngine')),
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_subtable_when_show_goals' => true,
-                )
-            ),
-        );
+        $view->config->subtable_controller_action  = 'getKeywordsFromSearchEngineId';
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_search = false;
+        $view->config->show_goals  = true;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnSearchEngine'));
+
+        $view->requestConfig->filter_limit = 25;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_subtable_when_show_goals = true;
+        }
     }
 
-    private function getDisplayPropertiesForGetKeywordsFromSearchEngineId()
+    private function configureViewForGetKeywordsFromSearchEngineId(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('General_ColumnKeyword'))
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('General_ColumnKeyword'));
     }
 
-    private function getDisplayPropertiesForGetWebsites()
+    private function configureViewForGetWebsites(ViewDataTable $view)
     {
-        return array(
-            'subtable_controller_action'  => 'getUrlsFromWebsiteId',
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 25,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnWebsite')),
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_subtable_when_show_goals' => true,
-                )
-            ),
-        );
+        $view->config->subtable_controller_action  = 'getUrlsFromWebsiteId';
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_goals = true;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnWebsite'));
+
+        $view->requestConfig->filter_limit = 25;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_subtable_when_show_goals = true;
+        }
     }
 
-    private function getDisplayPropertiesForGetSocials()
+    private function configureViewForGetSocials(ViewDataTable $view)
     {
-        $result = array(
-            'default_view_type'           => 'graphPie',
-            'subtable_controller_action'  => 'getUrlsForSocial',
-            'show_exclude_low_population' => false,
-            'filter_limit'                => 10,
-            'show_goals'                  => true,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnSocial')),
-            'visualization_properties'    => array(
-                'table' => array(
-                    'disable_subtable_when_show_goals' => true,
-                )
-            ),
-        );
+        $view->config->subtable_controller_action  = 'getUrlsForSocial';
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_goals = true;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnSocial'));
+
+        $view->requestConfig->filter_limit = 10;
+
+        if ($view->isViewDataTableId(HtmlTable::ID)) {
+            $view->config->disable_subtable_when_show_goals = true;
+        }
 
         $widget = Common::getRequestVar('widget', false);
         if (empty($widget)) {
-            $result['show_footer_message'] = Piwik::translate('Referrers_SocialFooterMessage');
+            $view->config->show_footer_message = Piwik::translate('Referrers_SocialFooterMessage');
         }
-
-        return $result;
     }
 
-    private function getDisplayPropertiesForGetUrlsForSocial()
+    private function configureViewForGetUrlsForSocial(ViewDataTable $view)
     {
-        return array(
-            'show_exclude_low_population' => false,
-            'filter_limit'                => 10,
-            'show_goals'                  => true,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnWebsitePage'))
-        );
+        $view->config->show_goals = true;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnWebsitePage'));
+
+        $view->requestConfig->filter_limit = 10;
     }
 
-    private function getDisplayPropertiesForGetCampaigns()
+    private function configureViewForGetCampaigns(ViewDataTable $view)
     {
-        $result = array(
-            'subtable_controller_action'  => 'getKeywordsFromCampaignId',
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 25,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnCampaign')),
-        );
+        $view->config->show_goals = true;
+        $view->config->subtable_controller_action  = 'getKeywordsFromCampaignId';
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnCampaign'));
+
+        $view->requestConfig->filter_limit = 25;
 
         if (Common::getRequestVar('viewDataTable', false) != 'graphEvolution') {
-            $result['show_footer_message'] = Piwik::translate('Referrers_CampaignFooterHelp',
+            $view->config->show_footer_message = Piwik::translate('Referrers_CampaignFooterHelp',
                 array('<a target="_blank" href="http://piwik.org/docs/tracking-campaigns/">',
                       '</a> - <a target="_blank" href="http://piwik.org/docs/tracking-campaigns/url-builder/">',
                       '</a>')
             );
         }
-
-        return $result;
     }
 
-    private function getDisplayPropertiesForGetKeywordsFromCampaignId()
+    private function configureViewForGetKeywordsFromCampaignId(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('General_ColumnKeyword'))
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('General_ColumnKeyword'));
     }
 
-    private function getDisplayPropertiesForGetUrlsFromWebsiteId()
+    private function configureViewForGetUrlsFromWebsiteId(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'translations'                => array('label' => Piwik::translate('Referrers_ColumnWebsitePage')),
-            'tooltip_metadata_name'       => 'url'
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->tooltip_metadata_name       = 'url';
+        $view->config->addTranslation('label', Piwik::translate('Referrers_ColumnWebsitePage'));
     }
 
     /**
diff --git a/plugins/SecurityInfo b/plugins/SecurityInfo
index 2eb4c066acbe1293abde25017fa100637ad5bd2d..fd8f764b9b6af55ed821aa6737a88d43ba3e76ac 160000
--- a/plugins/SecurityInfo
+++ b/plugins/SecurityInfo
@@ -1 +1 @@
-Subproject commit 2eb4c066acbe1293abde25017fa100637ad5bd2d
+Subproject commit fd8f764b9b6af55ed821aa6737a88d43ba3e76ac
diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php
index 612d6de6f1d231c52623f11649db3e520c40e4e9..3a8ba91bfa3ce21b92eb0e9dba3968eb9b7c5451 100644
--- a/plugins/SitesManager/API.php
+++ b/plugins/SitesManager/API.php
@@ -42,7 +42,7 @@ use Piwik\UrlHelper;
  * The existing values can be fetched via "getExcludedIpsGlobal" and "getExcludedQueryParametersGlobal".
  * See also the documentation about <a href='http://piwik.org/docs/manage-websites/' target='_blank'>Managing Websites</a> in Piwik.
  * @package SitesManager
- * @method \Piwik\Plugins\SitesManager\API getInstance()
+ * @static \Piwik\Plugins\SitesManager\API getInstance()
  */
 class API extends \Piwik\Plugin\API
 {
diff --git a/plugins/TreemapVisualization b/plugins/TreemapVisualization
index c7aa4ca6d2f24f9a105134ea533d43e90c5b1890..dd0a8cdc4a377d4eff49f53d0015dd25332ef9d7 160000
--- a/plugins/TreemapVisualization
+++ b/plugins/TreemapVisualization
@@ -1 +1 @@
-Subproject commit c7aa4ca6d2f24f9a105134ea533d43e90c5b1890
+Subproject commit dd0a8cdc4a377d4eff49f53d0015dd25332ef9d7
diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php
index b207bc24970b187f0e4d3391e4131748ac0bf3ef..7390c8d687b89bd8984d978ae82738d9ab165b99 100644
--- a/plugins/UserCountry/Controller.php
+++ b/plugins/UserCountry/Controller.php
@@ -365,7 +365,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
     public function getLastDistinctCountriesGraph($fetch = false)
     {
         $view = $this->getLastUnitGraph('UserCountry', __FUNCTION__, "UserCountry.getNumberOfDistinctCountries");
-        $view->columns_to_display = array('UserCountry_distinctCountries');
+        $view->config->columns_to_display = array('UserCountry_distinctCountries');
         return $this->renderView($view, $fetch);
     }
 
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index 2a8fb5af51c21b95fe8c350149eb80ece2b1fc14..64bd49c3b26bc5028e499509553297a1cb3cf4d3 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -16,6 +16,7 @@ use Piwik\IP;
 use Piwik\Menu\MenuAdmin;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
 use Piwik\Plugins\UserCountry\LocationProvider\DefaultProvider;
 use Piwik\Plugins\UserCountry\LocationProvider;
 use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
@@ -40,21 +41,21 @@ class UserCountry extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'Menu.Admin.addItems'                      => 'addAdminMenu',
-            'Goals.getReportsWithGoalMetrics'          => 'getReportsWithGoalMetrics',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'AssetManager.getStylesheetFiles'          => 'getStylesheetFiles',
-            'AssetManager.getJavaScriptFiles'          => 'getJsFiles',
-            'Tracker.newVisitorInformation'            => 'getVisitorLocation',
-            'TaskScheduler.getScheduledTasks'          => 'getScheduledTasks',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
-            'Translate.getClientSideTranslationKeys'   => 'getClientSideTranslationKeys',
-            'Tracker.setTrackerCacheGeneral'           => 'setTrackerCacheGeneral'
+            'ArchiveProcessor.Day.compute'           => 'archiveDay',
+            'ArchiveProcessor.Period.compute'        => 'archivePeriod',
+            'WidgetsList.addWidgets'                 => 'addWidgets',
+            'Menu.Reporting.addItems'                => 'addMenu',
+            'Menu.Admin.addItems'                    => 'addAdminMenu',
+            'Goals.getReportsWithGoalMetrics'        => 'getReportsWithGoalMetrics',
+            'API.getReportMetadata'                  => 'getReportMetadata',
+            'API.getSegmentsMetadata'                => 'getSegmentsMetadata',
+            'AssetManager.getStylesheetFiles'        => 'getStylesheetFiles',
+            'AssetManager.getJavaScriptFiles'        => 'getJsFiles',
+            'Tracker.newVisitorInformation'          => 'getVisitorLocation',
+            'TaskScheduler.getScheduledTasks'        => 'getScheduledTasks',
+            'ViewDataTable.configure'                => 'configureViewDataTable',
+            'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+            'Tracker.setTrackerCacheGeneral'         => 'setTrackerCacheGeneral'
         );
         return $hooks;
     }
@@ -363,23 +364,32 @@ class UserCountry extends \Piwik\Plugin
                      'bind' => '-'); // HACK: SegmentExpression requires a $bind, even if there's nothing to bind
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        $properties['UserCountry.getCountry'] = $this->getDisplayPropertiesForGetCountry();
-        $properties['UserCountry.getContinent'] = $this->getDisplayPropertiesForGetContinent();
-        $properties['UserCountry.getRegion'] = $this->getDisplayPropertiesForGetRegion();
-        $properties['UserCountry.getCity'] = $this->getDisplayPropertiesForGetCity();
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'UserCountry.getCountry':
+                $this->configureViewForGetCountry($view);
+                break;
+            case 'UserCountry.getContinent':
+                $this->configureViewForGetContinent($view);
+                break;
+            case 'UserCountry.getRegion':
+                $this->configureViewForGetRegion($view);
+                break;
+            case 'UserCountry.getCity':
+                $this->configureViewForGetCity($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetCountry()
+    private function configureViewForGetCountry(ViewDataTable $view)
     {
-        $result = array(
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 5,
-            'translations'                => array('label' => Piwik::translate('UserCountry_Country')),
-            'documentation'               => Piwik::translate('UserCountry_getCountryDocumentation')
-        );
+        $view->config->show_goals = true;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('UserCountry_Country'));
+        $view->config->documentation = Piwik::translate('UserCountry_getCountryDocumentation');
+
+        $view->requestConfig->filter_limit = 5;
 
         if (LocationProvider::getCurrentProviderId() == DefaultProvider::ID) {
             // if we're using the default location provider, add a note explaining how it works
@@ -387,52 +397,44 @@ class UserCountry extends \Piwik\Plugin
                 . Piwik::translate('UserCountry_DefaultLocationProviderExplanation',
                     array('<a target="_blank" href="http://piwik.org/docs/geo-locate/">', '</a>'));
 
-            $result['show_footer_message'] = $footerMessage;
+            $view->config->show_footer_message = $footerMessage;
         }
-
-        return $result;
     }
 
-    private function getDisplayPropertiesForGetContinent()
+    private function configureViewForGetContinent(ViewDataTable $view)
     {
-        return array(
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'show_search'                 => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'translations'                => array('label' => Piwik::translate('UserCountry_Continent')),
-            'documentation'               => Piwik::translate('UserCountry_getContinentDocumentation')
-        );
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_goals = true;
+        $view->config->show_search = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control = false;
+        $view->config->documentation = Piwik::translate('UserCountry_getContinentDocumentation');
+        $view->config->addTranslation('label', Piwik::translate('UserCountry_Continent'));
     }
 
-    private function getDisplayPropertiesForGetRegion()
+    private function configureViewForGetRegion(ViewDataTable $view)
     {
-        $result = array(
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 5,
-            'translations'                => array('label' => Piwik::translate('UserCountry_Region')),
-            'documentation'               => Piwik::translate('UserCountry_getRegionDocumentation') . '<br/>'
-                . $this->getGeoIPReportDocSuffix()
-        );
-        $this->checkIfNoDataForGeoIpReport($result);
-        return $result;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_goals = true;
+        $view->config->documentation = Piwik::translate('UserCountry_getRegionDocumentation') . '<br/>' . $this->getGeoIPReportDocSuffix();
+        $view->config->addTranslation('label', Piwik::translate('UserCountry_Region'));
+
+        $view->requestConfig->filter_limit = 5;
+
+        $this->checkIfNoDataForGeoIpReport($view);
     }
 
-    private function getDisplayPropertiesForGetCity()
+    private function configureViewForGetCity(ViewDataTable $view)
     {
-        $result = array(
-            'show_exclude_low_population' => false,
-            'show_goals'                  => true,
-            'filter_limit'                => 5,
-            'translations'                => array('label' => Piwik::translate('UserCountry_City')),
-            'documentation'               => Piwik::translate('UserCountry_getCityDocumentation') . '<br/>'
-                . $this->getGeoIPReportDocSuffix()
-        );
-        $this->checkIfNoDataForGeoIpReport($result);
-        return $result;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_goals = true;
+        $view->config->documentation = Piwik::translate('UserCountry_getCityDocumentation') . '<br/>' . $this->getGeoIPReportDocSuffix();
+        $view->config->addTranslation('label', Piwik::translate('UserCountry_City'));
+
+        $view->requestConfig->filter_limit = 5;
+
+        $this->checkIfNoDataForGeoIpReport($view);
     }
 
     private function getGeoIPReportDocSuffix()
@@ -449,10 +451,10 @@ class UserCountry extends \Piwik\Plugin
      * Checks if a datatable for a view is empty and if so, displays a message in the footer
      * telling users to configure GeoIP.
      */
-    private function checkIfNoDataForGeoIpReport(&$properties)
+    private function checkIfNoDataForGeoIpReport(ViewDataTable $view)
     {
         $self = $this;
-        $properties['filters'][] = function ($dataTable, $view) use ($self) {
+        $view->config->filters[] = function ($dataTable) use ($self, $view) {
             // if there's only one row whose label is 'Unknown', display a message saying there's no data
             if ($dataTable->getRowsCount() == 1
                 && $dataTable->getFirstRow()->getColumn('label') == Piwik::translate('General_Unknown')
@@ -472,7 +474,7 @@ class UserCountry extends \Piwik\Plugin
                             array('<a target="_blank" href="http://piwik.org/faq/how-to/#faq_167">', '</a>'));
                 }
 
-                $view->show_footer_message = $footerMessage;
+                $view->config->show_footer_message = $footerMessage;
             }
         };
     }
diff --git a/plugins/UserSettings/UserSettings.php b/plugins/UserSettings/UserSettings.php
index 8db1ba1dbf23ab1cb0e4fd6f4c1043a8e726f957..2f0124952ea973563433d3f08fd9722ba623d282 100644
--- a/plugins/UserSettings/UserSettings.php
+++ b/plugins/UserSettings/UserSettings.php
@@ -13,6 +13,10 @@ namespace Piwik\Plugins\UserSettings;
 use Piwik\ArchiveProcessor;
 use Piwik\Menu\MenuMain;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
 use Piwik\WidgetsList;
 
 /**
@@ -165,150 +169,185 @@ class UserSettings extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'               => 'archiveDay',
+            'ArchiveProcessor.Period.compute'            => 'archivePeriod',
+            'WidgetsList.addWidgets'                     => 'addWidgets',
+            'Menu.Reporting.addItems'                    => 'addMenu',
+            'API.getReportMetadata'                      => 'getReportMetadata',
+            'API.getSegmentsMetadata'                    => 'getSegmentsMetadata',
+            'ViewDataTable.configure'                    => 'configureViewDataTable',
+            'Visualization.getDefaultViewTypeForReports' => 'getDefaultViewTypeForReports'
         );
         return $hooks;
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function getDefaultViewTypeForReports(&$defaultViewTypes)
     {
-        $properties['UserSettings.getResolution'] = $this->getDisplayPropertiesForGetResolution();
-        $properties['UserSettings.getConfiguration'] = $this->getDisplayPropertiesForGetConfiguration();
-        $properties['UserSettings.getOS'] = $this->getDisplayPropertiesForGetOS();
-        $properties['UserSettings.getOSFamily'] = $this->getDisplayPropertiesForGetOSFamily();
-        $properties['UserSettings.getBrowserVersion'] = $this->getDisplayPropertiesForGetBrowserVersion();
-        $properties['UserSettings.getBrowser'] = $this->getDisplayPropertiesForGetBrowser();
-        $properties['UserSettings.getBrowserType'] = $this->getDisplayPropertiesForGetBrowserType();
-        $properties['UserSettings.getWideScreen'] = $this->getDisplayPropertiesForGetWideScreen();
-        $properties['UserSettings.getMobileVsDesktop'] = $this->getDisplayPropertiesForGetMobileVsDesktop();
-        $properties['UserSettings.getPlugin'] = $this->getDisplayPropertiesForGetPlugin();
-        $properties['UserSettings.getLanguage'] = $this->getDisplayPropertiesForGetLanguage();
+        $defaultViewTypes['UserSettings.getBrowserType'] = Pie::ID;
     }
 
-    private function getDisplayPropertiesForGetResolution()
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations' => array('label' => Piwik::translate('UserSettings_ColumnResolution'))
-                                                                           ));
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'UserSettings.getResolution':
+                $this->configureViewForGetResolution($view);
+                break;
+            case 'UserSettings.getConfiguration':
+                $this->configureViewForGetConfiguration($view);
+                break;
+            case 'UserSettings.getOS':
+                $this->configureViewForGetOS($view);
+                break;
+            case 'UserSettings.getOSFamily':
+                $this->configureViewForGetOSFamily($view);
+                break;
+            case 'UserSettings.getBrowserVersion':
+                $this->configureViewForGetBrowserVersion($view);
+                break;
+            case 'UserSettings.getBrowser':
+                $this->configureViewForGetBrowser($view);
+                break;
+            case 'UserSettings.getBrowserType':
+                $this->configureViewForGetBrowserType($view);
+                break;
+            case 'UserSettings.getWideScreen':
+                $this->configureViewForGetWideScreen($view);
+                break;
+            case 'UserSettings.getMobileVsDesktop':
+                $this->configureViewForGetMobileVsDesktop($view);
+                break;
+            case 'UserSettings.getPlugin':
+                $this->configureViewForGetPlugin($view);
+                break;
+            case 'UserSettings.getLanguage':
+                $this->configureViewForGetLanguage($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetConfiguration()
+    private function configureViewForGetResolution(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'filter_limit' => 3,
-                                                                                'translations' => array('label' => Piwik::translate('UserSettings_ColumnConfiguration'))
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnResolution'));
     }
 
-    private function getDisplayPropertiesForGetOS()
+    private function configureViewForGetConfiguration(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations'    => array('label' => Piwik::translate('UserSettings_ColumnOperatingSystem')),
-                                                                                'title'           => Piwik::translate('UserSettings_OperatingSystems'),
-                                                                                'related_reports' => $this->getOsRelatedReports()
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnConfiguration'));
+
+        $view->requestConfig->filter_limit = 3;
     }
 
-    private function getDisplayPropertiesForGetOSFamily()
+    private function configureViewForGetOS(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations'    => array('label' => Piwik::translate('UserSettings_OperatingSystemFamily')),
-                                                                                'title'           => Piwik::translate('UserSettings_OperatingSystemFamily'),
-                                                                                'related_reports' => $this->getOsRelatedReports()
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->title = Piwik::translate('UserSettings_OperatingSystems');
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnOperatingSystem'));
+        $view->config->addRelatedReports($this->getOsRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetBrowserVersion()
+    private function configureViewForGetOSFamily(ViewDataTable $view)
     {
-        $result = array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                   'translations'    => array('label' => Piwik::translate('UserSettings_ColumnBrowserVersion')),
-                                                                                   'title'           => Piwik::translate('UserSettings_ColumnBrowserVersion'),
-                                                                                   'related_reports' => $this->getBrowserRelatedReports()
-                                                                              ));
-        $result['visualization_properties']['graph']['max_graph_elements'] = 7;
-        return $result;
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->title = Piwik::translate('UserSettings_OperatingSystemFamily');
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_OperatingSystemFamily'));
+        $view->config->addRelatedReports($this->getOsRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetBrowser()
+    private function configureViewForGetBrowserVersion(ViewDataTable $view)
     {
-        $result = array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                   'translations'    => array('label' => Piwik::translate('UserSettings_ColumnBrowser')),
-                                                                                   'title'           => Piwik::translate('UserSettings_Browsers'),
-                                                                                   'related_reports' => $this->getBrowserRelatedReports()
-                                                                              ));
-        $result['visualization_properties']['graph']['max_graph_elements'] = 7;
-        return $result;
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->title = Piwik::translate('UserSettings_ColumnBrowserVersion');
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnBrowserVersion'));
+        $view->config->addRelatedReports($this->getBrowserRelatedReports());
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = 7;
+        }
     }
 
-    private function getDisplayPropertiesForGetBrowserType()
+    private function configureViewForGetBrowser(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations'            => array('label' => Piwik::translate('UserSettings_ColumnBrowserFamily')),
-                                                                                'show_offset_information' => false,
-                                                                                'show_pagination_control' => false,
-                                                                                'show_limit_control'      => false,
-                                                                                'default_view_type'       => 'graphPie',
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->title = Piwik::translate('UserSettings_Browsers');
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnBrowser'));
+        $view->config->addRelatedReports($this->getBrowserRelatedReports());
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = 7;
+        }
     }
 
-    private function getDisplayPropertiesForGetWideScreen()
+    private function configureViewForGetBrowserType(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations'            => array('label' => Piwik::translate('UserSettings_ColumnTypeOfScreen')),
-                                                                                'show_offset_information' => false,
-                                                                                'show_pagination_control' => false,
-                                                                                'show_limit_control'      => false,
-                                                                                'title'                   => Piwik::translate('UserSettings_ColumnTypeOfScreen'),
-                                                                                'related_reports'         => $this->getWideScreenDeviceTypeRelatedReports()
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnBrowserFamily'));
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
     }
 
-    private function getDisplayPropertiesForGetMobileVsDesktop()
+    private function configureViewForGetWideScreen(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations'    => array('label' => Piwik::translate('UserSettings_MobileVsDesktop')),
-                                                                                'title'           => Piwik::translate('UserSettings_MobileVsDesktop'),
-                                                                                'related_reports' => $this->getWideScreenDeviceTypeRelatedReports()
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->title = Piwik::translate('UserSettings_ColumnTypeOfScreen');
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_ColumnTypeOfScreen'));
+        $view->config->addRelatedReports($this->getWideScreenDeviceTypeRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetPlugin()
+    private function configureViewForGetMobileVsDesktop(ViewDataTable $view)
     {
-        return array_merge($this->getBasicUserSettingsDisplayProperties(), array(
-                                                                                'translations'            => array(
-                                                                                    'label'                => Piwik::translate('General_Plugin'),
-                                                                                    'nb_visits_percentage' =>
-                                                                                        str_replace(' ', '&nbsp;', Piwik::translate('General_ColumnPercentageVisits'))
-                                                                                ),
-                                                                                'show_offset_information' => false,
-                                                                                'show_pagination_control' => false,
-                                                                                'show_limit_control'      => false,
-                                                                                'show_all_views_icons'    => false,
-                                                                                'show_table_all_columns'  => false,
-                                                                                'columns_to_display'      => array('label', 'nb_visits_percentage', 'nb_visits'),
-                                                                                'filter_sort_column'      => 'nb_visits_percentage',
-                                                                                'filter_sort_order'       => 'desc',
-                                                                                'filter_limit'            => 10,
-                                                                                'show_footer_message'     => Piwik::translate('UserSettings_PluginDetectionDoesNotWorkInIE'),
-                                                                           ));
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->title = Piwik::translate('UserSettings_MobileVsDesktop');
+        $view->config->addTranslation('label', Piwik::translate('UserSettings_MobileVsDesktop'));
+        $view->config->addRelatedReports($this->getWideScreenDeviceTypeRelatedReports());
     }
 
-    private function getDisplayPropertiesForGetLanguage()
+    private function configureViewForGetPlugin(ViewDataTable $view)
     {
-        return array(
-            'translations'                => array('label' => Piwik::translate('General_Language')),
-            'filter_sort_column'          => 'nb_visits',
-            'filter_sort_order'           => 'desc',
-            'show_search'                 => false,
-            'columns_to_display'          => array('label', 'nb_visits'),
-            'show_exclude_low_population' => false,
-        );
+        $this->getBasicUserSettingsDisplayProperties($view);
+
+        $view->config->addTranslations(array(
+            'label'                => Piwik::translate('General_Plugin'),
+            'nb_visits_percentage' =>
+            str_replace(' ', '&nbsp;', Piwik::translate('General_ColumnPercentageVisits'))
+        ));
+
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->show_all_views_icons    = false;
+        $view->config->show_table_all_columns  = false;
+        $view->config->columns_to_display  = array('label', 'nb_visits_percentage', 'nb_visits');
+        $view->config->show_footer_message = Piwik::translate('UserSettings_PluginDetectionDoesNotWorkInIE');
+
+        $view->requestConfig->filter_sort_column = 'nb_visits_percentage';
+        $view->requestConfig->filter_sort_order  = 'desc';
+        $view->requestConfig->filter_limit       = 10;
+    }
+
+    private function configureViewForGetLanguage(ViewDataTable $view)
+    {
+        $view->config->show_search = false;
+        $view->config->columns_to_display = array('label', 'nb_visits');
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('General_Language'));
+
+        $view->requestConfig->filter_sort_column = 'nb_visits';
+        $view->requestConfig->filter_sort_order  = 'desc';
     }
 
     private function getWideScreenDeviceTypeRelatedReports()
@@ -335,18 +374,16 @@ class UserSettings extends \Piwik\Plugin
         );
     }
 
-    private function getBasicUserSettingsDisplayProperties()
+    private function getBasicUserSettingsDisplayProperties(ViewDataTable $view)
     {
-        return array(
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'filter_limit'                => 5,
-            'visualization_properties'    => array(
-                'graph' => array(
-                    'max_graph_elements' => 5
-                )
-            )
-        );
+        $view->config->show_search = false;
+        $view->config->show_exclude_low_population = false;
+
+        $view->requestConfig->filter_limit = 5;
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = 5;
+        }
     }
 
     /**
diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php
index 62c3f6fc9f7cbb2623e9cc0125824ab0ebd38053..0f4ad71b28e725709584d4859e9b4c9c045e9857 100644
--- a/plugins/VisitTime/VisitTime.php
+++ b/plugins/VisitTime/VisitTime.php
@@ -17,6 +17,9 @@ use Piwik\Common;
 use Piwik\Menu\MenuMain;
 use Piwik\Period;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Bar;
 use Piwik\Site;
 use Piwik\WidgetsList;
 
@@ -32,14 +35,15 @@ class VisitTime extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'Goals.getReportsWithGoalMetrics'          => 'getReportsWithGoalMetrics',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'API.getSegmentsMetadata'                  => 'getSegmentsMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'               => 'archiveDay',
+            'ArchiveProcessor.Period.compute'            => 'archivePeriod',
+            'WidgetsList.addWidgets'                     => 'addWidgets',
+            'Menu.Reporting.addItems'                    => 'addMenu',
+            'Goals.getReportsWithGoalMetrics'            => 'getReportsWithGoalMetrics',
+            'API.getReportMetadata'                      => 'getReportMetadata',
+            'API.getSegmentsMetadata'                    => 'getSegmentsMetadata',
+            'ViewDataTable.configure'                    => 'configureViewDataTable',
+            'Visualization.getDefaultViewTypeForReports' => 'getDefaultViewTypeForReports'
         );
         return $hooks;
     }
@@ -122,61 +126,73 @@ class VisitTime extends \Piwik\Plugin
         );
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function getDefaultViewTypeForReports(&$defaultViewTypes)
     {
-        $commonProperties = array(
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'show_search'                 => false,
-            'show_exclude_low_population' => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'default_view_type'           => 'graphVerticalBar'
-        );
+        $defaultViewTypes['VisitTime.getVisitInformationPerServerTime'] = Bar::ID;
+        $defaultViewTypes['VisitTime.getVisitInformationPerLocalTime']  = Bar::ID;
+        $defaultViewTypes['VisitTime.getByDayOfWeek']                   = Bar::ID;
+    }
+
+    public function configureViewDataTable(ViewDataTable $view)
+    {
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'VisitTime.getVisitInformationPerServerTime':
+                $this->setBasicConfigViewProperties($view);
+                $this->configureViewForVisitInformationPerServerTime($view);
+                break;
+            case 'VisitTime.getVisitInformationPerLocalTime':
+                $this->setBasicConfigViewProperties($view);
+                $this->configureViewForVisitInformationPerLocalTime($view);
+                break;
+            case 'VisitTime.getByDayOfWeek':
+                $this->setBasicConfigViewProperties($view);
+                $this->configureViewForByDayOfWeek($view);
+                break;
+        }
+    }
+
+    protected function configureViewForVisitInformationPerServerTime(ViewDataTable $view)
+    {
+        $view->requestConfig->filter_limit = 24;
+        $view->requestConfig->request_parameters_to_modify['hideFutureHoursWhenToday'] = 1;
+
+        $view->config->show_goals = true;
+        $view->config->addTranslation('label', Piwik::translate('VisitTime_ColumnServerTime'));
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = false;
+        }
+    }
+
+    protected function configureViewForVisitInformationPerLocalTime(ViewDataTable $view)
+    {
+        $view->requestConfig->filter_limit = 24;
 
-        $properties['VisitTime.getVisitInformationPerServerTime'] = array_merge($commonProperties, array(
-                                                                                                        'filter_limit'                 => 24,
-                                                                                                        'show_goals'                   => true,
-                                                                                                        'translations'                 => array('label' => Piwik::translate('VisitTime_ColumnServerTime')),
-                                                                                                        'request_parameters_to_modify' => array('hideFutureHoursWhenToday' => 1),
-                                                                                                        'visualization_properties'     => array(
-                                                                                                            'graph' => array(
-                                                                                                                'max_graph_elements' => false,
-                                                                                                            )
-                                                                                                        )
-                                                                                                   ));
-
-        $properties['VisitTime.getVisitInformationPerLocalTime'] = array_merge($commonProperties, array(
-                                                                                                       'filter_limit'             => 24,
-                                                                                                       'title'                    => Piwik::translate('VisitTime_ColumnLocalTime'),
-                                                                                                       'translations'             => array('label' => Piwik::translate('VisitTime_LocalTime')),
-                                                                                                       'visualization_properties' => array(
-                                                                                                           'graph' => array(
-                                                                                                               'max_graph_elements' => false,
-                                                                                                           )
-                                                                                                       )
-                                                                                                  ));
-
-        $properties['VisitTime.getByDayOfWeek'] = array_merge($commonProperties, array(
-                                                                                      'filter_limit'             => 7,
-                                                                                      'enable_sort'              => false,
-                                                                                      'show_footer_message'      =>
-                                                                                          Piwik::translate('General_ReportGeneratedFrom', self::getDateRangeForFooterMessage()),
-                                                                                      'translations'             => array('label' => Piwik::translate('VisitTime_DayOfWeek')),
-                                                                                      'visualization_properties' => array(
-                                                                                          'graph' => array(
-                                                                                              'show_all_ticks'     => true,
-                                                                                              'max_graph_elements' => false,
-                                                                                          )
-                                                                                      )
-                                                                                 ));
+        $view->config->title = Piwik::translate('VisitTime_ColumnLocalTime');
+        $view->config->addTranslation('label', Piwik::translate('VisitTime_LocalTime'));
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = false;
+        }
 
         // add the visits by day of week as a related report, if the current period is not 'day'
         if (Common::getRequestVar('period', 'day') != 'day') {
-            $properties['VisitTime.getVisitInformationPerLocalTime']['related_reports'] = array(
-                'VisitTime.getByDayOfWeek' => Piwik::translate('VisitTime_VisitsByDayOfWeek')
-            );
+            $view->config->addRelatedReport('VisitTime.getByDayOfWeek', Piwik::translate('VisitTime_VisitsByDayOfWeek'));
+        }
+
+    }
+
+    protected function configureViewForByDayOfWeek(ViewDataTable $view)
+    {
+        $view->requestConfig->filter_limit = 7;
+
+        $view->config->enable_sort = false;
+        $view->config->show_footer_message = Piwik::translate('General_ReportGeneratedFrom', self::getDateRangeForFooterMessage());
+        $view->config->addTranslation('label', Piwik::translate('VisitTime_DayOfWeek'));
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = false;
+            $view->config->show_all_ticks     = true;
         }
     }
 
@@ -220,4 +236,18 @@ class VisitTime extends \Piwik\Plugin
         }
         return $dateRange;
     }
+
+    /**
+     * @param ViewDataTable $view
+     */
+    private function setBasicConfigViewProperties(ViewDataTable $view)
+    {
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order = 'asc';
+        $view->config->show_search = false;
+        $view->config->show_limit_control = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+    }
 }
\ No newline at end of file
diff --git a/plugins/VisitorGenerator b/plugins/VisitorGenerator
index 1634842ace2842e54f95a91e71c078bc10e32673..924b69d524edea4a326216fe6de7a8df7e9a9ddc 160000
--- a/plugins/VisitorGenerator
+++ b/plugins/VisitorGenerator
@@ -1 +1 @@
-Subproject commit 1634842ace2842e54f95a91e71c078bc10e32673
+Subproject commit 924b69d524edea4a326216fe6de7a8df7e9a9ddc
diff --git a/plugins/VisitorInterest/VisitorInterest.php b/plugins/VisitorInterest/VisitorInterest.php
index 4225f5cfc3d34d81f5f14522069a5c6feb8ef822..ccfe90c03a3894d3430e94f9df405f1dddcb8080 100644
--- a/plugins/VisitorInterest/VisitorInterest.php
+++ b/plugins/VisitorInterest/VisitorInterest.php
@@ -16,6 +16,9 @@ use Piwik\FrontController;
 use Piwik\Menu\MenuMain;
 use Piwik\Metrics;
 use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
 use Piwik\WidgetsList;
 
 /**
@@ -30,12 +33,13 @@ class VisitorInterest extends \Piwik\Plugin
     public function getListHooksRegistered()
     {
         $hooks = array(
-            'ArchiveProcessor.Day.compute'             => 'archiveDay',
-            'ArchiveProcessor.Period.compute'          => 'archivePeriod',
-            'WidgetsList.addWidgets'                   => 'addWidgets',
-            'Menu.Reporting.addItems'                  => 'addMenu',
-            'API.getReportMetadata'                    => 'getReportMetadata',
-            'Visualization.getReportDisplayProperties' => 'getReportDisplayProperties',
+            'ArchiveProcessor.Day.compute'               => 'archiveDay',
+            'ArchiveProcessor.Period.compute'            => 'archivePeriod',
+            'WidgetsList.addWidgets'                     => 'addWidgets',
+            'Menu.Reporting.addItems'                    => 'addMenu',
+            'API.getReportMetadata'                      => 'getReportMetadata',
+            'ViewDataTable.configure'                    => 'configureViewDataTable',
+            'Visualization.getDefaultViewTypeForReports' => 'getDefaultViewTypeForReports'
         );
         return $hooks;
     }
@@ -151,97 +155,105 @@ class VisitorInterest extends \Piwik\Plugin
         $out .= '</div>';
     }
 
-    public function getReportDisplayProperties(&$properties)
+    public function getDefaultViewTypeForReports(&$defaultViewTypes)
     {
-        $properties['VisitorInterest.getNumberOfVisitsPerVisitDuration'] =
-            $this->getDisplayPropertiesForGetNumberOfVisitsPerVisitDuration();
-        $properties['VisitorInterest.getNumberOfVisitsPerPage'] =
-            $this->getDisplayPropertiesForGetNumberOfVisitsPerPage();
-        $properties['VisitorInterest.getNumberOfVisitsByVisitCount'] =
-            $this->getDisplayPropertiesForGetNumberOfVisitsByVisitCount();
-        $properties['VisitorInterest.getNumberOfVisitsByDaysSinceLast'] =
-            $this->getDisplayPropertiesForGetNumberOfVisitsByDaysSinceLast();
+        $defaultViewTypes['VisitorInterest.getNumberOfVisitsPerVisitDuration'] = Cloud::ID;
+        $defaultViewTypes['VisitorInterest.getNumberOfVisitsPerPage']          = Cloud::ID;
     }
 
-    private function getDisplayPropertiesForGetNumberOfVisitsPerVisitDuration()
+    public function configureViewDataTable(ViewDataTable $view)
     {
-        return array(
-            'default_view_type'           => 'cloud',
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'translations'                => array('label' => Piwik::translate('VisitorInterest_ColumnVisitDuration')),
-            'enable_sort'                 => false,
-            'show_exclude_low_population' => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'show_search'                 => false,
-            'show_table_all_columns'      => false,
-            'visualization_properties'    => array(
-                'graph' => array(
-                    'max_graph_elements' => 10
-                )
-            )
-        );
+        switch ($view->requestConfig->apiMethodToRequestDataTable) {
+            case 'VisitorInterest.getNumberOfVisitsPerVisitDuration':
+                $this->configureViewForGetNumberOfVisitsPerVisitDuration($view);
+                break;
+            case 'VisitorInterest.getNumberOfVisitsPerPage':
+                $this->configureViewForGetNumberOfVisitsPerPage($view);
+                break;
+            case 'VisitorInterest.getNumberOfVisitsByVisitCount':
+                $this->configureViewForGetNumberOfVisitsByVisitCount($view);
+                break;
+            case 'VisitorInterest.getNumberOfVisitsByDaysSinceLast':
+                $this->configureViewForGetNumberOfVisitsByDaysSinceLast($view);
+                break;
+        }
     }
 
-    private function getDisplayPropertiesForGetNumberOfVisitsPerPage()
+    private function configureViewForGetNumberOfVisitsPerVisitDuration(ViewDataTable $view)
     {
-        return array(
-            'default_view_type'           => 'cloud',
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'translations'                => array('label' => Piwik::translate('VisitorInterest_ColumnPagesPerVisit')),
-            'enable_sort'                 => false,
-            'show_exclude_low_population' => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'show_search'                 => false,
-            'show_table_all_columns'      => false,
-            'visualization_properties'    => array(
-                'graph' => array(
-                    'max_graph_elements' => 10
-                )
-            )
-        );
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order  = 'asc';
+
+        $view->config->addTranslation('label', Piwik::translate('VisitorInterest_ColumnVisitDuration'));
+        $view->config->enable_sort = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->show_search             = false;
+        $view->config->show_table_all_columns  = false;
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = 10;
+        }
     }
 
-    private function getDisplayPropertiesForGetNumberOfVisitsByVisitCount()
+    private function configureViewForGetNumberOfVisitsPerPage(ViewDataTable $view)
     {
-        return array(
-            'columns_to_display'          => array('label', 'nb_visits', 'nb_visits_percentage'),
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'translations'                => array('label'                => Piwik::translate('VisitorInterest_VisitNum'),
-                                                   'nb_visits_percentage' => Metrics::getPercentVisitColumn()),
-            'show_exclude_low_population' => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'filter_limit'                => 15,
-            'show_search'                 => false,
-            'enable_sort'                 => false,
-            'show_table_all_columns'      => false,
-            'show_all_views_icons'        => false,
-        );
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order  = 'asc';
+
+        $view->config->addTranslation('label', Piwik::translate('VisitorInterest_ColumnVisitDuration'));
+        $view->config->enable_sort = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->show_search             = false;
+        $view->config->show_table_all_columns  = false;
+
+        if ($view->isViewDataTableId(Graph::ID)) {
+            $view->config->max_graph_elements = 10;
+        }
     }
 
-    private function getDisplayPropertiesForGetNumberOfVisitsByDaysSinceLast()
+    private function configureViewForGetNumberOfVisitsByVisitCount(ViewDataTable $view)
     {
-        return array(
-            'filter_sort_column'          => 'label',
-            'filter_sort_order'           => 'asc',
-            'translations'                => array('label' => Piwik::translate('General_DaysSinceLastVisit')),
-            'show_exclude_low_population' => false,
-            'show_offset_information'     => false,
-            'show_pagination_control'     => false,
-            'show_limit_control'          => false,
-            'show_all_views_icons'        => false,
-            'filter_limit'                => 15,
-            'show_search'                 => false,
-            'enable_sort'                 => false,
-            'show_table_all_columns'      => false
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order  = 'asc';
+        $view->requestConfig->filter_limit = 15;
+
+        $view->config->addTranslations(array(
+            'label'                => Piwik::translate('VisitorInterest_VisitNum'),
+            'nb_visits_percentage' => Metrics::getPercentVisitColumn())
         );
+
+        $view->config->columns_to_display = array('label', 'nb_visits', 'nb_visits_percentage');
+        $view->config->show_exclude_low_population = false;
+
+        $view->config->enable_sort = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->show_search             = false;
+        $view->config->show_table_all_columns  = false;
+        $view->config->show_all_views_icons    = false;
+    }
+
+    private function configureViewForGetNumberOfVisitsByDaysSinceLast(ViewDataTable $view)
+    {
+        $view->requestConfig->filter_sort_column = 'label';
+        $view->requestConfig->filter_sort_order  = 'asc';
+        $view->requestConfig->filter_limit = 15;
+
+        $view->config->show_search = false;
+        $view->config->enable_sort = false;
+        $view->config->show_offset_information = false;
+        $view->config->show_pagination_control = false;
+        $view->config->show_limit_control      = false;
+        $view->config->show_all_views_icons    = false;
+        $view->config->show_table_all_columns  = false;
+        $view->config->show_exclude_low_population = false;
+        $view->config->addTranslation('label', Piwik::translate('General_DaysSinceLastVisit'));
     }
 }
\ No newline at end of file
diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php
index ca9aaa7df985005eacd14b4972bd2dc64212f669..27c249f7a909cc955421172af62c2af0078607e8 100644
--- a/plugins/VisitsSummary/Controller.php
+++ b/plugins/VisitsSummary/Controller.php
@@ -91,6 +91,7 @@ class Controller extends \Piwik\Plugin\Controller
             $selectableColumns[] = 'nb_searches';
             $selectableColumns[] = 'nb_keywords';
         }
+
         $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
             $selectableColumns, $documentation);
 
diff --git a/tests/PHPUnit/UI b/tests/PHPUnit/UI
index f54bb82611655eb8dd9deff89c32b37f5846793b..a4c99cd1676bb7fea4fb1fb11997c08449bb7cfa 160000
--- a/tests/PHPUnit/UI
+++ b/tests/PHPUnit/UI
@@ -1 +1 @@
-Subproject commit f54bb82611655eb8dd9deff89c32b37f5846793b
+Subproject commit a4c99cd1676bb7fea4fb1fb11997c08449bb7cfa