"use strict";

/* WorkbookView.js
 *
 * Author: Dmitry.Sokolov@avsmedia.net
 * Date:   Jan 27, 2012
 */
(/**
 * @param {jQuery} $
 * @param {Window} window
 * @param {undefined} undefined
 */
  function($, window, undefined) {


  /*
   * Import
   * -----------------------------------------------------------------------------
   */
  var asc = window["Asc"];
  var asc_applyFunction = asc.applyFunction;
  var asc_round = asc.round;
  var asc_typeof = asc.typeOf;
  var asc_CMM = asc.asc_CMouseMoveData;
  var asc_CPrintPagesData = asc.CPrintPagesData;
  var asc_getcvt = asc.getCvtRatio;
  var asc_CSP = asc.asc_CStylesPainter;

  function WorkbookCommentsModel(handlers) {
    this.workbook = {handlers: handlers};
  }

  WorkbookCommentsModel.prototype.getId = function() {
    return "workbook";
  };
  WorkbookCommentsModel.prototype.getMergedByCell = function() {
    return null;
  };

  function WorksheetViewSettings() {
    this.header = {
      style: [// Header colors
        { // kHeaderDefault
          background: new CColor(244, 244, 244), border: new CColor(213, 213, 213), color: new CColor(54, 54, 54)
        }, { // kHeaderActive
          background: new CColor(193, 193, 193), border: new CColor(146, 146, 146), color: new CColor(54, 54, 54)
        }, { // kHeaderHighlighted
          background: new CColor(223, 223, 223), border: new CColor(175, 175, 175), color: new CColor(101, 106, 112)
        }, { // kHeaderSelected
          background: new CColor(170, 170, 170), border: new CColor(117, 119, 122), color: new CColor(54, 54, 54)
        }], cornerColor: new CColor(193, 193, 193)
    };
    this.cells = {
      defaultState: {
        background: new CColor(255, 255, 255), border: new CColor(212, 212, 212), color: new CColor(0, 0, 0)
      }, padding: -1, /*px horizontal padding*/
      paddingPlusBorder: -1
    };
    this.activeCellBorderColor = new CColor(126, 152, 63);
    this.activeCellBorderColor2 = new CColor(255, 255, 255, 0.75);
    this.activeCellBackground = new CColor(157, 185, 85, 0.2);

    // Цвет заливки границы выделения области автозаполнения
    this.fillHandleBorderColorSelect = new CColor(255, 255, 255);

    // Цвет закрепленных областей
    this.frozenColor = new CColor(105, 119, 62, 1);

    // Число знаков для математической информации
    this.mathMaxDigCount = 9;

    var cnv = document.createElement("canvas");
    cnv.width = 2;
    cnv.height = 2;
    var ctx = cnv.getContext("2d");
    ctx.clearRect(0, 0, 2, 2);
    ctx.fillStyle = "#000";
    ctx.fillRect(0, 0, 1, 1);
    ctx.fillRect(1, 1, 1, 1);
    this.ptrnLineDotted1 = ctx.createPattern(cnv, "repeat");

    return this;
  }


  /**
   * Widget for displaying and editing Workbook object
   * -----------------------------------------------------------------------------
   * @param {Workbook} model                        Workbook
   * @param {asc_CEventsController} controller          Events controller
   * @param {HandlersList} handlers                  Events handlers for WorkbookView events
   * @param {Element} elem                          Container element
   * @param {Element} inputElem                      Input element for top line editor
   * @param {Object} Api
   * @param {CCollaborativeEditing} collaborativeEditing
   * @param {c_oAscFontRenderingModeType} fontRenderingMode
   *
   * @constructor
   * @memberOf Asc
   */
  function WorkbookView(model, controller, handlers, elem, inputElem, Api, collaborativeEditing, fontRenderingMode) {
    this.defaults = {
      scroll: {
        widthPx: 14, heightPx: 14
      }, worksheetView: new WorksheetViewSettings()
    };

    this.model = model;
    this.enableKeyEvents = true;
    this.controller = controller;
    this.handlers = handlers;
    this.wsViewHandlers = null;
    this.element = elem;
    this.input = inputElem;
    this.clipboard = new asc.Clipboard();
    this.Api = Api;
    this.collaborativeEditing = collaborativeEditing;
    this.lastSendInfoRange = null;
    this.canUpdateAfterShiftUp = false;	// Нужно ли обновлять информацию после отпускания Shift

    //----- declaration -----
    this.canvas = undefined;
    this.canvasOverlay = undefined;
    this.canvasGraphic = undefined;
    this.canvasGraphicOverlay = undefined;
    this.wsActive = -1;
    this.wsMustDraw = false; // Означает, что мы выставили активный, но не отрисовали его
    this.wsViews = [];
    this.cellEditor = undefined;
    this.fontRenderingMode = null;
    this.lockDraw = false;		// Lock отрисовки на некоторое время

	this.isCellEditMode = false;

    this.formulasList = [];		// Список всех формул
    this.lastFormulaPos = -1; 		// Последняя позиция формулы
    this.lastFormulaNameLength = '';		// Последний кусок формулы
    this.skipHelpSelector = false;	// Пока true - не показываем окно подсказки
    // Константы для подстановке формулы (что не нужно добавлять скобки)
    this.arrExcludeFormulas = [];

    this.lastFindOptions = null;	// Последний поиск (параметры)
    this.lastFindResults = {};		// Результаты поиска (для поиска по всей книге, чтобы перейти на другой лист)
    this.fReplaceCallback = null;	// Callback для замены текста

    // Фонт, который выставлен в DrawingContext, он должен быть один на все DrawingContext-ы
    this.m_oFont = new asc.FontProperties(this.model.getDefaultFont(), this.model.getDefaultSize());

    // Теперь у нас 2 FontManager-а на весь документ + 1 для автофигур (а не на каждом листе свой)
    this.fmgrGraphics = [];						// FontManager for draw (1 для обычного + 1 для поворотного текста)
    this.fmgrGraphics.push(new CFontManager());	// Для обычного
    this.fmgrGraphics.push(new CFontManager());	// Для поворотного
    this.fmgrGraphics.push(new CFontManager());	// Для автофигур
    this.fmgrGraphics.push(new CFontManager());	// Для измерений

    this.fmgrGraphics[0].Initialize(true); // IE memory enable
    this.fmgrGraphics[1].Initialize(true); // IE memory enable
    this.fmgrGraphics[2].Initialize(true); // IE memory enable
    this.fmgrGraphics[3].Initialize(true); // IE memory enable

    this.buffers = {};
    this.drawingCtx = undefined;
    this.overlayCtx = undefined;
    this.drawingGraphicCtx = undefined;
    this.overlayGraphicCtx = undefined;
    this.stringRender = undefined;

    this.stateFormatPainter = c_oAscFormatPainterState.kOff;
    this.rangeFormatPainter = null;

    this.selectionDialogType = c_oAscSelectionDialogType.None;
    this.copyActiveSheet = -1;

    // Комментарии для всего документа
    this.cellCommentator = null;

    // Флаг о подписке на эвенты о смене позиции документа (скролл) для меню
    this.isDocumentPlaceChangedEnabled = false;

    // Максимальная ширина числа из 0,1,2...,9, померенная в нормальном шрифте(дефалтовый для книги) в px(целое)
    // Ecma-376 Office Open XML Part 1, пункт 18.3.1.13
    this.maxDigitWidth = 0;
    this.defaultFont = new asc.FontProperties(this.model.getDefaultFont(), this.model.getDefaultSize());
    //-----------------------

    this.m_dScrollY = 0;
    this.m_dScrollX = 0;
    this.m_dScrollY_max = 1;
    this.m_dScrollX_max = 1;

    this.MobileTouchManager = null;

    this.defNameAllowCreate = true;

    this._init(fontRenderingMode);

    return this;
  }

  WorkbookView.prototype._init = function(fontRenderingMode) {
    var self = this;

    // Init font managers rendering
    // Изначально мы инициализируем c_oAscFontRenderingModeType.hintingAndSubpixeling
    this.setFontRenderingMode(fontRenderingMode, /*isInit*/true);

    // add style
    var _head = document.getElementsByTagName('head')[0];
    var style0 = document.createElement('style');
    style0.type = 'text/css';
    style0.innerHTML = ".block_elem { position:absolute;padding:0;margin:0; }";
    _head.appendChild(style0);

    // create canvas
    if (null != this.element) {
      this.element.innerHTML = '<div id="ws-canvas-outer">\
											<canvas id="ws-canvas"></canvas>\
											<canvas id="ws-canvas-overlay"></canvas>\
											<canvas id="ws-canvas-graphic"></canvas>\
											<canvas id="ws-canvas-graphic-overlay"></canvas>\
											<canvas id="id_target_cursor" class="block_elem" width="1" height="1"\
												style="width:2px;height:13px;display:none;z-index:1004;"></canvas>\
										</div>';

      this.canvas = document.getElementById("ws-canvas");
      this.canvasOverlay = document.getElementById("ws-canvas-overlay");
      this.canvasGraphic = document.getElementById("ws-canvas-graphic");
      this.canvasGraphicOverlay = document.getElementById("ws-canvas-graphic-overlay");
    }

    // Для мобильных не поддерживаем ретину
    if (this.Api.isMobileVersion) {
      AscBrowser.isRetina = false;
    }

    this.buffers.main = new asc.DrawingContext({
      canvas: this.canvas, units: 1/*pt*/, fmgrGraphics: this.fmgrGraphics, font: this.m_oFont
    });
    this.buffers.overlay = new asc.DrawingContext({
      canvas: this.canvasOverlay, units: 1/*pt*/, fmgrGraphics: this.fmgrGraphics, font: this.m_oFont
    });

    this.buffers.mainGraphic = new asc.DrawingContext({
      canvas: this.canvasGraphic, units: 1/*pt*/, fmgrGraphics: this.fmgrGraphics, font: this.m_oFont
    });
    this.buffers.overlayGraphic = new asc.DrawingContext({
      canvas: this.canvasGraphicOverlay, units: 1/*pt*/, fmgrGraphics: this.fmgrGraphics, font: this.m_oFont
    });

    this.drawingCtx = this.buffers.main;
    this.overlayCtx = this.buffers.overlay;
    this.drawingGraphicCtx = this.buffers.mainGraphic;
    this.overlayGraphicCtx = this.buffers.overlayGraphic;

    // Обновляем размеры (чуть ниже, потому что должны быть проинициализированы ctx)
    this._canResize();

    // Shapes


    var canvasWidth = this.drawingGraphicCtx.canvas.width;
    var canvasHeight = this.drawingGraphicCtx.canvas.height;
    this.buffers.shapeCtx = new CGraphics();
    this.buffers.shapeCtx.init(this.drawingGraphicCtx.ctx, canvasWidth, canvasHeight, (canvasWidth * 25.4 / this.drawingGraphicCtx.ppiX), (canvasHeight * 25.4 / this.drawingGraphicCtx.ppiY));
    this.buffers.shapeCtx.m_oFontManager = this.fmgrGraphics[2];


    var overlayWidth = this.overlayGraphicCtx.canvas.width;
    var overlayHeight = this.overlayGraphicCtx.canvas.height;
    this.buffers.shapeOverlayCtx = new CGraphics();
    this.buffers.shapeOverlayCtx.init(this.overlayGraphicCtx.ctx, overlayWidth, overlayHeight, (overlayWidth * 25.4 / this.overlayGraphicCtx.ppiX), (overlayHeight * 25.4 / this.overlayGraphicCtx.ppiY));
    this.buffers.shapeOverlayCtx.m_oFontManager = this.fmgrGraphics[2];

    this.stringRender = new asc.StringRender(this.buffers.main);
    this.stringRender.setDefaultFont(this.defaultFont);

    // Мерить нужно только со 100% и один раз для всего документа
    this._calcMaxDigitWidth();

    if (!window["NATIVE_EDITOR_ENJINE"]) {
      // initialize events controller
      this.controller.init(this, this.element, /*this.canvasOverlay*/ this.canvasGraphicOverlay, /*handlers*/{
        "resize": function() {
          self.resize.apply(self, arguments);
        }, "reinitializeScroll": function() {
          self._onScrollReinitialize.apply(self, arguments);
        }, "scrollY": function() {
          self._onScrollY.apply(self, arguments);
        }, "scrollX": function() {
          self._onScrollX.apply(self, arguments);
        }, "changeSelection": function() {
          self._onChangeSelection.apply(self, arguments);
        }, "changeSelectionDone": function() {
          self._onChangeSelectionDone.apply(self, arguments);
        }, "changeSelectionRightClick": function() {
          self._onChangeSelectionRightClick.apply(self, arguments);
        }, "selectionActivePointChanged": function() {
          self._onSelectionActivePointChanged.apply(self, arguments);
        }, "updateWorksheet": function() {
          self._onUpdateWorksheet.apply(self, arguments);
        }, "resizeElement": function() {
          self._onResizeElement.apply(self, arguments);
        }, "resizeElementDone": function() {
          self._onResizeElementDone.apply(self, arguments);
        }, "changeFillHandle": function() {
          self._onChangeFillHandle.apply(self, arguments);
        }, "changeFillHandleDone": function() {
          self._onChangeFillHandleDone.apply(self, arguments);
        }, "moveRangeHandle": function() {
          self._onMoveRangeHandle.apply(self, arguments);
        }, "moveRangeHandleDone": function() {
          self._onMoveRangeHandleDone.apply(self, arguments);
        }, "moveResizeRangeHandle": function() {
          self._onMoveResizeRangeHandle.apply(self, arguments);
        }, "moveResizeRangeHandleDone": function() {
          self._onMoveResizeRangeHandleDone.apply(self, arguments);
        }, "editCell": function() {
          self._onEditCell.apply(self, arguments);
        },
		  "stopCellEditing": function() {
          return self._onStopCellEditing.apply(self, arguments);
        },
		  "getCellEditMode": function() {
          return self.isCellEditMode;
        },
		  "empty": function() {
          self._onEmpty.apply(self, arguments);
        },
		  "canEnterCellRange": function() {
          self.cellEditor.setFocus(false);
          var ret = self.cellEditor.canEnterCellRange();
          ret ? self.cellEditor.activateCellRange() : true;
          return ret;
        }, "enterCellRange": function() {
          self.lockDraw = true;
          self.cellEditor.setFocus(false);
          self.getWorksheet().enterCellRange(self.cellEditor);
          self.lockDraw = false;
        }, "copy": function() {
          self.copyToClipboard.apply(self, arguments);
        }, "paste": function() {
          self.pasteFromClipboard.apply(self, arguments);
        }, "cut": function() {
          self.cutToClipboard.apply(self, arguments);
        }, "undo": function() {
          self.undo.apply(self, arguments);
        }, "redo": function() {
          self.redo.apply(self, arguments);
        }, "addColumn": function() {
          self._onAddColumn.apply(self, arguments);
        }, "addRow": function() {
          self._onAddRow.apply(self, arguments);
        }, "mouseDblClick": function() {
          self._onMouseDblClick.apply(self, arguments);
        }, "showNextPrevWorksheet": function() {
          self._onShowNextPrevWorksheet.apply(self, arguments);
        }, "setFontAttributes": function() {
          self._onSetFontAttributes.apply(self, arguments);
        }, "selectColumnsByRange": function() {
          self._onSelectColumnsByRange.apply(self, arguments);
        }, "selectRowsByRange": function() {
          self._onSelectRowsByRange.apply(self, arguments);
        }, "save": function() {
          self.Api.asc_Save();
        }, "showCellEditorCursor": function() {
          self._onShowCellEditorCursor.apply(self, arguments);
        }, "print": function() {
          self.Api.asc_Print();
        }, "addFunction": function() {
          self.insertFormulaInEditor.apply(self, arguments);
        }, "canvasClick": function() {
          self.enableKeyEventsHandler(true);
        }, "autoFiltersClick": function() {
          self._onAutoFiltersClick.apply(self, arguments);
        }, "commentCellClick": function() {
          self._onCommentCellClick.apply(self, arguments);
        }, "isGlobalLockEditCell": function() {
          return self.collaborativeEditing.getGlobalLockEditCell();
        }, "updateSelectionName": function() {
          self._onUpdateSelectionName.apply(self, arguments);
        }, "stopFormatPainter": function() {
          self._onStopFormatPainter.apply(self, arguments);
        },

        // Shapes
        "graphicObjectMouseDown": function() {
          self._onGraphicObjectMouseDown.apply(self, arguments);
        }, "graphicObjectMouseMove": function() {
          self._onGraphicObjectMouseMove.apply(self, arguments);
        }, "graphicObjectMouseUp": function() {
          self._onGraphicObjectMouseUp.apply(self, arguments);
        }, "graphicObjectMouseUpEx": function() {
          self._onGraphicObjectMouseUpEx.apply(self, arguments);
        }, "graphicObjectWindowKeyDown": function() {
          return self._onGraphicObjectWindowKeyDown.apply(self, arguments);
        }, "graphicObjectWindowKeyPress": function() {
          return self._onGraphicObjectWindowKeyPress.apply(self, arguments);
        }, "getGraphicsInfo": function() {
          return self._onGetGraphicsInfo.apply(self, arguments);
        }, "getSelectedGraphicObjects": function() {
          return self._onGetSelectedGraphicObjects.apply(self, arguments);
        }, "updateSelectionShape": function() {
          return self._onUpdateSelectionShape.apply(self, arguments);
        }, "canReceiveKeyPress": function() {
          return self.getWorksheet().objectRender.controller.canReceiveKeyPress();
        }, "stopAddShape": function() {
          self.getWorksheet().objectRender.controller.checkEndAddShape();
        },

        // Frozen anchor
        "moveFrozenAnchorHandle": function() {
          self._onMoveFrozenAnchorHandle.apply(self, arguments);
        }, "moveFrozenAnchorHandleDone": function() {
          self._onMoveFrozenAnchorHandleDone.apply(self, arguments);
        },

        // AutoComplete
        "showAutoComplete": function() {
          self._onShowAutoComplete.apply(self, arguments);
        }, "onContextMenu": function(event) {
          self.handlers.trigger("asc_onContextMenu", event);
        },

        // FormatPainter
        'isFormatPainter': function() {
          return self.stateFormatPainter;
        }
      });

      if (this.input && this.input.addEventListener) {
        this.input.addEventListener("focus", function() {
          self.input.isFocused = true;
          if (self.controller.settings.isViewerMode) {
            return;
          }
          self._onStopFormatPainter();
          self.controller.setStrictClose(true);
          self.cellEditor.callTopLineMouseup = true;
          if (!self.getCellEditMode() && !self.controller.isFillHandleMode) {
            self._onEditCell(0, 0, /*isCoord*/false, /*isFocus*/true);
          }
        }, false);
      }
    }
      this.cellEditor = new asc.CellEditor(this.element, this.input, this.fmgrGraphics, this.m_oFont, /*handlers*/{
        "closed": function() {
          self._onCloseCellEditor.apply(self, arguments);
        }, "updated": function() {
          self._onUpdateCellEditor.apply(self, arguments);
        }, "gotFocus": function(hasFocus) {
          self.controller.setFocus(!hasFocus);
        }, "copy": function() {
          self.copyToClipboard.apply(self, arguments);
        }, "paste": function() {
          self.pasteFromClipboard.apply(self, arguments);
        }, "cut": function() {
          self.cutToClipboard.apply(self, arguments);
        }, "updateFormulaEditMod": function() {
          self.controller.setFormulaEditMode.apply(self.controller, arguments);
          var ws = self.getWorksheet();
          if (ws) {
            if (!self.lockDraw) {
              ws.cleanSelection();
            }
  		    for (var i in self.wsViews) {
				self.wsViews[i].cleanFormulaRanges();
		    }
//            ws.cleanFormulaRanges();
            ws.setFormulaEditMode.apply(ws, arguments);
          }
        }, "updateEditorState": function(state) {
          self.handlers.trigger("asc_onEditCell", state);
        }, "isGlobalLockEditCell": function() {
          return self.collaborativeEditing.getGlobalLockEditCell();
        }, "updateFormulaEditModEnd": function() {
          if (!self.lockDraw) {
            self.getWorksheet().updateSelection();
          }
        }, "newRange": function(range, ws) {
          if (!ws) {
            self.getWorksheet().addFormulaRange(range);
          } else {
            self.getWorksheet(self.model.getWorksheetIndexByName(ws)).addFormulaRange(range);
          }
        }, "existedRange": function(range, ws) {
              if (!ws) {
                  self.getWorksheet().activeFormulaRange(range);
              } else {
                  self.getWorksheet(self.model.getWorksheetIndexByName(ws)).activeFormulaRange(range);
              }
        }, "updateUndoRedoChanged": function(bCanUndo, bCanRedo) {
          self.handlers.trigger("asc_onCanUndoChanged", bCanUndo);
          self.handlers.trigger("asc_onCanRedoChanged", bCanRedo);
        }, "applyCloseEvent": function() {
          self.controller._onWindowKeyDown.apply(self.controller, arguments);
        }, "isViewerMode": function() {
          return self.controller.settings.isViewerMode;
        }, "getFormulaRanges": function() {
          return self.cellFormulaEnterWSOpen ? self.cellFormulaEnterWSOpen.getFormulaRanges() : self.getWorksheet().getFormulaRanges();
        }, "getCellFormulaEnterWSOpen": function() {
          return self.cellFormulaEnterWSOpen;
        }, "getActiveWS": function() {
          return self.getWorksheet().model;
        }, "setStrictClose": function(val) {
          self.controller.setStrictClose(val);
        }, "updateEditorSelectionInfo": function(info) {
          self.handlers.trigger("asc_onEditorSelectionChanged", info);
        }, "onContextMenu": function(event) {
          self.handlers.trigger("asc_onContextMenu", event);
        }
      }, /*settings*/{
        font: this.defaultFont, padding: this.defaults.worksheetView.cells.padding
      });


    this.wsViewHandlers = new asc.asc_CHandlersList(/*handlers*/{
      "getViewerMode": function() {
        return self.controller.getViewerMode ? self.controller.getViewerMode() : true;
      }, "reinitializeScroll": function() {
        self.controller.reinitializeScroll(/*All*/);
      }, "reinitializeScrollY": function() {
        self.controller.reinitializeScroll(/*vertical*/1);
      }, "reinitializeScrollX": function() {
        self.controller.reinitializeScroll(/*horizontal*/2);
      }, "selectionChanged": function() {
        self._onWSSelectionChanged.apply(self, arguments);
      }, "selectionNameChanged": function() {
        self._onSelectionNameChanged.apply(self, arguments);
      }, "selectionMathInfoChanged": function() {
        self._onSelectionMathInfoChanged.apply(self, arguments);
      }, "onErrorEvent": function(errorId, level) {
        self.handlers.trigger("asc_onError", errorId, level);
      }, "slowOperation": function(isStart) {
        (isStart ? self.Api.sync_StartAction : self.Api.sync_EndAction).call(self.Api, c_oAscAsyncActionType.BlockInteraction, c_oAscAsyncAction.SlowOperation);
      }, "setAutoFiltersDialog": function(arrVal) {
        self.handlers.trigger("asc_onSetAFDialog", arrVal);
      }, "selectionRangeChanged": function(val) {
        self.handlers.trigger("asc_onSelectionRangeChanged", val);
      }, "onRenameCellTextEnd": function(countFind, countReplace) {
        self.handlers.trigger("asc_onRenameCellTextEnd", countFind, countReplace);
      }, 'onStopFormatPainter': function() {
        self._onStopFormatPainter();
      }, 'getRangeFormatPainter': function() {
        return self.rangeFormatPainter;
      },"onDocumentPlaceChanged": function() {
        self._onDocumentPlaceChanged();
      }, "updateSheetViewSettings": function() {
        self.handlers.trigger("asc_onUpdateSheetViewSettings");
      }, "onScroll": function(d) {
        self.controller.scroll(d);
      }, "getLockDefNameManagerStatus": function() {
        return self.defNameAllowCreate;
      }, 'isActive': function() {
        return (-1 === self.copyActiveSheet || self.wsActive === self.copyActiveSheet);
      },
		"getCellEditMode": function() {
			return self.isCellEditMode;
		}
    });

    this.model.handlers.add("cleanCellCache", function(wsId, oRanges, canChangeColWidth, bLockDraw, updateHeight) {
      var ws = self.getWorksheetById(wsId);
      if (ws) {
        ws.updateRanges(oRanges, canChangeColWidth, bLockDraw || wsId != self.getWorksheet(self.wsActive).model.getId(), updateHeight);
      }
    });
    this.model.handlers.add("changeWorksheetUpdate", function(wsId, val) {
      var ws = self.getWorksheetById(wsId);
      if (ws) {
        ws.changeWorksheet("update", val);
      }
    });
    this.model.handlers.add("showWorksheet", function(wsId) {
      var wsModel = self.model.getWorksheetById(wsId), index;
      if (wsModel) {
        index = wsModel.getIndex();
        self.showWorksheet(index, false, true);
        self.handlers.trigger("asc_onActiveSheetChanged", index);
      }
    });
    this.model.handlers.add("setSelection", function() {
      self._onSetSelection.apply(self, arguments);
    });
    this.model.handlers.add("getSelection", function() {
      return self._onGetSelection.apply(self);
    });
    this.model.handlers.add("getSelectionState", function() {
      return self._onGetSelectionState.apply(self);
    });
    this.model.handlers.add("setSelectionState", function() {
      self._onSetSelectionState.apply(self, arguments);
    });
    this.model.handlers.add("reInit", function() {
      self.reInit.apply(self, arguments);
    });
    this.model.handlers.add("drawWS", function() {
      self.drawWS.apply(self, arguments);
    });
    this.model.handlers.add("showDrawingObjects", function() {
      self.onShowDrawingObjects.apply(self, arguments);
    });
    this.model.handlers.add("setCanUndo", function(bCanUndo) {
      self.handlers.trigger("asc_onCanUndoChanged", bCanUndo);
    });
    this.model.handlers.add("setCanRedo", function(bCanRedo) {
      self.handlers.trigger("asc_onCanRedoChanged", bCanRedo);
    });
    this.model.handlers.add("setDocumentModified", function(bIsModified) {
      self.Api.onUpdateDocumentModified(bIsModified);
    });
    this.model.handlers.add("initCommentsToSave", function() {
      self._initCommentsToSave();
    });
    this.model.handlers.add("replaceWorksheet", function(from, to) {
      self.replaceWorksheet(from, to);
    });
    this.model.handlers.add("removeWorksheet", function(nIndex) {
      self.removeWorksheet(nIndex);
    });
    this.model.handlers.add("spliceWorksheet", function() {
      self.spliceWorksheet.apply(self, arguments);
    });
    this.model.handlers.add("updateWorksheetByModel", function() {
      self.updateWorksheetByModel.apply(self, arguments);
    });
    this.model.handlers.add("undoRedoAddRemoveRowCols", function(sheetId, type, range, bUndo) {
      if (true === bUndo) {
        if (historyitem_Worksheet_AddRows === type) {
          self.collaborativeEditing.removeRowsRange(sheetId, range.clone(true));
          self.collaborativeEditing.undoRows(sheetId, range.r2 - range.r1 + 1);
        } else if (historyitem_Worksheet_RemoveRows === type) {
          self.collaborativeEditing.addRowsRange(sheetId, range.clone(true));
          self.collaborativeEditing.undoRows(sheetId, range.r2 - range.r1 + 1);
        } else if (historyitem_Worksheet_AddCols === type) {
          self.collaborativeEditing.removeColsRange(sheetId, range.clone(true));
          self.collaborativeEditing.undoCols(sheetId, range.c2 - range.c1 + 1);
        } else if (historyitem_Worksheet_RemoveCols === type) {
          self.collaborativeEditing.addColsRange(sheetId, range.clone(true));
          self.collaborativeEditing.undoCols(sheetId, range.c2 - range.c1 + 1);
        }
      } else {
        if (historyitem_Worksheet_AddRows === type) {
          self.collaborativeEditing.addRowsRange(sheetId, range.clone(true));
          self.collaborativeEditing.addRows(sheetId, range.r1, range.r2 - range.r1 + 1);
        } else if (historyitem_Worksheet_RemoveRows === type) {
          self.collaborativeEditing.removeRowsRange(sheetId, range.clone(true));
          self.collaborativeEditing.removeRows(sheetId, range.r1, range.r2 - range.r1 + 1);
        } else if (historyitem_Worksheet_AddCols === type) {
          self.collaborativeEditing.addColsRange(sheetId, range.clone(true));
          self.collaborativeEditing.addCols(sheetId, range.c1, range.c2 - range.c1 + 1);
        } else if (historyitem_Worksheet_RemoveCols === type) {
          self.collaborativeEditing.removeColsRange(sheetId, range.clone(true));
          self.collaborativeEditing.removeCols(sheetId, range.c1, range.c2 - range.c1 + 1);
        }
      }
    });
    this.model.handlers.add("undoRedoHideSheet", function(sheetId) {
      self.showWorksheet(sheetId);
      // Посылаем callback об изменении списка листов
      self.handlers.trigger("asc_onSheetsChanged");
    });

    this.handlers.add("asc_onLockDefNameManager", function(reason) {
      self.defNameAllowCreate = !(reason == c_oAscDefinedNameReason.LockDefNameManager);
    });

    this.cellCommentator = new CCellCommentator({
      model: new WorkbookCommentsModel(this.handlers),
      collaborativeEditing: this.collaborativeEditing,
      draw: function() {
      },
      handlers: {
        trigger: function() {
          return true;
        }
      }
    });
    var commentList = this.cellCommentator.prepareComments(this.model.aComments);
    if (0 < commentList.length) {
      this.handlers.trigger("asc_onAddComments", commentList);
    }

    this.clipboard.Api = this.Api;
    this.clipboard.init();

    this.initFormulasList();

    this.fReplaceCallback = function() {
      self._replaceCellTextCallback.apply(self, arguments);
    };

    if (this.Api.isMobileVersion) {
      this.MobileTouchManager = new CMobileTouchManager();
      this.MobileTouchManager.Init(this);
    }
    return this;
  };

  WorkbookView.prototype.destroy = function() {
    this.controller.destroy();
    this.cellEditor.destroy();
    return this;
  };

  WorkbookView.prototype._createWorksheetView = function(wsModel) {
    return new asc.WorksheetView(wsModel, this.wsViewHandlers, this.buffers, this.stringRender, this.maxDigitWidth, this.collaborativeEditing, this.defaults.worksheetView);
  };

  WorkbookView.prototype._onSelectionNameChanged = function(name) {
    this.handlers.trigger("asc_onSelectionNameChanged", name);
  };

  WorkbookView.prototype._onSelectionMathInfoChanged = function(info) {
    this.handlers.trigger("asc_onSelectionMathChanged", info);
  };

  // Проверяет, сменили ли мы диапазон (для того, чтобы не отправлять одинаковую информацию о диапазоне)
  WorkbookView.prototype._isEqualRange = function(range, isSelectOnShape) {
    if (null === this.lastSendInfoRange) {
      return false;
    }

    return this.lastSendInfoRange.isEqual(range) && this.lastSendInfoRangeIsSelectOnShape === isSelectOnShape;
  };

  WorkbookView.prototype._onWSSelectionChanged = function(info) {
    var ws = this.getWorksheet();

    if (this.cellFormulaEnterWSOpen) {
      ws = this.cellFormulaEnterWSOpen;
    }

    var ar = ws.activeRange;
    this.lastSendInfoRange = ar.clone(true);
    this.lastSendInfoRangeIsSelectOnShape = ws.getSelectionShape();

    if (null === info) {
      info = ws.getSelectionInfo();
    }
    // При редактировании ячейки не нужно пересылать изменения
    if (this.input && false === ws.getCellEditMode() && c_oAscSelectionDialogType.None === this.selectionDialogType) {
      // Сами запретим заходить в строку формул, когда выделен shape
      if (this.lastSendInfoRangeIsSelectOnShape) {
        this.input.disabled = true;
        this.input.value = '';
      } else {
        this.input.disabled = false;
        this.input.value = info.text;
      }
    }
    this.handlers.trigger("asc_onSelectionChanged", info);
  };


  WorkbookView.prototype._onScrollReinitialize = function(whichSB, callback) {
    var ws = this.getWorksheet(), vsize = !whichSB || whichSB === 1 ? ws.getVerticalScrollRange() : undefined, hsize = !whichSB || whichSB === 2 ? ws.getHorizontalScrollRange() : undefined;

    if (vsize != undefined) {
      this.m_dScrollY_max = Math.max(this.controller.settings.vscrollStep * (vsize + 1), 1);
    }
    if (hsize != undefined) {
      this.m_dScrollX_max = Math.max(this.controller.settings.hscrollStep * (hsize + 1), 1);
    }

    asc_applyFunction(callback, vsize, hsize);
  };

  WorkbookView.prototype._onScrollY = function(pos) {
    var ws = this.getWorksheet();
    var delta = asc_round(pos - ws.getFirstVisibleRow(/*allowPane*/true));
    if (delta !== 0) {
      ws.scrollVertical(delta, this.cellEditor);
    }
  };

  WorkbookView.prototype._onScrollX = function(pos) {
    var ws = this.getWorksheet();
    var delta = asc_round(pos - ws.getFirstVisibleCol(/*allowPane*/true));
    if (delta !== 0) {
      ws.scrollHorizontal(delta, this.cellEditor);
    }
  };

  WorkbookView.prototype._onSetSelection = function(range, validRange) {
    var ws = this.getWorksheet();
    ws._checkSelectionShape();
    var d = ws.setSelectionUndoRedo(range, validRange);
    this.controller.scroll(d);
  };

  WorkbookView.prototype._onGetSelection = function() {
    var ws = this.getWorksheet();
    return ws.getActiveRangeObj();
  };

  WorkbookView.prototype._onGetSelectionState = function() {
    var ws = this.getWorksheet();
    var res = null;
    if (isRealObject(ws.objectRender) && isRealObject(ws.objectRender.controller)) {
      res = ws.objectRender.controller.getSelectionState();
    }
    // ToDo лучше на getSelectionState возвращать null
    return (res && res[0] && res[0].focus) ? res : null;
  };

  WorkbookView.prototype._onSetSelectionState = function(state) {
    if (null !== state) {
      var ws = this.getWorksheetById(state[0].worksheetId);
      if (ws && ws.objectRender && ws.objectRender.controller) {
        ws.objectRender.controller.setSelectionState(state);
        ws.setSelectionShape(true);
        var d = ws._calcActiveCellOffset(ws.objectRender.getSelectedDrawingsRange());
        this.controller.scroll(d);
        ws.objectRender.showDrawingObjectsEx(true);
        ws.objectRender.controller.updateOverlay();
        ws.objectRender.controller.updateSelectionState();
      }
      // Селектим после выставления состояния
    }
  };

  WorkbookView.prototype._onChangeSelection = function(isStartPoint, dc, dr, isCoord, isSelectMode, callback) {
    var ws = this.getWorksheet();
    var d = isStartPoint ? ws.changeSelectionStartPoint(dc, dr, isCoord, isSelectMode) : ws.changeSelectionEndPoint(dc, dr, isCoord, isSelectMode);
    if (!isCoord && !isStartPoint && !isSelectMode) {
      // Выделение с зажатым shift
      this.canUpdateAfterShiftUp = true;
    }
    asc_applyFunction(callback, d);
  };

  // Окончание выделения
  WorkbookView.prototype._onChangeSelectionDone = function(x, y) {
    if (c_oAscSelectionDialogType.None !== this.selectionDialogType) {
      return;
    }
    var ws = this.getWorksheet();
    ws.changeSelectionDone();
    this._onSelectionNameChanged(ws.getSelectionName(/*bRangeText*/false));
    // Проверим, нужно ли отсылать информацию о ячейке
    var ar = ws.activeRange;
    var isSelectOnShape = ws.getSelectionShape();
    if (!this._isEqualRange(ar, isSelectOnShape)) {
      this._onWSSelectionChanged(ws.getSelectionInfo());
      this._onSelectionMathInfoChanged(ws.getSelectionMathInfo());
    }

    // Нужно очистить поиск
    this._cleanFindResults();

    var ct = ws.getCursorTypeFromXY(x, y, this.controller.settings.isViewerMode);

    if (c_oTargetType.Hyperlink === ct.target) {
      // Проверим замерженность
      var isHyperlinkClick = false;
      if ((ar.c1 === ar.c2 && ar.r1 === ar.r2) || isSelectOnShape) {
        isHyperlinkClick = true;
      } else {
        var mergedRange = ws.model.getMergedByCell(ar.r1, ar.c1);
        if (mergedRange && ar.isEqual(mergedRange)) {
          isHyperlinkClick = true;
        }
      }
      if (isHyperlinkClick) {
        if (false === ct.hyperlink.hyperlinkModel.getVisited() && !isSelectOnShape) {
          ct.hyperlink.hyperlinkModel.setVisited(true);
          if (ct.hyperlink.hyperlinkModel.Ref) {
            ws.updateRange(ct.hyperlink.hyperlinkModel.Ref.getBBox0(), false, false);
          }
        }
        switch (ct.hyperlink.asc_getType()) {
          case c_oAscHyperlinkType.WebLink:
            this.handlers.trigger("asc_onHyperlinkClick", ct.hyperlink.asc_getHyperlinkUrl());
            break;
          case c_oAscHyperlinkType.RangeLink:
            // ToDo надо поправить отрисовку комментария для данной ячейки (с которой уходим)
            this.handlers.trigger("asc_onHideComment");
            this.Api._asc_setWorksheetRange(ct.hyperlink);
            break;
        }
      }
    }
  };

  // Обработка нажатия правой кнопки мыши
  WorkbookView.prototype._onChangeSelectionRightClick = function(dc, dr) {
    var ws = this.getWorksheet();
    ws.changeSelectionStartPointRightClick(dc, dr);
  };

  // Обработка движения в выделенной области
  WorkbookView.prototype._onSelectionActivePointChanged = function(dc, dr, callback) {
    var ws = this.getWorksheet();
    var d = ws.changeSelectionActivePoint(dc, dr);
    asc_applyFunction(callback, d);
  };

  WorkbookView.prototype._onUpdateWorksheet = function(canvasElem, x, y, ctrlKey, callback) {
    var ws = this.getWorksheet(), ct = undefined;
    var arrMouseMoveObjects = [];					// Теперь это массив из объектов, над которыми курсор

    //ToDo: включить определение target, если находимся в режиме редактирования ячейки.
    if (this.getCellEditMode() && !this.controller.isFormulaEditMode) {
      canvasElem.style.cursor = "";
    } else if (x === undefined && y === undefined) {
      ws.cleanHighlightedHeaders();
    } else {
      ct = ws.getCursorTypeFromXY(x, y, this.controller.settings.isViewerMode);

      // Отправление эвента об удалении всего листа (именно удалении, т.к. если просто залочен, то не рисуем рамку вокруг)
      if (undefined !== ct.userIdAllSheet) {
        arrMouseMoveObjects.push(new asc_CMM({
          type: c_oAscMouseMoveType.LockedObject,
          x: ct.lockAllPosLeft,
          y: ct.lockAllPosTop,
          userId: ct.userIdAllSheet,
          lockedObjectType: c_oAscMouseMoveLockedObjectType.Sheet
        }));
      } else {
        // Отправление эвента о залоченности свойств всего листа (только если не удален весь лист)
        if (undefined !== ct.userIdAllProps) {
          arrMouseMoveObjects.push(new asc_CMM({
            type: c_oAscMouseMoveType.LockedObject,
            x: ct.lockAllPosLeft,
            y: ct.lockAllPosTop,
            userId: ct.userIdAllProps,
            lockedObjectType: c_oAscMouseMoveLockedObjectType.TableProperties
          }));
        }
      }
      // Отправление эвента о наведении на залоченный объект
      if (undefined !== ct.userId) {
        arrMouseMoveObjects.push(new asc_CMM({
          type: c_oAscMouseMoveType.LockedObject,
          x: ct.lockRangePosLeft,
          y: ct.lockRangePosTop,
          userId: ct.userId,
          lockedObjectType: c_oAscMouseMoveLockedObjectType.Range
        }));
      }

      // Проверяем комментарии ячейки
      if (undefined !== ct.commentIndexes) {
        arrMouseMoveObjects.push(new asc_CMM({
          type: c_oAscMouseMoveType.Comment,
          x: ct.commentCoords.asc_getLeftPX(),
          reverseX: ct.commentCoords.asc_getReverseLeftPX(),
          y: ct.commentCoords.asc_getTopPX(),
          aCommentIndexes: ct.commentIndexes
        }));
      }
      // Проверяем гиперссылку
      if (ct.target === c_oTargetType.Hyperlink) {
        if (true === ctrlKey) {
          // Мы без нажатия на гиперлинк
        } else {
          ct.cursor = ct.cellCursor.cursor;
        }
        arrMouseMoveObjects.push(new asc_CMM({
          type: c_oAscMouseMoveType.Hyperlink, x: x, y: y, hyperlink: ct.hyperlink
        }));
      }

      /* Проверяем, может мы на никаком объекте (такая схема оказалась приемлимой
       * для отдела разработки приложений)
       */
      if (0 === arrMouseMoveObjects.length) {
        // Отправляем эвент, что мы ни на какой области
        arrMouseMoveObjects.push(new asc_CMM({type: c_oAscMouseMoveType.None}));
      }
      // Отсылаем эвент с объектами
      this.handlers.trigger("asc_onMouseMove", arrMouseMoveObjects);

      if (ct.target === c_oTargetType.MoveRange && ctrlKey && ct.cursor == "move") {
        ct.cursor = "copy";
      }

      if (canvasElem.style.cursor !== ct.cursor) {
        canvasElem.style.cursor = ct.cursor;
      }
      if (ct.target === c_oTargetType.ColumnHeader || ct.target === c_oTargetType.RowHeader) {
        ws.drawHighlightedHeaders(ct.col, ct.row);
      } else {
        ws.cleanHighlightedHeaders();
      }
    }
    asc_applyFunction(callback, ct);
  };

  WorkbookView.prototype._onResizeElement = function(target, x, y) {
    var arrMouseMoveObjects = [];
    if (target.target === c_oTargetType.ColumnResize) {
      arrMouseMoveObjects.push(this.getWorksheet().drawColumnGuides(target.col, x, y, target.mouseX));
    } else if (target.target === c_oTargetType.RowResize) {
      arrMouseMoveObjects.push(this.getWorksheet().drawRowGuides(target.row, x, y, target.mouseY));
    }

    /* Проверяем, может мы на никаком объекте (такая схема оказалась приемлимой
     * для отдела разработки приложений)
     */
    if (0 === arrMouseMoveObjects.length) {
      // Отправляем эвент, что мы ни на какой области
      arrMouseMoveObjects.push(new asc_CMM({type: c_oAscMouseMoveType.None}));
    }
    // Отсылаем эвент с объектами
    this.handlers.trigger("asc_onMouseMove", arrMouseMoveObjects);
  };

  WorkbookView.prototype._onResizeElementDone = function(target, x, y, isResizeModeMove) {
    var ws = this.getWorksheet();
    if (isResizeModeMove) {
      if (ws.objectRender) {
        ws.objectRender.saveSizeDrawingObjects();
      }
      if (target.target === c_oTargetType.ColumnResize) {
        ws.changeColumnWidth(target.col, x, target.mouseX);
      } else if (target.target === c_oTargetType.RowResize) {
        ws.changeRowHeight(target.row, y, target.mouseY);
      }

      ws.cellCommentator.updateCommentPosition();
      this._onDocumentPlaceChanged();
    }
    ws.draw();

    // Отсылаем окончание смены размеров (в FF не срабатывало обычное движение)
    this.handlers.trigger("asc_onMouseMove", [new asc_CMM({type: c_oAscMouseMoveType.None})]);
  };

  // Обработка автозаполнения
  WorkbookView.prototype._onChangeFillHandle = function(x, y, callback) {
    var ws = this.getWorksheet();
    var d = ws.changeSelectionFillHandle(x, y);
    asc_applyFunction(callback, d);
  };

  // Обработка окончания автозаполнения
  WorkbookView.prototype._onChangeFillHandleDone = function(x, y, ctrlPress) {
    var ws = this.getWorksheet();
    ws.applyFillHandle(x, y, ctrlPress);
  };

  // Обработка перемещения диапазона
  WorkbookView.prototype._onMoveRangeHandle = function(x, y, callback, ctrlKey) {
    var ws = this.getWorksheet();
    var d = ws.changeSelectionMoveRangeHandle(x, y, ctrlKey);
    asc_applyFunction(callback, d);
  };

  // Обработка окончания перемещения диапазона
  WorkbookView.prototype._onMoveRangeHandleDone = function(ctrlKey) {
    var ws = this.getWorksheet();
    ws.applyMoveRangeHandle(ctrlKey);
  };

  WorkbookView.prototype._onMoveResizeRangeHandle = function(x, y, target, callback) {
    var ws = this.getWorksheet();
    var d = ws.changeSelectionMoveResizeRangeHandle(x, y, target, this.cellEditor);
    asc_applyFunction(callback, d);
  };

  WorkbookView.prototype._onMoveResizeRangeHandleDone = function(target) {
    var ws = this.getWorksheet();
    ws.applyMoveResizeRangeHandle(target);
  };

  // Frozen anchor
  WorkbookView.prototype._onMoveFrozenAnchorHandle = function(x, y, target) {
    var ws = this.getWorksheet();
    ws.drawFrozenGuides(x, y, target);
  };

  WorkbookView.prototype._onMoveFrozenAnchorHandleDone = function(x, y, target) {
    // Закрепляем область
    var ws = this.getWorksheet();
    ws.applyFrozenAnchor(x, y, target);
  };

  WorkbookView.prototype._onShowAutoComplete = function() {
    var ws = this.getWorksheet();
    var arrValues = ws.getCellAutoCompleteValues(ws.activeRange.startCol, ws.activeRange.startRow);
    this.handlers.trigger('asc_onEntriesListMenu', arrValues);
  };

  WorkbookView.prototype._onAutoFiltersClick = function(idFilter) {
    this.getWorksheet().autoFilters.onAutoFilterClick(idFilter);
  };

  WorkbookView.prototype._onCommentCellClick = function(x, y) {
    var ws = this.getWorksheet();
    var comments = ws.cellCommentator.getCommentsXY(x, y);
    if (comments.length) {
      ws.cellCommentator.showComment(comments[0].asc_getId());
    }
  };

  WorkbookView.prototype._onUpdateSelectionName = function() {
    if (this.canUpdateAfterShiftUp) {
      this.canUpdateAfterShiftUp = false;
      var ws = this.getWorksheet();
      this._onSelectionNameChanged(ws.getSelectionName(/*bRangeText*/false));
    }
  };

  WorkbookView.prototype._onStopFormatPainter = function() {
    if (this.stateFormatPainter) {
      this.formatPainter(c_oAscFormatPainterState.kOff);
    }
  };

  // Shapes
  WorkbookView.prototype._onGraphicObjectMouseDown = function(e, x, y) {
    var ws = this.getWorksheet();
    ws.objectRender.graphicObjectMouseDown(e, x, y);
  };

  WorkbookView.prototype._onGraphicObjectMouseMove = function(e, x, y) {
    var ws = this.getWorksheet();
    ws.objectRender.graphicObjectMouseMove(e, x, y);
  };

  WorkbookView.prototype._onGraphicObjectMouseUp = function(e, x, y) {
    var ws = this.getWorksheet();
    ws.objectRender.graphicObjectMouseUp(e, x, y);
  };

  WorkbookView.prototype._onGraphicObjectMouseUpEx = function(e, x, y) {
    //var ws = this.getWorksheet();
    //ws.objectRender.coordsManager.calculateCell(x, y);
  };

  WorkbookView.prototype._onGraphicObjectWindowKeyDown = function(e) {
    var ws = this.getWorksheet();
    return ws.objectRender.graphicObjectKeyDown(e);
  };

  WorkbookView.prototype._onGraphicObjectWindowKeyPress = function(e) {
    var ws = this.getWorksheet();
    return ws.objectRender.graphicObjectKeyPress(e);
  };

  WorkbookView.prototype._onGetGraphicsInfo = function(x, y) {
    var ws = this.getWorksheet();
    return ws.objectRender.checkCursorDrawingObject(x, y);
  };

  WorkbookView.prototype._onGetSelectedGraphicObjects = function() {
    var ws = this.getWorksheet();
    return ws.objectRender.getSelectedGraphicObjects();
  };

  WorkbookView.prototype._onUpdateSelectionShape = function(isSelectOnShape) {
    var ws = this.getWorksheet();
    return ws.setSelectionShape(isSelectOnShape);
  };

  // Double click
  WorkbookView.prototype._onMouseDblClick = function(x, y, isHideCursor, callback) {
    var ws = this.getWorksheet();
    var ct = ws.getCursorTypeFromXY(x, y, this.controller.settings.isViewerMode);

    if (ct.target === c_oTargetType.ColumnResize || ct.target === c_oTargetType.RowResize) {
      ct.target === c_oTargetType.ColumnResize ? ws.optimizeColWidth(ct.col) : ws.optimizeRowHeight(ct.row);
      asc_applyFunction(callback);
    } else {
      if (ct.col >= 0 && ct.row >= 0) {
        this.controller.setStrictClose(!ws._isCellEmptyText(ct.col, ct.row));
      }

      // Для нажатия на колонку/строку/all/frozenMove обрабатывать dblClick не нужно
      if (c_oTargetType.ColumnHeader === ct.target || c_oTargetType.RowHeader === ct.target || c_oTargetType.Corner === ct.target || c_oTargetType.FrozenAnchorH === ct.target || c_oTargetType.FrozenAnchorV === ct.target) {
        asc_applyFunction(callback);
        return;
      }

      if (ws.objectRender.checkCursorDrawingObject(x, y)) {
        asc_applyFunction(callback);
        return;
      }

      // При dbl клике фокус выставляем в зависимости от наличия текста в ячейке
      this._onEditCell(x, y, /*isCoord*/true, /*isFocus*/undefined, /*isClearCell*/undefined, /*isHideCursor*/isHideCursor, /*isQuickInput*/false);
    }
  };

  WorkbookView.prototype._onEditCell = function(x, y, isCoord, isFocus, isClearCell, isHideCursor, isQuickInput, callback, event) {
    var t = this;

    // Проверка глобального лока
    if (this.collaborativeEditing.getGlobalLock() || this.controller.isResizeMode) {
      return;
    }

    var ws = t.getWorksheet();
    var activeCellRange = ws.getActiveCell(x, y, isCoord);
    var arn = ws.activeRange.clone(true);

    var editFunction = function() {
      t.setCellEditMode(true);
      ws.setCellEditMode(true);
      if (!ws.openCellEditor(t.cellEditor, x, y, isCoord, /*fragments*/undefined, /*cursorPos*/undefined, isFocus, isClearCell, /*isHideCursor*/isHideCursor, /*isQuickInput*/isQuickInput, /*activeRange*/arn)) {
        t.setCellEditMode(false);
        t.controller.setStrictClose(false);
        t.controller.setFormulaEditMode(false);
        ws.setCellEditMode(false);
        ws.setFormulaEditMode(false);
        t.input.disabled = true;
        asc_applyFunction(callback, false);
        return;
      }

      t.input.disabled = false;
      t.handlers.trigger("asc_onEditCell", c_oAscCellEditorState.editStart);
      // Эвент от предыдущего нажатия на символ или на backspace
      if (event) {
        if ("keydown" === event.type) {
          t.cellEditor._onWindowKeyDown(event);
        } else if ("keypress" === event.type) {
          t.cellEditor._onWindowKeyPress(event);
        }
      }

      // Эвент на обновление состояния редактора
      t.cellEditor._updateEditorState();
      asc_applyFunction(callback, true);
    };

    var editLockCallback = function(res) {
      if (!res) {
        t.setCellEditMode(false);
        t.controller.setStrictClose(false);
        t.controller.setFormulaEditMode(false);
        ws.setCellEditMode(false);
        ws.setFormulaEditMode(false);
        t.input.disabled = true;

        // Выключаем lock для редактирования ячейки
        t.collaborativeEditing.onStopEditCell();
        t.cellEditor.close(false);
        t._onWSSelectionChanged(null);
      }
    };

    // Стартуем редактировать ячейку
    this.collaborativeEditing.onStartEditCell();
    if (ws._isLockedCells(activeCellRange, /*subType*/null, editLockCallback)) {
      editFunction();
    }
  };

  WorkbookView.prototype._onStopCellEditing = function() {
    return this.cellEditor.close(true);
  };

  WorkbookView.prototype._onCloseCellEditor = function() {
    this.setCellEditMode(false);
    this.controller.setStrictClose(false);
    this.controller.setFormulaEditMode(false);
      var ws = this.getWorksheet(), isCellEditMode, index;
	  isCellEditMode = ws.getCellEditMode();
      ws.setCellEditMode(false);

      if( this.cellFormulaEnterWSOpen ){
		  index = this.cellFormulaEnterWSOpen.model.getIndex();
		  isCellEditMode = isCellEditMode ? isCellEditMode : this.cellFormulaEnterWSOpen.getCellEditMode();
		  this.cellFormulaEnterWSOpen.setCellEditMode(false);
		  this.cellFormulaEnterWSOpen = null;
		  if( index != ws.model.getIndex() ){
			  this.showWorksheet(index);
			  this.handlers.trigger("asc_onActiveSheetChanged", index);
		  }
		  ws = this.getWorksheet(index);
     }

	  for (var i in this.wsViews) {
		  this.wsViews[i].setFormulaEditMode(false);
	  }

      ws.updateSelection();

	  for (var i in this.wsViews) {
		  this.wsViews[i].cleanFormulaRanges();
	  }

    if (isCellEditMode) {
      this.handlers.trigger("asc_onEditCell", c_oAscCellEditorState.editEnd);
    }
    // Обновляем состояние Undo/Redo
    History._sendCanUndoRedo();
    // Обновляем состояние информации
    this._onWSSelectionChanged(null);

    // Закрываем подбор формулы
    if (-1 !== this.lastFormulaPos) {
      this.handlers.trigger('asc_onFormulaCompleteMenu', null);
      this.lastFormulaPos = -1;
      this.lastFormulaNameLength = 0;
    }

  };

  WorkbookView.prototype._onEmpty = function() {
    this.getWorksheet().emptySelection(c_oAscCleanOptions.Text);
  };

  WorkbookView.prototype._onAddColumn = function(isNotActive) {
    var res = this.getWorksheet().expandColsOnScroll(isNotActive);
    if (res) {
		if(res == 1)
      		this.controller.reinitializeScroll(/*horizontal*/2);
		else
      		this.controller.reinitializeScroll(/*horizontal*/2,true);
    }
  };

  WorkbookView.prototype._onAddRow = function(isNotActive) {
    var res = this.getWorksheet().expandRowsOnScroll(isNotActive);
    if (res) {  // Добавлены строки
      // после добавления controller.settings.wheelScrollLines
      // ws.scrollVertical() здесь не нужен, scroll.js сам все разрулит
		if(res == 1)
      		this.controller.reinitializeScroll(/*vertical*/1);
		else
			this.controller.reinitializeScroll(/*vertical*/1,true);
    }
  };

  WorkbookView.prototype._onShowNextPrevWorksheet = function(direction) {
    // Проверка на неправильное направление
    if (0 === direction) {
      return false;
    }
    // Колличество листов
    var countWorksheets = this.model.getWorksheetCount();
    // Покажем следующий лист или предыдущий (если больше нет)
    var i, ws;
    for (i = this.wsActive + direction; (0 > direction) ? (i >= 0) : (i < countWorksheets); i += direction) {
      ws = this.model.getWorksheet(i);
      if (false === ws.getHidden()) {
        this.showWorksheet(i);
        this.handlers.trigger("asc_onActiveSheetChanged", i);
        return true;
      }
    }

    return false;
  };

  WorkbookView.prototype._onSetFontAttributes = function(prop) {
    var val;
    var selectionInfo = this.getWorksheet().getSelectionInfo().asc_getFont();
    switch (prop) {
      case "b":
        val = !(selectionInfo.asc_getBold());
        break;
      case "i":
        val = !(selectionInfo.asc_getItalic());
        break;
      case "u":
        // ToDo для двойного подчеркивания нужно будет немного переделать схему
        val = !(selectionInfo.asc_getUnderline());
        val = val ? Asc.EUnderline.underlineSingle : Asc.EUnderline.underlineNone;
        break;
      case "s":
        val = !(selectionInfo.asc_getStrikeout());
        break;
    }
    return this.setFontAttributes(prop, val);
  };

  WorkbookView.prototype._onSelectColumnsByRange = function() {
    this.getWorksheet()._selectColumnsByRange();
  };

  WorkbookView.prototype._onSelectRowsByRange = function() {
    this.getWorksheet()._selectRowsByRange();
  };

  WorkbookView.prototype._onShowCellEditorCursor = function() {
    var ws = this.getWorksheet();
    // Показываем курсор
    if (ws.getCellEditMode()) {
      this.cellEditor.showCursor();
    }
  };

  WorkbookView.prototype._onDocumentPlaceChanged = function() {
    if (this.isDocumentPlaceChangedEnabled) {
      this.handlers.trigger("asc_onDocumentPlaceChanged");
    }
  };

  WorkbookView.prototype.getTablePictures = function() {
    var autoFilters = new asc.AutoFilters();
    return autoFilters.getTablePictures(this.model, this.fmgrGraphics, this.m_oFont);
  };

  WorkbookView.prototype.getCellStyles = function() {
    var oStylesPainter = new asc_CSP();
    oStylesPainter.generateStylesAll(this.model.CellStyles, this.fmgrGraphics, this.m_oFont, this.stringRender);
    return oStylesPainter;
  };

  WorkbookView.prototype.getWorksheetById = function(id) {
    var wsModel = this.model.getWorksheetById(id);
    if (wsModel) {
      return this.getWorksheet(wsModel.getIndex());
    }
    return null;
  };

  /**
   * @param {Number} [index]
   * @return {WorksheetView}
   */
  WorkbookView.prototype.getWorksheet = function(index) {
    var wb = this.model;
    var i = asc_typeof(index) === "number" && index >= 0 ? index : wb.getActive();
    var ws = this.wsViews[i];
    if (null == ws) {
      ws = this.wsViews[i] = this._createWorksheetView(wb.getWorksheet(i));
      ws._prepareComments();
      ws._prepareDrawingObjects();
    }
    return ws;
  };

  /**
   *
   * @param index
   * @param [isResized]
   * @param [bLockDraw]
   * @returns {WorkbookView}
   */
  WorkbookView.prototype.showWorksheet = function(index, isResized, bLockDraw) {
    if (index === this.wsActive) {
      return this;
    }

    var isSendInfo = (-1 === this.wsActive) || !isResized, tmpWorksheet, selectionRange = null;
    // Только если есть активный
    if (-1 !== this.wsActive) {
      var ws = this.getWorksheet();
      // Останавливаем ввод данных в редакторе ввода. Если в режиме ввода формул, то продолжаем работать с cellEditor'ом, чтобы можно было
      // выбирать ячейки для формулы
        if (ws.getCellEditMode()){
            if( this.cellEditor && this.cellEditor.formulaIsOperator() ){

                this.copyActiveSheet = this.wsActive;
                if( !this.cellFormulaEnterWSOpen ){
                    this.cellFormulaEnterWSOpen = ws;
                } else {
                    ws.setFormulaEditMode(false);
                }
            }
            else{
                if (!isResized)
                    this._onStopCellEditing();
            }
        }
      // Делаем очистку селекта
      ws.cleanSelection();
      this.stopTarget(ws);

    }

    if (c_oAscSelectionDialogType.Chart === this.selectionDialogType) {
      // Когда идет выбор диапазона, то должны на закрываемом листе отменить выбор диапазона
      tmpWorksheet = this.getWorksheet();
      selectionRange = tmpWorksheet.activeRange.clone(true);
      tmpWorksheet.setSelectionDialogMode(c_oAscSelectionDialogType.None);
    }
    if (this.stateFormatPainter) {
      // Должны отменить выбор на закрываемом листе
      this.getWorksheet().formatPainter(c_oAscFormatPainterState.kOff);
    }

    var wb = this.model;
    if (asc_typeof(index) === "number" && index >= 0) {
      if (index !== wb.getActive()) {
        wb.setActive(index);
      }
    } else {
      index = wb.getActive();
    }
    this.wsActive = index;
    this.wsMustDraw = bLockDraw;

    ws = this.getWorksheet(index);
    // Мы делали resize или меняли zoom, но не перерисовывали данный лист (он был не активный)
      if ( ws.updateResize && ws.updateZoom ) {
          ws.changeZoomResize();
      }
      else if ( ws.updateResize ) {
          ws.resize( true );
      }
      else if ( ws.updateZoom ) {
          ws.changeZoom( true );
      }

      if (this.cellEditor && this.cellFormulaEnterWSOpen ) {
          if( ws.model.getId() == this.cellFormulaEnterWSOpen.model.getId() ){
              this.cellFormulaEnterWSOpen.setFormulaEditMode( true );
              this.cellEditor._showCanvas();
          }
          else if (this.cellFormulaEnterWSOpen.getCellEditMode() && this.cellEditor.isFormula() ) {
              this.cellFormulaEnterWSOpen.setFormulaEditMode( false );
              /*скрываем cellEditor, в редактор добавляем %selected sheet name%+"!" */
              this.cellEditor._hideCanvas();
              ws.cleanSelection();
              ws.setFormulaEditMode(true);
          }
      }

    if (!bLockDraw) {
      ws.draw();
    }

    if (c_oAscSelectionDialogType.Chart === this.selectionDialogType) {
      // Когда идет выбор диапазона, то на показываемом листе должны выставить нужный режим
      ws.setSelectionDialogMode(this.selectionDialogType, selectionRange);
      this.handlers.trigger("asc_onSelectionRangeChanged", ws.getSelectionRangeValue());
    }
    if (this.stateFormatPainter) {
      // Должны отменить выбор на закрываемом листе
      this.getWorksheet().formatPainter(this.stateFormatPainter);
    }
    if (!bLockDraw) {
      ws.objectRender.controller.updateSelectionState();
      ws.objectRender.controller.updateOverlay();
    }

    if (isSendInfo) {
      this._onSelectionNameChanged(ws.getSelectionName(/*bRangeText*/false));
      this._onWSSelectionChanged(ws.getSelectionInfo());
      this._onSelectionMathInfoChanged(ws.getSelectionMathInfo());
    }
    this.controller.reinitializeScroll();
    if (this.Api.isMobileVersion) {
      this.MobileTouchManager.Resize();
    }
    // Zoom теперь на каждом листе одинаковый, не отправляем смену

    // Нужно очистить поиск
    this._cleanFindResults();
    return this;
  };

  /** @param nIndex {Number} массив индексов */
  WorkbookView.prototype.removeWorksheet = function(nIndex) {
    this.stopTarget(null);
    this.wsViews.splice(nIndex, 1);
    // Сбрасываем активный (чтобы не досчитывать после смены)
    this.wsActive = -1;
  };

  // Меняет местами 2 элемента просмотра
  WorkbookView.prototype.replaceWorksheet = function(indexFrom, indexTo) {
    // Только если есть активный
    if (-1 !== this.wsActive) {
      var ws = this.getWorksheet(this.wsActive);
      // Останавливаем ввод данных в редакторе ввода
      if (ws.getCellEditMode()) {
        this._onStopCellEditing();
      }
      // Делаем очистку селекта
      ws.cleanSelection();

      this.stopTarget(ws);
      this.wsActive = -1;
      // Чтобы поменять, нужно его добавить
      this.getWorksheet(indexTo);
    }
    var movedSheet = this.wsViews.splice(indexFrom, 1);
    this.wsViews.splice(indexTo, 0, movedSheet[0])
  };

  WorkbookView.prototype.stopTarget = function(ws) {
    if (null === ws && -1 !== this.wsActive) {
      ws = this.getWorksheet(this.wsActive);
    }
    if (null !== ws && ws.objectRender && ws.objectRender.drawingDocument) {
      ws.objectRender.drawingDocument.TargetEnd();
    }
  };

  // Копирует элемент перед другим элементом
  WorkbookView.prototype.copyWorksheet = function(index, insertBefore) {
    // Только если есть активный
    if (-1 !== this.wsActive) {
      var ws = this.getWorksheet();
      // Останавливаем ввод данных в редакторе ввода
      if (ws.getCellEditMode()) {
        this._onStopCellEditing();
      }
      // Делаем очистку селекта
      ws.cleanSelection();

      this.stopTarget(ws);
      this.wsActive = -1;
    }

    if (null != insertBefore && insertBefore >= 0 && insertBefore < this.wsViews.length) {
      // Помещаем нулевой элемент перед insertBefore
      this.wsViews.splice(insertBefore, 0, null);
    }
  };

  WorkbookView.prototype.updateWorksheetByModel = function() {
    // ToDo Сделал небольшую заглушку с показом листа. Нужно как мне кажется перейти от wsViews на wsViewsId (хранить по id)
    var oldActiveWs;
    if (-1 !== this.wsActive) {
      oldActiveWs = this.wsViews[this.wsActive];
    }

    //расставляем ws так как они идут в модели.
    var oNewWsViews = [];
    for (var i in this.wsViews) {
      var item = this.wsViews[i];
      if (null != item && null != this.model.getWorksheetById(item.model.getId())) {
        oNewWsViews[item.model.getIndex()] = item;
      }
    }
    this.wsViews = oNewWsViews;
    var wsActive = this.model.getActive();

    var newActiveWs = this.wsViews[wsActive];
    if (undefined === newActiveWs || oldActiveWs !== newActiveWs) {
      // Если сменили, то покажем
      this.wsActive = -1;
      this.showWorksheet(undefined, false, true);
    } else {
      this.wsActive = wsActive;
    }
  };

  WorkbookView.prototype.spliceWorksheet = function() {
    this.stopTarget(null);
    this.wsViews.splice.apply(this.wsViews, arguments);
    this.wsActive = -1;
  };

  WorkbookView.prototype._canResize = function() {
    var oldWidth = this.canvas.width;
    var oldHeight = this.canvas.height;
    var width = this.element.offsetWidth - (this.Api.isMobileVersion ? 0 : this.defaults.scroll.widthPx);
    var height = this.element.offsetHeight - (this.Api.isMobileVersion ? 0 : this.defaults.scroll.heightPx);
    var styleWidth, styleHeight, isRetina = AscBrowser.isRetina;

    if (isRetina) {
      styleWidth = width;
      styleHeight = height;
      width <<= 1;
      height <<= 1;
    }

    if (oldWidth === width && oldHeight === height) {
      return false;
    }

    this.canvas.width = this.canvasOverlay.width = this.canvasGraphic.width = this.canvasGraphicOverlay.width = width;
    this.canvas.height = this.canvasOverlay.height = this.canvasGraphic.height = this.canvasGraphicOverlay.height = height;
    if (isRetina) {
      this.canvas.style.width = this.canvasOverlay.style.width = this.canvasGraphic.style.width = this.canvasGraphicOverlay.style.width = styleWidth + 'px';
      this.canvas.style.height = this.canvasOverlay.style.height = this.canvasGraphic.style.height = this.canvasGraphicOverlay.style.height = styleHeight + 'px';
    }

    // При смене ориентации у планшета, сбрасываются флаги у canvas!
    // ToDo перепроверить на новых исходниках, должно поправиться, был баг в отрисовке!!!!!!!!!!!!!
    //this.drawingCtx.initContextSmoothing();
    //this.overlayCtx.initContextSmoothing();
    return true;
  };

  /** @param event {jQuery.Event} */
  WorkbookView.prototype.resize = function(event) {
    if (this._canResize()) {
      var item;
      var activeIndex = this.model.getActive();
      for (var i in this.wsViews) {
        item = this.wsViews[i];
        // Делаем resize (для не активных сменим как только сделаем его активным)
        item.resize(/*isDraw*/i == activeIndex);
      }
      this.showWorksheet(undefined, true);
    } else {
      // ToDo не должно происходить ничего, но нам приходит resize сверху, поэтому проверим отрисовывали ли мы
      if (-1 === this.wsActive || this.wsMustDraw) {
        this.showWorksheet(undefined, true);
      }
    }
    this.wsMustDraw = false;
  };

  // Получаем свойство: редактируем мы сейчас или нет
  WorkbookView.prototype.getCellEditMode = function() {
	  return this.isCellEditMode;
  };

	WorkbookView.prototype.setCellEditMode = function(flag) {
		this.isCellEditMode = !!flag;
	};

  WorkbookView.prototype.getIsTrackShape = function() {
    var ws = this.getWorksheet();
    if (!ws) {
      return false;
    }
    if (ws.objectRender && ws.objectRender.controller) {
      return ws.objectRender.controller.checkTrackDrawings();
    }
  };

  WorkbookView.prototype.getZoom = function() {
    return this.drawingCtx.getZoom();
  };

  WorkbookView.prototype.changeZoom = function(factor) {
    if (factor === this.getZoom()) {
      return;
    }

    this.buffers.main.changeZoom(factor);
    this.buffers.overlay.changeZoom(factor);
    this.buffers.mainGraphic.changeZoom(factor);
    this.buffers.overlayGraphic.changeZoom(factor);
    // Нужно сбросить кэш букв
    var i, length;
    for (i = 0, length = this.fmgrGraphics.length; i < length; ++i)
      this.fmgrGraphics[i].ClearFontsRasterCache();

    var item;
    var activeIndex = this.model.getActive();
    for (i in this.wsViews) {
      item = this.wsViews[i];
      // Меняем zoom (для не активных сменим как только сделаем его активным)
      item.changeZoom(/*isDraw*/i == activeIndex);
      item.objectRender.changeZoom(this.drawingCtx.scaleFactor);
      if (i == activeIndex) {
        item.draw();
        //ToDo item.drawDepCells();
      }
    }

    this.controller.reinitializeScroll();
    this.handlers.trigger("asc_onZoomChanged", this.getZoom());
  };

  WorkbookView.prototype.getEnableKeyEventsHandler = function(bIsNaturalFocus) {
    var res = this.enableKeyEvents;
    if (res && bIsNaturalFocus && this.getCellEditMode() && this.input.isFocused) {
      res = false;
    }
    return res;
  };
  WorkbookView.prototype.enableKeyEventsHandler = function(f) {
    this.enableKeyEvents = !!f;
    this.controller.enableKeyEventsHandler(this.enableKeyEvents);
    if (this.cellEditor) {
      this.cellEditor.enableKeyEventsHandler(this.enableKeyEvents);
    }
  };

  // Останавливаем ввод данных в редакторе ввода
  WorkbookView.prototype.closeCellEditor = function() {
    var ws = this.getWorksheet();
    // Останавливаем ввод данных в редакторе ввода
    if (ws.getCellEditMode() && !this.cellEditor.formulaIsOperator() /*&& !this.cellFormulaEnterWSOpen*/) {
      this._onStopCellEditing();
    }
  };

  WorkbookView.prototype.restoreFocus = function() {
    if (window["NATIVE_EDITOR_ENJINE"]) {
      return;
    }

    if (this.cellEditor.hasFocus) {
      this.cellEditor.restoreFocus();
    }
  };

  WorkbookView.prototype._onUpdateCellEditor = function(text, cursorPosition, isFormula, formulaPos, formulaName) {
    if (this.skipHelpSelector) {
      return;
    }
    // ToDo для ускорения можно завести объект, куда класть результаты поиска по формулам и второй раз не искать.
    var i, arrResult = [], defNamesList, defName;
    if (isFormula && formulaName) {
      formulaName = formulaName.toUpperCase();
      for (i = 0; i < this.formulasList.length; ++i) {
        if (0 === this.formulasList[i].indexOf(formulaName)) {
          arrResult.push(new Asc.asc_CCompleteMenu(this.formulasList[i], c_oAscPopUpSelectorType.Func));
        }
      }
      defNamesList = this.getDefinedNames(c_oAscGetDefinedNamesList.WorksheetWorkbook);
      formulaName = formulaName.toLowerCase();
      for (i = 0; i < defNamesList.length; ++i) {
        defName = defNamesList[i];
        if (0 === defName.Name.toLowerCase().indexOf(formulaName)) {
          arrResult.push(new Asc.asc_CCompleteMenu(defName.Name, !defName.isTable ? c_oAscPopUpSelectorType.Range : c_oAscPopUpSelectorType.Table));
        }
      }
    }
    if (0 < arrResult.length) {
      this.handlers.trigger('asc_onFormulaCompleteMenu', arrResult);

      this.lastFormulaPos = formulaPos;
      this.lastFormulaNameLength = formulaName.length;
    } else {
      this.handlers.trigger('asc_onFormulaCompleteMenu', null);

      this.lastFormulaPos = -1;
      this.lastFormulaNameLength = 0;
    }
  };

  // Вставка формулы в редактор
  WorkbookView.prototype.insertFormulaInEditor = function(name, type, autoComplete) {
    var t = this, ws = this.getWorksheet(), cursorPos, isNotFunction;

    if (c_oAscPopUpSelectorType.None === type) {
      this.getWorksheet().setSelectionInfo("value", name, /*onlyActive*/true);
      return;
    }

    isNotFunction = c_oAscPopUpSelectorType.Func !== type;

    // Проверяем, открыт ли редактор
    if (ws.getCellEditMode()) {
      if (isNotFunction) {
        this.skipHelpSelector = true;
      }
      if (-1 !== this.lastFormulaPos) {
        if (-1 === this.arrExcludeFormulas.indexOf(name) && !isNotFunction) {
          name += '('; // ToDo сделать проверки при добавлении, чтобы не вызывать постоянно окно
        } else {
          this.skipHelpSelector = true;
        }
        this.cellEditor.replaceText(this.lastFormulaPos, this.lastFormulaNameLength, name);
      } else if (false === this.cellEditor.insertFormula(name, isNotFunction)) {
        // Не смогли вставить формулу, закроем редактор, с сохранением текста
        this.cellEditor.close(true);
      }
      this.skipHelpSelector = false;
    } else {
      // Проверка глобального лока
      if (this.collaborativeEditing.getGlobalLock()) {
        return false;
      }

      // Редактор закрыт
      var cellRange = null;
      // Если нужно сделать автозаполнение формулы, то ищем ячейки)
      if (autoComplete) {
        cellRange = ws.autoCompleteFormula(name);
      }
      if (isNotFunction) {
        name = "=" + name;
      } else {
        if (cellRange) {
          if (cellRange.notEditCell) {
            // Мы уже ввели все что нужно, редактор открывать не нужно
            return;
          }
          // Меняем значение ячейки
          name = "=" + name + "(" + cellRange.text + ")";
        } else {
          // Меняем значение ячейки
          name = "=" + name + "()";
        }
        // Вычисляем позицию курсора (он должен быть в функции)
        cursorPos = name.length - 1;
      }

      var arn = ws.activeRange.clone(true);

      var openEditor = function(res) {
        if (res) {
          // Выставляем переменные, что мы редактируем
          t.setCellEditMode(true);
          ws.setCellEditMode(true);

          t.handlers.trigger("asc_onEditCell", c_oAscCellEditorState.editStart);
          if (isNotFunction) {
            t.skipHelpSelector = true;
          }
          // Открываем, с выставлением позиции курсора
          if (!ws.openCellEditorWithText(t.cellEditor, name, cursorPos, /*isFocus*/false, /*activeRange*/arn)) {
            t.handlers.trigger("asc_onEditCell", c_oAscCellEditorState.editEnd);
            t.setCellEditMode(false);
            t.controller.setStrictClose(false);
            t.controller.setFormulaEditMode(false);
            ws.setCellEditMode(false);
            ws.setFormulaEditMode(false);
          }
          if (isNotFunction) {
            t.skipHelpSelector = false;
          }
        } else {
          t.setCellEditMode(false);
          t.controller.setStrictClose(false);
          t.controller.setFormulaEditMode(false);
          ws.setCellEditMode(false);
          ws.setFormulaEditMode(false);
        }
      };

      var activeCellRange = ws.getActiveCell(0, 0, /*isCoord*/false);

      ws._isLockedCells(activeCellRange, /*subType*/null, openEditor);
    }
  };

  WorkbookView.prototype.copyToClipboard = function() {
    var t = this, ws, v;
    if (!t.getCellEditMode()) {
      ws = t.getWorksheet();
      t.clipboard.copyRange(ws.getSelectedRange(), ws);
    } else {
      v = t.cellEditor.copySelection();
      if (v) {
        t.clipboard.copyCellValue(v);
      }
    }
  };

  WorkbookView.prototype.copyToClipboardButton = function() {
    var t = this, ws, v;
    if (!t.getCellEditMode()) {
      ws = t.getWorksheet();
      return t.clipboard.copyRangeButton(ws.getSelectedRange(), ws);
    } else {
      v = t.cellEditor.copySelection();
      if (v) {
        return t.clipboard.copyCellValueButton(v);
      } else {
        return true;
      }
    }
  };

  WorkbookView.prototype.pasteFromClipboard = function() {
    var t = this;
    if (!t.getCellEditMode()) {
      var ws = t.getWorksheet();
      t.clipboard.pasteRange(ws);
    } else {
      t.clipboard.pasteAsText(function(text) {
        t.cellEditor.pasteText(text);
      });
    }
  };

  WorkbookView.prototype.pasteFromClipboardButton = function() {
    var t = this;
    if (!t.getCellEditMode()) {
      var ws = t.getWorksheet();
      return t.clipboard.pasteRangeButton(ws);
    } else {
      return t.clipboard.pasteAsTextButton(function(text) {
        t.cellEditor.pasteText(text);
      });
    }
  };

  WorkbookView.prototype.cutToClipboard = function() {
    var t = this, ws, v;
    if (!t.getCellEditMode() && !window.USER_AGENT_SAFARI_MACOS) {
      ws = t.getWorksheet();

      // Запрещаем копирование диаграмм в iframe
      //if ( t.Api.isChartEditor && ws.objectRender.selectedGraphicObjectsExists() )
      //	return;

      t.clipboard.copyRange(ws.getSelectedRange(), ws, true);
      ws.emptySelection(c_oAscCleanOptions.All);
    } else if (!window.USER_AGENT_SAFARI_MACOS) {
      v = t.cellEditor.cutSelection();
      if (v) {
        t.clipboard.copyCellValue(v);
      }
    }
  };

  WorkbookView.prototype.bIsEmptyClipboard = function() {
    return this.clipboard.bIsEmptyClipboard(this.getCellEditMode());
  };

  WorkbookView.prototype.cutToClipboardButton = function() {
    var t = this, ws, v;
    if (!t.getCellEditMode()) {
      ws = t.getWorksheet();
      var result = t.clipboard.copyRangeButton(ws.getSelectedRange(), ws, true);
      if (result) {
        ws.emptySelection(c_oAscCleanOptions.All);
      }
      return result;
    } else {
      v = t.cellEditor.cutSelection();
      if (v) {
        return t.clipboard.copyCellValueButton(v);
      } else {
        return true;
      }
    }
  };
  
   WorkbookView.prototype.checkCopyToClipboard = function(_clipboard, _formats) {
    var t = this, ws, v;
    ws = t.getWorksheet();
    t.clipboard.checkCopyToClipboard(ws, _clipboard, _formats);
  };

  WorkbookView.prototype.undo = function() {
	gFormulaLocaleParse = false;
	gFormulaLocaleDigetSep = false;
    if (!this.getCellEditMode()) {
      if (!History.Undo() && this.collaborativeEditing.getFast() && this.collaborativeEditing.getCollaborativeEditing()) {
        this.Api.sync_TryUndoInFastCollaborative();
      }
    } else {
      this.cellEditor.undo();
    }
	gFormulaLocaleParse = true;
	gFormulaLocaleDigetSep = true;
  };

  WorkbookView.prototype.redo = function() {
    if (!this.getCellEditMode()) {
      History.Redo();
    } else {
      this.cellEditor.redo();
    }
  };

  WorkbookView.prototype.setFontAttributes = function(prop, val) {
    if (!this.getCellEditMode()) {
      this.getWorksheet().setSelectionInfo(prop, val);
    } else {
      this.cellEditor.setTextStyle(prop, val);
    }
  };

  WorkbookView.prototype.changeFontSize = function(prop, val) {
    if (!this.getCellEditMode()) {
      this.getWorksheet().setSelectionInfo(prop, val);
    } else {
      this.cellEditor.setTextStyle(prop, val);
    }
  };

  WorkbookView.prototype.emptyCells = function(options) {
    if (!this.getCellEditMode()) {
      this.getWorksheet().emptySelection(options);
      this.restoreFocus();
    } else {
      this.cellEditor.empty(options);
    }
  };

  WorkbookView.prototype.setSelectionDialogMode = function(selectionDialogType, selectRange) {
    if (selectionDialogType === this.selectionDialogType) {
      return;
    }

    if (c_oAscSelectionDialogType.None === selectionDialogType) {
      this.selectionDialogType = selectionDialogType;
      this.getWorksheet().setSelectionDialogMode(selectionDialogType, selectRange);
      if (this.copyActiveSheet !== this.wsActive) {
        this.showWorksheet(this.copyActiveSheet);
        // Посылаем эвент о смене активного листа
        this.handlers.trigger("asc_onActiveSheetChanged", this.copyActiveSheet);
      }
      this.copyActiveSheet = -1;
      this.input.disabled = false;
    } else {
      this.copyActiveSheet = this.wsActive;

      var index, tmpSelectRange = parserHelp.parse3DRef(selectRange);
      if (tmpSelectRange) {
        if (c_oAscSelectionDialogType.Chart === selectionDialogType) {
          // Получаем sheet по имени
          var ws = this.model.getWorksheetByName(tmpSelectRange.sheet);
          if (!ws || ws.getHidden()) {
            tmpSelectRange = null;
          } else {
            index = ws.getIndex();
            this.showWorksheet(index);
            // Посылаем эвент о смене активного листа
            this.handlers.trigger("asc_onActiveSheetChanged", index);

            tmpSelectRange = tmpSelectRange.range;
          }
        } else {
          tmpSelectRange = tmpSelectRange.range;
        }
      } else {
        // Это не 3D ссылка
        tmpSelectRange = selectRange;
      }

      this.getWorksheet().setSelectionDialogMode(selectionDialogType, tmpSelectRange);
      // Нужно выставить после, т.к. при смене листа не должны проставлять режим
      this.selectionDialogType = selectionDialogType;
      this.input.disabled = true;
    }
  };

  WorkbookView.prototype.formatPainter = function(stateFormatPainter) {
    // Если передали состояние, то выставляем его. Если нет - то меняем на противоположное.
    this.stateFormatPainter = (null != stateFormatPainter) ? stateFormatPainter : ((c_oAscFormatPainterState.kOff !== this.stateFormatPainter) ? c_oAscFormatPainterState.kOff : c_oAscFormatPainterState.kOn);

    this.rangeFormatPainter = this.getWorksheet().formatPainter(this.stateFormatPainter);
    if (this.stateFormatPainter) {
      this.copyActiveSheet = this.wsActive;
    } else {
      this.copyActiveSheet = -1;
      this.handlers.trigger('asc_onStopFormatPainter');
    }
  };

  WorkbookView.prototype._cleanFindResults = function() {
    this.lastFindOptions = null;
    this.lastFindResults = {};
  };

  // Поиск текста в листе
  WorkbookView.prototype.findCellText = function(options) {
    // Для поиска эта переменная не нужна (но она может остаться от replace)
    options.activeRange = null;

    var ws = this.getWorksheet();
    // Останавливаем ввод данных в редакторе ввода
    if (ws.getCellEditMode()) {
      this._onStopCellEditing();
    }
    var result = ws.findCellText(options);
    if (false === options.scanOnOnlySheet) {
      // Поиск по всей книге
      var key = result ? (result.c1 + "-" + result.r1) : null;
      if (null === key || options.isEqual(this.lastFindOptions)) {
        if (null === key || this.lastFindResults[key]) {
          // Мы уже находили данную ячейку, попробуем на другом листе
          var i, active = this.model.getActive(), start = 0, end = this.model.getWorksheetCount();
          var inc = options.scanForward ? +1 : -1;
          var tmpWs, tmpResult = null;
          for (i = active + inc; i < end && i >= start; i += inc) {
            tmpWs = this.getWorksheet(i);
            tmpResult = tmpWs.findCellText(options);
            if (tmpResult) {
              break;
            }
          }
          if (!tmpResult) {
            // Мы дошли до конца или начала (в зависимости от направления, теперь пойдем до активного)
            if (options.scanForward) {
              i = 0;
              end = active;
            } else {
              i = end - 1;
              start = active + 1;
            }
            inc *= -1;
            for (; i < end && i >= start; i += inc) {
              tmpWs = this.getWorksheet(i);
              tmpResult = tmpWs.findCellText(options);
              if (tmpResult) {
                break;
              }
            }
          }

          if (tmpResult) {
            ws = tmpWs;
            result = tmpResult;
            this.showWorksheet(i);
            // Посылаем эвент о смене активного листа
            this.handlers.trigger("asc_onActiveSheetChanged", i);
            key = result.c1 + "-" + result.r1;
          }

          this.lastFindResults = {};
        }
      }
      if (null !== key) {
        this.lastFindOptions = options.clone();
        this.lastFindResults[key] = true;
      }
    }

    if (result) {
      return ws._setActiveCell(result.c1, result.r1);
    }
    this._cleanFindResults();
    return null;
  };

  // Замена текста в листе
  WorkbookView.prototype.replaceCellText = function(options) {
    var ws = this.getWorksheet();
    // Останавливаем ввод данных в редакторе ввода
    if (ws.getCellEditMode()) {
      this._onStopCellEditing();
    }

    History.Create_NewPoint();
    History.StartTransaction();

    options.clearFindAll();
    if (options.isReplaceAll) {
      // На ReplaceAll ставим медленную операцию
      this.Api.sync_StartAction(c_oAscAsyncActionType.BlockInteraction, c_oAscAsyncAction.SlowOperation);
    }

    ws.replaceCellText(options, false, this.fReplaceCallback);
  };
  WorkbookView.prototype._replaceCellTextCallback = function(options) {
    options.updateFindAll();
    if (!options.scanOnOnlySheet && options.isReplaceAll) {
      // Замена на всей книге
      var i = ++options.sheetIndex;
      if (this.model.getActive() === i) {
        i = ++options.sheetIndex;
      }

      if (i < this.model.getWorksheetCount()) {
        var ws = this.getWorksheet(i);
        ws.replaceCellText(options, true, this.fReplaceCallback);
        return;
      }
    }

    this.handlers.trigger("asc_onRenameCellTextEnd", options.countFindAll, options.countReplaceAll);

    History.EndTransaction();
    if (options.isReplaceAll) {
      // Заканчиваем медленную операцию
      this.Api.sync_EndAction(c_oAscAsyncActionType.BlockInteraction, c_oAscAsyncAction.SlowOperation);
    }
  };

  // Поиск ячейки по ссылке
  WorkbookView.prototype.findCell = function(reference) {
    var ws = this.getWorksheet(), retRange;
    // Останавливаем ввод данных в редакторе ввода
    if (ws.getCellEditMode()) {
      this._onStopCellEditing();
    }


    return ws.findCell(reference);
  };

  WorkbookView.prototype.getDefinedNames = function(defNameListId) {
    return this.model.getDefinedNamesWB(defNameListId);
  };

  WorkbookView.prototype.setDefinedNames = function(defName) {
    //ToDo проверка defName.ref на знак "=" в начале ссылки. знака нет тогда это либо число либо строка, так делает Excel.

    this.model.setDefinesNames(defName.Name, defName.Ref, defName.Scope);
    this.handlers.trigger("asc_onDefName");

  };

  WorkbookView.prototype.checkDefName = function(checkName, scope) {

    return this.model.checkDefName(checkName, scope);

  };

  WorkbookView.prototype.editDefinedNames = function(oldName, newName) {
    //ToDo проверка defName.ref на знак "=" в начале ссылки. знака нет тогда это либо число либо строка, так делает Excel.
    if (this.collaborativeEditing.getGlobalLock()) {
      return;
    }

    var ws = this.getWorksheet(), t = this;

    var editDefinedNamesCallback = function(res) {
      if (res) {
        t.model.editDefinesNames(oldName, newName);
        t.handlers.trigger("asc_onEditDefName", oldName, newName);
        t.handlers.trigger("asc_onRefreshDefNameList");
      } else {
        t.handlers.trigger("asc_onError", c_oAscError.ID.LockCreateDefName, c_oAscError.Level.NoCritical);
      }
      t._onSelectionNameChanged(ws.getSelectionName(/*bRangeText*/false));
    };
    var defNameId;
    if (oldName) {
      defNameId = t.model.getDefinedName(oldName);
      defNameId = defNameId ? defNameId.nodeId : null;
    }

    ws._isLockedDefNames(editDefinedNamesCallback, defNameId);

  };

  WorkbookView.prototype.delDefinedNames = function(oldName) {
    //ToDo проверка defName.ref на знак "=" в начале ссылки. знака нет тогда это либо число либо строка, так делает Excel.
    if (this.collaborativeEditing.getGlobalLock()) {
      return;
    }

    var ws = this.getWorksheet(), t = this

    if (oldName) {

      var delDefinedNamesCallback = function(res) {
        if (res) {
          t.handlers.trigger("asc_onDelDefName", t.model.delDefinesNames(oldName));
          t.handlers.trigger("asc_onRefreshDefNameList");
        } else {
          t.handlers.trigger("asc_onError", c_oAscError.ID.LockCreateDefName, c_oAscError.Level.NoCritical);
        }
        t._onSelectionNameChanged(ws.getSelectionName(/*bRangeText*/false));
      };
      var defNameId = t.model.getDefinedName(oldName).nodeId;

      ws._isLockedDefNames(delDefinedNamesCallback, defNameId);

    }

  };

  WorkbookView.prototype.getDefaultDefinedName = function() {
    //ToDo проверка defName.ref на знак "=" в начале ссылки. знака нет тогда это либо число либо строка, так делает Excel.

    var ws = this.getWorksheet();

    return new Asc.asc_CDefName("", ws.getSelectionRangeValue(), null);

  };
  WorkbookView.prototype.unlockDefName = function() {
    this.model.unlockDefName();
    this.handlers.trigger("asc_onRefreshDefNameList");
    this.handlers.trigger("asc_onLockDefNameManager", c_oAscDefinedNameReason.OK);
  };

  WorkbookView.prototype._onCheckDefNameLock = function() {
    return this.model.checkDefNameLock();
  };

  // Печать
  WorkbookView.prototype.printSheet = function(pdf_writer, printPagesData) {
    var ws;
    // Закончили печать или нет
    var isEndPrint = false;
    if (null === printPagesData.arrPages || 0 === printPagesData.arrPages.length) {
      // Печать пустой страницы
      ws = this.getWorksheet();
      ws.drawForPrint(pdf_writer, null);
      isEndPrint = true;
    } else {
      var indexWorksheet = -1;
      var indexWorksheetTmp = -1;
      for (var i = 0; i < printPagesData.arrPages.length; ++i) {
        indexWorksheetTmp = printPagesData.arrPages[i].indexWorksheet;
        if (indexWorksheetTmp !== indexWorksheet) {
          ws = this.getWorksheet(indexWorksheetTmp);
          indexWorksheet = indexWorksheetTmp;
        }
        ws.drawForPrint(pdf_writer, printPagesData.arrPages[i]);
      }
      isEndPrint = (i === printPagesData.arrPages.length);
    }

    return isEndPrint;
  };

  WorkbookView.prototype.calcPagesPrint = function(adjustPrint) {
    var ws = null;
    var wb = this.model;
    var activeWs;
    var printPagesData = new asc_CPrintPagesData();
    var printType = adjustPrint.asc_getPrintType();
//			var layoutPageType = adjustPrint.asc_getLayoutPageType();
    var bFitToWidth = adjustPrint.getFitToWidth();
    var bFitToHeight = adjustPrint.getFitToHeight();
    if (printType == c_oAscPrintType.ActiveSheets) {
      activeWs = wb.getActive();
      ws = this.getWorksheet();
      printPagesData.arrPages = ws.calcPagesPrint(wb.getWorksheet(activeWs).PagePrintOptions, /*printOnlySelection*/false, /*indexWorksheet*/activeWs, bFitToWidth, bFitToHeight);
    } else if (printType == c_oAscPrintType.EntireWorkbook) {
      // Колличество листов
      var countWorksheets = this.model.getWorksheetCount();
      for (var i = 0; i < countWorksheets; ++i) {
        ws = this.getWorksheet(i);
        var arrPages = ws.calcPagesPrint(wb.getWorksheet(i).PagePrintOptions, /*printOnlySelection*/false, /*indexWorksheet*/i, bFitToWidth, bFitToHeight);
        if (null !== arrPages) {
          if (null === printPagesData.arrPages) {
            printPagesData.arrPages = [];
          }
          printPagesData.arrPages = printPagesData.arrPages.concat(arrPages);
        }
      }
    } else if (printType == c_oAscPrintType.Selection) {
      activeWs = wb.getActive();
      ws = this.getWorksheet();
      printPagesData.arrPages = ws.calcPagesPrint(wb.getWorksheet(activeWs).PagePrintOptions, /*printOnlySelection*/true, /*indexWorksheet*/activeWs, bFitToWidth, bFitToHeight);
    }

    return printPagesData;
  };

  // Вызывать только для нативной печати
  WorkbookView.prototype._nativeCalculate = function() {
    var item;
    for (var i in this.wsViews) {
      item = this.wsViews[i];
      item._prepareDrawingObjects();
    }
  };

  WorkbookView.prototype._initCommentsToSave = function() {
    var isFirst = true;
    for (var wsKey in this.wsViews) {
      var wsView = this.wsViews[wsKey];
      var wsModel = wsView.model;
      wsView.cellCommentator.prepareCommentsToSave();
      wsModel.aComments = wsView.cellCommentator.aComments;
      wsModel.aCommentsCoords = wsView.cellCommentator.aCommentCoords;

      if (isFirst) {
        isFirst = false;
        this.cellCommentator.worksheet = wsView;
        this.cellCommentator.overlayCtx = wsView.overlayCtx;
        this.cellCommentator.drawingCtx = wsView.drawingCtx;
        this.cellCommentator.prepareCommentsToSave();
        wsModel.aComments = wsModel.aComments.concat(this.cellCommentator.aComments);
        wsModel.aCommentsCoords = wsModel.aCommentsCoords.concat(this.cellCommentator.aCommentCoords);
      }
    }
  };

  WorkbookView.prototype.reInit = function() {
    var ws = this.getWorksheet();
    ws._initCellsArea(/*fullRecalc*/true);
    ws._updateVisibleColsCount();
    ws._updateVisibleRowsCount();
  };
  WorkbookView.prototype.drawWS = function() {
    this.getWorksheet().draw();
  };
  WorkbookView.prototype.onShowDrawingObjects = function(clearCanvas) {
    var ws = this.getWorksheet();
    ws.objectRender.showDrawingObjects(clearCanvas);
  };

  WorkbookView.prototype.insertHyperlink = function(options) {
    var ws = this.getWorksheet();
    if (ws.objectRender.selectedGraphicObjectsExists()) {
      if (ws.objectRender.controller.canAddHyperlink()) {
        ws.objectRender.controller.insertHyperlink(options);
      }
    } else {
      // На всякий случай проверка (вдруг кто собирается вызвать...)
      this.closeCellEditor();
      ws.setSelectionInfo("hyperlink", options);
      this.restoreFocus();
    }
  };
  WorkbookView.prototype.removeHyperlink = function() {
    var ws = this.getWorksheet();
    if (ws.objectRender.selectedGraphicObjectsExists()) {
      ws.objectRender.controller.removeHyperlink();
    } else {
      ws.setSelectionInfo("rh");
    }
  };

  WorkbookView.prototype.setDocumentPlaceChangedEnabled = function(val) {
    this.isDocumentPlaceChangedEnabled = val;
  };

  /*
   * @param {c_oAscRenderingModeType} mode Режим отрисовки
   * @param {Boolean} isInit инициализация или нет
   */
  WorkbookView.prototype.setFontRenderingMode = function(mode, isInit) {
    var ws;
    if (mode !== this.fontRenderingMode) {
      this.fontRenderingMode = mode;
      if (c_oAscFontRenderingModeType.noHinting === mode) {
        this._setHintsProps(false, false);
      } else if (c_oAscFontRenderingModeType.hinting === mode) {
        this._setHintsProps(true, false);
      } else if (c_oAscFontRenderingModeType.hintingAndSubpixeling === mode) {
        this._setHintsProps(true, true);
      }

      if (!isInit) {
        ws = this.getWorksheet();
        ws.draw();
        this.cellEditor.setFontRenderingMode(mode);
      }
    }
  };

  WorkbookView.prototype.initFormulasList = function() {
    this.formulasList = [];
    var oFormulaList = cFormulaFunctionLocalized ? cFormulaFunctionLocalized : cFormulaFunction;
    for (var f in oFormulaList) {
      this.formulasList.push(f);
    }
    this.arrExcludeFormulas = [cBoolLocal["t"].toUpperCase(), cBoolLocal["f"].toUpperCase()];
  };

  WorkbookView.prototype._setHintsProps = function(bIsHinting, bIsSubpixHinting) {
    var manager, hintProps;
    for (var i = 0, length = this.fmgrGraphics.length; i < length; ++i) {
      manager = this.fmgrGraphics[i];
      hintProps = manager.m_oLibrary.tt_hint_props;
      if (!hintProps) {
        continue;
      }

      // Последний без хинтования (только для измерения)
      if (i === length - 1) {
        bIsHinting = bIsSubpixHinting = false;
      }

      if (bIsHinting && bIsSubpixHinting) {
        hintProps.TT_USE_BYTECODE_INTERPRETER = true;
        hintProps.TT_CONFIG_OPTION_SUBPIXEL_HINTING = true;

        manager.LOAD_MODE = 40968;
      } else if (bIsHinting) {
        hintProps.TT_USE_BYTECODE_INTERPRETER = true;
        hintProps.TT_CONFIG_OPTION_SUBPIXEL_HINTING = false;

        manager.LOAD_MODE = 40968;
      } else {
        hintProps.TT_USE_BYTECODE_INTERPRETER = true;
        hintProps.TT_CONFIG_OPTION_SUBPIXEL_HINTING = false;

        manager.LOAD_MODE = 40970;
      }

      manager.ClearFontsRasterCache();
    }
  };

  WorkbookView.prototype._calcMaxDigitWidth = function() {
    // set default worksheet header font for calculations
    this.buffers.main.setFont(this.defaultFont);
    // Измеряем в pt
    this.stringRender.measureString("0123456789", {
      wrapText: false, shrinkToFit: false, isMerged: false, textAlign: /*khaLeft*/"left"
    });

    var ppiX = 96; // Мерить только с 96
    var ptConvToPx = asc_getcvt(1/*pt*/, 0/*px*/, ppiX);

    // Максимальная ширина в Pt
    var maxWidthInPt = this.stringRender.getWidestCharWidth();
    // Переводим в px и приводим к целому (int)
    this.maxDigitWidth = asc_round(maxWidthInPt * ptConvToPx);
    // Проверка для Calibri 11 должно быть this.maxDigitWidth = 7

    if (!this.maxDigitWidth) {
      throw "Error: can't measure text string";
    }

    // Padding рассчитывается исходя из maxDigitWidth (http://social.msdn.microsoft.com/Forums/en-US/9a6a9785-66ad-4b6b-bb9f-74429381bd72/margin-padding-in-cell-excel?forum=os_binaryfile)
    this.defaults.worksheetView.cells.padding = Math.max(asc.ceil(this.maxDigitWidth / 4), 2);
    this.defaults.worksheetView.cells.paddingPlusBorder = 2 * this.defaults.worksheetView.cells.padding + 1;
  };

  /*
   * Export
   * -----------------------------------------------------------------------------
   */
  window["Asc"].WorkbookView = WorkbookView;
})(jQuery, window);