1
2
3
4
5
6
7
8
9
10
11 package de.jaret.util.ui.table.strategies;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.StringTokenizer;
19
20 import org.eclipse.swt.dnd.Clipboard;
21 import org.eclipse.swt.dnd.TextTransfer;
22 import org.eclipse.swt.dnd.Transfer;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.widgets.Display;
25
26 import de.jaret.util.ui.table.JaretTable;
27 import de.jaret.util.ui.table.model.IJaretTableCell;
28 import de.jaret.util.ui.table.model.IJaretTableSelection;
29
30 /***
31 * Default implementation for cut, copy, paste. See the the description of the methods for details. The implementation
32 * is not yet perfect. It uses "brutal" String conversions. May be it would best to introduce converter services in the
33 * table model (optional) or use methods in renderers or editors for conversion.
34 *
35 * @author Peter Kliem
36 * @version $Id: DefaultCCPStrategy.java 385 2007-04-29 20:31:49Z olk $
37 */
38 public class DefaultCCPStrategy implements ICCPStrategy {
39 /*** Delimiter used when copying. */
40 private static final String COPY_DELIMITER = "\t";
41 /*** Delimiters for separating fields in paste operations. */
42 private static final String PASTE_DELIMITERS = "\t;";
43
44 /*** Clipboard instance. */
45 private Clipboard _clipboard;
46 /*** If set to true header labels will always included in copies. */
47 private boolean _includeHeadersInCopy = false;
48
49 /***
50 * Aquire clipboard.
51 *
52 * @return Clipboard instance
53 */
54 private synchronized Clipboard getClipboard() {
55 if (_clipboard == null) {
56 _clipboard = new Clipboard(Display.getCurrent());
57 }
58 return _clipboard;
59 }
60
61 /***
62 * {@inheritDoc}
63 */
64 public void dispose() {
65 if (_clipboard != null) {
66 _clipboard.dispose();
67 }
68 }
69
70 /***
71 * Do the copy operation using the constant COPY_DELIMITER. Empty lines will be omitted, missing cels will be empty.
72 *
73 * @param table jaret table the operation is invoked on
74 */
75 public void copy(JaretTable table) {
76 cutOrCopy(table, false);
77 }
78
79 /***
80 * Do the cut operation. Basicly a a copy and a empty operation.
81 *
82 * @param table jaret table the operation is invoked on
83 */
84 public void cut(JaretTable table) {
85 cutOrCopy(table, true);
86 }
87
88 /***
89 * Do the actual copy or cut operation.
90 *
91 * @param table table
92 * @param cut if set to true cells we be emptied
93 */
94 protected void cutOrCopy(JaretTable table, boolean cut) {
95 IJaretTableSelection selection = table.getSelectionModel().getSelection();
96 Clipboard cb = getClipboard();
97 if (!selection.isEmpty()) {
98 Set<IJaretTableCell> cells = selection.getAllSelectedCells(table.getTableModel());
99 int minx = -1;
100 int maxx = -1;
101 int miny = -1;
102 int maxy = -1;
103
104 Map<Integer, Map<Integer, IJaretTableCell>> cellMap = new HashMap<Integer, Map<Integer, IJaretTableCell>>();
105 for (IJaretTableCell cell : cells) {
106 Point p = table.getCellDisplayIdx(cell);
107 Map<Integer, IJaretTableCell> lineMap = cellMap.get(p.y);
108 if (lineMap == null) {
109 lineMap = new HashMap<Integer, IJaretTableCell>();
110 cellMap.put(p.y, lineMap);
111 }
112 if (miny == -1 || p.y < miny) {
113 miny = p.y;
114 }
115 if (maxy == -1 || p.y > maxy) {
116 maxy = p.y;
117 }
118 lineMap.put(p.x, cell);
119 if (minx == -1 || p.x < minx) {
120 minx = p.x;
121 }
122 if (maxx == -1 || p.x > maxx) {
123 maxx = p.x;
124 }
125 }
126 StringBuilder buf = new StringBuilder();
127 if (_includeHeadersInCopy) {
128 for (int x = minx; x <= maxx; x++) {
129 String headerLabel = table.getColumn(x).getHeaderLabel();
130 buf.append(headerLabel);
131 buf.append(COPY_DELIMITER);
132 }
133 buf.append("\n");
134 }
135 for (int y = miny; y <= maxy; y++) {
136 Map<Integer, IJaretTableCell> lineMap = cellMap.get(y);
137
138 if (lineMap != null) {
139 for (int x = minx; x <= maxx; x++) {
140 IJaretTableCell cell = lineMap.get(x);
141 String value = null;
142 if (cell != null) {
143 Object val = cell.getColumn().getValue(cell.getRow());
144 value = val != null ? val.toString() : null;
145 if (cut) {
146 emptyCell(cell);
147 }
148 }
149 if (value != null) {
150 buf.append(value);
151 }
152 buf.append(COPY_DELIMITER);
153 }
154 buf.append("\n");
155 }
156 }
157 TextTransfer textTransfer = TextTransfer.getInstance();
158 cb.setContents(new Object[] {buf.toString()}, new Transfer[] {textTransfer});
159 }
160 }
161
162 /***
163 * Empty the given cell. First try null, if an exception is thrown by the modell try the empty string.
164 *
165 * @param cell cell to be emptied
166 */
167 protected void emptyCell(IJaretTableCell cell) {
168 try {
169 cell.getColumn().setValue(cell.getRow(), null);
170 } catch (Exception e) {
171 try {
172 cell.getColumn().setValue(cell.getRow(), "");
173 } catch (Exception ex) {
174
175 }
176 }
177 }
178
179 /***
180 * Paste pastes textual context starting at the focussed cell (does not use the selection by now). Uses TAB and
181 * semicolon as delimiters (Excel uses TAB, semicolon for pasting csv).
182 *
183 * @param table the jaret table
184 */
185 public void paste(JaretTable table) {
186 Clipboard cb = getClipboard();
187
188 TextTransfer textTransfer = TextTransfer.getInstance();
189 Object content = cb.getContents(textTransfer);
190 if (content != null) {
191 if (content instanceof String) {
192 String string = (String) content;
193 List<String> lines = new ArrayList<String>();
194 StringTokenizer tokenizer = new StringTokenizer(string, "\n");
195 while (tokenizer.hasMoreTokens()) {
196 lines.add(tokenizer.nextToken());
197 }
198 Point focus = table.getFocussedCellIdx();
199 if (focus == null) {
200 table.setFocus();
201 focus = table.getFocussedCellIdx();
202 }
203 int lineOff = 0;
204 for (String line : lines) {
205 tokenizer = new StringTokenizer(line, PASTE_DELIMITERS, true);
206 int colOff = 0;
207 String last = null;
208 while (tokenizer.hasMoreTokens()) {
209 String value = tokenizer.nextToken();
210 boolean ignore = false;
211 if (PASTE_DELIMITERS.indexOf(value) != -1) {
212
213 if (last != null && last.equals(value)) {
214 value = "";
215 } else {
216 ignore = true;
217 }
218 }
219 if (!ignore) {
220 try {
221 table.setValue(focus.x + colOff, focus.y + lineOff, value);
222 } catch (Exception e) {
223
224 }
225
226 colOff++;
227 }
228 last = value;
229 }
230 lineOff++;
231 }
232 }
233 }
234 }
235
236 /***
237 * Retrieve the state of header include in the copied content.
238 *
239 * @return the includeHeadersInCopy
240 */
241 public boolean getIncludeHeadersInCopy() {
242 return _includeHeadersInCopy;
243 }
244
245 /***
246 * Set includeHeaders: if set to true in copy and cut context the headline (=col headers) labels will be included.
247 *
248 * @param includeHeadersInCopy the includeHeadersInCopy to set
249 */
250 public void setIncludeHeadersInCopy(boolean includeHeadersInCopy) {
251 _includeHeadersInCopy = includeHeadersInCopy;
252 }
253
254 }