devexpress-richedit
Version:
DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.
500 lines (499 loc) • 23 kB
JavaScript
import { SectionColumnCountHistoryItem, SectionColumnsInfoHistoryItem, SectionEqualWidthColumnsHistoryItem } from '../../model/history/items/section-properties-history-items';
import { ControlOptions } from '../../model/options/control';
import { SectionColumnProperties } from '../../model/section/section-column-properties';
import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed';
import { SectionPropertiesCommandBase } from '../section-properties/section-properties-command-base';
import { SectionPropertiesApplyType } from './dialog-page-setup-command';
import { DialogParametersBase, ShowDialogCommandBase } from './show-dialog-command-base';
export class DialogColumnsCommand extends ShowDialogCommandBase {
isEnabled() {
return super.isEnabled() && ControlOptions.isEnabled(this.control.modelManager.richOptions.control.sections) && this.selection.activeSubDocument.isMain() &&
SectionPropertiesCommandBase.rangePermissionIncludeFullSection(this.control, this.selection.activeSubDocument, this.selection.intervals);
}
createParameters(_options) {
var columnsInfo = new ColumnsInfoUI();
var secProps = this.inputPosition.getMergedSectionPropertiesRaw();
columnsInfo.equalColumnWidth = secProps.equalWidthColumns;
if (secProps.pageWidth != undefined && secProps.marginLeft != undefined && secProps.marginRight != undefined)
columnsInfo.pageWidth = secProps.pageWidth - secProps.marginLeft - secProps.marginRight;
else
columnsInfo.pageWidth = ColumnsInfoUI.minColumnWidth;
var columnCount = secProps.columnCount == undefined ? 0 : secProps.columnCount;
columnsInfo.changeColumnCount(columnCount);
for (var i = 0, info; info = secProps.columnsInfo[i]; i++) {
columnsInfo.columns[i].width = info.width;
columnsInfo.columns[i].spacing = info.space;
}
return new ColumnsDialogParameters().init(columnsInfo, this.control.uiUnitConverter);
}
applyParameters(_state, newParams) {
var interval = this.getInterval(newParams.columnsInfo.applyType);
var modelManipulator = this.modelManipulator;
var columnsInfo = newParams.columnsInfo;
this.history.beginTransaction();
var columns = [];
for (var i = 0, columnInfo; columnInfo = columnsInfo.columns[i]; i++) {
var column = new SectionColumnProperties(columnInfo.width, columnInfo.spacing);
columns.push(column);
}
this.history.addAndRedo(new SectionColumnsInfoHistoryItem(modelManipulator, interval, columns));
this.history.addAndRedo(new SectionColumnCountHistoryItem(modelManipulator, interval, columnsInfo.columnCount));
this.history.addAndRedo(new SectionEqualWidthColumnsHistoryItem(modelManipulator, interval, columnsInfo.equalColumnWidth));
this.history.endTransaction();
return true;
}
getInterval(applyTo) {
if (applyTo == SectionPropertiesApplyType.WholeDocument)
return new FixedInterval(0, this.control.modelManager.model.mainSubDocument.getDocumentEndPosition() - 1);
var selectedSections = this.control.modelManager.model.getSectionsByInterval(this.selection.lastSelectedInterval);
if (applyTo == SectionPropertiesApplyType.SelectedSections) {
var lastSection = selectedSections[selectedSections.length - 1];
return FixedInterval.fromPositions(selectedSections[0].startLogPosition.value, lastSection.startLogPosition.value + lastSection.getLength() - 1);
}
if (applyTo == SectionPropertiesApplyType.ThisPointForward)
return FixedInterval.fromPositions(selectedSections[0].startLogPosition.value, this.control.modelManager.model.mainSubDocument.getDocumentEndPosition());
return new FixedInterval(selectedSections[0].startLogPosition.value, selectedSections[0].getLength() - 1);
}
getDialogName() {
return "Columns";
}
}
export class ColumnsDialogParameters extends DialogParametersBase {
init(columnsInfo, unitConverter) {
this.columnsInfo = columnsInfo;
this.unitConverter = unitConverter;
return this;
}
copyFrom(obj) {
super.copyFrom(obj);
var columnsInfo = new ColumnsInfoUI();
columnsInfo.copyFrom(obj.columnsInfo);
this.columnsInfo = columnsInfo;
this.unitConverter = obj.unitConverter;
}
clone() {
const newInstance = new ColumnsDialogParameters();
newInstance.copyFrom(this);
return newInstance;
}
applyConverter(_converter) {
return this;
}
}
export class ColumnsInfoUI {
constructor() {
this.columns = [];
this.equalColumnWidth = false;
this.applyType = SectionPropertiesApplyType.WholeDocument;
}
getMaxColumnCount() {
return Math.ceil(this.pageWidth / (ColumnsInfoUI.minColumnWidth + ColumnsInfoUI.minSpacingWidth));
}
hasColumnsNull() {
if (this.columnCount > this.columns.length)
return true;
for (var i = 0; i < this.columnCount; i++) {
if (!this.columns[i].width)
return true;
if (!this.columns[i].spacing && this.columns[i].spacing != 0)
return true;
}
return false;
}
hasColumnsInfoUINull() {
if (!this.columnCount)
return true;
return this.hasColumnsNull();
}
changeColumnCount(count) {
if (count < 0)
return;
count = Math.min(count, this.getMaxColumnCount());
var previousCount = this.columns.length;
var hasColumnInfoUINull = this.hasColumnsInfoUINull();
for (var i = this.columns.length; i < count; i++)
this.columns[i] = new ColumnInfoUI(i + 1);
this.columns.splice(count);
this.columnCount = count;
if (hasColumnInfoUINull) {
this.calculateEqualColumnsOnChangeCount();
return;
}
if (!this.equalColumnWidth && previousCount > 0)
this.calculateNotEqualColumnsOnChangeCount(previousCount);
else
this.calculateEqualColumnsOnChangeCount();
}
calculateEqualColumnsOnChangeCount() {
if (this.columns.length <= 0)
return;
var spacingValue;
if (this.columns[0].spacing && this.columns[0].spacing != 0)
spacingValue = this.columns[0].spacing;
else
spacingValue = ColumnsInfoUI.minColumnWidth;
this.calculateUniformColumnsByColumnSpacing(spacingValue);
}
calculateNotEqualColumnsOnChangeCount(previousCount) {
if (this.columns.length <= 0)
return;
if (this.columns.length == 1)
this.columns[0].width = this.pageWidth;
var calculateCount = Math.min(previousCount, this.columns.length);
for (var i = 0; i < calculateCount; i++)
this.columns[i].width = Math.max(ColumnsInfoUI.minColumnWidth, this.columns[i].width * previousCount / this.columns.length);
for (var i = 0; i < calculateCount - 1; i++)
this.columns[i].spacing = Math.max(ColumnsInfoUI.minSpacingWidth, this.columns[i].spacing * (previousCount - 1) / (this.columns.length - 1));
if (calculateCount > 0)
for (var i = calculateCount; i < this.columns.length; i++)
this.columns[i].width = this.columns[calculateCount - 1].width;
if (calculateCount > 1)
for (var i = calculateCount - 1; i < this.columns.length - 1; i++)
this.columns[i].spacing = this.columns[calculateCount - 2].spacing;
this.disableTheLastSpacing();
this.correctColumns();
}
correctColumns() {
if (!this.columnCount || this.columnCount <= 0)
return;
var difference = -this.calculateAvailableSpace();
var calculatorWidth = new ColumnsDistributionWidthPriorityCalculator(this.columns);
var calculatorSpacing = new ColumnsDistributionSpacingPriorityCalculator(this.columns);
var sumWidth = calculatorWidth.calculateTotal(0, this.columns.length - 1);
var sumSpacing = calculatorSpacing.calculateTotal(0, this.columns.length - 1);
var partWidth = sumWidth / (sumWidth + sumSpacing);
var differenceWidth = Math.ceil(difference * partWidth);
var differenceSpacing = difference - differenceWidth;
calculatorWidth.distributeSpace(0, this.columns.length - 1, differenceWidth);
calculatorSpacing.distributeSpace(0, this.columns.length - 2, differenceSpacing);
}
disableTheLastSpacing() {
this.columns[this.columns.length - 1].spacing = 0;
}
recalculateColumnsByWidthAfterIndex(index) {
if (this.hasColumnsInfoUINull())
return;
if (this.equalColumnWidth)
this.calculateColumnWidthForUniformColumns();
else
this.changeColumnsNotEqualByWidthAfterIndex(index);
}
recalculateColumnsBySpacingAfterIndex(index) {
if (this.hasColumnsInfoUINull())
return;
if (this.equalColumnWidth)
this.calculateColumnSpacingForUniformColumns();
else
this.changeColumnsNotEqualBySpacingAfterIndex(index);
}
calculateUniformColumnsCore(columnWidth, columnSpacing, restWidth, restSpacing) {
var calculatorWidth = new ColumnsDistributionWidthPriorityCalculator(this.columns);
var calculatorSpacing = new ColumnsDistributionSpacingPriorityCalculator(this.columns);
calculatorWidth.setAllValues(columnWidth, restWidth);
calculatorSpacing.setAllValues(columnSpacing, restSpacing);
this.disableTheLastSpacing();
}
calculateColumnWidthForUniformColumns() {
var columnWidth = (this.columns[0].width) ? this.columns[0].width : ColumnsInfoUI.minColumnWidth;
this.calculateUniformColumnsByColumnWidth(columnWidth);
}
calculateUniformColumnsByColumnWidth(columnWidth) {
if (!this.columnCount || this.columnCount <= 0)
return;
if (this.columnCount <= 1)
columnWidth = this.pageWidth;
if (columnWidth * this.columnCount > this.pageWidth)
columnWidth = this.pageWidth / this.columnCount;
columnWidth = Math.max(columnWidth, ColumnsInfoUI.minColumnWidth);
var dividend = this.pageWidth - columnWidth * this.columnCount;
var divider = Math.max(1, this.columnCount - 1);
var restSpacing = dividend % divider;
var columnSpacing = dividend / divider;
this.calculateUniformColumnsCore(columnWidth, columnSpacing, 0, restSpacing);
}
calculateColumnSpacingForUniformColumns() {
if (this.hasColumnsInfoUINull())
return;
var columnSpacing = (this.columns[0].spacing) ? this.columns[0].spacing : ColumnsInfoUI.minSpacingWidth;
this.calculateUniformColumnsByColumnSpacing(columnSpacing);
}
calculateUniformColumnsByColumnSpacing(columnSpacing) {
if (!this.columnCount || this.columnCount <= 0)
return;
columnSpacing = Math.max(columnSpacing, ColumnsInfoUI.minSpacingWidth);
if (columnSpacing * (this.columnCount - 1) > this.pageWidth - ColumnsInfoUI.minColumnWidth * this.columnCount)
columnSpacing = Math.ceil((this.pageWidth - ColumnsInfoUI.minColumnWidth * this.columnCount) / (this.columnCount - 1));
if (this.columnCount == 1)
columnSpacing = 0;
var dividend = Math.ceil(this.pageWidth - columnSpacing * (this.columnCount - 1));
var restWidth = Math.ceil(dividend % this.columnCount);
var columnWidth = Math.ceil(dividend / this.columnCount);
this.calculateUniformColumnsCore(columnWidth, columnSpacing, restWidth, 0);
}
calculateAvailableSpace() {
var usedSpace = 0;
for (var i = 0; i < this.columnCount; i++)
usedSpace += ((this.columns[i].width) ? this.columns[i].width : 0) + ((this.columns[i].spacing) ? this.columns[i].spacing : 0);
return this.pageWidth - usedSpace;
}
changeColumnsNotEqualByWidthAfterIndex(index) {
if (!this.columnCount || this.columnCount <= 0 || index >= this.columnCount)
return;
var calculatorWidth = new ColumnsDistributionWidthPriorityCalculator(this.columns);
var calculatorSpacing = new ColumnsDistributionSpacingPriorityCalculator(this.columns);
calculatorWidth.correctValue(index);
var difference = -this.calculateAvailableSpace();
difference = calculatorWidth.distributeSpace(index + 1, this.columnCount - 1, difference);
difference = calculatorWidth.distributeSpace(0, index - 1, difference);
difference = calculatorSpacing.distributeSpace(0, this.columnCount - 2, difference);
this.columns[index].width -= difference;
this.disableTheLastSpacing();
}
changeColumnsNotEqualBySpacingAfterIndex(index) {
if (!this.columnCount || this.columnCount <= 0 || index >= this.columnCount)
return;
var calculatorWidth = new ColumnsDistributionWidthPriorityCalculator(this.columns);
var calculatorSpacing = new ColumnsDistributionSpacingPriorityCalculator(this.columns);
calculatorSpacing.correctValue(index);
var difference = -this.calculateAvailableSpace();
difference = calculatorWidth.distributeSpace(index + 1, this.columnCount - 1, difference);
difference = calculatorWidth.distributeSpace(0, index, difference);
difference = calculatorSpacing.distributeSpace(0, index - 1, difference);
difference = calculatorSpacing.distributeSpace(index + 1, this.columnCount - 2, difference);
this.columns[index].spacing -= difference;
this.disableTheLastSpacing();
}
clone() {
var obj = new ColumnsInfoUI();
obj.copyFrom(this);
return obj;
}
copyFrom(info) {
this.applyType = info.applyType;
this.equalColumnWidth = info.equalColumnWidth;
this.pageWidth = info.pageWidth;
this.changeColumnCount(info.columns.length);
for (var i = 0; i < this.columns.length; i++) {
this.columns[i].width = info.columns[i].width;
this.columns[i].spacing = info.columns[i].spacing;
}
}
}
ColumnsInfoUI.minColumnWidth = 720;
ColumnsInfoUI.minSpacingWidth = 0;
export class ColumnInfoUI {
constructor(num) {
this.num = num;
}
}
export class ColumnsDistributionCalculator {
constructor(columns) {
this.columns = [];
this.columns = columns;
}
calculateTotal(from, to) {
var result = 0;
for (var i = from; i <= to; i++)
result += this.getValue(this.columns[i]);
return result;
}
hasEnoughSpaceForDistribution(from, to, space) {
var total = this.calculateTotal(from, to);
return space < total - this.getMinValue() * (to - from + 1);
}
setMinValues(from, to, space) {
for (var i = from; i <= to; i++) {
space -= this.getValue(this.columns[i]) - this.getMinValue();
this.setValue(this.columns[i], this.getMinValue());
}
return space;
}
correctValue(index) {
if (index >= this.columns.length)
return;
if (this.getValue(this.columns[index]) < this.getMinValue())
this.setValue(this.columns[index], this.getMinValue());
}
distributeRemainder(from, to, remainder) {
var correction = (remainder > 0) ? 1 : -1;
while (remainder != 0) {
for (var i = from; i <= to && (remainder != 0); i++) {
var newValue = this.getValue(this.columns[i]) - correction;
if (newValue > this.getMinValue()) {
this.setValue(this.columns[i], newValue);
remainder -= correction;
}
}
}
return 0;
}
distributeSpaceCore(from, to, space) {
var remainder = Math.round(space % (to - from + 1));
var difference = Math.round(space / (to - from + 1));
for (var i = from; i <= to; i++) {
var newValue = this.getValue(this.columns[i]) - difference;
if (newValue >= this.getMinValue())
this.setValue(this.columns[i], newValue);
else {
this.setValue(this.columns[i], this.getMinValue());
remainder += (this.getMinValue() - newValue);
}
}
this.distributeRemainder(from, to, remainder);
return 0;
}
distributeSpace(from, to, space) {
if (from > to)
return space;
if (this.hasEnoughSpaceForDistribution(from, to, space))
return this.distributeSpaceCore(from, to, space);
else
return this.setMinValues(from, to, space);
}
setAllValues(value, rest) {
var count = this.columns.length;
for (var i = 0; i < count; i++)
this.setValue(this.columns[i], value);
this.distributeSpace(0, count - 1, -rest);
}
getMinValue() { return null; }
getValue(_column) { return null; }
setValue(_column, _value) { }
}
export class ColumnsDistributionWidthPriorityCalculator extends ColumnsDistributionCalculator {
getMinValue() {
return 720;
}
getValue(column) {
return (column.width) ? column.width : 0;
}
setValue(column, value) {
column.width = value;
}
}
export class ColumnsDistributionSpacingPriorityCalculator extends ColumnsDistributionCalculator {
getMinValue() {
return 0;
}
getValue(column) {
return (column.spacing) ? column.spacing : 0;
}
setValue(column, value) {
column.spacing = value;
}
}
export class ColumnsEditorController {
constructor(parameters) {
this.presets = [];
this.columnsInfo = parameters.columnsInfo;
this.unitConverter = parameters.unitConverter;
this.presets.push(new SingleColumnsInfoPreset());
this.presets.push(new TwoColumnsInfoPreset());
this.presets.push(new ThreeColumnsInfoPreset());
this.presets.push(new LeftNarrowColumnsInfoPreset());
this.presets.push(new RightNarrowColumnsInfoPreset());
}
changeColumnCount(count) {
this.columnsInfo.changeColumnCount(count);
}
setEqualColumnWidth(value) {
this.columnsInfo.equalColumnWidth = value;
if (value)
this.columnsInfo.calculateColumnSpacingForUniformColumns();
}
applyPreset(index) {
this.presets[index].applyTo(this.columnsInfo);
}
matchPreset(index) {
return this.presets[index].matchTo(this.columnsInfo);
}
getWidth(index) {
var width = this.columnsInfo.columns[index].width;
return this.unitConverter.twipsToUI(width);
}
getSpacing(index) {
var spacing = this.columnsInfo.columns[index].spacing;
return this.unitConverter.twipsToUI(spacing);
}
setWidth(index, value) {
var width = this.unitConverter.UIToTwips(value);
this.columnsInfo.columns[index].width = width;
this.columnsInfo.recalculateColumnsByWidthAfterIndex(index);
}
setSpacing(index, value) {
var spacing = this.unitConverter.UIToTwips(value);
this.columnsInfo.columns[index].spacing = spacing;
this.columnsInfo.recalculateColumnsBySpacingAfterIndex(index);
}
}
export class ColumnsInfoPreset {
getSpacing() { return 1800; }
matchTo(_columnsInfo) { return false; }
}
export class UniformColumnsInfoPreset extends ColumnsInfoPreset {
getColumnCount() { return null; }
matchTo(columnsInfo) {
if (!columnsInfo.equalColumnWidth)
return false;
if (!columnsInfo.columnCount)
return false;
return columnsInfo.columnCount == this.getColumnCount();
}
applyTo(columnsInfo) {
columnsInfo.equalColumnWidth = true;
if (columnsInfo.columns.length > 0)
columnsInfo.columns[0].spacing = this.getSpacing();
columnsInfo.changeColumnCount(this.getColumnCount());
}
}
export class SingleColumnsInfoPreset extends UniformColumnsInfoPreset {
getColumnCount() { return 1; }
}
export class TwoColumnsInfoPreset extends UniformColumnsInfoPreset {
getColumnCount() { return 2; }
}
export class ThreeColumnsInfoPreset extends UniformColumnsInfoPreset {
getColumnCount() { return 3; }
}
export class TwoNonUniformColumnsInfoPreset extends ColumnsInfoPreset {
getFirstColumnRelativeWidth() { return null; }
matchTo(columnsInfo) {
if (columnsInfo.equalColumnWidth)
return false;
if (columnsInfo.columnCount != 2)
return false;
if (columnsInfo.columns.length != 2)
return false;
if (!columnsInfo.columns[0].width)
return false;
if (!columnsInfo.columns[0].spacing && columnsInfo.columns[1].spacing != 0)
return false;
if (!columnsInfo.columns[1].width)
return false;
if (!columnsInfo.columns[1].spacing && columnsInfo.columns[1].spacing != 0)
return false;
var totalWidth = columnsInfo.pageWidth - this.getSpacing();
if (columnsInfo.columns[0].width != Math.round(totalWidth * this.getFirstColumnRelativeWidth()))
return false;
if (columnsInfo.columns[0].spacing != this.getSpacing())
return false;
if (columnsInfo.columns[1].width != Math.round(totalWidth - columnsInfo.columns[0].width))
return false;
return columnsInfo.columns[1].spacing == 0;
}
applyTo(columnsInfo) {
columnsInfo.equalColumnWidth = false;
columnsInfo.changeColumnCount(2);
var totalWidth = columnsInfo.pageWidth - this.getSpacing();
columnsInfo.columns[0].width = Math.round(totalWidth * this.getFirstColumnRelativeWidth());
columnsInfo.columns[0].spacing = this.getSpacing();
columnsInfo.columns[1].width = Math.round(totalWidth - columnsInfo.columns[0].width);
columnsInfo.columns[1].spacing = 0;
}
}
export class LeftNarrowColumnsInfoPreset extends TwoNonUniformColumnsInfoPreset {
getFirstColumnRelativeWidth() { return 0.292; }
}
export class RightNarrowColumnsInfoPreset extends TwoNonUniformColumnsInfoPreset {
getFirstColumnRelativeWidth() { return 0.708; }
}