|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
SHTMLEditorPane.java | 16.7% | 33.7% | 44% | 29.8% |
|
1 |
/*
|
|
2 |
* SimplyHTML, a word processor based on Java, HTML and CSS
|
|
3 |
* Copyright (C) 2002 Ulrich Hilger
|
|
4 |
*
|
|
5 |
* This program is free software; you can redistribute it and/or
|
|
6 |
* modify it under the terms of the GNU General Public License
|
|
7 |
* as published by the Free Software Foundation; either version 2
|
|
8 |
* of the License, or (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
18 |
*/
|
|
19 |
|
|
20 |
|
|
21 |
import java.awt.*;
|
|
22 |
import javax.swing.SwingUtilities;
|
|
23 |
import javax.swing.JComponent;
|
|
24 |
import javax.swing.ActionMap;
|
|
25 |
import javax.swing.InputMap;
|
|
26 |
import javax.swing.JFrame;
|
|
27 |
import java.awt.Graphics;
|
|
28 |
import java.awt.Graphics2D;
|
|
29 |
import java.awt.RenderingHints;
|
|
30 |
import javax.swing.JEditorPane;
|
|
31 |
import java.awt.Color;
|
|
32 |
import java.awt.Component;
|
|
33 |
import java.awt.Cursor;
|
|
34 |
import java.awt.Dimension;
|
|
35 |
import java.awt.datatransfer.Clipboard;
|
|
36 |
import java.awt.datatransfer.ClipboardOwner;
|
|
37 |
|
|
38 |
import java.awt.datatransfer.DataFlavor;
|
|
39 |
import java.awt.datatransfer.Transferable;
|
|
40 |
|
|
41 |
import java.awt.datatransfer.ClipboardOwner;
|
|
42 |
import javax.swing.text.Document;
|
|
43 |
import javax.swing.text.Caret;
|
|
44 |
import javax.swing.text.*;
|
|
45 |
|
|
46 |
import java.awt.dnd.DnDConstants;
|
|
47 |
import java.awt.dnd.DragGestureEvent;
|
|
48 |
import java.awt.dnd.DragGestureListener;
|
|
49 |
|
|
50 |
import java.awt.dnd.DragSource;
|
|
51 |
import java.awt.dnd.DragSourceDragEvent;
|
|
52 |
import java.awt.dnd.DragSourceDropEvent;
|
|
53 |
import java.awt.dnd.DragSourceEvent;
|
|
54 |
import java.awt.dnd.DragSourceListener;
|
|
55 |
import java.awt.dnd.DropTarget;
|
|
56 |
import java.awt.dnd.DropTargetDragEvent;
|
|
57 |
import java.awt.dnd.DropTargetDropEvent;
|
|
58 |
import java.awt.dnd.DropTargetEvent;
|
|
59 |
import java.awt.dnd.DropTargetListener;
|
|
60 |
import java.awt.event.ActionEvent;
|
|
61 |
import java.awt.event.InputEvent;
|
|
62 |
import java.awt.event.KeyEvent;
|
|
63 |
import java.awt.event.MouseAdapter;
|
|
64 |
import java.awt.event.MouseEvent;
|
|
65 |
import java.awt.image.BufferedImage;
|
|
66 |
import java.io.File;
|
|
67 |
import java.io.FileOutputStream;
|
|
68 |
import java.io.IOException;
|
|
69 |
import java.io.OutputStream;
|
|
70 |
import java.io.StringReader;
|
|
71 |
import java.io.StringWriter;
|
|
72 |
import java.util.Vector;
|
|
73 |
|
|
74 |
import javax.swing.AbstractAction;
|
|
75 |
import javax.swing.ActionMap;
|
|
76 |
import javax.swing.InputMap;
|
|
77 |
import javax.swing.JComponent;
|
|
78 |
import javax.swing.JEditorPane;
|
|
79 |
import javax.swing.JTextPane;
|
|
80 |
import javax.swing.KeyStroke;
|
|
81 |
import javax.swing.text.AttributeSet;
|
|
82 |
import javax.swing.text.BadLocationException;
|
|
83 |
import javax.swing.text.Caret;
|
|
84 |
import javax.swing.text.Element;
|
|
85 |
import javax.swing.text.ElementIterator;
|
|
86 |
|
|
87 |
|
|
88 |
import javax.swing.text.MutableAttributeSet;
|
|
89 |
import javax.swing.text.SimpleAttributeSet;
|
|
90 |
import javax.swing.text.html.CSS;
|
|
91 |
import javax.swing.text.html.HTML;
|
|
92 |
import javax.swing.plaf.basic.BasicTextUI;
|
|
93 |
|
|
94 |
import com.sun.image.codec.jpeg.JPEGCodec;
|
|
95 |
import com.sun.image.codec.jpeg.JPEGImageEncoder;
|
|
96 |
|
|
97 |
import java.awt.print.*;
|
|
98 |
|
|
99 |
|
|
100 |
/**
|
|
101 |
* An editor pane for application SimplyHTML.
|
|
102 |
*
|
|
103 |
* <p>This is extending <code>JEditorPane</code> by cut and paste
|
|
104 |
* and drag and drop for HTML text.
|
|
105 |
* <code>JEditorPane</code> inherits cut and paste from <code>
|
|
106 |
* JTextComponent</code> where handling for plain text is implemented only.
|
|
107 |
* <code>JEditorPane</code> has no additional functionality to add cut
|
|
108 |
* and paste for the various content types it supports
|
|
109 |
* (such as 'text/html').</p>
|
|
110 |
*
|
|
111 |
* <p>In stage 4 support for caret movement inside tables and
|
|
112 |
* table manipulation methods are added.</p>
|
|
113 |
*
|
|
114 |
* <p>In stage 6 support for list manipulation was added.</p>
|
|
115 |
*
|
|
116 |
* @author Ulrich Hilger
|
|
117 |
* @author Light Development
|
|
118 |
* @author <a href="http://www.lightdev.com">http://www.lightdev.com</a>
|
|
119 |
* @author <a href="mailto:info@lightdev.com">info@lightdev.com</a>
|
|
120 |
* @author published under the terms and conditions of the
|
|
121 |
* GNU General Public License,
|
|
122 |
* for details see file gpl.txt in the distribution
|
|
123 |
* package of this software
|
|
124 |
*
|
|
125 |
* @version stage 11, April 27, 2003
|
|
126 |
*
|
|
127 |
* @see com.lightdev.app.shtm.HTMLText
|
|
128 |
* @see com.lightdev.app.shtm.HTMLTextSelection
|
|
129 |
*/
|
|
130 |
|
|
131 |
|
|
132 |
public class SHTMLEditorPane extends JEditorPane implements |
|
133 |
DropTargetListener, DragSourceListener, DragGestureListener, Printable |
|
134 |
|
|
135 |
{ |
|
136 |
|
|
137 |
public int currentPrintJobPages; |
|
138 |
boolean pagesSet = false; |
|
139 |
protected PrintView m_printView;
|
|
140 | 2 |
public int print(Graphics pg, PageFormat pageFormat, |
141 |
int pageIndex) throws PrinterException { |
|
142 | 2 |
pg.translate((int)pageFormat.getImageableX(),
|
143 |
(int)pageFormat.getImageableY());
|
|
144 | 2 |
int wPage = (int)pageFormat.getImageableWidth(); |
145 | 2 |
int hPage = (int)pageFormat.getImageableHeight(); |
146 | 2 |
pg.setClip(0, 0, wPage, hPage); |
147 |
|
|
148 |
// Only do this once per print
|
|
149 | 2 |
if (m_printView == null) { |
150 | 1 |
BasicTextUI btui = (BasicTextUI)this.getUI();
|
151 | 1 |
View root = btui.getRootView(this);
|
152 | 1 |
m_printView = new PrintView(
|
153 |
this.getDocument().getDefaultRootElement(),
|
|
154 |
root, wPage, hPage); |
|
155 |
} |
|
156 |
|
|
157 | 2 |
boolean bContinue = m_printView.paintPage(pg,
|
158 |
hPage, pageIndex); |
|
159 | 2 |
System.gc(); |
160 |
|
|
161 | 2 |
if (bContinue)
|
162 | 1 |
return Printable.PAGE_EXISTS;
|
163 |
else {
|
|
164 | 1 |
m_printView = null;
|
165 | 1 |
return Printable.NO_SUCH_PAGE;
|
166 |
} |
|
167 |
} |
|
168 |
class PrintView extends BoxView |
|
169 |
{ |
|
170 |
protected int m_firstOnPage = 0; |
|
171 |
protected int m_lastOnPage = 0; |
|
172 |
protected int m_pageIndex = 0; |
|
173 |
|
|
174 | 1 |
public PrintView(Element elem, View root, int w, int h) { |
175 | 1 |
super(elem, Y_AXIS);
|
176 | 1 |
setParent(root); |
177 | 1 |
setSize(w, h); |
178 | 1 |
layout(w, h); |
179 |
} |
|
180 |
|
|
181 | 2 |
public boolean paintPage(Graphics g, int hPage, |
182 |
int pageIndex) {
|
|
183 | 2 |
if (pageIndex > m_pageIndex) {
|
184 | 1 |
m_firstOnPage = m_lastOnPage + 1; |
185 | 1 |
if (m_firstOnPage >= getViewCount())
|
186 | 1 |
return false; |
187 | 0 |
m_pageIndex = pageIndex; |
188 |
} |
|
189 | 1 |
int yMin = getOffset(Y_AXIS, m_firstOnPage);
|
190 | 1 |
int yMax = yMin + hPage;
|
191 | 1 |
Rectangle rc = new Rectangle();
|
192 |
|
|
193 | 1 |
for (int k = m_firstOnPage; k < getViewCount(); k++) { |
194 | 2 |
rc.x = getOffset(X_AXIS, k); |
195 | 2 |
rc.y = getOffset(Y_AXIS, k); |
196 | 2 |
rc.width = getSpan(X_AXIS, k); |
197 | 2 |
rc.height = getSpan(Y_AXIS, k); |
198 | 2 |
if (rc.y+rc.height > yMax)
|
199 | 0 |
break;
|
200 | 2 |
m_lastOnPage = k; |
201 | 2 |
rc.y -= yMin; |
202 | 2 |
paintChild(g, rc, k); |
203 |
} |
|
204 | 1 |
return true; |
205 |
} |
|
206 |
} |
|
207 |
|
|
208 |
|
|
209 |
DocumentPane dp; |
|
210 |
|
|
211 |
/**
|
|
212 |
* construct a new <code>SHTMLEditorPane</code>
|
|
213 |
*/
|
|
214 | 158 |
public SHTMLEditorPane(DocumentPane dp) {
|
215 | 158 |
super();
|
216 | 158 |
this.dp = dp;
|
217 | 158 |
setCaretColor(Color.black); |
218 |
|
|
219 |
|
|
220 |
/**
|
|
221 |
* set the cursor by adding
|
|
222 |
* a MouseListener that allows to display a text cursor when the
|
|
223 |
* mouse pointer enters the editor. For some reason
|
|
224 |
* (probably someone knows why and could let me know...) the method
|
|
225 |
* setCursor does not have the same effect.
|
|
226 |
*/
|
|
227 |
|
|
228 | 158 |
addMouseListener( |
229 |
new MouseAdapter() {
|
|
230 | 89 |
public void mouseEntered(MouseEvent e) { |
231 | 89 |
Component gp = getRootPane().getGlassPane(); |
232 | 88 |
gp.setCursor(textCursor); |
233 | 88 |
gp.setVisible(true);
|
234 |
} |
|
235 | 76 |
public void mouseExited(MouseEvent e) { |
236 | 76 |
Component gp = getRootPane().getGlassPane(); |
237 | 76 |
gp.setCursor(defaultCursor); |
238 | 76 |
gp.setVisible(false);
|
239 |
} |
|
240 |
} |
|
241 |
); |
|
242 |
|
|
243 |
/** implement customized caret movement */
|
|
244 | 158 |
adjustKeyBindings(); |
245 |
|
|
246 |
/** init drag and drop */
|
|
247 | 158 |
initDnd(); |
248 |
} |
|
249 |
|
|
250 |
|
|
251 |
|
|
252 |
|
|
253 |
/**
|
|
254 |
* adjust the key bindings of the key map existing for this
|
|
255 |
* editor pane to our needs (i.e. add actions to certain keys
|
|
256 |
* such as tab/shift tab for caret movement inside tables, etc.)
|
|
257 |
*
|
|
258 |
* This method had to be redone for using InputMap / ActionMap
|
|
259 |
* instead of Keymap.
|
|
260 |
*/
|
|
261 | 158 |
private void adjustKeyBindings() { |
262 | 158 |
ActionMap myActionMap = new ActionMap();
|
263 | 158 |
InputMap myInputMap = new InputMap();
|
264 |
|
|
265 | 158 |
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0); |
266 | 158 |
myActionMap.put(FrmMain.nextTableCellAction, new NextTableCellAction(FrmMain.nextTableCellAction));
|
267 | 158 |
myInputMap.put(tab, FrmMain.nextTableCellAction); |
268 |
|
|
269 | 158 |
KeyStroke shiftTab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK); |
270 | 158 |
myActionMap.put(FrmMain.prevTableCellAction, new PrevTableCellAction(FrmMain.prevTableCellAction));
|
271 | 158 |
myInputMap.put(shiftTab,FrmMain.prevTableCellAction); |
272 |
|
|
273 | 158 |
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); |
274 | 158 |
myActionMap.put(newListItemAction, new NewListItemAction());
|
275 | 158 |
myInputMap.put(enter, newListItemAction); |
276 |
|
|
277 | 158 |
myActionMap.setParent(getActionMap()); |
278 | 158 |
myInputMap.setParent(getInputMap()); |
279 | 158 |
setActionMap(myActionMap); |
280 | 158 |
setInputMap(JComponent.WHEN_FOCUSED, myInputMap); |
281 |
|
|
282 |
/*
|
|
283 |
implementation before 1.4.1
|
|
284 |
-------------------------------------
|
|
285 |
|
|
286 |
Keymap map = getKeymap();
|
|
287 |
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
|
|
288 |
map.addActionForKeyStroke(tab, new NextTableCellAction(map.getAction(tab)));
|
|
289 |
KeyStroke shiftTab = KeyStroke.getKeyStroke(
|
|
290 |
KeyEvent.VK_TAB, InputEvent.SHIFT_MASK);
|
|
291 |
map.addActionForKeyStroke(shiftTab,
|
|
292 |
new PrevTableCellAction(map.getAction(shiftTab)));
|
|
293 |
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
|
294 |
map.addActionForKeyStroke(enter,
|
|
295 |
new NewListItemAction(map.getAction(enter)));
|
|
296 |
setKeymap(map);
|
|
297 |
*/
|
|
298 |
} |
|
299 |
|
|
300 |
/* ------- list manipulation start ------------------- */
|
|
301 |
|
|
302 |
/** start of block to remove */
|
|
303 |
private int removeStart; |
|
304 |
|
|
305 |
/** end of block to remove */
|
|
306 |
private int removeEnd; |
|
307 |
|
|
308 |
/**
|
|
309 |
* apply a set of attributes to the list the caret is
|
|
310 |
* currently in (if any)
|
|
311 |
*
|
|
312 |
* @param a the set of attributes to apply
|
|
313 |
*/
|
|
314 | 0 |
public void applyListAttributes(AttributeSet a) { |
315 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
316 | 0 |
Element first = doc.getParagraphElement(getSelectionStart()); |
317 | 0 |
Element list = getListElement(first); |
318 | 0 |
if(list != null) { |
319 | 0 |
if(a.getAttributeCount() > 0) {
|
320 | 0 |
doc.addAttributes(list, a); |
321 |
/**
|
|
322 |
* for some reason above code does not show the changed attributes
|
|
323 |
* of the table, although the element really has them (maybe somebody
|
|
324 |
* could let me know why...). Therefore we update the editor pane
|
|
325 |
* contents comparably rude (any other more elegant alternatives
|
|
326 |
* welcome!)
|
|
327 |
*
|
|
328 |
* --> found out why: the swing package does not render short hand
|
|
329 |
* properties such as MARGIN or PADDING. When
|
|
330 |
* contained in a document inside an AttributeSet
|
|
331 |
* they already have to be split into MARGIN-TOP,
|
|
332 |
* MARGIN-LEFT, etc.
|
|
333 |
* adjusted AttributeComponents accordingly so
|
|
334 |
* we don't need refresh anymore
|
|
335 |
*/
|
|
336 |
//refresh();
|
|
337 |
} |
|
338 |
} |
|
339 |
} |
|
340 |
|
|
341 |
/**
|
|
342 |
* <code>Action</code> to create a new list item.
|
|
343 |
*/
|
|
344 |
public class NewListItemAction extends AbstractAction { |
|
345 |
|
|
346 |
/** action to use when not inside a table */
|
|
347 |
/* removed for changes in J2SE 1.4.1
|
|
348 |
Action alternateAction;
|
|
349 |
*/
|
|
350 |
|
|
351 |
/** construct a <code>NewListItemAction</code> */
|
|
352 | 158 |
public NewListItemAction() {
|
353 |
} |
|
354 |
|
|
355 |
/**
|
|
356 |
* construct a <code>NewListItemAction</code>
|
|
357 |
*
|
|
358 |
* @param altAction the action to use when the caret
|
|
359 |
* is not inside a list
|
|
360 |
*/
|
|
361 |
/* removed for changes in J2SE 1.4.1
|
|
362 |
public NewListItemAction(Action altAction) {
|
|
363 |
alternateAction = altAction;
|
|
364 |
}
|
|
365 |
*/
|
|
366 |
|
|
367 |
/**
|
|
368 |
* create a new list item, when the caret is inside a list
|
|
369 |
*
|
|
370 |
* <p>The new item is created after the item at the caret position</p>
|
|
371 |
*/
|
|
372 | 0 |
public void actionPerformed(ActionEvent ae) { |
373 | 0 |
try {
|
374 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
375 | 0 |
Element elem = doc.getParagraphElement(getSelectionStart()); |
376 |
// if we are in a list, create a new item
|
|
377 | 0 |
if(getListElement(elem) != null) { |
378 | 0 |
String li = HTML.Tag.LI.toString(); |
379 | 0 |
String p = HTML.Tag.P.toString(); |
380 |
// get LI having the caret
|
|
381 | 0 |
while(elem != null && |
382 |
!elem.getName().equalsIgnoreCase(li)) |
|
383 |
{ |
|
384 | 0 |
elem = elem.getParentElement(); |
385 |
} |
|
386 |
// if LI found, append new LI after the found one
|
|
387 | 0 |
if(elem != null) { |
388 | 0 |
StringWriter sw = new StringWriter();
|
389 | 0 |
SHTMLWriter w = new SHTMLWriter(sw);
|
390 | 0 |
w.startTag(li, null);
|
391 | 0 |
w.startTag(p, null);
|
392 | 0 |
w.endTag(p); |
393 | 0 |
w.endTag(li); |
394 | 0 |
doc.insertAfterEnd(elem, sw.getBuffer().toString()); |
395 | 0 |
int newPos = elem.getEndOffset();
|
396 | 0 |
select(newPos, newPos); |
397 |
} |
|
398 |
} |
|
399 |
// we are not in a list, call alternate action
|
|
400 |
else {
|
|
401 | 0 |
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); |
402 | 0 |
Object key = getInputMap().getParent().get(enter); |
403 | 0 |
if(key != null) { |
404 | 0 |
getActionMap().getParent().get(key).actionPerformed(ae); |
405 |
} |
|
406 |
|
|
407 |
/* removed for changes in J2SE 1.4.1
|
|
408 |
if(alternateAction != null) {
|
|
409 |
alternateAction.actionPerformed(ae);
|
|
410 |
}
|
|
411 |
*/
|
|
412 |
} |
|
413 |
} |
|
414 |
catch(Exception e) {
|
|
415 | 0 |
Util.errMsg(null, e.getMessage(), e);
|
416 |
} |
|
417 |
} |
|
418 |
} |
|
419 |
|
|
420 |
/**
|
|
421 |
* toggle list formatting on or off for the currently
|
|
422 |
* selected text portion.
|
|
423 |
*
|
|
424 |
* <p>Switches list display on for the given type, if the selection
|
|
425 |
* contains parts not formatted as list or parts formatted as list
|
|
426 |
* of another type.</p>
|
|
427 |
*
|
|
428 |
* <p>Switches list formatting off, if the selection contains
|
|
429 |
* only parts formatted as list of the given type.</p>
|
|
430 |
*
|
|
431 |
* @param listTag the list tag type to toggle on or off (UL or OL)
|
|
432 |
* @param a the attributes to use for the list to toggle to
|
|
433 |
* @param forceOff indicator for toggle operation. If true, possibly
|
|
434 |
* exisiting list formatting inside the selected parts always is switched
|
|
435 |
* off. If false, the method decides, if list formatting for the parts
|
|
436 |
* inside the selection needs to be switched on or off.
|
|
437 |
*/
|
|
438 | 2 |
public void toggleList(String listTag, AttributeSet a, boolean forceOff) { |
439 | 2 |
try {
|
440 | 2 |
boolean listOn = false; |
441 | 2 |
Element parent; |
442 | 2 |
Element elem; |
443 | 2 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
444 | 2 |
Element first = doc.getParagraphElement(getSelectionStart()); |
445 | 2 |
int oStart = getSelectionStart();
|
446 | 2 |
int oEnd = getSelectionEnd();
|
447 | 2 |
int start = first.getStartOffset();
|
448 | 2 |
int end = doc.getParagraphElement(oEnd).getEndOffset();
|
449 | 2 |
removeStart = start; |
450 | 2 |
removeEnd = end; |
451 | 2 |
Element list = getListElement(first); |
452 | 2 |
if(list == null) { |
453 | 2 |
parent = first.getParentElement(); |
454 |
} |
|
455 |
else {
|
|
456 | 0 |
parent = list.getParentElement(); |
457 |
} |
|
458 | 2 |
StringWriter sw = new StringWriter();
|
459 | 2 |
if(forceOff) {
|
460 | 0 |
listOff(new SHTMLWriter(sw, doc), listTag, parent, start, end, first);
|
461 |
} |
|
462 |
else {
|
|
463 | 2 |
if(switchOn(listTag, parent, start, end)) {
|
464 | 2 |
listOn(new SHTMLWriter(sw, doc), listTag, parent,
|
465 |
start, end, first, a); |
|
466 |
} |
|
467 |
else {
|
|
468 | 0 |
listOff(new SHTMLWriter(sw, doc), listTag, parent,
|
469 |
start, end, first); |
|
470 |
} |
|
471 |
} |
|
472 | 2 |
StringBuffer newHTML = sw.getBuffer(); |
473 | 2 |
if(newHTML.length() > 0) {
|
474 |
//System.out.println("newHTML=\r\n\r\n" + newHTML.toString());
|
|
475 | 2 |
if(parent.getName() != HTML.Tag.TD.toString()) {
|
476 | 2 |
select(removeStart, removeEnd); |
477 | 2 |
replaceSelection("");
|
478 | 2 |
SHTMLEditorKit kit = (SHTMLEditorKit) getEditorKit(); |
479 | 2 |
kit.read(new StringReader(newHTML.toString()),
|
480 |
doc, getCaretPosition()); |
|
481 |
} |
|
482 |
else {
|
|
483 | 0 |
doc.setInnerHTML(parent, newHTML.toString()); |
484 |
} |
|
485 | 2 |
if(oStart == oEnd) {
|
486 | 2 |
setCaretPosition(oStart); |
487 |
} |
|
488 |
else {
|
|
489 | 0 |
select(oStart, oEnd); |
490 |
} |
|
491 | 2 |
requestFocus(); |
492 |
} |
|
493 |
} |
|
494 |
catch(Exception e) {
|
|
495 | 0 |
Util.errMsg(null, e.getMessage(), e);
|
496 |
} |
|
497 |
} |
|
498 |
|
|
499 |
/**
|
|
500 |
* decide to switch on or off list formatting
|
|
501 |
*
|
|
502 |
* @param listTag the tag name to sitch on or off
|
|
503 |
* @param parent the parent element of the selection
|
|
504 |
* @param start the start of the selection
|
|
505 |
* @param end the end of the selection
|
|
506 |
*
|
|
507 |
* @return true, if list formatting is to be switched on, false if not
|
|
508 |
*/
|
|
509 | 2 |
private boolean switchOn(String listTag, Element parent, |
510 |
int start, int end) |
|
511 |
{ |
|
512 | 2 |
boolean listOn = false; |
513 | 2 |
int i = 0;
|
514 | 2 |
int count = parent.getElementCount();
|
515 | 2 |
Element elem = parent.getElement(i); |
516 | 2 |
int eStart;
|
517 | 2 |
int eEnd;
|
518 | 2 |
while(i < count && !listOn) {
|
519 | 2 |
eStart = elem.getStartOffset(); |
520 | 2 |
eEnd = elem.getEndOffset(); |
521 | 2 |
if(!elem.getName().equalsIgnoreCase(listTag)) {
|
522 | 2 |
if(((eStart > start) && (eStart < end)) ||
|
523 |
((eEnd > start) && (eEnd < end)) || |
|
524 |
((start >= eStart) && (end <= eEnd))) |
|
525 |
{ |
|
526 | 2 |
listOn = true;
|
527 |
} |
|
528 |
} |
|
529 | 2 |
i++; |
530 | 2 |
if(i < count) {
|
531 | 0 |
elem = parent.getElement(i); |
532 |
} |
|
533 |
} |
|
534 | 2 |
return listOn;
|
535 |
} |
|
536 |
|
|
537 |
/**
|
|
538 |
* switch OFF list formatting for a given block of elements.
|
|
539 |
*
|
|
540 |
* <p>switches off all list formatting inside the block for the
|
|
541 |
* given tag.</p>
|
|
542 |
*
|
|
543 |
* <p>Splits lists if the selection covers only part of a list.</p>
|
|
544 |
*
|
|
545 |
* @param w the SHTMLWriter to write to
|
|
546 |
* @param tag the list tag to switch list formitting off for (UL or OL)
|
|
547 |
* @param parent the parent element having the list
|
|
548 |
* @param start the start of the selected block
|
|
549 |
* @param end the end of the selected block
|
|
550 |
* @param doc the document containing the list
|
|
551 |
* @param first the first element in the block of elements to turn
|
|
552 |
* list formatting off for
|
|
553 |
*/
|
|
554 | 0 |
private void listOff(SHTMLWriter w, String tag, Element parent, |
555 |
int start, int end, Element first) |
|
556 |
{ |
|
557 | 0 |
int elemIndex;
|
558 | 0 |
int count;
|
559 | 0 |
Element elem; |
560 | 0 |
String elemName; |
561 | 0 |
String listName = null;
|
562 | 0 |
boolean inTag = false; |
563 | 0 |
try {
|
564 | 0 |
removeStart = start; |
565 | 0 |
removeEnd = end; |
566 | 0 |
Element list = getListElement(first); |
567 | 0 |
if(list == null) { |
568 | 0 |
parent = first.getParentElement(); |
569 |
} |
|
570 |
else {
|
|
571 | 0 |
parent = list.getParentElement(); |
572 |
} |
|
573 | 0 |
for(int i = 0; i < parent.getElementCount(); i++) { |
574 | 0 |
elem = parent.getElement(i); |
575 | 0 |
elemName = elem.getName(); |
576 | 0 |
if((elemName.equalsIgnoreCase(HTML.Tag.UL.toString()) ||
|
577 |
elemName.equalsIgnoreCase(HTML.Tag.OL.toString())) && |
|
578 |
(elem.getStartOffset() <= end) && (elem.getEndOffset() >= start)) |
|
579 |
{ |
|
580 | 0 |
list = elem; |
581 | 0 |
listName = elem.getName(); |
582 | 0 |
count = list.getElementCount(); |
583 | 0 |
if(removeStart > elem.getStartOffset()) {
|
584 | 0 |
removeStart = elem.getStartOffset(); |
585 |
} |
|
586 | 0 |
if(removeEnd < elem.getEndOffset()) {
|
587 | 0 |
removeEnd = elem.getEndOffset(); |
588 |
} |
|
589 |
|
|
590 | 0 |
elemIndex = 0; |
591 | 0 |
elem = list.getElement(elemIndex); |
592 | 0 |
while(elemIndex < count && elem.getStartOffset() < start) {
|
593 | 0 |
if(!inTag) {
|
594 | 0 |
inTag = true;
|
595 | 0 |
w.startTag(listName, null);
|
596 |
} |
|
597 | 0 |
w.write(elem); |
598 | 0 |
elemIndex++; |
599 | 0 |
if(elemIndex < count) {
|
600 | 0 |
elem = list.getElement(elemIndex); |
601 |
} |
|
602 |
} |
|
603 | 0 |
if(inTag) {
|
604 | 0 |
inTag = false;
|
605 | 0 |
w.endTag(listName); |
606 |
} |
|
607 |
|
|
608 | 0 |
while(elemIndex < count &&
|
609 |
elem.getStartOffset() >= start && |
|
610 |
elem.getEndOffset() <= end) |
|
611 |
{ |
|
612 | 0 |
w.writeChildElements(elem); |
613 | 0 |
elemIndex++; |
614 | 0 |
if(elemIndex < count) {
|
615 | 0 |
elem = list.getElement(elemIndex); |
616 |
} |
|
617 |
} |
|
618 |
|
|
619 | 0 |
while(elemIndex < count && elem.getEndOffset() > end) {
|
620 | 0 |
if(!inTag) {
|
621 | 0 |
inTag = true;
|
622 | 0 |
w.startTag(listName, null);
|
623 |
} |
|
624 | 0 |
w.write(elem); |
625 | 0 |
elemIndex++; |
626 | 0 |
if(elemIndex < count) {
|
627 | 0 |
elem = list.getElement(elemIndex); |
628 |
} |
|
629 |
} |
|
630 | 0 |
if(elemIndex >= count && inTag) {
|
631 | 0 |
inTag = false;
|
632 | 0 |
w.endTag(listName); |
633 |
} |
|
634 |
} |
|
635 |
} |
|
636 |
} |
|
637 |
catch(Exception e) {
|
|
638 | 0 |
Util.errMsg(null, e.getMessage(), e);
|
639 |
} |
|
640 |
} |
|
641 |
|
|
642 |
/**
|
|
643 |
* switch ON list formatting for a given block of elements.
|
|
644 |
*
|
|
645 |
* <p>Takes care of merging existing lists before, after and inside
|
|
646 |
* respective element block.</p>
|
|
647 |
*
|
|
648 |
* <p>Working but ugly code, optimization welcome!</p>
|
|
649 |
*
|
|
650 |
* @param w the SHTMLWriter to write to
|
|
651 |
* @param tag the list tag to switch the selection to (UL or OL)
|
|
652 |
* @param parent the parent element having the selection
|
|
653 |
* @param start the start of the selected block
|
|
654 |
* @param end the end of the selected block
|
|
655 |
* @param doc the document containing the selection
|
|
656 |
* @param first the first element of the block to switch
|
|
657 |
* list formatting on for
|
|
658 |
*/
|
|
659 | 2 |
private void listOn(SHTMLWriter w, String tag, Element parent, |
660 |
int start, int end, Element first, AttributeSet la) |
|
661 |
{ |
|
662 | 2 |
int k;
|
663 | 2 |
int count;
|
664 | 2 |
Element elem; |
665 | 2 |
String elemName; |
666 | 2 |
String listName = null;
|
667 | 2 |
int eStart;
|
668 | 2 |
int eEnd;
|
669 | 2 |
boolean bStarted = false; |
670 | 2 |
boolean iStarted = false; |
671 | 2 |
boolean aStarted = false; |
672 | 2 |
boolean mergeList = false; |
673 | 2 |
try {
|
674 | 2 |
removeStart = start; |
675 | 2 |
removeEnd = end; |
676 | 2 |
Element list = getListElement(first); |
677 | 2 |
if(list == null) { |
678 | 2 |
parent = first.getParentElement(); |
679 |
} |
|
680 |
else {
|
|
681 | 0 |
parent = list.getParentElement(); |
682 |
} |
|
683 | 2 |
for(int i = 0; i < parent.getElementCount(); i++) { |
684 |
// for every element of the parent
|
|
685 | 2 |
elem = parent.getElement(i); |
686 | 2 |
elemName = elem.getName(); |
687 | 2 |
eStart = elem.getStartOffset(); |
688 | 2 |
eEnd = elem.getEndOffset(); |
689 | 2 |
if(elemName.equalsIgnoreCase(HTML.Tag.UL.toString()) ||
|
690 |
elemName.equalsIgnoreCase(HTML.Tag.OL.toString())) |
|
691 |
{ |
|
692 |
// elem is a list
|
|
693 | 0 |
list = elem; |
694 | 0 |
listName = elem.getName(); |
695 | 0 |
count = list.getElementCount(); |
696 | 0 |
if(eEnd == start && listName.equalsIgnoreCase(tag))
|
697 |
{ |
|
698 |
// a list of the same name directly before the selection
|
|
699 | 0 |
mergeList = true;
|
700 | 0 |
if(removeStart > eStart) {
|
701 | 0 |
removeStart = eStart; |
702 |
} |
|
703 | 0 |
if(!bStarted) {
|
704 | 0 |
bStarted = true;
|
705 | 0 |
w.startTag(listName, list.getAttributes()); |
706 |
} |
|
707 | 0 |
k = 0; |
708 | 0 |
elem = list.getElement(k); |
709 | 0 |
while(k < count) {
|
710 | 0 |
w.write(elem); |
711 | 0 |
k++; |
712 | 0 |
if(k < count) {
|
713 | 0 |
elem = list.getElement(k); |
714 |
} |
|
715 |
} |
|
716 |
} |
|
717 | 0 |
else if(eStart < start && eEnd >= start) { |
718 |
// list starts outside the selection before
|
|
719 | 0 |
if(removeStart > eStart) {
|
720 | 0 |
removeStart = eStart; |
721 |
} |
|
722 | 0 |
if(removeEnd < eEnd) {
|
723 | 0 |
removeEnd = eEnd; |
724 |
} |
|
725 | 0 |
if(!bStarted) {
|
726 | 0 |
bStarted = true;
|
727 | 0 |
w.startTag(listName, list.getAttributes()); |
728 |
} |
|
729 | 0 |
k = 0; |
730 | 0 |
elem = list.getElement(k); |
731 | 0 |
while(k < count && elem.getStartOffset() < start) {
|
732 | 0 |
w.write(elem); |
733 | 0 |
k++; |
734 | 0 |
if(k < count) {
|
735 | 0 |
elem = list.getElement(k); |
736 |
} |
|
737 |
} |
|
738 | 0 |
while(k < count &&
|
739 |
elem.getStartOffset() >= start && |
|
740 |
elem.getEndOffset() <= end) { |
|
741 | 0 |
if(bStarted) {
|
742 | 0 |
bStarted = false;
|
743 | 0 |
if(!listName.equalsIgnoreCase(tag)) {
|
744 | 0 |
w.endTag(listName); |
745 |
} |
|
746 |
} |
|
747 | 0 |
if(!iStarted) {
|
748 | 0 |
iStarted = true;
|
749 | 0 |
if(!listName.equalsIgnoreCase(tag)) {
|
750 | 0 |
w.startTag(tag, la); |
751 |
} |
|
752 |
} |
|
753 | 0 |
w.write(elem); |
754 | 0 |
k++; |
755 | 0 |
if(k < count) {
|
756 | 0 |
elem = list.getElement(k); |
757 |
} |
|
758 |
} |
|
759 | 0 |
while(k < count && elem.getEndOffset() > end) {
|
760 | 0 |
if(iStarted) {
|
761 | 0 |
iStarted = false;
|
762 | 0 |
if(!listName.equalsIgnoreCase(tag)) {
|
763 | 0 |
w.endTag(tag); |
764 |
} |
|
765 |
} |
|
766 | 0 |
if(!aStarted) {
|
767 | 0 |
aStarted = true;
|
768 | 0 |
if(!listName.equalsIgnoreCase(tag)) {
|
769 | 0 |
w.startTag(listName, list.getAttributes()); |
770 |
} |
|
771 |
} |
|
772 | 0 |
w.write(elem); |
773 | 0 |
k++; |
774 | 0 |
if(k < count) {
|
775 | 0 |
elem = list.getElement(k); |
776 |
} |
|
777 |
} |
|
778 |
} |
|
779 | 0 |
else if(eStart >= start && eStart < end) { |
780 |
// list starts inside the selection
|
|
781 | 0 |
if(eEnd > removeEnd) {
|
782 | 0 |
removeEnd = eEnd; |
783 |
} |
|
784 | 0 |
k = 0; |
785 | 0 |
elem = list.getElement(k); |
786 | 0 |
while(k < count &&
|
787 |
elem.getStartOffset() >= start && |
|
788 |
elem.getEndOffset() <= end) { |
|
789 | 0 |
if(bStarted) {
|
790 | 0 |
bStarted = false;
|
791 | 0 |
if((!mergeList) && (!listName.equalsIgnoreCase(tag))) {
|
792 | 0 |
w.endTag(listName); |
793 |
} |
|
794 |
} |
|
795 | 0 |
if(!iStarted) {
|
796 | 0 |
iStarted = true;
|
797 | 0 |
if((!mergeList) && (!listName.equalsIgnoreCase(tag))) {
|
798 | 0 |
w.startTag(tag, la); |
799 |
} |
|
800 |
} |
|
801 | 0 |
w.write(elem); |
802 | 0 |
k++; |
803 | 0 |
if(k < count) {
|
804 | 0 |
elem = list.getElement(k); |
805 |
} |
|
806 |
} |
|
807 | 0 |
while(k < count && elem.getEndOffset() > end) {
|
808 | 0 |
if(iStarted) {
|
809 | 0 |
iStarted = false;
|
810 | 0 |
if(!listName.equalsIgnoreCase(tag)) {
|
811 | 0 |
w.endTag(tag); |
812 |
} |
|
813 |
} |
|
814 | 0 |
if(!aStarted) {
|
815 | 0 |
aStarted = true;
|
816 | 0 |
if(!listName.equalsIgnoreCase(tag)) {
|
817 | 0 |
w.startTag(listName, list.getAttributes()); |
818 |
} |
|
819 |
} |
|
820 | 0 |
w.write(elem); |
821 | 0 |
k++; |
822 | 0 |
if(k < count) {
|
823 | 0 |
elem = list.getElement(k); |
824 |
} |
|
825 |
} |
|
826 |
} |
|
827 | 0 |
else if(eStart == end && listName.equalsIgnoreCase(tag)) { |
828 |
// list with same name directly after selection
|
|
829 | 0 |
if(removeEnd < eEnd) {
|
830 | 0 |
removeEnd = eEnd; |
831 |
} |
|
832 | 0 |
k = 0; |
833 | 0 |
elem = list.getElement(k); |
834 | 0 |
while(k < count) {
|
835 | 0 |
w.write(elem); |
836 | 0 |
k++; |
837 | 0 |
if(k < count) {
|
838 | 0 |
elem = list.getElement(k); |
839 |
} |
|
840 |
} |
|
841 | 0 |
w.endTag(tag); |
842 | 0 |
aStarted = false;
|
843 | 0 |
iStarted = false;
|
844 |
} |
|
845 |
} |
|
846 |
else {
|
|
847 |
// elem is not a list
|
|
848 | 2 |
list = null;
|
849 | 2 |
if(eStart >= start && eEnd <= end) {
|
850 |
// element is inside the selection
|
|
851 | 2 |
if(!iStarted) {
|
852 | 2 |
iStarted = true;
|
853 | 2 |
if(!bStarted) {
|
854 | 2 |
w.startTag(tag, la); |
855 |
} |
|
856 |
else {
|
|
857 | 0 |
if(!tag.equalsIgnoreCase(listName)) {
|
858 | 0 |
w.endTag(listName); |
859 | 0 |
bStarted = false;
|
860 | 0 |
w.startTag(tag, la); |
861 |
} |
|
862 |
} |
|
863 |
} |
|
864 | 2 |
w.startTag(HTML.Tag.LI.toString(), null);
|
865 | 2 |
w.write(elem); |
866 | 2 |
w.endTag(HTML.Tag.LI.toString()); |
867 |
} |
|
868 |
} |
|
869 |
} |
|
870 | 2 |
if(iStarted) {
|
871 | 2 |
iStarted = false;
|
872 | 2 |
if(list == null) { |
873 | 2 |
w.endTag(tag); |
874 |
} |
|
875 |
else {
|
|
876 | 0 |
if(!aStarted) {
|
877 | 0 |
w.endTag(listName); |
878 |
} |
|
879 |
} |
|
880 |
} |
|
881 | 2 |
if(aStarted) {
|
882 | 0 |
aStarted = false;
|
883 | 0 |
w.endTag(listName); |
884 |
} |
|
885 |
} |
|
886 |
catch(Exception e) {
|
|
887 | 0 |
Util.errMsg(null, e.getMessage(), e);
|
888 |
} |
|
889 |
} |
|
890 |
|
|
891 |
/**
|
|
892 |
* get the list element a given element is inside (if any).
|
|
893 |
*
|
|
894 |
* @param elem the element to get the list element for
|
|
895 |
*
|
|
896 |
* @return the list element the given element is inside, or null, if
|
|
897 |
* the given element is not inside a list
|
|
898 |
*/
|
|
899 | 4 |
private Element getListElement(Element elem) {
|
900 | 4 |
Element list = Util.findElementUp(HTML.Tag.UL.toString(), elem); |
901 | 4 |
if(list == null) { |
902 | 4 |
list = Util.findElementUp(HTML.Tag.OL.toString(), elem); |
903 |
} |
|
904 | 4 |
return list;
|
905 |
} |
|
906 |
|
|
907 |
/* ------- list manipulation end ------------------- */
|
|
908 |
|
|
909 |
/* ------- table manipulation start ------------------ */
|
|
910 |
|
|
911 |
/** range indicator for applying attributes to the current cell only */
|
|
912 |
public static final int THIS_CELL = 0; |
|
913 |
|
|
914 |
/** range indicator for applying attributes to cells of the current column only */
|
|
915 |
public static final int THIS_COLUMN = 1; |
|
916 |
|
|
917 |
/** range indicator for applying attributes to cells of the current row only */
|
|
918 |
public static final int THIS_ROW = 2; |
|
919 |
|
|
920 |
/** range indicator for applying attributes to all cells */
|
|
921 |
public static final int ALL_CELLS = 3; |
|
922 |
|
|
923 |
/** default table width */
|
|
924 |
public static final String DEFAULT_TABLE_WIDTH = "80%"; |
|
925 |
|
|
926 |
/** default vertical alignment */
|
|
927 |
public static final String DEFAULT_VERTICAL_ALIGN = "top"; |
|
928 |
|
|
929 |
/**
|
|
930 |
* insert a table
|
|
931 |
*
|
|
932 |
* @param colCount the number of columns the new table shall have
|
|
933 |
*/
|
|
934 | 2 |
public void insertTable(int colCount) { |
935 | 2 |
int start = getSelectionStart();
|
936 | 2 |
StringWriter sw = new StringWriter();
|
937 | 2 |
SHTMLWriter w = new SHTMLWriter(sw);
|
938 |
// some needed constants
|
|
939 | 2 |
String table = HTML.Tag.TABLE.toString(); |
940 | 2 |
String tr = HTML.Tag.TR.toString(); |
941 | 2 |
String td = HTML.Tag.TD.toString(); |
942 | 2 |
String p = HTML.Tag.P.toString(); |
943 |
// the attribute set to use for applying attributes to tags
|
|
944 | 2 |
SimpleAttributeSet set = new SimpleAttributeSet();
|
945 |
// build table attribute
|
|
946 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.WIDTH, DEFAULT_TABLE_WIDTH); |
947 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_STYLE, "solid");
|
948 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_TOP_WIDTH, "0");
|
949 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_RIGHT_WIDTH, "0");
|
950 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_BOTTOM_WIDTH, "0");
|
951 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_LEFT_WIDTH, "0");
|
952 | 2 |
set.addAttribute(HTML.Attribute.BORDER, "0");
|
953 | 2 |
try {
|
954 | 2 |
w.startTag(table, set); |
955 |
// start row tag
|
|
956 | 2 |
w.startTag(tr, null);
|
957 |
// get width of each cell according to column count
|
|
958 | 2 |
String tdWidth = Integer.toString(100 / colCount); |
959 |
// build cell width attribute
|
|
960 | 2 |
Util.styleSheet().addCSSAttribute(set, |
961 |
CSS.Attribute.WIDTH, |
|
962 |
Integer.toString(100 / colCount) + Util.pct); |
|
963 | 2 |
set.addAttribute(HTML.Attribute.VALIGN, DEFAULT_VERTICAL_ALIGN); |
964 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_TOP_WIDTH, "1");
|
965 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_RIGHT_WIDTH, "1");
|
966 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_BOTTOM_WIDTH, "1");
|
967 | 2 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.BORDER_LEFT_WIDTH, "1");
|
968 | 2 |
SimpleAttributeSet pSet = new SimpleAttributeSet();
|
969 | 2 |
Util.styleSheet().addCSSAttribute(pSet, CSS.Attribute.MARGIN_TOP, "1");
|
970 | 2 |
Util.styleSheet().addCSSAttribute(pSet, CSS.Attribute.MARGIN_RIGHT, "1");
|
971 | 2 |
Util.styleSheet().addCSSAttribute(pSet, CSS.Attribute.MARGIN_BOTTOM, "1");
|
972 | 2 |
Util.styleSheet().addCSSAttribute(pSet, CSS.Attribute.MARGIN_LEFT, "1");
|
973 | 2 |
set.removeAttribute(HTML.Attribute.BORDER); |
974 |
// add cells
|
|
975 | 2 |
for(int i=0; i<colCount; i++) { |
976 | 6 |
w.startTag(td, set); |
977 | 6 |
w.startTag(p, pSet); |
978 | 6 |
w.endTag(p); |
979 | 6 |
w.endTag(td); |
980 |
} |
|
981 |
// end row and table tags
|
|
982 | 2 |
w.endTag(tr); |
983 | 2 |
w.endTag(table); |
984 |
// read table html into document
|
|
985 | 2 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
986 | 2 |
Element para = doc.getParagraphElement(getSelectionStart()); |
987 | 2 |
if(para != null) { |
988 | 2 |
doc.insertAfterEnd(para, sw.getBuffer().toString()); |
989 |
} |
|
990 |
} |
|
991 |
catch(Exception ex) {
|
|
992 | 0 |
Util.errMsg(null, ex.getMessage(), ex);
|
993 |
} |
|
994 | 2 |
select(start, start); |
995 |
} |
|
996 |
|
|
997 |
/**
|
|
998 |
* apply a new anchor to the currently selected text
|
|
999 |
*
|
|
1000 |
* <p>If nothing is selected, this method does nothing</p>
|
|
1001 |
*
|
|
1002 |
* @param anchorName the name of the new anchor
|
|
1003 |
*/
|
|
1004 | 1 |
public void insertAnchor(String anchorName) { |
1005 | 1 |
if(getSelectionStart() != getSelectionEnd()) {
|
1006 | 1 |
String a = HTML.Tag.A.toString(); |
1007 | 1 |
String selectedText = getSelectedText(); |
1008 | 1 |
SimpleAttributeSet aSet = new SimpleAttributeSet();
|
1009 | 1 |
aSet.addAttribute(HTML.Attribute.NAME, anchorName); |
1010 | 1 |
SimpleAttributeSet set = new SimpleAttributeSet();
|
1011 | 1 |
set.addAttribute(HTML.Tag.A, aSet); |
1012 | 1 |
applyAttributes(set, false);
|
1013 |
} |
|
1014 |
} |
|
1015 |
|
|
1016 |
/**
|
|
1017 |
* insert a line break (i.e. a break for which paragraph
|
|
1018 |
* spacing is not applied)
|
|
1019 |
*/
|
|
1020 | 2 |
public void insertBreak() { |
1021 | 2 |
int caretPos = getCaretPosition();
|
1022 | 2 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1023 | 2 |
try {
|
1024 | 2 |
((SHTMLEditorKit) getEditorKit()).insertHTML( |
1025 |
doc, caretPos, "<BR>", 0, 0, HTML.Tag.BR);
|
|
1026 |
} |
|
1027 |
catch(Exception e) {}
|
|
1028 | 2 |
setCaretPosition(caretPos + 1); |
1029 |
} |
|
1030 |
|
|
1031 |
/**
|
|
1032 |
* set a text link at the current selection replacing the selection
|
|
1033 |
* with a given text.
|
|
1034 |
*
|
|
1035 |
* <p>If nothing is selected, but the caret is inside a link, this will
|
|
1036 |
* replace the existing link. If nothing is selected and the caret
|
|
1037 |
* is not inside a link, this method does nothing.</p>
|
|
1038 |
*
|
|
1039 |
* @param linkText the text that shall appear as link at the current selection
|
|
1040 |
* @param href the target this link shall refer to
|
|
1041 |
* @param className the style class to be used
|
|
1042 |
*/
|
|
1043 | 0 |
public void setLink(String linkText, String href, String className) { |
1044 | 0 |
setLink(linkText, href, className, null, null); |
1045 |
} |
|
1046 |
|
|
1047 |
/**
|
|
1048 |
* set a link at the current selection replacing the selection
|
|
1049 |
* with the given text or image.
|
|
1050 |
*
|
|
1051 |
* @param linkText the text to show as link (or null, if an image shall appear instead)
|
|
1052 |
* @param href the link reference
|
|
1053 |
* @param className the style name to be used for the link
|
|
1054 |
* @param linkImage the file name of the image be used for the link (or null, if a text link is to be set instead)
|
|
1055 |
* @param size the size of the image or null
|
|
1056 |
*/
|
|
1057 | 1 |
public void setLink(String linkText, String href, String className, String linkImage, Dimension size) { |
1058 | 1 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1059 | 1 |
Element e = Util.findLinkElementUp(doc.getCharacterElement(getSelectionStart())); |
1060 | 1 |
if(linkImage == null) { |
1061 | 1 |
setTextLink(e, href, className, linkText, doc); |
1062 |
} |
|
1063 |
else {
|
|
1064 | 0 |
setImageLink(doc, e, href, className, linkImage, size); |
1065 |
} |
|
1066 |
} |
|
1067 |
|
|
1068 |
/**
|
|
1069 |
* set an image link replacing the current selection
|
|
1070 |
*
|
|
1071 |
* @param doc the document to apply the link to
|
|
1072 |
* @param e the link element found at the selection, or null if none was found
|
|
1073 |
* @param href the link reference
|
|
1074 |
* @param className the style name to be used for the link
|
|
1075 |
* @param linkImage the file name of the image be used for the link
|
|
1076 |
* @param size the size of the image
|
|
1077 |
*/
|
|
1078 | 0 |
private void setImageLink(SHTMLDocument doc, Element e, String href, String className, String linkImage, Dimension size) { |
1079 | 0 |
String a = HTML.Tag.A.toString(); |
1080 | 0 |
SimpleAttributeSet set = new SimpleAttributeSet();
|
1081 | 0 |
set.addAttribute(HTML.Attribute.HREF, href); |
1082 | 0 |
set.addAttribute(HTML.Attribute.CLASS, className); |
1083 | 0 |
StringWriter sw = new StringWriter();
|
1084 | 0 |
SHTMLWriter w = new SHTMLWriter(sw);
|
1085 | 0 |
try {
|
1086 | 0 |
w.startTag(a, set); |
1087 | 0 |
set = new SimpleAttributeSet();
|
1088 | 0 |
set.addAttribute(HTML.Attribute.SRC, |
1089 |
Util.getRelativePath(new File(doc.getBase().getFile()), new File(linkImage))); |
|
1090 | 0 |
set.addAttribute(HTML.Attribute.BORDER, "0");
|
1091 | 0 |
if(size != null) { |
1092 | 0 |
set.addAttribute(HTML.Attribute.WIDTH, Integer.toString(new Double(size.getWidth()).intValue()));
|
1093 | 0 |
set.addAttribute(HTML.Attribute.HEIGHT, Integer.toString(new Double(size.getHeight()).intValue()));
|
1094 |
} |
|
1095 | 0 |
w.startTag(HTML.Tag.IMG.toString(), set); |
1096 | 0 |
w.endTag(a); |
1097 | 0 |
if(e != null) { |
1098 | 0 |
System.out.println("SHTMLEditorPane.setImageLink setOuterHTML html='" + sw.getBuffer() + "'"); |
1099 | 0 |
doc.setOuterHTML(e, sw.getBuffer().toString()); |
1100 |
} |
|
1101 |
else {
|
|
1102 | 0 |
int start = getSelectionStart();
|
1103 | 0 |
if(start < getSelectionEnd()) {
|
1104 | 0 |
replaceSelection("");
|
1105 | 0 |
System.out.println("SHTMLEditorPane.setImageLink insertAfterEnd html='" + sw.getBuffer() + "'"); |
1106 | 0 |
doc.insertAfterEnd(doc.getCharacterElement(start), sw.getBuffer().toString()); |
1107 |
} |
|
1108 |
} |
|
1109 |
} |
|
1110 |
catch(Exception ex) {
|
|
1111 | 0 |
Util.errMsg(this, ex.getMessage(), ex);
|
1112 |
} |
|
1113 |
} |
|
1114 |
|
|
1115 |
/**
|
|
1116 |
* set a text link replacing the current selection
|
|
1117 |
*
|
|
1118 |
* @param e the link element found at the selection, or null if none was found
|
|
1119 |
* @param href the link reference
|
|
1120 |
* @param className the style name to be used for the link
|
|
1121 |
* @param linkText the text to show as link
|
|
1122 |
* @param doc the document to apply the link to
|
|
1123 |
*/
|
|
1124 | 1 |
private void setTextLink(Element e, String href, String className, String linkText, SHTMLDocument doc) { |
1125 | 1 |
SimpleAttributeSet aSet = new SimpleAttributeSet();
|
1126 | 1 |
aSet.addAttribute(HTML.Attribute.HREF, href); |
1127 | 1 |
String sStyleName = FrmMain.dynRes.getResourceString(FrmMain.resources, "standardStyleName");
|
1128 | 1 |
if(className != null && !className.equalsIgnoreCase(sStyleName)) { |
1129 | 0 |
aSet.addAttribute(HTML.Attribute.CLASS, className); |
1130 |
} |
|
1131 | 1 |
SimpleAttributeSet set = new SimpleAttributeSet();
|
1132 | 1 |
if(e != null) { |
1133 |
// replace existing link
|
|
1134 | 0 |
set.addAttributes(e.getAttributes()); |
1135 | 0 |
set.addAttribute(HTML.Tag.A, aSet); |
1136 | 0 |
int start = e.getStartOffset();
|
1137 | 0 |
try {
|
1138 | 0 |
doc.replace(start, e.getEndOffset() - start, linkText, set); |
1139 |
} |
|
1140 |
catch(BadLocationException ex) {
|
|
1141 | 0 |
Util.errMsg(this, ex.getMessage(), ex);
|
1142 |
} |
|
1143 |
} |
|
1144 |
else {
|
|
1145 |
// create new link for text selection
|
|
1146 | 1 |
int start = getSelectionStart();
|
1147 | 1 |
if(start < getSelectionEnd()) {
|
1148 | 1 |
set.addAttribute(HTML.Tag.A, aSet); |
1149 | 1 |
replaceSelection(linkText); |
1150 | 1 |
doc.setCharacterAttributes(start, linkText.length(), set, false);
|
1151 |
} |
|
1152 |
} |
|
1153 |
} |
|
1154 |
|
|
1155 |
/**
|
|
1156 |
* remove an anchor with a given name
|
|
1157 |
*
|
|
1158 |
* @param anchorName the name of the anchor to remove
|
|
1159 |
*/
|
|
1160 | 0 |
public void removeAnchor(String anchorName) { |
1161 |
//System.out.println("SHTMLEditorPane removeAnchor");
|
|
1162 | 0 |
String aTag = HTML.Tag.A.toString(); |
1163 | 0 |
AttributeSet attrs; |
1164 | 0 |
Object nameAttr; |
1165 | 0 |
Object link; |
1166 | 0 |
ElementIterator eli = new ElementIterator(getDocument());
|
1167 | 0 |
Element elem = eli.first(); |
1168 | 0 |
while(elem != null) { |
1169 | 0 |
attrs = elem.getAttributes(); |
1170 | 0 |
link = attrs.getAttribute(HTML.Tag.A); |
1171 | 0 |
if(link != null /*&& link.toString().equalsIgnoreCase(HTML.Tag.A.toString())*/) { |
1172 |
//System.out.println("found anchor attribute");
|
|
1173 | 0 |
nameAttr = ((AttributeSet) link).getAttribute(HTML.Attribute.NAME); |
1174 | 0 |
if(nameAttr != null && nameAttr.toString().equalsIgnoreCase(anchorName)) { |
1175 |
// remove anchor here
|
|
1176 |
//System.out.println("removing anchor name=" + nameAttr);
|
|
1177 | 0 |
SimpleAttributeSet newSet = new SimpleAttributeSet(attrs);
|
1178 | 0 |
newSet.removeAttribute(HTML.Tag.A); |
1179 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1180 | 0 |
int start = elem.getStartOffset();
|
1181 | 0 |
doc.setCharacterAttributes(elem.getStartOffset(), elem.getEndOffset() - start, newSet, true);
|
1182 |
} |
|
1183 |
} |
|
1184 | 0 |
elem = eli.next(); |
1185 |
} |
|
1186 |
} |
|
1187 |
|
|
1188 |
/**
|
|
1189 |
* insert a table column before the current column
|
|
1190 |
* (if any)
|
|
1191 |
*/
|
|
1192 | 1 |
public void insertTableColumn() { |
1193 | 1 |
Element cell = getCurTableCell(); |
1194 | 1 |
if(cell != null) { |
1195 | 1 |
createTableColumn(cell, Util.getElementIndex(cell)/*getColNumber(cell)*/, true); |
1196 |
} |
|
1197 |
} |
|
1198 |
|
|
1199 |
/**
|
|
1200 |
* append a table column after the last column
|
|
1201 |
* (if any)
|
|
1202 |
*/
|
|
1203 | 0 |
public void appendTableColumn() { |
1204 | 0 |
Element cell = getCurTableCell(); |
1205 | 0 |
if(cell != null) { |
1206 | 0 |
Element lastCell = getLastTableCell(cell); |
1207 | 0 |
createTableColumn(lastCell, Util.getElementIndex(cell)/*getColNumber(lastCell)*/, false); |
1208 |
} |
|
1209 |
} |
|
1210 |
|
|
1211 |
/**
|
|
1212 |
* create a table column before or after a given column
|
|
1213 |
*
|
|
1214 |
* the width of the first cell in the column
|
|
1215 |
* (if there is a width attribute) is split into
|
|
1216 |
* half so that the new column and the column
|
|
1217 |
* inserted before are sharing the space originally
|
|
1218 |
* taken by the column inserted before.
|
|
1219 |
*
|
|
1220 |
* @param cell the cell to copy from
|
|
1221 |
* @param cIndex the number of the column 'cell' is in
|
|
1222 |
* @param before true indicates insert before, false append after
|
|
1223 |
*/
|
|
1224 | 1 |
private void createTableColumn(Element cell, int cIndex, boolean before) { |
1225 |
|
|
1226 |
// get the new width setting for this column and the new column
|
|
1227 | 1 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1228 | 1 |
Element table = cell.getParentElement().getParentElement(); |
1229 | 1 |
Element srcCell = table.getElement(0).getElement(cIndex); |
1230 | 1 |
SimpleAttributeSet set = new SimpleAttributeSet(srcCell.getAttributes());
|
1231 | 1 |
Object attr = set.getAttribute(CSS.Attribute.WIDTH); |
1232 | 1 |
if(attr != null) { |
1233 |
//LengthValue lv = new LengthValue(attr);
|
|
1234 |
//String unit = lv.getUnit();
|
|
1235 |
//int width = (int) lv.getAttrValue(attr.toString(), unit);
|
|
1236 | 1 |
int width = (int) Util.getAbsoluteAttrVal(attr); // Util.getAttrValue(attr); |
1237 |
//System.out.println("SHTMLEditorPane.createTableColumn width=" + width);
|
|
1238 | 1 |
String unit = Util.getLastAttrUnit(); |
1239 |
//System.out.println("SHTMLEditorPane.createTableColumn unit=" + unit);
|
|
1240 | 1 |
String widthString = Integer.toString(width / 2) + unit; |
1241 |
//System.out.println("SHTMLEditorPane.createTableColumn widthString=" + widthString);
|
|
1242 | 1 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.WIDTH, |
1243 |
widthString); |
|
1244 |
} |
|
1245 |
|
|
1246 |
// adjust width and insert new column
|
|
1247 |
//SimpleAttributeSet a = new SimpleAttributeSet(set.copyAttributes());
|
|
1248 |
//int cellIndex = getCellIndex(srcCell);
|
|
1249 |
//boolean insertFirst = (before && (cellIndex == 0));
|
|
1250 | 1 |
for(int rIndex = 0; rIndex < table.getElementCount(); rIndex++) { |
1251 | 2 |
srcCell = table.getElement(rIndex).getElement(cIndex); |
1252 |
/*
|
|
1253 |
if(rIndex > 0) {
|
|
1254 |
adjustBorder(a, a, a, CombinedAttribute.ATTR_TOP);
|
|
1255 |
}
|
|
1256 |
adjustBorder(a, a, a, CombinedAttribute.ATTR_LEFT);
|
|
1257 |
*/
|
|
1258 | 2 |
doc.addAttributes(srcCell, set); |
1259 | 2 |
try {
|
1260 | 2 |
if(before) {
|
1261 | 2 |
doc.insertBeforeStart(srcCell, getTableCellHTML(srcCell)); |
1262 |
} |
|
1263 |
else {
|
|
1264 | 0 |
doc.insertAfterEnd(srcCell, getTableCellHTML(srcCell)); |
1265 |
} |
|
1266 |
} |
|
1267 |
catch(IOException ioe) {
|
|
1268 | 0 |
Util.errMsg(null, ioe.getMessage(), ioe);
|
1269 |
} |
|
1270 |
catch(BadLocationException ble) {
|
|
1271 | 0 |
Util.errMsg(null, ble.getMessage(), ble);
|
1272 |
} |
|
1273 |
} |
|
1274 |
//adjustColumnBorders(table.getElement(0).getElement(cIndex));
|
|
1275 |
//adjustColumnBorders(table.getElement(0).getElement(++cIndex));
|
|
1276 |
} |
|
1277 |
|
|
1278 |
/**
|
|
1279 |
* append a row to a table assuming the caret currently
|
|
1280 |
* is inside a table
|
|
1281 |
*/
|
|
1282 | 0 |
public void appendTableRow() { |
1283 | 0 |
Element cell = getCurTableCell(); |
1284 | 0 |
if(cell != null) { |
1285 | 0 |
Element table = cell.getParentElement().getParentElement(); |
1286 | 0 |
Element lastRow = table.getElement(table.getElementCount()-1); |
1287 | 0 |
createTableRow(lastRow, Util.getRowIndex(lastRow.getElement(0)), false);
|
1288 |
} |
|
1289 |
} |
|
1290 |
|
|
1291 |
/**
|
|
1292 |
* insert a row to a table assuming the caret currently
|
|
1293 |
* is inside a table
|
|
1294 |
*/
|
|
1295 | 1 |
public void insertTableRow() { |
1296 | 1 |
Element cell = getCurTableCell(); |
1297 | 1 |
if(cell != null) { |
1298 | 1 |
createTableRow(cell.getParentElement(), Util.getRowIndex(cell), true);
|
1299 |
} |
|
1300 |
} |
|
1301 |
|
|
1302 |
/**
|
|
1303 |
* create a new table row by either inserting it before a
|
|
1304 |
* given row or appending it after a given row
|
|
1305 |
*
|
|
1306 |
* this method is shared by appendRow and insertRow
|
|
1307 |
*
|
|
1308 |
* @param srcRow the row element to copy from
|
|
1309 |
* @param before true indicates insert before, false append after
|
|
1310 |
*/
|
|
1311 | 1 |
private void createTableRow(Element srcRow, int rowIndex, boolean before) { |
1312 | 1 |
try {
|
1313 | 1 |
if(before) {
|
1314 | 1 |
((SHTMLDocument) getDocument()).insertBeforeStart(srcRow, |
1315 |
getTableRowHTML(srcRow)); |
|
1316 | 1 |
if(rowIndex == 0) {
|
1317 | 1 |
rowIndex++; |
1318 |
} |
|
1319 |
} |
|
1320 |
else {
|
|
1321 | 0 |
((SHTMLDocument) getDocument()).insertAfterEnd(srcRow, |
1322 |
getTableRowHTML(srcRow)); |
|
1323 | 0 |
rowIndex++; |
1324 |
} |
|
1325 |
} |
|
1326 |
catch(IOException ioe) {
|
|
1327 | 0 |
Util.errMsg(null, ioe.getMessage(), ioe);
|
1328 |
} |
|
1329 |
catch(BadLocationException ble) {
|
|
1330 | 0 |
Util.errMsg(null, ble.getMessage(), ble);
|
1331 |
} |
|
1332 |
} |
|
1333 |
|
|
1334 |
/**
|
|
1335 |
* build an HTML string copying from an existing table row.
|
|
1336 |
*
|
|
1337 |
* For each table column found in srcRow a start and end
|
|
1338 |
* tag TD is created with the same attributes as in the
|
|
1339 |
* column found in srcRow. The attributes of srcRow
|
|
1340 |
* are applied to the newly created row HTML string as well.
|
|
1341 |
*
|
|
1342 |
* @param srcRow the table row Element to copy from
|
|
1343 |
* @param insert indicates if a row is inserted before another row
|
|
1344 |
*
|
|
1345 |
* @return an HTML string representing the new table row
|
|
1346 |
* (without cell contents)
|
|
1347 |
*/
|
|
1348 | 1 |
public String getTableRowHTML(Element srcRow) {
|
1349 | 1 |
String tr = HTML.Tag.TR.toString(); |
1350 | 1 |
String td = HTML.Tag.TD.toString(); |
1351 | 1 |
String p = HTML.Tag.P.toString(); |
1352 | 1 |
StringWriter sw = new StringWriter();
|
1353 | 1 |
SHTMLWriter w = new SHTMLWriter(sw);
|
1354 | 1 |
try {
|
1355 | 1 |
w.startTag(tr, srcRow.getAttributes()); |
1356 | 1 |
for(int i = 0; i < srcRow.getElementCount(); i++) { |
1357 | 3 |
w.startTag(td, srcRow.getElement(i).getAttributes()); |
1358 | 3 |
w.startTag(p, srcRow.getElement(i).getElement(0).getAttributes()); |
1359 | 3 |
w.endTag(p); |
1360 | 3 |
w.endTag(td); |
1361 |
} |
|
1362 | 1 |
w.endTag(tr); |
1363 |
} |
|
1364 |
catch(IOException ex) {
|
|
1365 | 0 |
Util.errMsg(null, ex.getMessage(), ex);
|
1366 |
} |
|
1367 | 1 |
return sw.getBuffer().toString();
|
1368 |
} |
|
1369 |
|
|
1370 |
/**
|
|
1371 |
* build an HTML string copying from an existing table cell
|
|
1372 |
*
|
|
1373 |
* @param srcCell the cell to get the HTML for
|
|
1374 |
* @param a set of attributes to copy if we are inserting first table column
|
|
1375 |
* @param insertFirst indicates if we are inserting first table column
|
|
1376 |
* @param rNum number of row a cell is to be inserted to
|
|
1377 |
* (can be any value if insertFirst is false)
|
|
1378 |
*
|
|
1379 |
* @return the HTML string for the given cell (without cell contents)
|
|
1380 |
*/
|
|
1381 | 2 |
public String getTableCellHTML(Element srcCell)
|
1382 |
{ |
|
1383 | 2 |
StringWriter sw = new StringWriter();
|
1384 | 2 |
SHTMLWriter w = new SHTMLWriter(sw);
|
1385 | 2 |
String td = HTML.Tag.TD.toString(); |
1386 | 2 |
String p = HTML.Tag.P.toString(); |
1387 | 2 |
try {
|
1388 | 2 |
w.startTag(td, srcCell.getAttributes()); |
1389 | 2 |
w.startTag(p, null);
|
1390 | 2 |
w.endTag(p); |
1391 | 2 |
w.endTag(td); |
1392 |
} |
|
1393 |
catch(IOException e) {
|
|
1394 | 0 |
Util.errMsg(null, e.getMessage(), e);
|
1395 |
} |
|
1396 |
//System.out.println("getTableCellHTML buffer='" + sw.getBuffer().toString() + "'");
|
|
1397 | 2 |
return sw.getBuffer().toString();
|
1398 |
} |
|
1399 |
|
|
1400 |
/**
|
|
1401 |
* delete the row of the table the caret is currently in (if any)
|
|
1402 |
*/
|
|
1403 | 0 |
public void deleteTableRow() { |
1404 | 0 |
Element cell = getCurTableCell(); |
1405 | 0 |
if(cell != null) { |
1406 | 0 |
removeElement(cell.getParentElement()); |
1407 |
} |
|
1408 |
} |
|
1409 |
|
|
1410 |
/**
|
|
1411 |
* delete the column of the table the caret is currently in (if any)
|
|
1412 |
*
|
|
1413 |
* <p>width of adjacent column is adjusted, if there is more than one
|
|
1414 |
* column in the table. Width adjustment only works, if width
|
|
1415 |
* attributes of both the column to remove and its adjacent column
|
|
1416 |
* have the same unit (pt or %).</p>
|
|
1417 |
*
|
|
1418 |
* <p>If there is only one cell or if the caret is not in a table,
|
|
1419 |
* this method does nothing</p>
|
|
1420 |
*
|
|
1421 |
* <p>Smart border handling automatically sets the left border of a cell
|
|
1422 |
* to zero, if the cell on the left of that cell has a right border and
|
|
1423 |
* both cells have no margin. In that case removing the first column
|
|
1424 |
* will cause all cells of the new first column to have no left border.</p>
|
|
1425 |
*/
|
|
1426 | 0 |
public void deleteTableCol() { |
1427 | 0 |
Element cell = getCurTableCell(); |
1428 | 0 |
if(cell != null) { |
1429 |
|
|
1430 | 0 |
Element row = cell.getParentElement(); |
1431 | 0 |
int lastColIndex = row.getElementCount() - 1;
|
1432 |
|
|
1433 | 0 |
if(lastColIndex > 0) {
|
1434 | 0 |
int cIndex = Util.getElementIndex(cell); //getColNumber(cell); |
1435 | 0 |
int offset = -1; // adjacent cell is left of current cell |
1436 | 0 |
if(cIndex == 0) { // if current cell is in first column... |
1437 | 0 |
offset *= -1; // ...adjacent cell is right of current cell
|
1438 |
} |
|
1439 |
|
|
1440 | 0 |
Object attrC = cell.getAttributes().getAttribute(CSS.Attribute.WIDTH); |
1441 | 0 |
Object attrA = row.getElement(cIndex + offset).getAttributes(). |
1442 |
getAttribute(CSS.Attribute.WIDTH); |
|
1443 | 0 |
SimpleAttributeSet set = null;
|
1444 |
|
|
1445 | 0 |
if(attrC != null && attrA != null) { |
1446 |
//LengthValue lvC = new LengthValue(attrC);
|
|
1447 |
//LengthValue lvA = new LengthValue(attrA);
|
|
1448 | 0 |
int widthC = (int) Util.getAbsoluteAttrVal(attrC); // Util.getAttrValue(attrC); |
1449 | 0 |
String cUnit = Util.getLastAttrUnit(); |
1450 |
//String cUnit = lvC.getUnit();
|
|
1451 | 0 |
int widthA = (int) Util.getAbsoluteAttrVal(attrA); // Util.getAttrValue(attrA); |
1452 | 0 |
String aUnit = Util.getLastAttrUnit(); |
1453 | 0 |
if(aUnit.equalsIgnoreCase(cUnit)) {
|
1454 | 0 |
int width = 0;
|
1455 | 0 |
width += widthC; |
1456 | 0 |
width += widthA; |
1457 | 0 |
if(width > 0)
|
1458 |
{ |
|
1459 | 0 |
String widthString = Integer.toString(width) + cUnit; |
1460 | 0 |
set = new SimpleAttributeSet(
|
1461 |
row.getElement(cIndex + offset).getAttributes()); |
|
1462 | 0 |
Util.styleSheet().addCSSAttribute(set, CSS.Attribute.WIDTH, |
1463 |
widthString); |
|
1464 |
} |
|
1465 |
} |
|
1466 |
} |
|
1467 |
|
|
1468 | 0 |
Element table = row.getParentElement(); |
1469 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1470 |
|
|
1471 | 0 |
if(cIndex < lastColIndex) {
|
1472 | 0 |
offset = 0; |
1473 |
} |
|
1474 |
|
|
1475 | 0 |
for(int rIndex = table.getElementCount() - 1; rIndex >= 0; rIndex--) { |
1476 | 0 |
row = table.getElement(rIndex); |
1477 | 0 |
try {
|
1478 | 0 |
doc.removeElements(row, cIndex, 1); |
1479 |
/*
|
|
1480 |
the following line does not work for the last column in a table
|
|
1481 |
so we use above code instead
|
|
1482 |
|
|
1483 |
removeElement(row.getElement(cIndex));
|
|
1484 |
*/
|
|
1485 |
} |
|
1486 |
catch(BadLocationException ble) {
|
|
1487 | 0 |
Util.errMsg(null, ble.getMessage(), ble);
|
1488 |
} |
|
1489 | 0 |
if(set != null) { |
1490 | 0 |
doc.addAttributes(row.getElement(cIndex + offset), set); |
1491 |
} |
|
1492 |
//adjustColumnBorders(table.getElement(0).getElement(cIndex + offset));
|
|
1493 |
} |
|
1494 |
} |
|
1495 |
} |
|
1496 |
} |
|
1497 |
|
|
1498 |
/**
|
|
1499 |
* remove an element from the document of this editor
|
|
1500 |
* (shared by deleteTableRow and deleteTableCol)
|
|
1501 |
*
|
|
1502 |
* @param e the element to remove
|
|
1503 |
*/
|
|
1504 | 0 |
private void removeElement(Element e) { |
1505 | 0 |
int start = e.getStartOffset();
|
1506 | 0 |
try {
|
1507 | 0 |
((SHTMLDocument) getDocument()).remove(start, e.getEndOffset() - start); |
1508 |
} |
|
1509 |
catch(BadLocationException ble) {
|
|
1510 | 0 |
Util.errMsg(null, ble.getMessage(), ble);
|
1511 |
} |
|
1512 |
|
|
1513 |
} |
|
1514 |
|
|
1515 |
/**
|
|
1516 |
* apply a set of attributes to the table the caret is
|
|
1517 |
* currently in (if any)
|
|
1518 |
*
|
|
1519 |
* @param a the set of attributes to apply
|
|
1520 |
*/
|
|
1521 | 2 |
public void applyTableAttributes(AttributeSet a) { |
1522 | 2 |
Element cell = getCurTableCell(); |
1523 | 2 |
if(cell != null) { |
1524 | 2 |
Element table = cell.getParentElement().getParentElement(); |
1525 | 2 |
if(a.getAttributeCount() > 0) {
|
1526 |
//System.out.println("applyTableAttributes count=" + a.getAttributeCount() + " a=" + a);
|
|
1527 | 2 |
((SHTMLDocument) getDocument()).addAttributes(table, a); |
1528 |
/**
|
|
1529 |
* for some reason above code does not show the changed attributes
|
|
1530 |
* of the table, although the element really has them (maybe somebody
|
|
1531 |
* could let me know why...). Therefore we update the editor pane
|
|
1532 |
* contents comparably rude (any other more elegant alternatives
|
|
1533 |
* welcome!)
|
|
1534 |
*
|
|
1535 |
* --> found out why: the swing package does not render short hand
|
|
1536 |
* properties such as MARGIN or PADDING. When
|
|
1537 |
* contained in a document inside an AttributeSet
|
|
1538 |
* they already have to be split into MARGIN-TOP,
|
|
1539 |
* MARGIN-LEFT, etc.
|
|
1540 |
* adjusted AttributeComponents accordingly so
|
|
1541 |
* we don't need refresh anymore
|
|
1542 |
*/
|
|
1543 |
//refresh();
|
|
1544 |
} |
|
1545 |
} |
|
1546 |
} |
|
1547 |
|
|
1548 |
/**
|
|
1549 |
* refresh the whole contents of this editor pane with brute force
|
|
1550 |
*/
|
|
1551 | 0 |
public void refresh() { |
1552 | 0 |
int pos = getCaretPosition();
|
1553 | 0 |
String data = getText(); |
1554 | 0 |
setText("");
|
1555 | 0 |
setText(data); |
1556 | 0 |
setCaretPosition(pos); |
1557 |
} |
|
1558 |
|
|
1559 |
|
|
1560 |
/**
|
|
1561 |
* apply a set of attributes to a given range of cells
|
|
1562 |
* of the table the caret is currently in (if any)
|
|
1563 |
*
|
|
1564 |
* @param a the set of attributes to apply
|
|
1565 |
* @param range the range of cells to apply attributes to
|
|
1566 |
*
|
|
1567 |
* @see adjustColWidths
|
|
1568 |
*/
|
|
1569 | 0 |
public void applyCellAttributes(AttributeSet a, int range) { |
1570 |
//System.out.println("SHTMLEditorPane applyCellAttributes a=" + a);
|
|
1571 | 0 |
Element cell = getCurTableCell(); |
1572 | 0 |
int cIndex = 0;
|
1573 | 0 |
int rIndex = 0;
|
1574 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1575 | 0 |
if(cell != null) { |
1576 | 0 |
Element row = cell.getParentElement(); |
1577 | 0 |
Element table = row.getParentElement(); |
1578 | 0 |
Element aCell; |
1579 | 0 |
switch(range) {
|
1580 | 0 |
case THIS_CELL:
|
1581 | 0 |
doc.addAttributes(cell, a); |
1582 | 0 |
break;
|
1583 | 0 |
case THIS_ROW:
|
1584 | 0 |
for(cIndex = 0; cIndex < row.getElementCount(); cIndex++) {
|
1585 | 0 |
aCell = row.getElement(cIndex); |
1586 | 0 |
doc.addAttributes(aCell, a); |
1587 |
} |
|
1588 | 0 |
break;
|
1589 | 0 |
case THIS_COLUMN:
|
1590 | 0 |
cIndex = Util.getElementIndex(cell); //getColNumber(cell);
|
1591 | 0 |
for(rIndex = 0; rIndex < table.getElementCount(); rIndex++) {
|
1592 | 0 |
aCell = table.getElement(rIndex).getElement(cIndex); |
1593 | 0 |
doc.addAttributes(aCell, a); |
1594 |
} |
|
1595 | 0 |
break;
|
1596 | 0 |
case ALL_CELLS:
|
1597 | 0 |
while(rIndex < table.getElementCount()) {
|
1598 | 0 |
row = table.getElement(rIndex); |
1599 | 0 |
cIndex = 0; |
1600 | 0 |
while(cIndex < row.getElementCount()) {
|
1601 | 0 |
aCell = row.getElement(cIndex); |
1602 |
//System.out.println("applyCellAttributes ALL_CELLS adjusted a=" + adjustCellBorders(aCell, a));
|
|
1603 | 0 |
doc.addAttributes(aCell, a); |
1604 | 0 |
cIndex++; |
1605 |
} |
|
1606 | 0 |
rIndex++; |
1607 |
} |
|
1608 | 0 |
break;
|
1609 |
} |
|
1610 |
} |
|
1611 |
} |
|
1612 |
|
|
1613 |
/**
|
|
1614 |
* get the number of the table column a given cell is in
|
|
1615 |
*
|
|
1616 |
* @param cell the cell to get the column number for
|
|
1617 |
* @return the column number of the given cell
|
|
1618 |
*/
|
|
1619 | 0 |
private int getColNumber(Element cell) { |
1620 | 0 |
int i = 0;
|
1621 | 0 |
Element thisRow = cell.getParentElement(); |
1622 | 0 |
int last = thisRow.getElementCount() - 1;
|
1623 | 0 |
Element aCell = thisRow.getElement(i); |
1624 | 0 |
if(aCell != cell) {
|
1625 | 0 |
while((i < last) && (aCell != cell)) {
|
1626 | 0 |
aCell = thisRow.getElement(++i); |
1627 |
} |
|
1628 |
} |
|
1629 | 0 |
return i;
|
1630 |
} |
|
1631 |
|
|
1632 |
/* ------- table manipulation end -------------------- */
|
|
1633 |
|
|
1634 |
/* ------- table cell navigation start --------------- */
|
|
1635 |
|
|
1636 |
/**
|
|
1637 |
* <code>Action</code> to move the caret from the current table cell
|
|
1638 |
* to the next table cell.
|
|
1639 |
*/
|
|
1640 |
public class NextTableCellAction extends AbstractAction { |
|
1641 |
|
|
1642 |
/** action to use when not inside a table */
|
|
1643 |
/* removed for changes in J2SE 1.4.1
|
|
1644 |
private Action alternateAction;
|
|
1645 |
*/
|
|
1646 |
|
|
1647 |
/** construct a <code>NextTableCellAction</code> */
|
|
1648 | 158 |
public NextTableCellAction(String actionName) {
|
1649 | 158 |
super(actionName);
|
1650 |
} |
|
1651 |
|
|
1652 |
/**
|
|
1653 |
* construct a <code>NextTableCellAction</code>
|
|
1654 |
*
|
|
1655 |
* @param altAction the action to use when the caret
|
|
1656 |
* is not inside a table
|
|
1657 |
*/
|
|
1658 |
/* removed for changes in J2SE 1.4.1
|
|
1659 |
public NextTableCellAction(Action altAction) {
|
|
1660 |
alternateAction = altAction;
|
|
1661 |
}
|
|
1662 |
*/
|
|
1663 |
|
|
1664 |
/**
|
|
1665 |
* move to the previous cell or invoke an alternate action if the
|
|
1666 |
* caret is not inside a table
|
|
1667 |
*
|
|
1668 |
* this will append a new table row when the caret
|
|
1669 |
* is inside the last table cell
|
|
1670 |
*/
|
|
1671 | 0 |
public void actionPerformed(ActionEvent ae) { |
1672 | 0 |
Element cell = getCurTableCell(); |
1673 | 0 |
if(cell != null) { |
1674 | 0 |
goNextCell(cell); |
1675 |
} |
|
1676 |
else {
|
|
1677 | 0 |
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0); |
1678 | 0 |
Object key = getInputMap().getParent().get(tab); |
1679 | 0 |
if(key != null) { |
1680 | 0 |
getActionMap().getParent().get(key).actionPerformed(ae); |
1681 |
} |
|
1682 |
|
|
1683 |
/* removed for changes in J2SE 1.4.1
|
|
1684 |
if(alternateAction != null) {
|
|
1685 |
alternateAction.actionPerformed(ae);
|
|
1686 |
}
|
|
1687 |
*/
|
|
1688 |
} |
|
1689 |
} |
|
1690 |
|
|
1691 |
} |
|
1692 |
|
|
1693 |
/**
|
|
1694 |
* <code>Action</code> to move the caret from the current table cell
|
|
1695 |
* to the previous table cell.
|
|
1696 |
*/
|
|
1697 |
public class PrevTableCellAction extends AbstractAction { |
|
1698 |
|
|
1699 |
/** action to use when not inside a table */
|
|
1700 |
/* removed for changes in J2SE 1.4.1
|
|
1701 |
private Action alternateAction;
|
|
1702 |
*/
|
|
1703 |
|
|
1704 |
/** construct a <code>PrevTableCellAction</code> */
|
|
1705 | 158 |
public PrevTableCellAction(String actionName) {
|
1706 | 158 |
super(actionName);
|
1707 |
} |
|
1708 |
|
|
1709 |
/**
|
|
1710 |
* construct a <code>PrevTableCellAction</code>
|
|
1711 |
*
|
|
1712 |
* @param altAction the action to use when the caret
|
|
1713 |
* is not inside a table
|
|
1714 |
*/
|
|
1715 |
/* removed for changes in J2SE 1.4.1
|
|
1716 |
public PrevTableCellAction(Action altAction) {
|
|
1717 |
alternateAction = altAction;
|
|
1718 |
}
|
|
1719 |
*/
|
|
1720 |
|
|
1721 |
/**
|
|
1722 |
* move to the previous cell or invoke an alternate action if the
|
|
1723 |
* caret is not inside a table
|
|
1724 |
*/
|
|
1725 | 0 |
public void actionPerformed(ActionEvent ae) { |
1726 | 0 |
Element cell = getCurTableCell(); |
1727 | 0 |
if(cell != null) { |
1728 | 0 |
goPrevCell(cell); |
1729 |
} |
|
1730 |
else {
|
|
1731 | 0 |
KeyStroke shiftTab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK); |
1732 | 0 |
Object key = getInputMap().getParent().get(shiftTab); |
1733 | 0 |
if(key != null) { |
1734 | 0 |
getActionMap().getParent().get(key).actionPerformed(ae); |
1735 |
} |
|
1736 |
|
|
1737 |
/* removed for changes in J2SE 1.4.1
|
|
1738 |
if(alternateAction != null) {
|
|
1739 |
alternateAction.actionPerformed(ae);
|
|
1740 |
}
|
|
1741 |
*/
|
|
1742 |
} |
|
1743 |
} |
|
1744 |
} |
|
1745 |
|
|
1746 | 0 |
public void goNextCell(Element cell) { |
1747 | 0 |
if(cell == getLastTableCell(cell)) {
|
1748 | 0 |
appendTableRow(); |
1749 | 0 |
cell = getCurTableCell(); |
1750 |
} |
|
1751 | 0 |
int pos = getNextCell(cell).getStartOffset();
|
1752 | 0 |
select(pos, pos); |
1753 |
} |
|
1754 |
|
|
1755 | 0 |
public void goPrevCell(Element cell) { |
1756 | 0 |
int newPos;
|
1757 | 0 |
if(cell != getFirstTableCell(cell)) {
|
1758 | 0 |
cell = getPrevCell(cell); |
1759 | 0 |
newPos = cell.getStartOffset(); |
1760 | 0 |
select(newPos, newPos); |
1761 |
} |
|
1762 |
} |
|
1763 |
|
|
1764 |
/**
|
|
1765 |
* get the table cell following a given table cell
|
|
1766 |
*
|
|
1767 |
* @param cell the cell whose following cell shall be found
|
|
1768 |
* @return the Element having the cell following the given cell or null
|
|
1769 |
* if the given cell is the last cell in the table
|
|
1770 |
*/
|
|
1771 | 0 |
private Element getNextCell(Element cell) {
|
1772 | 0 |
Element nextCell = null;
|
1773 | 0 |
Element thisRow = cell.getParentElement(); |
1774 | 0 |
Element nextRow = null;
|
1775 | 0 |
Element table = thisRow.getParentElement(); |
1776 | 0 |
int i = thisRow.getElementCount()-1;
|
1777 | 0 |
Element aCell = thisRow.getElement(i); |
1778 | 0 |
if(aCell != cell) {
|
1779 | 0 |
while((i > 0) && (aCell != cell)) {
|
1780 | 0 |
nextCell = aCell; |
1781 | 0 |
aCell = thisRow.getElement(--i); |
1782 |
} |
|
1783 |
} |
|
1784 |
else {
|
|
1785 | 0 |
i = table.getElementCount()-1; |
1786 | 0 |
Element aRow = table.getElement(i); |
1787 | 0 |
while((i > 0) && (aRow != thisRow)) {
|
1788 | 0 |
nextRow = aRow; |
1789 | 0 |
aRow = table.getElement(--i); |
1790 |
} |
|
1791 | 0 |
nextCell = nextRow.getElement(0); |
1792 |
} |
|
1793 | 0 |
return nextCell;
|
1794 |
} |
|
1795 |
|
|
1796 |
/**
|
|
1797 |
* get the table cell preceding a given table cell
|
|
1798 |
*
|
|
1799 |
* @param cell the cell whose preceding cell shall be found
|
|
1800 |
* @return the Element having the cell preceding the given cell or null
|
|
1801 |
* if the given cell is the first cell in the table
|
|
1802 |
*/
|
|
1803 | 0 |
private Element getPrevCell(Element cell) {
|
1804 | 0 |
Element thisRow = cell.getParentElement(); |
1805 | 0 |
Element table = thisRow.getParentElement(); |
1806 | 0 |
Element prevCell = null;
|
1807 | 0 |
int i = 0;
|
1808 | 0 |
Element aCell = thisRow.getElement(i); |
1809 | 0 |
if(aCell != cell) {
|
1810 | 0 |
while(aCell != cell) {
|
1811 | 0 |
prevCell = aCell; |
1812 | 0 |
aCell = thisRow.getElement(i++); |
1813 |
} |
|
1814 |
} |
|
1815 |
else {
|
|
1816 | 0 |
Element prevRow = null;
|
1817 | 0 |
Element aRow = table.getElement(i); |
1818 | 0 |
while(aRow != thisRow) {
|
1819 | 0 |
prevRow = aRow; |
1820 | 0 |
aRow = table.getElement(i++); |
1821 |
} |
|
1822 | 0 |
prevCell = prevRow.getElement(prevRow.getElementCount()-1); |
1823 |
} |
|
1824 | 0 |
return prevCell;
|
1825 |
} |
|
1826 |
|
|
1827 |
/**
|
|
1828 |
* get the last cell of the table a given table cell belongs to
|
|
1829 |
*
|
|
1830 |
* @param cell a cell of the table to get the last cell of
|
|
1831 |
* @return the Element having the last table cell
|
|
1832 |
*/
|
|
1833 | 0 |
private Element getLastTableCell(Element cell) {
|
1834 | 0 |
Element table = cell.getParentElement().getParentElement(); |
1835 | 0 |
Element lastRow = table.getElement(table.getElementCount()-1); |
1836 | 0 |
Element lastCell = lastRow.getElement(lastRow.getElementCount()-1); |
1837 | 0 |
return lastCell;
|
1838 |
} |
|
1839 |
|
|
1840 |
/**
|
|
1841 |
* get the first cell of the table a given table cell belongs to
|
|
1842 |
*
|
|
1843 |
* @param cell a cell of the table to get the first cell of
|
|
1844 |
* @return the Element having the first table cell
|
|
1845 |
*/
|
|
1846 | 0 |
private Element getFirstTableCell(Element cell) {
|
1847 | 0 |
Element table = cell.getParentElement().getParentElement(); |
1848 | 0 |
Element firstCell = table.getElement(0).getElement(0); |
1849 | 0 |
return firstCell;
|
1850 |
} |
|
1851 |
|
|
1852 |
/**
|
|
1853 |
* get the table cell at the current caret position
|
|
1854 |
*
|
|
1855 |
* @return the Element having the current table cell or null if
|
|
1856 |
* the caret is not inside a table cell
|
|
1857 |
*/
|
|
1858 | 1372 |
public Element getCurTableCell() {
|
1859 | 1372 |
return Util.findElementUp(HTML.Tag.TD.toString(),
|
1860 |
((SHTMLDocument)getDocument()).getCharacterElement(getSelectionStart())); |
|
1861 |
} |
|
1862 |
|
|
1863 |
/* ---------- table cell navigation end --------------*/
|
|
1864 |
|
|
1865 |
/**
|
|
1866 |
* Replaces the currently selected content with new content
|
|
1867 |
* represented by the given <code>HTMLText</code>. If there is no selection
|
|
1868 |
* this amounts to an insert of the given text. If there
|
|
1869 |
* is no replacement text this amounts to a removal of the
|
|
1870 |
* current selection.
|
|
1871 |
*
|
|
1872 |
* @overrides replaceSelection in <code>JEditorPane</code> for usage of
|
|
1873 |
* our own HTMLText object
|
|
1874 |
*
|
|
1875 |
* @param content the content to replace the selection with
|
|
1876 |
*/
|
|
1877 | 0 |
public void replaceSelection(HTMLText content) { |
1878 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
1879 | 0 |
String text; |
1880 | 0 |
Caret caret = getCaret(); |
1881 | 0 |
int insertPos = 0;
|
1882 | 0 |
int i;
|
1883 | 0 |
int contentSize;
|
1884 | 0 |
if (doc != null) { |
1885 | 0 |
try {
|
1886 | 0 |
int p0 = Math.min(caret.getDot(), caret.getMark());
|
1887 | 0 |
int p1 = Math.max(caret.getDot(), caret.getMark());
|
1888 | 0 |
if (p0 != p1) {
|
1889 | 0 |
doc.remove(p0, p1 - p0); |
1890 |
} |
|
1891 | 0 |
if (content != null) { |
1892 | 0 |
content.pasteHTML(doc, p0); |
1893 |
} |
|
1894 |
} |
|
1895 |
catch (Exception e) {
|
|
1896 | 0 |
getToolkit().beep(); |
1897 |
} |
|
1898 |
} |
|
1899 |
} |
|
1900 |
|
|
1901 |
/* ------ start of drag and drop implementation -------------------------
|
|
1902 |
(see also constructor of this class) */
|
|
1903 |
|
|
1904 |
/** enables this component to be a Drop Target */
|
|
1905 |
DropTarget dropTarget = null;
|
|
1906 |
|
|
1907 |
/** enables this component to be a Drag Source */
|
|
1908 |
DragSource dragSource = null;
|
|
1909 |
|
|
1910 |
/** the last selection start */
|
|
1911 |
private int lastSelStart = 0; |
|
1912 |
|
|
1913 |
/** the last selection end */
|
|
1914 |
private int lastSelEnd = 0; |
|
1915 |
|
|
1916 |
/** the location of the last event in the text component */
|
|
1917 |
private int dndEventLocation = 0; |
|
1918 |
|
|
1919 |
/**
|
|
1920 |
* <p>This flag is set by this objects dragGestureRecognizer to indicate that
|
|
1921 |
* a drag operation has been started from this object. It is cleared once
|
|
1922 |
* dragDropEnd is captured by this object.</p>
|
|
1923 |
*
|
|
1924 |
* <p>If a drop occurs in this object and this object started the drag
|
|
1925 |
* operation, then the element to be dropped comes from this object and thus
|
|
1926 |
* has to be removed somewhere else in this object.</p>
|
|
1927 |
*
|
|
1928 |
* <p>To the contrary if a drop occurs in this object and the drag operation
|
|
1929 |
* was not started in this object, then the element to be dropped does not
|
|
1930 |
* come from this object and has not to be removed here.</p>
|
|
1931 |
*/
|
|
1932 |
private boolean dragStartedHere = false; |
|
1933 |
|
|
1934 |
/**
|
|
1935 |
* Initialize the drag and drop implementation for this component.
|
|
1936 |
*
|
|
1937 |
* <p>DropTarget, DragSource and DragGestureRecognizer are instantiated
|
|
1938 |
* and a MouseListener is established to track the selection in drag
|
|
1939 |
* operations</p>
|
|
1940 |
*
|
|
1941 |
* <p>this ideally is called in the constructor of a class which
|
|
1942 |
* would like to implement drag and drop</p>
|
|
1943 |
*/
|
|
1944 | 158 |
public void initDnd() { |
1945 | 158 |
dropTarget = new DropTarget (this, this); |
1946 | 158 |
dragSource = new DragSource();
|
1947 | 158 |
dragSource.createDefaultDragGestureRecognizer( |
1948 |
this, DnDConstants.ACTION_MOVE, this); |
|
1949 | 158 |
this.addMouseListener(new MouseAdapter() { |
1950 | 1 |
public void mouseReleased(MouseEvent e) { |
1951 | 1 |
this_mouseReleased(e);
|
1952 |
} |
|
1953 | 0 |
public void mouseClicked(MouseEvent e) { |
1954 | 0 |
this_mouseClicked(e);
|
1955 |
} |
|
1956 |
}); |
|
1957 |
} |
|
1958 |
|
|
1959 |
/** a drag gesture has been initiated */
|
|
1960 | 1 |
public void dragGestureRecognized(DragGestureEvent event) { |
1961 | 1 |
int selStart = getSelectionStart();
|
1962 | 1 |
int selEnd = getSelectionEnd();
|
1963 | 1 |
try {
|
1964 | 1 |
if( (lastSelEnd > lastSelStart) &&
|
1965 |
(selStart >= lastSelStart) && |
|
1966 |
(selStart < lastSelEnd) ) |
|
1967 |
{ |
|
1968 | 0 |
dragStartedHere = true;
|
1969 | 0 |
select(lastSelStart, lastSelEnd); |
1970 | 0 |
HTMLText text = new HTMLText();
|
1971 | 0 |
int start = getSelectionStart();
|
1972 | 0 |
text.copyHTML(this, start, getSelectionEnd() - start);
|
1973 | 0 |
HTMLTextSelection trans = new HTMLTextSelection(text);
|
1974 | 0 |
dragSource.startDrag(event, DragSource.DefaultMoveDrop, trans, this);
|
1975 |
} |
|
1976 |
} |
|
1977 |
catch(Exception e) {
|
|
1978 |
//getToolkit().beep();
|
|
1979 |
} |
|
1980 |
} |
|
1981 |
|
|
1982 |
/**
|
|
1983 |
* this message goes to DragSourceListener, informing it that the dragging
|
|
1984 |
* has ended
|
|
1985 |
*/
|
|
1986 | 0 |
public void dragDropEnd (DragSourceDropEvent event) { |
1987 | 0 |
dragStartedHere = false;
|
1988 |
} |
|
1989 |
|
|
1990 |
/** is invoked when a drag operation is going on */
|
|
1991 | 0 |
public void dragOver (DropTargetDragEvent event) { |
1992 | 0 |
dndEventLocation = viewToModel(event.getLocation()); |
1993 | 0 |
try {
|
1994 | 0 |
setCaretPosition(dndEventLocation); |
1995 |
} |
|
1996 |
catch(Exception e) {
|
|
1997 |
//getToolkit().beep();
|
|
1998 |
} |
|
1999 |
} |
|
2000 |
|
|
2001 |
/**
|
|
2002 |
* a drop has occurred. If the dragged element has a suitable
|
|
2003 |
* <code>DataFlavor</code>, do the drop.
|
|
2004 |
*
|
|
2005 |
* @param event - the event specifiying the drop operation
|
|
2006 |
* @see java.awt.datatransfer.DataFlavor
|
|
2007 |
* @see de.calcom.cclib.text.StyledText
|
|
2008 |
* @see de.calcom.cclib.text.StyledTextSelection
|
|
2009 |
*/
|
|
2010 | 0 |
public void drop(DropTargetDropEvent event) { |
2011 | 0 |
dndEventLocation = viewToModel(event.getLocation()); |
2012 | 0 |
if( (dndEventLocation >= lastSelStart) &&
|
2013 |
(dndEventLocation <= lastSelEnd) ) |
|
2014 |
{ |
|
2015 | 0 |
event.rejectDrop(); |
2016 | 0 |
select(lastSelStart, lastSelEnd); |
2017 |
} |
|
2018 |
else {
|
|
2019 | 0 |
try {
|
2020 | 0 |
Transferable transferable = event.getTransferable(); |
2021 | 0 |
if(transferable.isDataFlavorSupported(df)){
|
2022 | 0 |
HTMLText s = (HTMLText) transferable.getTransferData(df); |
2023 | 0 |
doDrop(event, s); |
2024 |
} |
|
2025 | 0 |
else if(transferable.isDataFlavorSupported(DataFlavor.stringFlavor)){ |
2026 | 0 |
String s = (String) transferable.getTransferData( |
2027 |
DataFlavor.stringFlavor); |
|
2028 | 0 |
doDrop(event, s); |
2029 |
} |
|
2030 |
else {
|
|
2031 | 0 |
event.rejectDrop(); |
2032 |
} |
|
2033 |
} |
|
2034 |
catch (Exception exception) {
|
|
2035 | 0 |
exception.printStackTrace(); |
2036 | 0 |
event.rejectDrop(); |
2037 |
} |
|
2038 |
} |
|
2039 |
} |
|
2040 |
|
|
2041 |
/**
|
|
2042 |
* do the drop operation consisting of adding the dragged element and
|
|
2043 |
* necessarily removing the dragged element from the original position
|
|
2044 |
*/
|
|
2045 | 0 |
private void doDrop(DropTargetDropEvent event, Object s) { |
2046 | 0 |
int removeOffset = 0;
|
2047 | 0 |
int moveOffset = 0;
|
2048 | 0 |
int newSelStart;
|
2049 | 0 |
int newSelEnd;
|
2050 | 0 |
event.acceptDrop(DnDConstants.ACTION_MOVE); |
2051 | 0 |
setCaretPosition(dndEventLocation); |
2052 | 0 |
if(s instanceof HTMLText) { |
2053 | 0 |
replaceSelection((HTMLText) s); |
2054 |
} |
|
2055 | 0 |
else if(s instanceof String) { |
2056 | 0 |
replaceSelection((String) s); |
2057 |
} |
|
2058 | 0 |
if(dndEventLocation < lastSelStart) {
|
2059 | 0 |
removeOffset = s.toString().length(); |
2060 |
} |
|
2061 |
else {
|
|
2062 | 0 |
moveOffset = s.toString().length(); |
2063 |
} |
|
2064 | 0 |
newSelEnd = dndEventLocation + (lastSelEnd - lastSelStart) - moveOffset; |
2065 | 0 |
newSelStart = dndEventLocation - moveOffset; |
2066 | 0 |
if(dragStartedHere) {
|
2067 | 0 |
lastSelStart += removeOffset; |
2068 | 0 |
lastSelEnd += removeOffset; |
2069 | 0 |
select(lastSelStart, lastSelEnd); |
2070 | 0 |
replaceSelection("");
|
2071 |
} |
|
2072 | 0 |
lastSelEnd = newSelEnd; |
2073 | 0 |
lastSelStart = newSelStart; |
2074 | 0 |
select(lastSelStart, lastSelEnd); |
2075 | 0 |
event.getDropTargetContext().dropComplete(true);
|
2076 |
} |
|
2077 |
|
|
2078 |
/** remember current selection when mouse button is released */
|
|
2079 | 1 |
void this_mouseReleased(MouseEvent e) { |
2080 | 1 |
lastSelStart = getSelectionStart(); |
2081 | 1 |
lastSelEnd = getSelectionEnd(); |
2082 |
} |
|
2083 |
|
|
2084 |
/** remember current selection when mouse button is double clicked */
|
|
2085 | 0 |
void this_mouseClicked(MouseEvent e) { |
2086 | 0 |
if(e.getClickCount() > 1) {
|
2087 | 0 |
lastSelStart = getSelectionStart(); |
2088 | 0 |
lastSelEnd = getSelectionEnd(); |
2089 |
} |
|
2090 |
} |
|
2091 |
|
|
2092 |
/** is invoked if the user modifies the current drop gesture */
|
|
2093 | 0 |
public void dropActionChanged ( DropTargetDragEvent event ) { |
2094 |
} |
|
2095 |
|
|
2096 |
/** is invoked when the user changes the dropAction */
|
|
2097 | 0 |
public void dropActionChanged ( DragSourceDragEvent event) { |
2098 |
} |
|
2099 |
|
|
2100 |
/** is invoked when you are dragging over the DropSite */
|
|
2101 | 0 |
public void dragEnter (DropTargetDragEvent event) { |
2102 |
} |
|
2103 |
|
|
2104 |
/** is invoked when you are exit the DropSite without dropping */
|
|
2105 | 0 |
public void dragExit (DropTargetEvent event) { |
2106 |
} |
|
2107 |
|
|
2108 |
/**
|
|
2109 |
* this message goes to DragSourceListener, informing it that the dragging
|
|
2110 |
* has entered the DropSite
|
|
2111 |
*/
|
|
2112 | 0 |
public void dragEnter (DragSourceDragEvent event) { |
2113 |
} |
|
2114 |
|
|
2115 |
/**
|
|
2116 |
* this message goes to DragSourceListener, informing it that the dragging
|
|
2117 |
* has exited the DropSite
|
|
2118 |
*/
|
|
2119 | 0 |
public void dragExit (DragSourceEvent event) { |
2120 |
} |
|
2121 |
|
|
2122 |
/**
|
|
2123 |
* this message goes to DragSourceListener, informing it that
|
|
2124 |
* the dragging is currently ocurring over the DropSite
|
|
2125 |
*/
|
|
2126 | 0 |
public void dragOver (DragSourceDragEvent event) { |
2127 |
} |
|
2128 |
|
|
2129 |
// ------ end of drag and drop implementation ----------------------------
|
|
2130 |
|
|
2131 |
/* ------ start of cut, copy and paste implementation ------------------- */
|
|
2132 |
|
|
2133 |
/**
|
|
2134 |
* Transfers the currently selected range in the associated
|
|
2135 |
* text model to the system clipboard, removing the contents
|
|
2136 |
* from the model. The current selection is reset.
|
|
2137 |
*
|
|
2138 |
* @see #replaceSelection
|
|
2139 |
*/
|
|
2140 |
|
|
2141 | 0 |
public void cut() { |
2142 | 0 |
if (isEditable() && isEnabled()) {
|
2143 | 0 |
copy(); |
2144 | 0 |
replaceSelection("");
|
2145 |
} |
|
2146 |
} |
|
2147 |
|
|
2148 |
|
|
2149 |
/**
|
|
2150 |
* Transfers the currently selected range in the associated
|
|
2151 |
* text model to the system clipboard, leaving the contents
|
|
2152 |
* in the text model. The current selection remains intact.
|
|
2153 |
*/
|
|
2154 |
|
|
2155 | 0 |
public void copy() { |
2156 | 0 |
try
|
2157 |
{ |
|
2158 | 0 |
HTMLText st = new HTMLText();
|
2159 | 0 |
int start = getSelectionStart();
|
2160 | 0 |
st.copyHTML(this, start, getSelectionEnd() - start);
|
2161 | 0 |
HTMLTextSelection contents = new HTMLTextSelection(st);
|
2162 | 0 |
Clipboard clipboard = getToolkit().getSystemClipboard(); |
2163 | 0 |
clipboard.setContents(contents, defaultClipboardOwner); |
2164 |
} |
|
2165 |
catch(Exception e) {
|
|
2166 | 0 |
getToolkit().beep(); |
2167 |
} |
|
2168 |
} |
|
2169 |
|
|
2170 |
|
|
2171 | 0 |
public File saveAsJPEG(BufferedImage bi, String fileName) {
|
2172 | 0 |
BufferedImage myImage = bi; |
2173 | 0 |
Graphics2D g2 = myImage.createGraphics(); |
2174 | 0 |
File f = null;
|
2175 | 0 |
try {
|
2176 | 0 |
OutputStream out = new FileOutputStream(fileName);
|
2177 | 0 |
f= new File(fileName);
|
2178 | 0 |
Debug.print(f.getAbsolutePath()); |
2179 |
|
|
2180 | 0 |
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); |
2181 | 0 |
encoder.encode(myImage); |
2182 | 0 |
out.close(); |
2183 | 0 |
Debug.print("in saveASJPEG");
|
2184 |
} catch (Exception e) {
|
|
2185 | 0 |
System.out.println(e.toString()); |
2186 |
} |
|
2187 | 0 |
return f;
|
2188 |
} |
|
2189 |
|
|
2190 |
/**
|
|
2191 |
* Transfers the contents of the system clipboard into the
|
|
2192 |
* associated text model. If there is a selection in the
|
|
2193 |
* associated view, it is replaced with the contents of the
|
|
2194 |
* clipboard. If there is no selection, the clipboard contents
|
|
2195 |
* are inserted in front of the current insert position in
|
|
2196 |
* the associated view. If the clipboard is empty, does nothing.
|
|
2197 |
*
|
|
2198 |
* @see #replaceSelection
|
|
2199 |
*/
|
|
2200 |
|
|
2201 | 0 |
public void paste() { |
2202 | 0 |
Debug.print("IN OUR PASTE");
|
2203 | 0 |
Clipboard clipboard = getToolkit().getSystemClipboard(); |
2204 | 0 |
Transferable content = clipboard.getContents(this);
|
2205 | 0 |
FrmMain.pastingImage=false;
|
2206 | 0 |
if (content != null) { |
2207 | 0 |
try {
|
2208 | 0 |
if(content.isDataFlavorSupported(df)) {
|
2209 | 0 |
HTMLText st = (HTMLText) content.getTransferData(df); |
2210 | 0 |
replaceSelection(st); |
2211 | 0 |
Debug.print("HTMLText");
|
2212 |
} |
|
2213 | 0 |
else if(content.isDataFlavorSupported(DataFlavor.stringFlavor)) { |
2214 | 0 |
String text = (String) content.getTransferData(DataFlavor.stringFlavor); |
2215 | 0 |
replaceSelection(text); |
2216 | 0 |
Debug.print("stringFlavor");
|
2217 |
} |
|
2218 |
else {
|
|
2219 | 0 |
if ( content.isDataFlavorSupported(DataFlavor.imageFlavor) ) {
|
2220 | 0 |
FrmMain.pastingImage=true;
|
2221 | 0 |
Debug.print(content.getTransferData(DataFlavor.imageFlavor).getClass().getName()); |
2222 | 0 |
BufferedImage bi = (BufferedImage) content.getTransferData(DataFlavor.imageFlavor); |
2223 | 0 |
File saveloc = new File(dp.docTempDir.toString());
|
2224 | 0 |
System.out.println(saveloc.toString()); |
2225 |
// File f = saveAsJPEG(bi, saveloc.toString()+"/pastefile.jpg");
|
|
2226 |
//saveAsJPEG(bi, "/pastefile.jpg");
|
|
2227 |
//Util.copyFile(saveloc, )
|
|
2228 | 0 |
Debug.print("image?");
|
2229 | 0 |
File imgDir = dp.getImageDir(); |
2230 | 0 |
Debug.print("IMGDIR IS "+imgDir.toString()+ "and exists?"+imgDir.exists()); |
2231 | 0 |
imgDir.mkdirs(); |
2232 | 0 |
imgDir.mkdirs(); |
2233 | 0 |
imgDir.mkdirs(); |
2234 |
|
|
2235 | 0 |
if(!imgDir.exists()) {
|
2236 | 0 |
Debug.print("Made Image directory is "+(imgDir.mkdirs()==true)); |
2237 |
} |
|
2238 | 0 |
String imgDirName = imgDir.getAbsolutePath(); |
2239 | 0 |
File f = saveAsJPEG(bi, imgDir.toString()+"/pastefile.jpg");
|
2240 |
//for(int i = 0; i < sFiles.length; i++)
|
|
2241 |
{ |
|
2242 |
//System.out.println("file selected: " + sFiles[i] + " new name= " + imgDirName + File.separator + sFiles[i].getName());
|
|
2243 |
//File f2 = new File (imgDir.toString());
|
|
2244 |
// Debug.print(f2.toString());
|
|
2245 |
// Util.copyFile(f,f2);
|
|
2246 |
} |
|
2247 |
} |
|
2248 |
} |
|
2249 |
} |
|
2250 |
catch (Exception e) {
|
|
2251 |
//e.printStackTrace();
|
|
2252 | 0 |
getToolkit().beep(); |
2253 |
} |
|
2254 |
} |
|
2255 |
} |
|
2256 |
|
|
2257 |
|
|
2258 |
/* ------ end of cut, copy and paste implementation --------------- */
|
|
2259 |
|
|
2260 |
/* ------ start of Clipboard implementation --------------- */
|
|
2261 |
|
|
2262 |
private static ClipboardOwner defaultClipboardOwner = new ClipboardObserver(); |
|
2263 |
|
|
2264 |
static class ClipboardObserver implements ClipboardOwner { |
|
2265 | 0 |
public void lostOwnership(Clipboard clipboard, Transferable contents) { |
2266 |
} |
|
2267 |
} |
|
2268 |
|
|
2269 |
/* ------ end of Clipboard implementation --------------- */
|
|
2270 |
|
|
2271 |
/* ------ start of font/paragraph manipulation --------------- */
|
|
2272 |
|
|
2273 | 5 |
public void applyAttributes(AttributeSet a, boolean para) { |
2274 | 5 |
applyAttributes(a, para, false);
|
2275 |
} |
|
2276 |
|
|
2277 |
/**
|
|
2278 |
* set the attributes for a given part of this editor. If a range of
|
|
2279 |
* text is selected, the attributes are applied to the selection.
|
|
2280 |
* If nothing is selected, the input attributes of the given
|
|
2281 |
* editor are set thus applying the given attributes to future
|
|
2282 |
* inputs.
|
|
2283 |
*
|
|
2284 |
* @param a the set of attributes to apply
|
|
2285 |
* @param para true, if the attributes shall be applied to the whole
|
|
2286 |
* paragraph, false, if only the selected range of characters shall have them
|
|
2287 |
* @param replace true, if existing attribtes are to be replaced, false if not
|
|
2288 |
*/
|
|
2289 | 5 |
public void applyAttributes(AttributeSet a, boolean para, boolean replace) { |
2290 | 5 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
2291 | 5 |
requestFocus(); |
2292 | 5 |
int start = getSelectionStart();
|
2293 | 5 |
int end = getSelectionEnd();
|
2294 | 5 |
if(para) {
|
2295 | 1 |
doc.setParagraphAttributes(start, end - start, a, replace); |
2296 |
} |
|
2297 |
else {
|
|
2298 | 4 |
if(end != start) {
|
2299 | 2 |
doc.setCharacterAttributes(start, end - start, a, replace); |
2300 |
} |
|
2301 |
else {
|
|
2302 | 2 |
MutableAttributeSet inputAttributes = |
2303 |
((SHTMLEditorKit) getEditorKit()).getInputAttributes(); |
|
2304 | 2 |
inputAttributes.addAttributes(a); |
2305 |
} |
|
2306 |
} |
|
2307 |
} |
|
2308 |
|
|
2309 |
/**
|
|
2310 |
* switch elements in the current selection to a given tag
|
|
2311 |
*
|
|
2312 |
* @param tag the tag name to switche elements to
|
|
2313 |
* @param allowedTags tags that may be switched
|
|
2314 |
*/
|
|
2315 | 0 |
public void applyTag(String tag, Vector allowedTags) { |
2316 | 0 |
try {
|
2317 | 0 |
int start = getSelectionStart();
|
2318 | 0 |
int end = getSelectionEnd();
|
2319 |
//System.out.println("SHTMLEditorPane applyTag start=" + start + ", end=" + end);
|
|
2320 | 0 |
StringWriter sw = new StringWriter();
|
2321 | 0 |
SHTMLDocument doc = (SHTMLDocument) getDocument(); |
2322 | 0 |
SHTMLWriter w = new SHTMLWriter(sw, doc);
|
2323 | 0 |
Element elem = doc.getParagraphElement(start); |
2324 |
//System.out.println("SHTMLEditorPane applyTag elemName=" + elem.getName());
|
|
2325 | 0 |
start = elem.getStartOffset(); |
2326 | 0 |
if(end < elem.getEndOffset()) {
|
2327 | 0 |
end = elem.getEndOffset(); |
2328 |
} |
|
2329 |
//System.out.println("SHTMLEditorPane applyTag start=" + start + ", end=" + end);
|
|
2330 | 0 |
elem = elem.getParentElement(); |
2331 | 0 |
int replaceStart = -1;
|
2332 | 0 |
int replaceEnd = -1;
|
2333 | 0 |
int index = -1;
|
2334 | 0 |
int removeCount = 0;
|
2335 | 0 |
int eCount = elem.getElementCount();
|
2336 |
//System.out.println("SHTMLEditorPane applyTag parent elem=" + elem.getName() + ", eCount=" + eCount);
|
|
2337 | 0 |
for(int i = 0; i < eCount; i++) { |
2338 | 0 |
Element child = elem.getElement(i); |
2339 |
//System.out.println("SHTMLEditorPane applyTag child elem=" + child.getName() + ", eCount=" + eCount);
|
|
2340 | 0 |
int eStart = child.getStartOffset();
|
2341 | 0 |
int eEnd = child.getEndOffset();
|
2342 |
//System.out.println("SHTMLEditorPane applyTag eStart=" + eStart + ", eEnd=" + eEnd);
|
|
2343 | 0 |
if((eStart >= start && eStart < end) ||
|
2344 |
(eEnd > start && eEnd <= end)) |
|
2345 |
{ |
|
2346 | 0 |
++removeCount; |
2347 | 0 |
if(allowedTags.contains(child.getName())) {
|
2348 |
//System.out.println("SHTMLEditorPane applyTag element is in selection");
|
|
2349 | 0 |
w.startTag(tag.toString(), child.getAttributes()); |
2350 | 0 |
w.writeChildElements(child); |
2351 | 0 |
w.endTag(tag.toString()); |
2352 | 0 |
if(index < 0) {
|
2353 | 0 |
index = i; |
2354 |
} |
|
2355 | 0 |
if(replaceStart < 0 || replaceStart > eStart) {
|
2356 | 0 |
replaceStart = eStart; |
2357 |
} |
|
2358 | 0 |
if(replaceEnd < 0 || replaceEnd < eEnd) {
|
2359 | 0 |
replaceEnd = eEnd; |
2360 |
} |
|
2361 |
} |
|
2362 |
else {
|
|
2363 | 0 |
w.write(child); |
2364 |
} |
|
2365 |
} |
|
2366 |
} |
|
2367 |
//System.out.println("SHTMLEditorPane applyTag remove index=" + index + ", removeCount=" + removeCount);
|
|
2368 | 0 |
doc.insertAfterEnd(elem.getElement(index), sw.getBuffer().toString()); |
2369 | 0 |
doc.removeElements(elem, index, removeCount); |
2370 |
//SHTMLEditorKit kit = (SHTMLEditorKit) getEditorKit();
|
|
2371 |
//System.out.println("SHTMLEditorPane applyTag new HTML=\r\n" + sw.getBuffer().toString() );
|
|
2372 |
//kit.read(new StringReader(sw.getBuffer().toString()), doc, getCaretPosition());
|
|
2373 |
} |
|
2374 |
catch(Exception e) {
|
|
2375 | 0 |
Util.errMsg(this, e.getMessage(), e);
|
2376 |
} |
|
2377 |
} |
|
2378 |
|
|
2379 |
/* ------ end of font/paragraph manipulation --------------- */
|
|
2380 |
|
|
2381 |
/* ---------- class fields start -------------- */
|
|
2382 |
|
|
2383 |
public static final String newListItemAction = "newListItem"; |
|
2384 |
|
|
2385 |
/** a data flavor for transferables processed by this component */
|
|
2386 |
private DataFlavor df =
|
|
2387 |
new DataFlavor(HTMLText.class, "HTMLText"); |
|
2388 |
|
|
2389 |
/* Cursors for mouseovers in the editor */
|
|
2390 |
private Cursor textCursor = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
|
|
2391 |
private Cursor defaultCursor =
|
|
2392 |
Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); |
|
2393 |
|
|
2394 |
/* ---------- class fields end -------------- */
|
|
2395 |
|
|
2396 |
} |
|