diff --git a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
index fa784ee6..2f5b3786 100644
--- a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
+++ b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
@@ -58,6 +58,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         self._copies_rectangular_selection()
         self._shift_resizes_rectangular_selection()
         self._shift_resizes_column_selection()
+        self._mouseup_outside_grid_still_makes_a_selection()
 
     def _copies_rows(self):
         pyperclip.copy("old clipboard contents")
@@ -103,11 +104,12 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
     def _copies_rectangular_selection(self):
         pyperclip.copy("old clipboard contents")
 
-        topLeftCell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., 'Some-Other-Name')]")
-        bottomRightCell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., '14')]")
-
-        ActionChains(self.page.driver).click_and_hold(topLeftCell).move_to_element(bottomRightCell).release(bottomRightCell).perform()
+        top_left_cell = self.page.find_by_xpath(
+            "//div[contains(@class, 'slick-cell') and contains(., 'Some-Other-Name')]")
+        bottom_right_cell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., '14')]")
 
+        ActionChains(self.page.driver).click_and_hold(top_left_cell).move_to_element(bottom_right_cell) \
+            .release(bottom_right_cell).perform()
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
 
         self.assertEqual("""'Some-Other-Name','22'
@@ -116,9 +118,11 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
     def _shift_resizes_rectangular_selection(self):
         pyperclip.copy("old clipboard contents")
 
-        top_left_cell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., 'Some-Other-Name')]")
-        initial_bottom_right_cell = self.page.find_by_xpath("//div[contains(@class, 'slick-cell') and contains(., '14')]")
-        ActionChains(self.page.driver).click_and_hold(top_left_cell).move_to_element(initial_bottom_right_cell)\
+        top_left_cell = self.page.find_by_xpath(
+            "//div[contains(@class, 'slick-cell') and contains(., 'Some-Other-Name')]")
+        initial_bottom_right_cell = self.page.find_by_xpath(
+            "//div[contains(@class, 'slick-cell') and contains(., '14')]")
+        ActionChains(self.page.driver).click_and_hold(top_left_cell).move_to_element(initial_bottom_right_cell) \
             .release(initial_bottom_right_cell).perform()
 
         ActionChains(self.page.driver).key_down(Keys.SHIFT).send_keys(Keys.ARROW_RIGHT).key_up(Keys.SHIFT).perform()
@@ -131,7 +135,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         pyperclip.copy("old clipboard contents")
 
         self.page.find_by_xpath("//*[@data-test='output-column-header' and contains(., 'value')]").click()
-        ActionChains(self.page.driver).key_down(Keys.SHIFT).send_keys(Keys.ARROW_LEFT)\
+        ActionChains(self.page.driver).key_down(Keys.SHIFT).send_keys(Keys.ARROW_LEFT) \
             .key_up(Keys.SHIFT).perform()
 
         ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
@@ -142,6 +146,22 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 'Yet-Another-Name','14'""",
             pyperclip.paste())
 
+    def _mouseup_outside_grid_still_makes_a_selection(self):
+        pyperclip.copy("old clipboard contents")
+
+        bottom_right_cell = self.page.find_by_xpath(
+            "//div[contains(@class, 'slick-cell') and contains(., 'cool info')]")
+
+        load_button = self.page.find_by_xpath("//button[@id='btn-load-file']")
+        ActionChains(self.page.driver).click_and_hold(bottom_right_cell) \
+            .move_to_element(load_button) \
+            .release(load_button) \
+            .perform()
+
+        ActionChains(self.page.driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
+
+        self.assertEqual("'cool info'", pyperclip.paste())
+
     def after(self):
         self.page.close_query_tool()
         self.page.remove_server(self.server)
diff --git a/web/pgadmin/static/js/selection/column_selector.js b/web/pgadmin/static/js/selection/column_selector.js
index 8806b68c..53cdad82 100644
--- a/web/pgadmin/static/js/selection/column_selector.js
+++ b/web/pgadmin/static/js/selection/column_selector.js
@@ -8,36 +8,38 @@ define([
     var gridEventBus = new Slick.EventHandler();
 
     var init = function (grid) {
-      gridEventBus.subscribe(grid.onHeaderClick, function (event, eventArgument) {
-        var columnDefinition = eventArgument.column;
+      gridEventBus.subscribe(grid.onHeaderClick, handleHeaderClick.bind(null, grid));
+      grid.getSelectionModel().onSelectedRangesChanged
+        .subscribe(handleSelectedRangesChanged.bind(null, grid));
+    };
 
-        grid.focus();
+    var handleHeaderClick = function (grid, event, args) {
+      var columnDefinition = args.column;
 
-        if (isColumnSelectable(columnDefinition)) {
-          var $columnHeader = $(event.target);
-          if(hasClickedChildOfColumnHeader(event)) {
-            $columnHeader = $(event.target).parents(".slick-header-column");
-          }
-          $columnHeader.toggleClass('selected');
+      grid.focus();
 
-          updateRanges(grid, columnDefinition.id);
+      if (isColumnSelectable(columnDefinition)) {
+        var $columnHeader = $(event.target);
+        if (hasClickedChildOfColumnHeader(event)) {
+          $columnHeader = $(event.target).parents(".slick-header-column");
         }
-      });
-      grid.getSelectionModel().onSelectedRangesChanged
-        .subscribe(handleSelectedRangesChanged.bind(null, grid));
+        $columnHeader.toggleClass('selected');
+
+        updateRanges(grid, columnDefinition.id);
+      }
     };
 
-    var handleSelectedRangesChanged = function (grid, event, ranges) {
-      $('.slick-header-column.selected')
-        .each(function (index, columnHeader) {
-          var $spanHeaderColumn = $(columnHeader).find('[data-cell-type="column-header-row"]');
-          var columnIndex = grid.getColumnIndex($spanHeaderColumn.data('column-id'));
-          var isStillSelected = RangeSelectionHelper.isRangeSelected(ranges,
-            RangeSelectionHelper.rangeForColumn(grid, columnIndex));
-          if (!isStillSelected) {
-            $(columnHeader).toggleClass('selected')
-          }
-        });
+    var handleSelectedRangesChanged = function (grid, event, selectedRanges) {
+      $('.slick-header-column').each(function (index, columnHeader) {
+        var $spanHeaderColumn = $(columnHeader).find('[data-cell-type="column-header-row"]');
+        var columnIndex = grid.getColumnIndex($spanHeaderColumn.data('column-id'));
+
+        if (isColumnSelected(grid, selectedRanges, columnIndex)) {
+          $(columnHeader).addClass('selected');
+        } else {
+          $(columnHeader).removeClass('selected');
+        }
+      });
     };
 
     var updateRanges = function (grid, columnId) {
@@ -68,6 +70,19 @@ define([
       return columnDefinition.selectable !== false;
     };
 
+    var isColumnSelected = function (grid, selectedRanges, columnIndex) {
+      var allRangesAreRows = RangeSelectionHelper.areAllRangesCompleteRows(grid, selectedRanges);
+      return isAnyCellSelectedInColumn(grid, selectedRanges, columnIndex) && !allRangesAreRows;
+    };
+
+    var isAnyCellSelectedInColumn = function (grid, selectedRanges, columnIndex) {
+      var isStillSelected = RangeSelectionHelper.isRangeEntirelyWithinSelectedRanges(selectedRanges,
+        RangeSelectionHelper.rangeForColumn(grid, columnIndex));
+      var cellSelectedInColumn = RangeSelectionHelper.isAnyCellOfColumnSelected(selectedRanges, columnIndex);
+
+      return isStillSelected || cellSelectedInColumn;
+    };
+
     var getColumnDefinitions = function (columnDefinitions) {
       return _.map(columnDefinitions, function (columnDefinition) {
         if (isColumnSelectable(columnDefinition)) {
@@ -75,7 +90,10 @@ define([
             "<span data-cell-type='column-header-row' " +
             "       data-test='output-column-header'" +
             "       data-column-id='" + columnDefinition.id + "'>" +
-            "  <span class='column-description'>" + columnDefinition.name + "</span>" +
+            "  <span class='column-description'>" +
+            "    <span class='column-name'>" + columnDefinition.display_name + "</span>" +
+            "    <span class='column-type'>" + columnDefinition.column_type + "</span>" +
+            "  </span>" +
             "</span>";
           return _.extend(columnDefinition, {
             name: name
diff --git a/web/pgadmin/static/js/selection/copy_data.js b/web/pgadmin/static/js/selection/copy_data.js
index 166219ba..ad79d3eb 100644
--- a/web/pgadmin/static/js/selection/copy_data.js
+++ b/web/pgadmin/static/js/selection/copy_data.js
@@ -15,7 +15,7 @@ function ($, _, clipboard, RangeSelectionHelper, rangeBoundaryNavigator) {
     var data = grid.getData();
     var rows = grid.getSelectedRows();
 
-    if (allTheRangesAreFullRows(selectedRanges, columnDefinitions)) {
+    if (RangeSelectionHelper.areAllRangesCompleteRows(grid, selectedRanges)) {
       self.copied_rows = rows.map(function (rowIndex) {
         return data[rowIndex];
       });
diff --git a/web/pgadmin/static/js/selection/range_selection_helper.js b/web/pgadmin/static/js/selection/range_selection_helper.js
index 3d121f4f..936530ff 100644
--- a/web/pgadmin/static/js/selection/range_selection_helper.js
+++ b/web/pgadmin/static/js/selection/range_selection_helper.js
@@ -9,7 +9,26 @@ define(['slickgrid'], function () {
   var isRangeSelected = function (selectedRanges, range) {
     return _.any(selectedRanges, function (selectedRange) {
       return isSameRange(selectedRange, range)
-    })
+    });
+  };
+
+  var isAnyCellOfColumnSelected = function (selectedRanges, column) {
+    return _.any(selectedRanges, function (selectedRange) {
+      return selectedRange.fromCell <= column && selectedRange.toCell >= column
+    });
+  };
+
+  var isAnyCellOfRowSelected = function (selectedRanges, row) {
+    return _.any(selectedRanges, function (selectedRange) {
+      return selectedRange.fromRow <= row && selectedRange.toRow >= row
+    });
+  };
+
+  var isRangeEntirelyWithinSelectedRanges = function (selectedRanges, range) {
+    return _.any(selectedRanges, function (selectedRange) {
+      return selectedRange.fromCell <= range.fromCell && selectedRange.toCell >= range.toCell &&
+        selectedRange.fromRow <= range.fromRow && selectedRange.toRow >= range.toRow;
+    });
   };
 
   var removeRange = function (selectedRanges, range) {
@@ -30,10 +49,7 @@ define(['slickgrid'], function () {
   };
 
   var areAllRangesSingleColumns = function (ranges, grid) {
-    return _.every(ranges, function (range) {
-      return range.fromCell == range.toCell &&
-        range.fromRow == 0 && range.toRow == grid.getDataLength() - 1
-    })
+    return _.every(ranges, isRangeAColumn.bind(this, grid))
   };
 
   var rangeForRow = function (grid, rowId) {
@@ -62,6 +78,12 @@ define(['slickgrid'], function () {
     return !_.isUndefined(columnDefinitions[0].pos);
   };
 
+  var areAllRangesCompleteColumns = function (grid, ranges) {
+    return _.every(ranges, function (range) {
+      return rangeHasCompleteColumns(grid, range);
+    })
+  };
+
   var areAllRangesCompleteRows = function (grid, ranges) {
     return _.every(ranges, function (range) {
       return rangeHasCompleteRows(grid, range);
@@ -78,10 +100,34 @@ define(['slickgrid'], function () {
     return indexArray;
   };
 
-  function rangeHasCompleteRows(grid, range) {
-    var firstDataColumn = isFirstColumnData(grid.getColumns()) ? 0 : 1;
-    return range.fromCell == firstDataColumn &&
-      range.toCell == grid.getColumns().length - 1;
+  var isRangeAColumn = function (grid, range) {
+    return range.fromCell == range.toCell &&
+      range.fromRow == 0 && range.toRow == grid.getDataLength() - 1;
+  };
+
+  var rangeHasCompleteColumns = function (grid, range) {
+    return range.fromRow === 0 && range.toRow === grid.getDataLength() - 1;
+  };
+
+  var rangeHasCompleteRows = function (grid, range) {
+    return range.fromCell === getFirstDataColumnIndex(grid) &&
+      range.toCell === getLastDataColumnIndex(grid);
+  };
+
+  function getFirstDataColumnIndex(grid) {
+    return _.findIndex(grid.getColumns(), function (columnDefinition) {
+      var pos = columnDefinition.pos;
+
+      return !_.isUndefined(pos) && isSelectable(columnDefinition);
+    });
+  }
+
+  function getLastDataColumnIndex(grid) {
+    return _.findLastIndex(grid.getColumns(), isSelectable);
+  }
+
+  function isSelectable(columnDefinition) {
+    return (_.isUndefined(columnDefinition.selectable) || columnDefinition.selectable === true);
   }
 
   function selectAll(grid) {
@@ -98,12 +144,19 @@ define(['slickgrid'], function () {
     areAllRangesSingleRows: areAllRangesSingleRows,
     areAllRangesSingleColumns: areAllRangesSingleColumns,
     areAllRangesCompleteRows: areAllRangesCompleteRows,
+    areAllRangesCompleteColumns: areAllRangesCompleteColumns,
     rangeForRow: rangeForRow,
     rangeForColumn: rangeForColumn,
     isEntireGridSelected: isEntireGridSelected,
     getRangeOfWholeGrid: getRangeOfWholeGrid,
     isFirstColumnData: isFirstColumnData,
-    selectAll: selectAll,
     getIndexesOfCompleteRows: getIndexesOfCompleteRows,
+    selectAll: selectAll,
+    isRangeAColumn: isRangeAColumn,
+    rangeHasCompleteColumns: rangeHasCompleteColumns,
+    rangeHasCompleteRows: rangeHasCompleteRows,
+    isAnyCellOfColumnSelected: isAnyCellOfColumnSelected,
+    isRangeEntirelyWithinSelectedRanges: isRangeEntirelyWithinSelectedRanges,
+    isAnyCellOfRowSelected: isAnyCellOfRowSelected,
   }
 });
\ No newline at end of file
diff --git a/web/pgadmin/static/js/selection/row_selector.js b/web/pgadmin/static/js/selection/row_selector.js
index 1088f879..33d5a72e 100644
--- a/web/pgadmin/static/js/selection/row_selector.js
+++ b/web/pgadmin/static/js/selection/row_selector.js
@@ -1,39 +1,44 @@
-define(['jquery', 'sources/selection/range_selection_helper', 'slickgrid'], function ($, RangeSelectionHelper) {
+define([
+  'jquery',
+  'sources/selection/range_selection_helper',
+  'slickgrid'
+], function ($, RangeSelectionHelper) {
   var RowSelector = function () {
     var Slick = window.Slick;
 
     var gridEventBus = new Slick.EventHandler();
 
     var init = function (grid) {
-      grid.getSelectionModel()
-        .onSelectedRangesChanged.subscribe(handleSelectedRangesChanged.bind(null, grid));
+      grid.getSelectionModel().onSelectedRangesChanged
+        .subscribe(handleSelectedRangesChanged.bind(null, grid));
       gridEventBus
-        .subscribe(grid.onClick, handleClick.bind(null, grid))
+        .subscribe(grid.onClick, handleClick.bind(null, grid));
     };
 
     var handleClick = function (grid, event, args) {
       if (grid.getColumns()[args.cell].id === 'row-header-column') {
         var $rowHeaderSpan = $(event.target);
 
-        if($rowHeaderSpan.data('cell-type') != "row-header-selector") {
+        if ($rowHeaderSpan.data('cell-type') != "row-header-selector") {
           $rowHeaderSpan = $(event.target).find('[data-cell-type="row-header-selector"]');
         }
-        $rowHeaderSpan.toggleClass('selected');
+
+        $rowHeaderSpan.parent().toggleClass('selected');
         updateRanges(grid, args.row);
       }
     };
 
-    var handleSelectedRangesChanged = function (grid, event, ranges) {
-      $('[data-cell-type="row-header-selector"].selected')
-        .each(function (index, rowHeaderSpan) {
-          var $rowHeaderSpan = $(rowHeaderSpan);
-          var row = parseInt($rowHeaderSpan.data('row'));
-          var isStillSelected = RangeSelectionHelper.isRangeSelected(ranges,
-            RangeSelectionHelper.rangeForRow(grid, row));
-          if (!isStillSelected) {
-            $rowHeaderSpan.toggleClass('selected');
-          }
-        });
+    var handleSelectedRangesChanged = function (grid, event, selectedRanges) {
+      $('[data-cell-type="row-header-selector"]').each(function (index, rowHeaderSpan) {
+        var $rowHeaderSpan = $(rowHeaderSpan);
+        var row = parseInt($rowHeaderSpan.data('row'));
+
+        if (isRowSelected(grid, selectedRanges, row)) {
+          $rowHeaderSpan.parent().addClass('selected');
+        } else {
+          $rowHeaderSpan.parent().removeClass('selected');
+        }
+      });
     };
 
     var updateRanges = function (grid, rowId) {
@@ -55,6 +60,19 @@ define(['jquery', 'sources/selection/range_selection_helper', 'slickgrid'], func
       selectionModel.setSelectedRanges(newRanges);
     };
 
+    var isAnyCellSelectedInRow = function (grid, selectedRanges, row) {
+      var isStillSelected = RangeSelectionHelper.isRangeEntirelyWithinSelectedRanges(selectedRanges,
+        RangeSelectionHelper.rangeForRow(grid, row));
+      var cellSelectedInRow = RangeSelectionHelper.isAnyCellOfRowSelected(selectedRanges, row);
+
+      return isStillSelected || cellSelectedInRow;
+    };
+
+    var isRowSelected = function (grid, selectedRanges, row) {
+      var allRangesAreColumns = RangeSelectionHelper.areAllRangesCompleteColumns(grid, selectedRanges);
+      return isAnyCellSelectedInRow(grid, selectedRanges, row) && !allRangesAreColumns;
+    };
+
     var getColumnDefinitions = function (columnDefinitions) {
       columnDefinitions.unshift({
         id: 'row-header-column',
diff --git a/web/pgadmin/static/js/selection/xcell_selection_model.js b/web/pgadmin/static/js/selection/xcell_selection_model.js
new file mode 100644
index 00000000..81f46cce
--- /dev/null
+++ b/web/pgadmin/static/js/selection/xcell_selection_model.js
@@ -0,0 +1,228 @@
+define([
+  'jquery',
+  'underscore',
+  'sources/selection/range_selection_helper',
+
+  'slickgrid',
+  'slickgrid/plugins/slick.cellrangeselector'
+], function ($, _, RangeSelectionHelper) {
+  var XCellSelectionModel = function (options) {
+
+    var KEY_ARROW_RIGHT = 39;
+    var KEY_ARROW_LEFT = 37;
+    var KEY_ARROW_UP = 38;
+    var KEY_ARROW_DOWN = 40;
+
+    var _grid;
+    var _canvas;
+    var _ranges = [];
+    var _self = this;
+    var _selector = new Slick.CellRangeSelector({
+      "selectionCss": {
+        "border": "2px solid black"
+      }
+    });
+    var _options;
+    var _defaults = {
+      selectActiveCell: true
+    };
+
+
+    function init(grid) {
+      _options = $.extend(true, {}, _defaults, options);
+      _grid = grid;
+      _canvas = _grid.getCanvasNode();
+      _grid.onActiveCellChanged.subscribe(handleActiveCellChange);
+      _grid.onKeyDown.subscribe(handleKeyDown);
+      grid.registerPlugin(_selector);
+      _selector.onCellRangeSelected.subscribe(handleCellRangeSelected);
+      _selector.onBeforeCellRangeSelected.subscribe(handleBeforeCellRangeSelected);
+      $(window.parent).mouseup(handleWindowMouseUp);
+    }
+
+    function destroy() {
+      _grid.onActiveCellChanged.unsubscribe(handleActiveCellChange);
+      _grid.onKeyDown.unsubscribe(handleKeyDown);
+      _selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected);
+      _selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected);
+      _grid.unregisterPlugin(_selector);
+      $(window.parent).off('mouseup', handleWindowMouseUp);
+    }
+
+    function removeInvalidRanges(ranges) {
+      var result = [];
+
+      for (var i = 0; i < ranges.length; i++) {
+        var r = ranges[i];
+        if (_grid.canCellBeSelected(r.fromRow, r.fromCell) && _grid.canCellBeSelected(r.toRow, r.toCell)) {
+          result.push(r);
+        }
+      }
+
+      return result;
+    }
+
+    function setSelectedRanges(ranges) {
+      // simple check for: empty selection didn't change, prevent firing onSelectedRangesChanged
+      if ((!_ranges || _ranges.length === 0) && (!ranges || ranges.length === 0)) { return; }
+
+      _ranges = removeInvalidRanges(ranges);
+      _self.onSelectedRangesChanged.notify(_ranges);
+    }
+
+    function getSelectedRanges() {
+      return _ranges;
+    }
+
+    function setSelectedRows(rows) {
+      _ranges = [];
+
+      for(var i = 0 ; i < rows.length ; i++) {
+        _ranges.push(RangeSelectionHelper.rangeForRow(_grid, rows[i]));
+      }
+    }
+
+    function handleBeforeCellRangeSelected(e, args) {
+      if (_grid.getEditorLock().isActive()) {
+        e.stopPropagation();
+        return false;
+      }
+    }
+
+    function handleCellRangeSelected(e, args) {
+      setSelectedRanges([args.range]);
+    }
+
+    function handleActiveCellChange(e, args) {
+      if (_options.selectActiveCell && args.row != null && args.cell != null) {
+        setSelectedRanges([new Slick.Range(args.row, args.cell)]);
+      }
+    }
+
+    function arrowKeyPressed(event) {
+      return event.which == KEY_ARROW_RIGHT
+        || event.which == KEY_ARROW_LEFT
+        || event.which == KEY_ARROW_UP
+        || event.which == KEY_ARROW_DOWN;
+    }
+
+    function shiftArrowKeyPressed(event) {
+      return event.shiftKey && !event.ctrlKey && !event.altKey &&
+        (arrowKeyPressed(event));
+    }
+
+    function needUpdateRange(newRange) {
+      return removeInvalidRanges([newRange]).length;
+    }
+
+    function handleKeyDown(e) {
+      var ranges;
+      var lastSelectedRange;
+      var anchorActiveCell = _grid.getActiveCell();
+
+      function isKey(key) { return e.which === key; }
+
+      function getKeycode() { return e.which; }
+
+      function shouldScrollToBottommostRow() { return anchorActiveCell.row === newSelectedRange.fromRow; }
+
+      function shouldScrollToRightmostColumn() { return anchorActiveCell.cell === newSelectedRange.fromCell; }
+
+      function getMobileCellFromRange(range, activeCell) {
+        var mobileCell = {};
+
+        mobileCell.row = range.fromRow === activeCell.row ? range.toRow : range.fromRow;
+        mobileCell.cell = range.fromCell === activeCell.cell ? range.toCell : range.fromCell;
+
+        return mobileCell;
+      }
+
+      function getNewRange(rangeCorner, oppositeCorner) {
+        var newFromCell = rangeCorner.cell <= oppositeCorner.cell ? rangeCorner.cell : oppositeCorner.cell;
+        var newToCell = rangeCorner.cell <= oppositeCorner.cell ? oppositeCorner.cell : rangeCorner.cell;
+
+        var newFromRow = rangeCorner.row <= oppositeCorner.row ? rangeCorner.row : oppositeCorner.row;
+        var newToRow = rangeCorner.row <= oppositeCorner.row ? oppositeCorner.row : rangeCorner.row;
+
+        return new Slick.Range(
+          newFromRow,
+          newFromCell,
+          newToRow,
+          newToCell
+        );
+      }
+
+      if (anchorActiveCell && shiftArrowKeyPressed(e)) {
+        ranges = getSelectedRanges();
+        if (!ranges.length) {
+          ranges.push(new Slick.Range(anchorActiveCell.row, anchorActiveCell.cell));
+        }
+
+        // keyboard can work with last range only
+        lastSelectedRange = ranges.pop();
+
+        // can't handle selection out of active cell
+        if (!lastSelectedRange.contains(anchorActiveCell.row, anchorActiveCell.cell)) {
+          lastSelectedRange = new Slick.Range(anchorActiveCell.row, anchorActiveCell.cell);
+        }
+
+        var mobileCell = getMobileCellFromRange(lastSelectedRange, anchorActiveCell);
+
+        switch (getKeycode()) {
+          case KEY_ARROW_LEFT:
+            mobileCell.cell -= 1;
+            break;
+          case KEY_ARROW_RIGHT:
+            mobileCell.cell += 1;
+            break;
+          case KEY_ARROW_UP:
+            mobileCell.row -= 1;
+            break;
+          case KEY_ARROW_DOWN:
+            mobileCell.row += 1;
+            break;
+        }
+
+        var newSelectedRange = getNewRange(anchorActiveCell, mobileCell);
+
+        if (needUpdateRange(newSelectedRange)) {
+          var rowToView = shouldScrollToBottommostRow() ? newSelectedRange.toRow : newSelectedRange.fromRow;
+          var columnToView = shouldScrollToRightmostColumn() ? newSelectedRange.toCell : newSelectedRange.fromCell;
+
+          if (isKey(KEY_ARROW_RIGHT) || isKey(KEY_ARROW_LEFT)) {
+            _grid.scrollColumnIntoView(columnToView);
+          } else if (isKey(KEY_ARROW_UP) || isKey(KEY_ARROW_DOWN)) {
+            _grid.scrollRowIntoView(rowToView);
+          }
+          ranges.push(newSelectedRange);
+        } else {
+          ranges.push(lastSelectedRange);
+        }
+
+        setSelectedRanges(ranges);
+
+        e.preventDefault();
+        e.stopPropagation();
+      }
+    }
+
+    function handleWindowMouseUp(event) {
+      var selectedRange = _selector.getCurrentRange();
+      if (!_.isUndefined(selectedRange)) {
+        _grid.onDragEnd.notify({range: selectedRange});
+      }
+    }
+
+    $.extend(this, {
+      "getSelectedRanges": getSelectedRanges,
+      "setSelectedRanges": setSelectedRanges,
+      "setSelectedRows": setSelectedRows,
+
+      "init": init,
+      "destroy": destroy,
+
+      "onSelectedRangesChanged": new Slick.Event()
+    });
+  };
+  return XCellSelectionModel;
+});
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js
index 8553d050..95c12ab5 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js
@@ -81,7 +81,7 @@
     }
 
     function setSelectedRanges(ranges) {
-      // simle check for: empty selection didn't change, prevent firing onSelectedRangesChanged
+      // simple check for: empty selection didn't change, prevent firing onSelectedRangesChanged
       if ((!_ranges || _ranges.length === 0) && (!ranges || ranges.length === 0)) { return; }
       _ranges = ranges;
       _self.onSelectedRangesChanged.notify(_ranges);
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.grid.js b/web/pgadmin/static/vendor/slickgrid/slick.grid.js
index 8ebfd68b..27e8009b 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.grid.js
+++ b/web/pgadmin/static/vendor/slickgrid/slick.grid.js
@@ -2794,6 +2794,25 @@ if (typeof Slick === "undefined") {
       }
     }
 
+    function scrollColumnIntoView(columnIndex) {
+      var colspan = getColspan(row, columnIndex);
+
+      var left = columnPosLeft[columnIndex],
+        right = columnPosRight[columnIndex + (colspan > 1 ? colspan - 1 : 0)],
+        scrollRight = scrollLeft + viewportW;
+
+      if (left < scrollLeft) {
+        $viewport.scrollLeft(left);
+        handleScroll();
+        render();
+      } else if (right > scrollRight) {
+        $viewport.scrollLeft(Math.min(left, right - $viewport[0].clientWidth));
+        handleScroll();
+        render();
+      }
+
+    }
+
     function scrollCellIntoView(row, cell, doPaging) {
       scrollRowIntoView(row, doPaging);
 
@@ -3740,6 +3759,7 @@ if (typeof Slick === "undefined") {
       "scrollRowIntoView": scrollRowIntoView,
       "scrollRowToTop": scrollRowToTop,
       "scrollCellIntoView": scrollCellIntoView,
+      "scrollColumnIntoView": scrollColumnIntoView,
       "getCanvasNode": getCanvasNode,
       "focus": setFocus,
 
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 7b83fd59..987832d4 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -260,7 +260,7 @@ li {
 }
 
 .slick-header-column.ui-state-default {
-    height: 40px !important;
+    height: 32px !important;
 }
 
 #datagrid .grid-header label {
@@ -350,9 +350,19 @@ li {
 
 #datagrid .slick-header .slick-header-column.ui-state-default {
   color: #222222;
-  padding: 4px 0 4px 6px;
+  padding: 4px 0 3px 6px;
   background-color: #E8E8E8;
-  border-bottom: 1px solid black;
+  border-bottom: 1px solid silver !important;
+}
+
+#datagrid .slick-header .slick-header-column.selected {
+  background-color: #2C76B4;
+  color: #FFFFFF;
+}
+
+#datagrid .slick-header .slick-header-column .column-name {
+  font-weight: bold;
+  display: block;
 }
 
 .column-description {
@@ -404,13 +414,8 @@ input.editor-checkbox:focus {
   outline: none;
 }
 
-/* Override selected row color */
-.slick-cell.selected {
-    background-color: #DEE8F1 !important;
-}
-
 /* Remove active cell border */
-.sc.active {
+.slick-cell.active {
   border: 1px solid transparent;
   border-right: 1px dotted silver;
   border-bottom-color: silver;
@@ -441,11 +446,20 @@ input.editor-checkbox:focus {
   color: #999999;
 }
 
+/* Override selected row color */
+#datagrid .slick-row .slick-cell.selected {
+    background-color: #DEE8F1;
+}
+
 /* color the first column */
-.slick-row .slick-cell.l0.r0 {
+#datagrid .slick-row .slick-cell.l0.r0 {
   background-color: #F3F3F3;
 }
 
+#datagrid .slick-row .slick-cell.l0.r0.selected {
+  background-color: #2C76B4;
+}
+
 #datagrid div.slick-header.ui-state-default {
   background: #ffffff;
   border-bottom: none;
@@ -464,10 +478,6 @@ input.editor-checkbox:focus {
   -ms-box-sizing: content-box;
 }
 
-.slick-row.ui-widget-content {
-  border-top: 1px solid silver;
-}
-
 .select-all-icon {
   margin-left: 9px;
   vertical-align: bottom;
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
index 63debacf..fa295b36 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
@@ -8,6 +8,7 @@ define(
     'sources/selection/copy_data',
     'sources/selection/range_selection_helper',
     'sources/slickgrid/event_handlers/handle_query_output_keyboard_event',
+    'sources/selection/xcell_selection_model',
 
     'slickgrid', 'bootstrap', 'pgadmin.browser', 'wcdocker',
     'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection',
@@ -32,7 +33,7 @@ define(
   ],
   function(
     $, _, S, alertify, pgAdmin, Backbone, Backgrid, CodeMirror, pgExplain, GridSelector,
-    ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent
+    ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent, XCellSelectionModel
   ) {
     /* Return back, this has been called more than once */
     if (pgAdmin.SqlEditor)
@@ -598,6 +599,8 @@ define(
               pos: c.pos,
               field: c.name,
               name: c.label,
+              display_name: c.display_name,
+              column_type: c.column_type,
               not_null: c.not_null,
               has_default_val: c.has_default_val
             };
@@ -683,7 +686,7 @@ define(
         var grid = new Slick.Grid($data_grid, collection, grid_columns, grid_options);
         grid.registerPlugin( new Slick.AutoTooltips({ enableForHeaderCells: false }) );
         grid.registerPlugin(new ActiveCellCapture());
-        grid.setSelectionModel(new Slick.CellSelectionModel());
+        grid.setSelectionModel(new XCellSelectionModel());
         grid.registerPlugin(gridSelector);
 
         var editor_data = {
@@ -2180,6 +2183,8 @@ define(
                     'cell': col_cell,
                     'can_edit': self.can_edit,
                     'type': type,
+                    'display_name': c.display_name,
+                    'column_type': col_type,
                     'not_null': c.not_null,
                     'has_default_val': c.has_default_val
                   };
diff --git a/web/regression/javascript/selection/column_selector_spec.js b/web/regression/javascript/selection/column_selector_spec.js
index 7e6f2a5f..679af52f 100644
--- a/web/regression/javascript/selection/column_selector_spec.js
+++ b/web/regression/javascript/selection/column_selector_spec.js
@@ -4,14 +4,14 @@ define(
     "sources/selection/column_selector",
     "sources/selection/active_cell_capture",
     "sources/selection/grid_selector",
+    'sources/selection/xcell_selection_model',
 
     "slickgrid",
-    'slickgrid/slick.cellrangedecorator',
-    'slickgrid/slick.cellrangeselector',
-    "slickgrid/slick.cellselectionmodel",
+    'slickgrid/plugins/slick.cellrangedecorator',
+    'slickgrid/plugins/slick.cellrangeselector',
     "slickgrid/slick.grid",
   ],
-  function ($, _, ColumnSelector, ActiveCellCapture, GridSelector) {
+  function ($, _, ColumnSelector, ActiveCellCapture, GridSelector, XCellSelectionModel) {
     var KEY_RIGHT = 39;
     var KEY_LEFT = 37;
     var KEY_UP = 38;
@@ -31,6 +31,10 @@ define(
           'some-column-name': 'first value',
           'second column': 'second value',
           'third column': 'nonselectable value'
+        }, {
+          'some-column-name': 'row 1 - first value',
+          'second column': 'row 1 - second value',
+          'third column': 'row 1 - nonselectable value'
         }];
 
         columns = [
@@ -38,26 +42,36 @@ define(
             id: 'row-header-column',
             name: 'row header column name',
             selectable: false,
+            display_name: 'row header column name',
+            column_type: 'text'
           },
           {
             id: '1',
             name: 'some-column-name',
-            pos: 0
+            pos: 0,
+            display_name: 'some-column-name',
+            column_type: 'text'
           },
           {
             id: '2',
             name: 'second column',
-            pos: 1
+            pos: 1,
+            display_name: 'second column',
+            column_type: 'json'
           },
           {
             id: 'third-column-id',
             name: 'third column',
-            pos: 2
+            pos: 2,
+            display_name: 'third column',
+            column_type: 'text'
           },
           {
             name: 'some-non-selectable-column',
             selectable: false,
-            pos: 3
+            pos: 3,
+            display_name: 'some-non-selectable-column',
+            column_type: 'numeric'
           }
         ];
       });
@@ -67,8 +81,12 @@ define(
 
         expect($(container.find('.slick-header-columns .slick-column-name')[1]).text())
           .toContain('some-column-name');
+        expect($(container.find('.slick-header-columns .slick-column-name')[1]).text())
+          .toContain('text');
         expect($(container.find('.slick-header-columns .slick-column-name')[2]).text())
           .toContain('second column');
+        expect($(container.find('.slick-header-columns .slick-column-name')[2]).text())
+          .toContain('json');
       });
 
       it("preserves the other attributes of column definitions", function () {
@@ -95,7 +113,7 @@ define(
           grid = new SlickGrid(container, data, columns);
 
           grid.registerPlugin(new ActiveCellCapture());
-          cellSelectionModel = new Slick.CellSelectionModel();
+          cellSelectionModel = new XCellSelectionModel();
           grid.setSelectionModel(cellSelectionModel);
 
           grid.registerPlugin(columnSelector);
@@ -128,10 +146,10 @@ define(
         describe("when the user clicks an additional column header", function () {
           beforeEach(function () {
             container.find('.slick-header-column:contains(some-column-name)').click();
+            container.find('.slick-header-column:contains(second column)').click();
           });
 
           it("selects additional columns", function () {
-            container.find('.slick-header-column:contains(second column)').click();
 
             var selectedRanges = cellSelectionModel.getSelectedRanges();
 
@@ -147,30 +165,34 @@ define(
 
           describe("and presses shift + right-arrow", function () {
             beforeEach(function () {
-              container.find('.slick-header-column:contains(second column)').click();
+              pressShiftArrow(KEY_RIGHT);
             });
 
             it("keeps the last column selected", function () {
-              pressShiftArrow(KEY_RIGHT);
-
               expect(cellSelectionModel.getSelectedRanges().length).toBe(1);
             });
 
             it("grows the selection to the right", function () {
-              pressShiftArrow(KEY_RIGHT);
-
               var selectedRange = cellSelectionModel.getSelectedRanges()[0];
               expect(selectedRange.fromCell).toBe(2);
               expect(selectedRange.toCell).toBe(3);
               expect(selectedRange.fromRow).toBe(0);
               expect(selectedRange.toRow).toBe(9);
             });
+
+            it("keeps selected class on columns 2 and 3", function () {
+              expect($(container.find('.slick-header-column:contains(second column)')).hasClass('selected'))
+                .toBe(true);
+              expect($(container.find('.slick-header-column:contains(third column)')).hasClass('selected'))
+                .toBe(true);
+              expect($(container.find('.slick-header-column:contains(some-column-name)')).hasClass('selected'))
+                .toBe(false);
+            });
           });
 
           describe("when the user deselects the last selected column header", function () {
             beforeEach(function () {
               container.find('.slick-header-column:contains(second column)').click();
-              container.find('.slick-header-column:contains(second column)').click();
             });
 
             describe("and presses shift + right-arrow", function () {
@@ -226,7 +248,7 @@ define(
             expect(column.toCell).toBe(1);
             expect(column.fromRow).toBe(0);
             expect(column.toRow).toBe(9);
-          })
+          });
         });
 
         describe("clicking a second time", function () {
@@ -266,7 +288,7 @@ define(
 
         describe("when a non-column range was already selected", function () {
           beforeEach(function () {
-            var selectedRanges = [new Slick.Range(0, 0, 1, 0)];
+            var selectedRanges = [new Slick.Range(0, 0, 2, 0)];
             cellSelectionModel.setSelectedRanges(selectedRanges);
           });
 
@@ -275,7 +297,90 @@ define(
 
             var selectedRanges = cellSelectionModel.getSelectedRanges();
             expectOnlyTheFirstColumnToBeSelected(selectedRanges);
-          })
+          });
+        });
+
+        describe('when a column is selected', function () {
+          beforeEach(function () {
+            container.find('.slick-header-column:contains(some-column-name)').click();
+          });
+
+          describe('when the user click a cell on the current range', function () {
+            beforeEach(function () {
+              container.find('.slick-cell.l1.r1')[1].click();
+            });
+
+            it('column is deselected', function () {
+
+              var selectedRanges = cellSelectionModel.getSelectedRanges();
+
+              expect(selectedRanges.length).toBe(1);
+
+              var column = selectedRanges[0];
+
+              expect(column.fromCell).toBe(1);
+              expect(column.toCell).toBe(1);
+              expect(column.fromRow).toBe(1);
+              expect(column.toRow).toBe(1);
+            });
+
+            it('keep select class on column header', function () {
+              expect($(container.find('.slick-header-column:contains(some-column-name)')).hasClass('selected'))
+                .toBeTruthy();
+            });
+          });
+
+          describe('when the user click a cell outside the current range', function () {
+            beforeEach(function () {
+              container.find('.slick-cell.l2.r2')[2].click();
+            });
+
+            it('column is deselected', function () {
+
+              var selectedRanges = cellSelectionModel.getSelectedRanges();
+
+              expect(selectedRanges.length).toBe(1);
+
+              var column = selectedRanges[0];
+
+              expect(column.fromCell).toBe(2);
+              expect(column.toCell).toBe(2);
+              expect(column.fromRow).toBe(2);
+              expect(column.toRow).toBe(2);
+            });
+
+            it('remove select class on "some-column-name" column header', function () {
+              expect($(container.find('.slick-header-column:contains(some-column-name)')).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-header-column:contains(second column)')).hasClass('selected'))
+                .toBeTruthy();
+            });
+          });
+
+          describe('when the user click in a row header', function () {
+            beforeEach(function () {
+              var selectedRanges = [new Slick.Range(1, 1, 1, 3)];
+              cellSelectionModel.setSelectedRanges(selectedRanges);
+            });
+
+            it('column is deselected', function () {
+              var selectedRanges = cellSelectionModel.getSelectedRanges();
+
+              expect(selectedRanges.length).toBe(1);
+
+              var column = selectedRanges[0];
+
+              expect(column.fromCell).toBe(1);
+              expect(column.toCell).toBe(3);
+              expect(column.fromRow).toBe(1);
+              expect(column.toRow).toBe(1);
+            });
+
+            it('no column should have the class "selected"', function () {
+              expect($(container.find('.slick-header-column:contains(some-column-name)')).hasClass('selected'))
+                .toBeFalsy();
+            });
+          });
         });
       });
 
@@ -284,7 +389,7 @@ define(
         columns = columnSelector.getColumnDefinitions(columns);
         var grid = new SlickGrid(container, data, columns, options);
 
-        var cellSelectionModel = new Slick.CellSelectionModel();
+        var cellSelectionModel = new XCellSelectionModel();
         grid.setSelectionModel(cellSelectionModel);
 
         grid.registerPlugin(columnSelector);
diff --git a/web/regression/javascript/selection/copy_data_spec.js b/web/regression/javascript/selection/copy_data_spec.js
index 718a830b..561576ce 100644
--- a/web/regression/javascript/selection/copy_data_spec.js
+++ b/web/regression/javascript/selection/copy_data_spec.js
@@ -10,21 +10,29 @@
 define(
   ["jquery",
     "slickgrid/slick.grid",
-    "slickgrid/slick.rowselectionmodel",
+    "sources/selection/xcell_selection_model",
     "sources/selection/copy_data",
     "sources/selection/clipboard",
     "sources/selection/range_selection_helper"
   ],
-  function ($, SlickGrid, RowSelectionModel, copyData, clipboard, RangeSelectionHelper) {
+  function ($, SlickGrid, XCellSelectionModel, copyData, clipboard, RangeSelectionHelper) {
     describe('copyData', function () {
-      var grid, sqlEditor;
+      var grid, sqlEditor, gridContainer, buttonPasteRow;
 
       beforeEach(function () {
         var data = [[1, "leopord", "12"],
           [2, "lion", "13"],
           [3, "puma", "9"]];
 
-        var columns = [{
+        var columns = [
+          {
+            id: 'row-header-column',
+            name: 'row header column name',
+            selectable: false,
+            display_name: 'row header column name',
+            column_type: 'text'
+          },
+          {
             name: "id",
             pos: 0,
             label: "id<br> numeric",
@@ -48,17 +56,18 @@ define(
           }
           ]
         ;
-        var gridContainer = $("<div id='grid'></div>");
+        gridContainer = $("<div id='grid'></div>");
         $("body").append(gridContainer);
-        $("body").append("<button id='btn-paste-row' disabled></button>");
+        buttonPasteRow = $("<button id='btn-paste-row' disabled></button>");
+        $("body").append(buttonPasteRow);
         grid = new Slick.Grid("#grid", data, columns, {});
-        grid.setSelectionModel(new Slick.RowSelectionModel({selectActiveRow: false}));
+        grid.setSelectionModel(new XCellSelectionModel());
         sqlEditor = {slickgrid: grid};
       });
 
       afterEach(function() {
-        $("body").remove('#grid');
-        $("body").remove('#btn-paste-row');
+        gridContainer.remove();
+        buttonPasteRow.remove();
       });
 
       describe("when rows are selected", function () {
@@ -92,8 +101,8 @@ define(
 
       describe("when a column is selected", function () {
         beforeEach(function () {
-          var firstColumn = new Slick.Range(0, 0, 2, 0);
-          grid.getSelectionModel().setSelectedRanges([firstColumn])
+          var firstDataColumn = RangeSelectionHelper.rangeForColumn(grid, 1);
+          grid.getSelectionModel().setSelectedRanges([firstDataColumn])
         });
 
         it("copies text to the clipboard", function () {
@@ -117,9 +126,11 @@ define(
         });
 
         describe("when the user can edit the grid", function () {
-          it("disables the paste row button", function () {
+          beforeEach(function () {
             copyData.apply(_.extend({can_edit: true}, sqlEditor));
+          });
 
+          it("disables the paste row button", function () {
             expect($("#btn-paste-row").prop('disabled')).toBe(true);
           });
         });
diff --git a/web/regression/javascript/selection/grid_selector_spec.js b/web/regression/javascript/selection/grid_selector_spec.js
index 5ea63692..d79d417f 100644
--- a/web/regression/javascript/selection/grid_selector_spec.js
+++ b/web/regression/javascript/selection/grid_selector_spec.js
@@ -1,12 +1,12 @@
 define(["jquery",
     "underscore",
     "slickgrid/slick.grid",
-    "slickgrid/slick.rowselectionmodel",
+    "sources/selection/xcell_selection_model",
     "sources/selection/grid_selector"
   ],
-  function ($, _, SlickGrid, RowSelectionModel, GridSelector) {
+  function ($, _, SlickGrid, XCellSelectionModel, GridSelector) {
     describe("GridSelector", function () {
-      var container, data, columns, gridSelector, rowSelectionModel;
+      var container, data, columns, gridSelector, xCellSelectionModel;
 
       beforeEach(function () {
         container = $("<div></div>");
@@ -30,8 +30,8 @@ define(["jquery",
         }
         var grid = new SlickGrid(container, data, columns);
 
-        rowSelectionModel = new RowSelectionModel();
-        grid.setSelectionModel(rowSelectionModel);
+        xCellSelectionModel = new XCellSelectionModel();
+        grid.setSelectionModel(xCellSelectionModel);
 
         grid.registerPlugin(gridSelector);
         grid.invalidate();
@@ -58,7 +58,7 @@ define(["jquery",
         it("selects the whole grid", function () {
           container.find("[title='Select/Deselect All']").parent().click();
 
-          var selectedRanges = rowSelectionModel.getSelectedRanges();
+          var selectedRanges = xCellSelectionModel.getSelectedRanges();
           expect(selectedRanges.length).toBe(1);
           var selectedRange = selectedRanges[0];
           expect(selectedRange.fromCell).toBe(1);
@@ -79,7 +79,7 @@ define(["jquery",
         it("selects all the cells", function () {
           container.find("[title='Select/Deselect All']").click();
 
-          var selectedRanges = rowSelectionModel.getSelectedRanges();
+          var selectedRanges = xCellSelectionModel.getSelectedRanges();
           expect(selectedRanges.length).toBe(1);
           var selectedRange = selectedRanges[0];
           expect(selectedRange.fromCell).toBe(1);
@@ -96,7 +96,7 @@ define(["jquery",
           it("deselects all the cells", function () {
             container.find("[title='Select/Deselect All']").click();
 
-            var selectedRanges = rowSelectionModel.getSelectedRanges();
+            var selectedRanges = xCellSelectionModel.getSelectedRanges();
             expect(selectedRanges.length).toBe(0);
           });
         });
diff --git a/web/regression/javascript/selection/row_selector_spec.js b/web/regression/javascript/selection/row_selector_spec.js
index 78348bca..e0bc63be 100644
--- a/web/regression/javascript/selection/row_selector_spec.js
+++ b/web/regression/javascript/selection/row_selector_spec.js
@@ -4,13 +4,17 @@ define(
     "slickgrid/slick.grid",
     "sources/selection/active_cell_capture",
     "sources/selection/row_selector",
+    'sources/selection/xcell_selection_model',
 
     "slickgrid",
-    'slickgrid/slick.cellrangedecorator',
-    'slickgrid/slick.cellrangeselector',
-    "slickgrid/slick.cellselectionmodel",
+    'slickgrid/plugins/slick.cellrangedecorator',
+    'slickgrid/plugins/slick.cellrangeselector',
   ],
-  function ($, _, SlickGrid, ActiveCellCapture, RowSelector, Slick) {
+  function ($, _, SlickGrid, ActiveCellCapture, RowSelector, XCellSelectionModel, Slick) {
+    var KEY_RIGHT = 39;
+    var KEY_LEFT = 37;
+    var KEY_UP = 38;
+    var KEY_DOWN = 40;
     describe("RowSelector", function () {
       var container, data, columnDefinitions, grid, cellSelectionModel;
 
@@ -40,7 +44,7 @@ define(
         grid = new SlickGrid(container, data, columnDefinitions);
 
         grid.registerPlugin(new ActiveCellCapture());
-        cellSelectionModel = new Slick.CellSelectionModel();
+        cellSelectionModel = new XCellSelectionModel();
         grid.setSelectionModel(cellSelectionModel);
 
         grid.registerPlugin(rowSelector);
@@ -81,28 +85,152 @@ define(
             expectOnlyTheFirstRowToBeSelected(selectedRanges);
           });
 
-          it("add selected class to span", function () {
+          it("add selected class to parent of the span", function () {
             container.find('.slick-row .slick-cell:first-child span[data-cell-type="row-header-selector"]')[5].click();
 
-            expect($(container.find('.slick-row .slick-cell:first-child span[data-cell-type="row-header-selector"]')[5])
+            expect($(container.find('.slick-row .slick-cell:first-child ')[5])
               .hasClass('selected')).toBeTruthy();
           });
         });
 
         describe("when the user clicks a row header", function () {
+          beforeEach(function () {
+            container.find('.slick-row .slick-cell:first-child')[1].click();
+
+          });
           it("selects the row", function () {
-            container.find('.slick-row .slick-cell:first-child')[0].click();
 
             var selectedRanges = cellSelectionModel.getSelectedRanges();
-            expectOnlyTheFirstRowToBeSelected(selectedRanges);
+            var row = selectedRanges[0];
+
+            expect(selectedRanges.length).toEqual(1);
+            expect(row.fromCell).toBe(1);
+            expect(row.toCell).toBe(2);
+            expect(row.fromRow).toBe(1);
+            expect(row.toRow).toBe(1);
           });
 
-          it("add selected class to span", function () {
-            container.find('.slick-row .slick-cell:first-child')[7].click();
+          it("add selected class to parent of the span", function () {
 
-            expect($(container.find('.slick-row .slick-cell:first-child span[data-cell-type="row-header-selector"]')[7])
+            expect($(container.find('.slick-row .slick-cell:first-child ')[1])
               .hasClass('selected')).toBeTruthy();
           });
+
+          describe("when the user clicks again the same row header", function () {
+            it("add selected class to parent of the span", function () {
+              container.find('.slick-row .slick-cell:first-child span[data-cell-type="row-header-selector"]')[1].click();
+
+              expect($(container.find('.slick-row .slick-cell:first-child ')[1])
+                .hasClass('selected')).toBeFalsy();
+            });
+          });
+
+          describe("and presses shift + down-arrow", function () {
+            beforeEach(function () {
+              pressShiftArrow(KEY_DOWN);
+            });
+
+            it("keeps the last row selected", function () {
+              expect(cellSelectionModel.getSelectedRanges().length).toBe(1);
+            });
+
+            it("grows the selection down", function () {
+              var selectedRanges = cellSelectionModel.getSelectedRanges();
+
+              var row = selectedRanges[0];
+
+              expect(selectedRanges.length).toEqual(1);
+              expect(row.fromCell).toBe(1);
+              expect(row.toCell).toBe(2);
+              expect(row.fromRow).toBe(1);
+              expect(row.toRow).toBe(2);
+            });
+
+            it("keeps selected class on rows 1 and 2", function () {
+              expect($(container.find('.slick-row .slick-cell:first-child ')[0])
+                .hasClass('selected')).toBeFalsy();
+              expect($(container.find('.slick-row .slick-cell:first-child ')[1])
+                .hasClass('selected')).toBeTruthy();
+              expect($(container.find('.slick-row .slick-cell:first-child ')[2])
+                .hasClass('selected')).toBeTruthy();
+              expect($(container.find('.slick-row .slick-cell:first-child ')[3])
+                .hasClass('selected')).toBeFalsy();
+            });
+          });
+
+          describe('when the user clicks a cell on the current range', function () {
+            beforeEach(function () {
+              container.find('.slick-cell.l1.r1')[5].click();
+            });
+
+            it('row gets deselected', function () {
+
+              var selectedRanges = cellSelectionModel.getSelectedRanges();
+
+              expect(selectedRanges.length).toBe(1);
+
+              var newSelection = selectedRanges[0];
+
+              expect(newSelection.fromCell).toBe(1);
+              expect(newSelection.fromRow).toBe(5);
+              expect(newSelection.toCell).toBe(1);
+              expect(newSelection.toRow).toBe(5);
+            });
+
+            it('keep select class on row header', function () {
+              expect($(container.find('.slick-cell.l0.r0')[5]).hasClass('selected'))
+                .toBeTruthy();
+            });
+          });
+
+          describe('when the user clicks a cell outside the current range', function () {
+            beforeEach(function () {
+              container.find('.slick-cell.l2.r2')[2].click();
+            });
+
+            it('row gets deselected', function () {
+
+              var selectedRanges = cellSelectionModel.getSelectedRanges();
+
+              expect(selectedRanges.length).toBe(1);
+
+              var newSelection = selectedRanges[0];
+
+              expect(newSelection.fromCell).toBe(2);
+              expect(newSelection.fromRow).toBe(2);
+              expect(newSelection.toCell).toBe(2);
+              expect(newSelection.toRow).toBe(2);
+            });
+
+            it('remove select class on "some-column-name" column header', function () {
+              expect($(container.find('.slick-cell.l0.r0')[5]).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-cell.l0.r0')[2]).hasClass('selected'))
+                .toBeTruthy();
+            });
+          });
+
+          describe('when the user has a column selected', function () {
+            beforeEach(function () {
+              var selectedRanges = [new Slick.Range(0, 1, 9, 1)];
+              cellSelectionModel.setSelectedRanges(selectedRanges);
+            });
+
+            it('no row should have the class "selected"', function () {
+              expect($(container.find('.slick-cell.l0.r0')[0]).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-cell.l0.r0')[1]).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-cell.l0.r0')[2]).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-cell.l0.r0')[3]).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-cell.l0.r0')[4]).hasClass('selected'))
+                .toBeFalsy();
+              expect($(container.find('.slick-cell.l0.r0')[5]).hasClass('selected'))
+                .toBeFalsy();
+            });
+          });
         });
 
         describe("when the user clicks multiple row headers", function () {
@@ -134,7 +262,7 @@ define(
             var selectedRanges = cellSelectionModel.getSelectedRanges();
 
             expectOnlyTheFirstRowToBeSelected(selectedRanges);
-          })
+          });
         });
 
         describe("when the row is deselected through setSelectedRanges", function () {
@@ -169,6 +297,16 @@ define(
           })
         });
       });
+
+      function pressShiftArrow(keyCode) {
+        var pressEvent = new $.Event("keydown");
+        pressEvent.shiftKey = true;
+        pressEvent.ctrlKey = false;
+        pressEvent.altKey = false;
+        pressEvent.which = keyCode;
+
+        $(container.find('.grid-canvas')).trigger(pressEvent);
+      }
     });
 
     function expectOnlyTheFirstRowToBeSelected(selectedRanges) {
diff --git a/web/regression/javascript/selection/xcell_selection_model_spec.js b/web/regression/javascript/selection/xcell_selection_model_spec.js
new file mode 100644
index 00000000..1682c244
--- /dev/null
+++ b/web/regression/javascript/selection/xcell_selection_model_spec.js
@@ -0,0 +1,513 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2017, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////////////////
+
+define([
+  'sources/selection/xcell_selection_model',
+  "slickgrid/slick.grid",
+  'slickgrid',
+], function (XCellSelectionModel, SlickGrid, Slick) {
+  describe('XCellSelectionModel', function () {
+    var KEY_RIGHT = 39;
+    var KEY_LEFT = 37;
+    var KEY_UP = 38;
+    var KEY_DOWN = 40;
+
+    var container, grid;
+    var oldWindowParent = window.parent;
+
+    beforeEach(function () {
+      window.parent = window;
+
+      var columns = [{
+        id: 'row-header-column',
+        name: 'row header column name',
+        selectable: false,
+      }, {
+        id: '1',
+        name: 'some-column-name',
+        pos: 0
+      }, {
+        id: 'second-column-id',
+        name: 'second column',
+        pos: 1
+      }, {
+        id: 'third-column-id',
+        name: 'third column',
+        pos: 2
+      },
+      ];
+
+      var data = [];
+      for (var i = 0; i < 10; i++) {
+        data.push({
+          'some-column-name': 'some-value-' + i,
+          'second column': 'second value ' + i,
+          'third column': 'third value ' + i,
+          'fourth column': 'fourth value ' + i,
+        });
+      }
+      container = $("<div></div>");
+      container.height(9999);
+      container.width(9999);
+
+      grid = new SlickGrid(container, data, columns);
+      grid.setSelectionModel(new XCellSelectionModel());
+      $("body").append(container);
+    });
+
+    afterEach(function () {
+      grid.destroy();
+      container.remove();
+      window.parent = oldWindowParent;
+    });
+
+    describe('handleKeyDown', function () {
+      describe('when we press a random key', function () {
+        it('should not change the range', function () {
+          var range = new Slick.Range(1, 2);
+          grid.setActiveCell(1, 2);
+          grid.getSelectionModel().setSelectedRanges([range]);
+          pressKey(72);
+
+          expect(grid.getSelectionModel().getSelectedRanges()[0]).toEqual(range);
+        });
+      });
+
+      describe('when we press an arrow key ', function () {
+        it('should select the cell to the right', function () {
+          var range = new Slick.Range(1, 2);
+          grid.setActiveCell(1, 2);
+          grid.getSelectionModel().setSelectedRanges([range]);
+          pressKey(KEY_RIGHT);
+
+          expectOneSelectedRange(1, 3, 1, 3);
+        });
+      });
+
+      describe('when we press shift', function () {
+        describe('and we press an arrow key', function () {
+          var scrollColumnIntoViewSpy, scrollRowIntoViewSpy;
+
+          beforeEach(function () {
+            scrollColumnIntoViewSpy = spyOn(grid, 'scrollColumnIntoView');
+            scrollRowIntoViewSpy = spyOn(grid, 'scrollRowIntoView');
+          });
+
+          describe('the right arrow', function () {
+            describe('when a cell is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(1, 1);
+                grid.setActiveCell(1, 1);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_RIGHT);
+              });
+
+              it('increases the range by one to the right', function () {
+                expectOneSelectedRange(1, 1, 1, 2);
+              });
+
+              it('should scroll the next column into view', function () {
+                expect(scrollColumnIntoViewSpy).toHaveBeenCalledWith(2);
+                expect(scrollRowIntoViewSpy).not.toHaveBeenCalled();
+              });
+
+              it('pressing right again grows the range right', function () {
+                pressShiftPlusKey(KEY_RIGHT);
+
+                expectOneSelectedRange(1, 1, 1, 3);
+              });
+
+              it('then pressing left keeps the original selection', function () {
+                pressShiftPlusKey(KEY_LEFT);
+
+                expectOneSelectedRange(1, 1, 1, 1);
+              });
+            });
+
+            describe('when a column is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(0, 1, 9, 1);
+                grid.setActiveCell(0, 1);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_RIGHT);
+              });
+
+              it('increases the range by one column to the right', function () {
+                expectOneSelectedRange(0, 1, 9, 2);
+              });
+
+              it('should scroll the next column into view', function () {
+                expect(scrollColumnIntoViewSpy).toHaveBeenCalledWith(2);
+                expect(scrollRowIntoViewSpy).not.toHaveBeenCalled();
+              });
+            });
+          });
+
+          describe('the left arrow', function () {
+            describe('when a cell is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(1, 3);
+                grid.setActiveCell(1, 3);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_LEFT);
+              });
+
+              it('increases the range by one to the left', function () {
+                expectOneSelectedRange(1, 2, 1, 3);
+              });
+
+              it('should scroll previous column into view', function () {
+                expect(scrollColumnIntoViewSpy).toHaveBeenCalledWith(2);
+                expect(scrollRowIntoViewSpy).not.toHaveBeenCalled();
+              });
+
+              it('pressing left again grows the range the left', function () {
+                pressShiftPlusKey(KEY_LEFT);
+
+                expectOneSelectedRange(1, 1, 1, 3);
+              });
+
+              it('then pressing right keeps the original selection', function () {
+                pressShiftPlusKey(KEY_RIGHT);
+
+                expectOneSelectedRange(1, 3, 1, 3);
+              });
+            });
+
+            describe('when a column is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(0, 2, 9, 2);
+                grid.setActiveCell(0, 2);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_LEFT);
+              });
+
+              it('increases the range by one column to the left', function () {
+                expectOneSelectedRange(0, 1, 9, 2);
+              });
+
+              it('should scroll previous column into view', function () {
+                expect(scrollColumnIntoViewSpy).toHaveBeenCalledWith(1);
+                expect(scrollRowIntoViewSpy).not.toHaveBeenCalled();
+              });
+            });
+          });
+
+          describe('the up arrow', function () {
+            describe('when a cell is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(2, 2);
+                grid.setActiveCell(2, 2);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_UP);
+              });
+
+              it('increases the range by one up', function () {
+                expectOneSelectedRange(1, 2, 2, 2);
+              });
+
+              it('should scroll the row above into view', function () {
+                expect(scrollRowIntoViewSpy).toHaveBeenCalledWith(1);
+                expect(scrollColumnIntoViewSpy).not.toHaveBeenCalled();
+              });
+
+              it('pressing up again grows the range up', function () {
+                pressShiftPlusKey(KEY_UP);
+
+                expectOneSelectedRange(0, 2, 2, 2);
+              });
+
+              it('then pressing down keeps the original selection', function () {
+                pressShiftPlusKey(KEY_DOWN);
+
+                expectOneSelectedRange(2, 2, 2, 2);
+              });
+            });
+
+            describe('when a row is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(2, 1, 2, 3);
+                grid.setActiveCell(2, 1);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_UP);
+              });
+
+              it('increases the range by one row up', function () {
+                expectOneSelectedRange(1, 1, 2, 3);
+              });
+
+              it('should scroll the row above into view', function () {
+                expect(scrollRowIntoViewSpy).toHaveBeenCalledWith(1);
+                expect(scrollColumnIntoViewSpy).not.toHaveBeenCalled();
+              });
+            });
+          });
+
+          describe('the down arrow', function () {
+            describe('when a cell is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(2, 2);
+                grid.setActiveCell(2, 2);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_DOWN);
+              });
+
+              it('increases the range by one down', function () {
+                expectOneSelectedRange(2, 2, 3, 2);
+              });
+
+              it('should scroll the row below into view', function () {
+                expect(scrollRowIntoViewSpy).toHaveBeenCalledWith(3);
+                expect(scrollColumnIntoViewSpy).not.toHaveBeenCalled();
+              });
+
+              it('pressing down again grows the range down', function () {
+                pressShiftPlusKey(KEY_DOWN);
+
+                expectOneSelectedRange(2, 2, 4, 2);
+              });
+
+              it('then pressing up keeps the original selection', function () {
+                pressShiftPlusKey(KEY_UP);
+
+                expectOneSelectedRange(2, 2, 2, 2);
+              });
+            });
+
+            describe('when a row is selected', function () {
+              beforeEach(function () {
+                var range = new Slick.Range(2, 1, 2, 3);
+                grid.setActiveCell(2, 1);
+                grid.getSelectionModel().setSelectedRanges([range]);
+                pressShiftPlusKey(KEY_DOWN);
+              });
+
+              it('increases the range by one row down', function () {
+                expectOneSelectedRange(2, 1, 3, 3);
+              });
+
+              it('should scroll the row below into view', function () {
+                expect(scrollRowIntoViewSpy).toHaveBeenCalledWith(3);
+                expect(scrollColumnIntoViewSpy).not.toHaveBeenCalled();
+              });
+            });
+          });
+
+          describe('rectangular selection works', function () {
+
+            it('in the down-and-rightward direction', function () {
+              var range = new Slick.Range(1, 1);
+              grid.setActiveCell(1, 1);
+              grid.getSelectionModel().setSelectedRanges([range]);
+
+              pressShiftPlusKey(KEY_DOWN);
+              pressShiftPlusKey(KEY_DOWN);
+              pressShiftPlusKey(KEY_DOWN);
+              pressShiftPlusKey(KEY_RIGHT);
+              pressShiftPlusKey(KEY_RIGHT);
+
+              expectOneSelectedRange(1, 1, 4, 3);
+            });
+
+            it('in the up-and-leftward direction', function () {
+              var range = new Slick.Range(4, 3);
+              grid.setActiveCell(4, 3);
+              grid.getSelectionModel().setSelectedRanges([range]);
+
+              pressShiftPlusKey(KEY_UP);
+              pressShiftPlusKey(KEY_UP);
+              pressShiftPlusKey(KEY_UP);
+              pressShiftPlusKey(KEY_LEFT);
+              pressShiftPlusKey(KEY_LEFT);
+
+              expectOneSelectedRange(1, 1, 4, 3);
+            });
+
+            it('in the up-and-rightward direction', function () {
+              var range = new Slick.Range(4, 1);
+              grid.setActiveCell(4, 1);
+              grid.getSelectionModel().setSelectedRanges([range]);
+
+              pressShiftPlusKey(KEY_UP);
+              pressShiftPlusKey(KEY_UP);
+              pressShiftPlusKey(KEY_UP);
+              pressShiftPlusKey(KEY_RIGHT);
+              pressShiftPlusKey(KEY_RIGHT);
+
+              expectOneSelectedRange(1, 1, 4, 3);
+            });
+
+            it('in the down-and-leftward direction', function () {
+              var range = new Slick.Range(1, 3);
+              grid.setActiveCell(1, 3);
+              grid.getSelectionModel().setSelectedRanges([range]);
+
+              pressShiftPlusKey(KEY_DOWN);
+              pressShiftPlusKey(KEY_DOWN);
+              pressShiftPlusKey(KEY_DOWN);
+              pressShiftPlusKey(KEY_LEFT);
+              pressShiftPlusKey(KEY_LEFT);
+
+              expectOneSelectedRange(1, 1, 4, 3);
+            });
+          });
+
+          describe('and we are on an edge', function () {
+            var range;
+
+            beforeEach(function () {
+              range = new Slick.Range(2, 1);
+              grid.setActiveCell(2, 1);
+              grid.getSelectionModel().setSelectedRanges([range]);
+            });
+
+            it('we still have the selected range before we arrowed', function () {
+              pressShiftPlusKey(KEY_LEFT);
+              expectOneSelectedRange(2, 1, 2, 1);
+            });
+          });
+        });
+      });
+    });
+
+    describe('when we drag and drop', function () {
+      var dd;
+      // We could not find an elegant way to calculate this value
+      // after changing window size we saw this was a constant value
+      var offsetLeftColumns = 100;
+
+      function cellTopPosition($cell, rowNumber) {
+        return $(grid.getCanvasNode()).offset().top + $cell[0].scrollHeight * rowNumber;
+      }
+
+      function cellLeftPosition(columnNumber) {
+        return $(grid.getCanvasNode()).offset().left + offsetLeftColumns * columnNumber;
+      }
+
+      beforeEach(function () {
+        var initialPosition = {cell: 3, row: 4};
+        var $cell = $($('.slick-cell.l3')[initialPosition.row]);
+        var event = {
+          target: $cell,
+          isPropagationStopped: jasmine.createSpy('isPropagationStopped').and.returnValue(false),
+          isImmediatePropagationStopped: jasmine.createSpy('isImmediatePropagationStopped').and.returnValue(false),
+          stopImmediatePropagation: jasmine.createSpy('stopImmediatePropagation')
+        };
+
+        dd = {
+          grid: grid,
+          startX: cellLeftPosition(initialPosition.cell),
+          startY: cellTopPosition($cell, initialPosition.row)
+        };
+
+        grid.onDragStart.notify(dd, event, grid);
+      });
+
+      describe('when the drop happens outside of the grid', function () {
+        beforeEach(function () {
+          var $cell = $($('.slick-cell.l1')[1]);
+          var finalPosition = {cell: 1, row: 1};
+
+          var event = {
+            target: $cell,
+            isPropagationStopped: jasmine.createSpy('isPropagationStopped').and.returnValue(false),
+            isImmediatePropagationStopped: jasmine.createSpy('isImmediatePropagationStopped').and.returnValue(false),
+            stopImmediatePropagation: jasmine.createSpy('stopImmediatePropagation'),
+
+            pageX: cellLeftPosition(finalPosition.cell),
+            pageY: cellTopPosition($cell, finalPosition.row)
+          };
+
+          grid.onDrag.notify(dd, event, grid);
+          $(window).mouseup();
+        });
+        it('should call handleDragEnd from CellRangeSelector', function () {
+          var newRange = grid.getSelectionModel().getSelectedRanges();
+
+          expect(newRange.length).toBe(1);
+
+          expect(newRange[0].fromCell).toBe(1);
+          expect(newRange[0].toCell).toBe(3);
+          expect(newRange[0].fromRow).toBe(1);
+          expect(newRange[0].toRow).toBe(4);
+        });
+      });
+    });
+
+    describe('when we mouse up and no drag and drop occured', function () {
+      beforeEach(function () {
+        grid.onDragEnd.notify = jasmine.createSpy('notify');
+        grid.onDragEnd.notify.calls.reset();
+        $(window).mouseup();
+      });
+
+      it('do not notify onDragEnd', function () {
+        expect(grid.onDragEnd.notify).not.toHaveBeenCalled()
+      });
+    });
+
+    describe('setSelectedRows', function () {
+
+      beforeEach(function () {
+        grid.getSelectionModel().setSelectedRanges(
+          [new Slick.Range(1, 1, 1, 1)]
+        );
+      });
+
+      describe('when passed an empty array', function () {
+        beforeEach(function () {
+          grid.getSelectionModel().setSelectedRows([]);
+        });
+        it('clears ranges', function () {
+          var newRanges = grid.getSelectionModel().getSelectedRanges();
+          expect(newRanges.length).toEqual(0);
+        });
+      });
+
+      it('sets ranges corresponding to rows', function () {
+        grid.getSelectionModel().setSelectedRows([0, 2]);
+
+        var selectedRanges = grid.getSelectionModel().getSelectedRanges();
+
+        expect(selectedRanges.length).toBe(2);
+        expectRangeToMatch(selectedRanges[0], 0, 1, 0, 3);
+        expectRangeToMatch(selectedRanges[1], 2, 1, 2, 3);
+      });
+    });
+
+    function pressKey(keyCode) {
+      var pressEvent = new $.Event("keydown");
+      pressEvent.which = keyCode;
+
+      $(container.find('.grid-canvas')).trigger(pressEvent);
+    }
+
+    function pressShiftPlusKey(keyCode) {
+      var pressEvent = new $.Event("keydown");
+      pressEvent.shiftKey = true;
+      pressEvent.which = keyCode;
+
+      $(container.find('.grid-canvas')).trigger(pressEvent);
+    }
+
+    function expectOneSelectedRange(fromRow, fromCell, toRow, toCell) {
+      var selectedRanges = grid.getSelectionModel().getSelectedRanges();
+      expect(selectedRanges.length).toBe(1);
+      expectRangeToMatch(selectedRanges[0], fromRow, fromCell, toRow, toCell);
+    }
+
+    function expectRangeToMatch(range, fromRow, fromCell, toRow, toCell) {
+      expect(range.fromRow).toBe(fromRow);
+      expect(range.toRow).toBe(toRow);
+      expect(range.fromCell).toBe(fromCell);
+      expect(range.toCell).toBe(toCell);
+    }
+  });
+})
+;
\ No newline at end of file
diff --git a/web/regression/javascript/slickgrid/cell_selector_spec.js b/web/regression/javascript/slickgrid/cell_selector_spec.js
index 841ea72b..ed7c0aee 100644
--- a/web/regression/javascript/slickgrid/cell_selector_spec.js
+++ b/web/regression/javascript/slickgrid/cell_selector_spec.js
@@ -9,11 +9,11 @@
 
 define(["jquery",
     "slickgrid/slick.grid",
-    "slickgrid/slick.cellselectionmodel",
+    "sources/selection/xcell_selection_model",
     "sources/slickgrid/cell_selector",
     "sources/selection/range_selection_helper"
   ],
-  function ($, SlickGrid, CellSelectionModel, CellSelector, RangeSelectionHelper) {
+  function ($, SlickGrid, XCellSelectionModel, CellSelector, RangeSelectionHelper) {
     describe("CellSelector", function () {
       var container, columns, cellSelector, data, cellSelectionModel, grid;
       beforeEach(function () {
@@ -34,7 +34,7 @@ define(["jquery",
         }
         grid = new SlickGrid(container, data, columns);
 
-        cellSelectionModel = new CellSelectionModel();
+        cellSelectionModel = new XCellSelectionModel();
         grid.setSelectionModel(cellSelectionModel);
 
         grid.registerPlugin(cellSelector);
diff --git a/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js b/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js
index b61e5aff..14768227 100644
--- a/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js
+++ b/web/regression/javascript/slickgrid/event_handlers/handle_query_output_keyboard_event_spec.js
@@ -11,12 +11,10 @@ define([
     'sources/slickgrid/event_handlers/handle_query_output_keyboard_event',
     'sources/selection/clipboard',
     'sources/selection/range_selection_helper',
-    'slickgrid',
-    'slickgrid/slick.cellrangedecorator',
-    'slickgrid/slick.cellrangeselector',
-    'slickgrid/slick.cellselectionmodel',
+    'sources/selection/xcell_selection_model',
+    'slickgrid'
   ],
-function (handleQueryOutputKeyboardEvent, clipboard, RangeSelectionHelper) {
+function (handleQueryOutputKeyboardEvent, clipboard, RangeSelectionHelper, XCellSelectionModel) {
   var Slick = window.Slick;
 
   describe('#handleQueryOutputKeyboardEvent', function () {
@@ -39,7 +37,7 @@ function (handleQueryOutputKeyboardEvent, clipboard, RangeSelectionHelper) {
         name: 'secondColumn'
       }];
       grid = new Slick.Grid($('<div></div>'), data, columnDefinitions);
-      grid.setSelectionModel(new Slick.CellSelectionModel());
+      grid.setSelectionModel(new XCellSelectionModel());
 
       slickEvent = {
         grid: grid
diff --git a/web/regression/javascript/test-main.js b/web/regression/javascript/test-main.js
index 1cabbe58..72e4d03b 100644
--- a/web/regression/javascript/test-main.js
+++ b/web/regression/javascript/test-main.js
@@ -35,10 +35,8 @@ require.config({
     'underscore.string': sourcesDir + 'vendor/underscore/underscore.string',
     'slickgrid': sourcesDir + 'vendor/slickgrid/slick.core',
     'slickgrid/slick.grid': sourcesDir + 'vendor/slickgrid/slick.grid',
-    'slickgrid/slick.rowselectionmodel': sourcesDir + 'vendor/slickgrid/plugins/slick.rowselectionmodel',
-    'slickgrid/slick.cellselectionmodel': sourcesDir + 'vendor/slickgrid/plugins/slick.cellselectionmodel',
-    'slickgrid/slick.cellrangedecorator': sourcesDir + 'vendor/slickgrid/plugins/slick.cellrangedecorator',
-    'slickgrid/slick.cellrangeselector': sourcesDir + 'vendor/slickgrid/plugins/slick.cellrangeselector',
+    'slickgrid/plugins/slick.cellrangedecorator': sourcesDir + 'vendor/slickgrid/plugins/slick.cellrangedecorator',
+    'slickgrid/plugins/slick.cellrangeselector': sourcesDir + 'vendor/slickgrid/plugins/slick.cellrangeselector',
     'translations': '/base/regression/javascript/fake_translations',
     'sources': sourcesDir + 'js'
   },
@@ -59,29 +57,23 @@ require.config({
       ],
       "exports": 'window.Slick.Grid'
     },
-    "slickgrid/slick.rowselectionmodel": {
-      "deps": [
-        "jquery"
-      ],
-      "exports": 'window.Slick.RowSelectionModel'
-    },
-    "slickgrid/slick.cellrangedecorator": {
+    "slickgrid/plugins/slick.cellrangedecorator": {
       "deps": [
         "jquery"
       ],
       "exports": 'window.Slick.RowRangeDecorator'
     },
-    "slickgrid/slick.cellrangeselector": {
+    "slickgrid/plugins/slick.cellrangeselector": {
       "deps": [
-        "jquery", "slickgrid/slick.cellrangedecorator"
+        "jquery", "slickgrid/plugins/slick.cellrangedecorator"
       ],
       "exports": 'window.Slick.CellRangeSelector'
     },
-    "slickgrid/slick.cellselectionmodel": {
+    "sources/selection/xcell_selection_model": {
       "deps": [
-        "jquery", "slickgrid/slick.cellrangeselector"
+        "jquery", "slickgrid/plugins/slick.cellrangeselector"
       ],
-      "exports": 'window.Slick.CellSelectionModel'
+      "exports": 'XCellSelectionModel'
     },
     "backbone": {
       "deps": ['underscore', 'jquery'],
