Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 21c532aa07d22069f2d3d0ccdeb3447dce904648 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*******************************************************************************
 * Copyright (c) 2004, 2008 John Krasnay and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     John Krasnay - initial API and implementation
 *     Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325)
 *******************************************************************************/
package org.eclipse.vex.ui.internal.handlers;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.ui.internal.swt.VexWidget;

/**
 * Inserts one or more table rows either above or below the currently selected
 * one(s). If more than one row is selected the same number of new rows will be
 * created.
 *
 * @see AddRowBelowHandler
 * @see AddRowAboveHandler
 */
public abstract class AbstractAddRowHandler extends AbstractVexWidgetHandler {

    @Override
    public void execute(final VexWidget widget) throws ExecutionException {
        widget.doWork(new Runnable() {
            public void run() {
                addRow(widget);
            }
        });
    }

    /**
     * @return {@code true} to add new table row above current row or
     *         {@code false} to add new row below current row
     */
    protected abstract boolean addAbove();

    private void addRow(final VexWidget widget) {
    	final List<RowCells> rowCellsToInsert = new ArrayList<RowCells>();

        VexHandlerUtil.iterateTableCells(widget, new ITableCellCallback() {

            private boolean selectedRow;
            private List<Object> cellsToInsert;

            public void startRow(Object row, int rowIndex) {
                selectedRow =
                	VexHandlerUtil.elementOrRangeIsPartiallySelected(widget,
                			                                         row);

                if (selectedRow) {
                    cellsToInsert = new ArrayList<Object>();
                }
            }

            public void onCell(Object row, Object cell,
                    int rowIndex, int cellIndex) {
                if (selectedRow) {
                    cellsToInsert.add(cell);
                }
            }

            public void endRow(Object row, int rowIndex) {
                if (selectedRow) {
                	rowCellsToInsert.add(new RowCells(row, cellsToInsert));
                }
            }

        });

        // something to do?
        if (rowCellsToInsert.isEmpty()) return;

        // save the caret offset to return inside the first table cell after
        // row has been added
        RowCells firstRow = rowCellsToInsert.get(0);
        int outerOffset = VexHandlerUtil.getOuterRange(firstRow.row).getStart();
        Object firstInner = firstRow.cells.isEmpty()
                            ? firstRow.row
                            : firstRow.cells.get(0);
        int innerOffset = VexHandlerUtil.getInnerRange(firstInner).getStart();
        int insertOffset = addAbove()
            ? VexHandlerUtil.getOuterRange(firstRow.row).getStart()
            : VexHandlerUtil.getOuterRange(rowCellsToInsert.get(rowCellsToInsert.size() - 1).row).getEnd();

        // (innerOffset - outerOffset) represents the final offset of
        // the caret, relative to the insertion point of the new rows
        int finalOffset = insertOffset + (innerOffset - outerOffset);
        widget.moveTo(insertOffset);
        
        for (RowCells rowCells : rowCellsToInsert) {
            if (rowCells.row instanceof Element) {
                widget.insertElement((Element) ((Element) rowCells.row).clone());
            }

            //cells that are to be inserted.
            for (Object cell : rowCells.cells) {
            	if (cell instanceof Element) {
                    widget.insertElement((Element) ((Element) cell).clone());
                    widget.moveBy(+1);
                } else {
                    widget.insertText(" ");
                }
			}

            if (rowCells.row instanceof Element) {
                widget.moveBy(+1);
            }
		}
        
        // move inside first inserted table cell
        widget.moveTo(finalOffset);
    }
    
    /** Represents a row and its cells. */
    private static class RowCells {
    	
    	/** The row. */
    	private final Object row;
    	
    	/** All cell objects that belong to this row.*/
    	private final List<Object> cells;
    	
		private RowCells(Object row, List<Object> cells) {
			this.row = row;
			this.cells = cells;
		}
		
    }
        
}

Back to the top