/******************************************************************************* * Copyright (c) 2007-2013, G. Weirich and Elexis * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * bogdan314 - initial implementation * Sponsor: * G. Weirich ******************************************************************************/ package ch.elexis.base.textplugin; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import java.util.Vector; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ExtendedModifyEvent; import org.eclipse.swt.custom.ExtendedModifyListener; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.ui.plugin.AbstractUIPlugin; import ch.elexis.core.ui.UiDesk; import ch.elexis.core.ui.text.ITextPlugin; import ch.elexis.core.ui.text.ITextPlugin.ICallback; /** * @author bogdan314 */ public class ElexisEditor extends Composite implements ExtendedModifyListener { protected Page page; private boolean isBold; private boolean isItalic; private boolean isUnderline; private String fontName = "Arial"; private int fontHeight = 10; protected ToolBar toolBar; private ToolItem newBoxToolItem; private ToolItem highlightToolItem; private ToolItem deleteToolItem; private ToolItem boldToolItem; private ToolItem italicToolItem; private ToolItem underlineToolItem; private ToolItem cutToolItem; private ToolItem copyToolItem; private ToolItem pasteToolItem; private ToolItem saveToolItem; private ToolItem saveAsToolItem; private ToolItem printToolItem; private Combo fontCombo; private Combo fontHeigtCombo; private final Listener caretListener; private StyledText lastSelectedText; private final Vector<StyleRange> cachedStyles = new Vector<StyleRange>(); private final ImageRegistry imageRegistry = UiDesk.getImageRegistry(); private final ICallback handler; protected ElexisEditor(final Composite parent, final ICallback handler){ super(parent, SWT.NONE); this.handler = handler; GridLayout layout = new GridLayout(); setLayout(layout); caretListener = new Listener() { public void handleEvent(final Event event){ caretUpdate(event); } }; checkImages(); createToolbar(); createPage(); layout(); } /** * Returns an image descriptor for the image file at the given plug-in relative path. * * @param path * the path * @return the image descriptor */ private ImageDescriptor getImageDescriptor(final String path){ return AbstractUIPlugin.imageDescriptorFromPlugin("ch.elexis.base.textplugin", path); //$NON-NLS-1$ } private void checkImages(){ if (imageRegistry.get("new-box") == null) { imageRegistry.put("new-box", getImageDescriptor("icons/new-box.gif")); } if (imageRegistry.get("italic") == null) { imageRegistry.put("italic", getImageDescriptor("icons/italic.gif")); } if (imageRegistry.get("bold") == null) { imageRegistry.put("bold", getImageDescriptor("icons/bold.gif")); } if (imageRegistry.get("underline") == null) { imageRegistry.put("underline", getImageDescriptor("icons/underline.gif")); } if (imageRegistry.get("font") == null) { imageRegistry.put("font", getImageDescriptor("icons/font.gif")); } if (imageRegistry.get("highlight-boxes") == null) { imageRegistry.put("highlight-boxes", getImageDescriptor("icons/highlight-boxes.gif")); } if (imageRegistry.get("delete") == null) { imageRegistry.put("delete", getImageDescriptor("icons/delete.gif")); } if (imageRegistry.get("paste") == null) { imageRegistry.put("paste", getImageDescriptor("icons/paste.gif")); } if (imageRegistry.get("copy") == null) { imageRegistry.put("copy", getImageDescriptor("icons/copy.gif")); } if (imageRegistry.get("cut") == null) { imageRegistry.put("cut", getImageDescriptor("icons/cut.gif")); } if (imageRegistry.get("save") == null) { imageRegistry.put("save", getImageDescriptor("icons/save.gif")); } if (imageRegistry.get("saveas") == null) { imageRegistry.put("saveas", getImageDescriptor("icons/saveas.gif")); } if (imageRegistry.get("print") == null) { imageRegistry.put("print", getImageDescriptor("icons/printer.png")); } } private void createPage(){ ScrolledComposite scrollable = new ScrolledComposite(this, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); page = new Page(scrollable, this); page.setHightlight(true); page.forceFocus(); page.addExtendedModifyListener(this); addCaretListener(page); scrollable.setContent(page); // size GridData data = new GridData(602, 350); data.grabExcessHorizontalSpace = true; data.grabExcessVerticalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; scrollable.setLayoutData(data); lastSelectedText = page; updateControls(); } private void addCaretListener(final StyledText text){ text.addListener(SWT.MouseDown, caretListener); text.addListener(SWT.KeyDown, caretListener); } private void createToolbar(){ toolBar = new ToolBar(this, SWT.NONE); GridData data = new GridData(); data.grabExcessHorizontalSpace = true; data.horizontalAlignment = GridData.FILL; toolBar.setLayoutData(data); newBoxToolItem = new ToolItem(toolBar, SWT.PUSH); newBoxToolItem.setToolTipText("Insert new text-box"); newBoxToolItem.setImage(imageRegistry.get("new-box")); deleteToolItem = new ToolItem(toolBar, SWT.PUSH); deleteToolItem.setToolTipText("Delete current text-box"); deleteToolItem.setImage(imageRegistry.get("delete")); highlightToolItem = new ToolItem(toolBar, SWT.CHECK); highlightToolItem.setToolTipText("Highlight text-boxes"); highlightToolItem.setSelection(true); highlightToolItem.setImage(imageRegistry.get("highlight-boxes")); new ToolItem(toolBar, SWT.SEPARATOR); saveToolItem = new ToolItem(toolBar, SWT.PUSH); saveToolItem.setToolTipText("Save"); saveToolItem.setImage(imageRegistry.get("save")); saveAsToolItem = new ToolItem(toolBar, SWT.PUSH); saveAsToolItem.setToolTipText("Save As"); saveAsToolItem.setImage(imageRegistry.get("saveas")); printToolItem = new ToolItem(toolBar, SWT.PUSH); printToolItem.setToolTipText("Print"); printToolItem.setImage(imageRegistry.get("print")); new ToolItem(toolBar, SWT.SEPARATOR); boldToolItem = new ToolItem(toolBar, SWT.CHECK); boldToolItem.setToolTipText("Bold"); boldToolItem.setImage(imageRegistry.get("bold")); italicToolItem = new ToolItem(toolBar, SWT.CHECK); italicToolItem.setToolTipText("Italic"); italicToolItem.setImage(imageRegistry.get("italic")); underlineToolItem = new ToolItem(toolBar, SWT.CHECK); underlineToolItem.setToolTipText("Underline"); underlineToolItem.setImage(imageRegistry.get("underline")); ToolItem sep = new ToolItem(toolBar, SWT.SEPARATOR); fontCombo = new Combo(toolBar, SWT.READ_ONLY); fontCombo.setToolTipText("Font"); FontData[] fonts = getDisplay().getFontList(null, true); Set<String> uniqueFonts = new TreeSet<String>(); for (int i = 0; i < fonts.length; i++) { FontData fd = fonts[i]; uniqueFonts.add(fd.getName()); } for (Iterator<String> it = uniqueFonts.iterator(); it.hasNext();) { String name = it.next(); fontCombo.add(name); } fontCombo.pack(); sep.setWidth(fontCombo.getSize().x); sep.setControl(fontCombo); new ToolItem(toolBar, SWT.SEPARATOR); fontHeigtCombo = new Combo(toolBar, SWT.READ_ONLY); int[] height = new int[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 72 }; for (int i = 0; i < height.length; i++) { fontHeigtCombo.add(String.valueOf(height[i])); } fontHeigtCombo.pack(); ToolItem sep2 = new ToolItem(toolBar, SWT.SEPARATOR); sep2.setWidth(fontHeigtCombo.getSize().x); sep2.setControl(fontHeigtCombo); new ToolItem(toolBar, SWT.SEPARATOR); cutToolItem = new ToolItem(toolBar, SWT.PUSH); cutToolItem.setToolTipText("Cut"); cutToolItem.setImage(imageRegistry.get("cut")); copyToolItem = new ToolItem(toolBar, SWT.PUSH); copyToolItem.setToolTipText("Copy"); copyToolItem.setImage(imageRegistry.get("copy")); pasteToolItem = new ToolItem(toolBar, SWT.PUSH); pasteToolItem.setToolTipText("Paste"); pasteToolItem.setImage(imageRegistry.get("paste")); Listener listener = new Listener() { public void handleEvent(Event e){ if (e.widget == highlightToolItem) { page.setHightlight(highlightToolItem.getSelection()); } else if (e.widget == newBoxToolItem) { insertBox(); } else if (e.widget == deleteToolItem) { deleteBox(); } else if (e.widget == boldToolItem) { isBold = !isBold; updateStylesOnText(); } else if (e.widget == italicToolItem) { isItalic = !isItalic; updateStylesOnText(); } else if (e.widget == underlineToolItem) { isUnderline = !isUnderline; updateStylesOnText(); } else if (e.widget == cutToolItem) { lastSelectedText.cut(); } else if (e.widget == copyToolItem) { lastSelectedText.copy(); testInsertTable(); } else if (e.widget == pasteToolItem) { lastSelectedText.paste(); } else if (e.widget == fontCombo) { changeFont(); } else if (e.widget == fontHeigtCombo) { changeFontHeight(); } else if (e.widget == saveToolItem) { if (handler != null) { handler.save(); } } else if (e.widget == saveAsToolItem) { if (handler != null) { handler.saveAs(); } } else if (e.widget == printToolItem) { print(); } } }; highlightToolItem.addListener(SWT.Selection, listener); newBoxToolItem.addListener(SWT.Selection, listener); deleteToolItem.addListener(SWT.Selection, listener); boldToolItem.addListener(SWT.Selection, listener); italicToolItem.addListener(SWT.Selection, listener); underlineToolItem.addListener(SWT.Selection, listener); cutToolItem.addListener(SWT.Selection, listener); copyToolItem.addListener(SWT.Selection, listener); pasteToolItem.addListener(SWT.Selection, listener); fontCombo.addListener(SWT.Selection, listener); fontHeigtCombo.addListener(SWT.Selection, listener); saveToolItem.addListener(SWT.Selection, listener); saveAsToolItem.addListener(SWT.Selection, listener); printToolItem.addListener(SWT.Selection, listener); } private void testInsertTable(){ String[][] contents = new String[6][]; contents[0] = new String[] { "Whatever", "Chemical", "Programming" }; contents[1] = new String[] { "1", "Mercur", "Python" }; contents[2] = new String[] { "2", "Iridium", "Ruby" }; contents[3] = new String[] { "3", "Iron", "C++" }; contents[4] = new String[] { "4", "Gold", "Java" }; contents[5] = new String[] { "5", "Silver", "Pascal" }; ElexisTextPlugin.tempInstance.setFont("Verdana", SWT.NONE, 13); // test insert table ElexisTextPlugin.tempInstance.insertTable("ab", ITextPlugin.FIRST_ROW_IS_HEADER | ITextPlugin.GRID_VISIBLE, contents, null); } public void print(){ /* * PrinterData data = Printer.getDefaultPrinterData(); if (data == null) { * System.out.println("Warning: No default printer."); return; } final Printer printer = new * Printer(data); if (printer.startJob("Elexis Printing")) { Color black = * printer.getSystemColor(SWT.COLOR_BLACK); Color white = * printer.getSystemColor(SWT.COLOR_WHITE); Rectangle trim = printer.computeTrim(0, 0, 0, * 0); GC gc = new GC(printer); * * if (printer.startPage()) { gc.setBackground(white); gc.setForeground(black); * * page.print(printer, gc); * * printer.endPage(); gc.dispose(); printer.endJob(); } } */ } private void changeFont(){ fontName = fontCombo.getItem(fontCombo.getSelectionIndex()); updateStylesOnText(); lastSelectedText.forceFocus(); } private void changeFontHeight(){ fontHeight = Integer.parseInt(fontHeigtCombo.getItem(fontHeigtCombo.getSelectionIndex())); updateStylesOnText(); lastSelectedText.forceFocus(); } protected TextBox insertBox(){ TextBox box = page.insertBox(); box.addExtendedModifyListener(this); addCaretListener(box); updateControls(); return box; } protected void insertTable(final int start, final int end, final String[][] contents, final boolean header, final boolean grid, final String fontName, final int fontHeight, final int fontStyle){ Table table = new Table(page, SWT.FULL_SELECTION | (grid ? SWT.BORDER : SWT.NONE)); table.setLinesVisible(grid); table.setHeaderVisible(false); int rowcount = contents.length; int columncount = contents[0].length; for (int i = 0; i < columncount; i++) { TableColumn column = new TableColumn(table, SWT.NONE); column.setText(String.valueOf(i)); } Font tableFont = table.getFont(); if (fontName != null) { tableFont = new Font(getDisplay(), fontName, fontHeight, fontStyle); } table.setFont(tableFont); for (int i = 0; i < rowcount; i++) { String[] rowcontent = contents[i]; TableItem row = new TableItem(table, SWT.NONE); for (int j = 0; j < rowcontent.length; j++) { row.setText(j, rowcontent[j]); if ((i == 0) && header) { row.setBackground(j, getDisplay().getSystemColor(SWT.COLOR_GRAY)); } } } for (int i = 0; i < columncount; i++) { table.getColumn(i).pack(); } table.pack(); Rectangle rect = table.getItem(rowcount - 1).getBounds(columncount - 1); table.setSize(rect.x + rect.width + 5, rect.y + rect.height + 5); page.replaceTextRange(start, end - start, " "); page.addTable(table, start); } protected TextBox insertBox(int x, int y, int w, int h){ TextBox box = insertBox(); w = Math.min(page.getSize().x, w); h = Math.min(page.getSize().y, h); x = Math.max(0, Math.min(page.getSize().x - w, x)); y = Math.max(0, Math.min(page.getSize().y - h, y)); box.forceLocation(x, y); box.setSize(w, h); return box; } private void deleteBox(){ StyledText text = lastSelectedText; if (text instanceof TextBox) { page.textBoxes.remove(text); text.dispose(); if (!page.textBoxes.isEmpty()) { (page.textBoxes.get(page.textBoxes.size() - 1)).forceFocus(); } updateControls(); } } public void setSelectedText(final EStyledText text){ lastSelectedText = text; } private void updateStylesOnText(){ int fontStyle = (isBold ? SWT.BOLD : SWT.NONE) | (isItalic ? SWT.ITALIC : SWT.NONE); StyledText text = lastSelectedText; Point sel = text.getSelectionRange(); if ((sel == null) || (sel.y == 0)) { return; } StyleRange style = new StyleRange(); for (int i = sel.x; i < sel.x + sel.y; i++) { StyleRange range = text.getStyleRangeAtOffset(i); style.start = i; style.length = 1; if (range != null) { style = (StyleRange) range.clone(); } style.fontStyle = fontStyle; style.underline = isUnderline; style.font = new Font(getDisplay(), fontName, fontHeight, fontStyle); text.setStyleRange(style); } } private void updateControls(){ StyledText text = lastSelectedText; if (text.getCharCount() == 0) { return; } StyleRange style = text.getStyleRangeAtOffset(Math.max(0, text.getCaretOffset() - 1)); if (style == null) { style = new StyleRange(); } isBold = (style.fontStyle & SWT.BOLD) != 0; isItalic = (style.fontStyle & SWT.ITALIC) != 0; isUnderline = style.underline; if ((style.font != null) && (style.font.getFontData() != null) && (style.font.getFontData().length > 0)) { FontData data = style.font.getFontData()[0]; isBold = (data.getStyle() & SWT.BOLD) != 0; isItalic = (data.getStyle() & SWT.ITALIC) != 0; fontName = data.getName(); fontHeight = data.getHeight(); } boldToolItem.setSelection(isBold); italicToolItem.setSelection(isItalic); underlineToolItem.setSelection(isUnderline); fontCombo.select(fontCombo.indexOf(fontName != null ? fontName : "")); fontHeigtCombo.select(fontHeigtCombo.indexOf(String.valueOf(fontHeight))); } public void caretUpdate(final Event ev){ updateControls(); } /* * Cache the style information for text that has been cutToolItem or copied. */ void handleCutCopy(final StyledText text){ // Save the cutToolItem/copied style info so that during pasteToolItem we will // maintain // the style information. Cut/copied text is put in the clipboard in // RTF format, but is not pasted in RTF format. The other way to // handle the pasting of styles would be to access the Clipboard // directly and // parse the RTF text. cachedStyles.clear(); Point sel = text.getSelectionRange(); int startX = sel.x; for (int i = sel.x; i <= sel.x + sel.y - 1; i++) { StyleRange style = text.getStyleRangeAtOffset(i); if (style != null) { style.start = style.start - startX; if (!cachedStyles.isEmpty()) { StyleRange lastStyle = cachedStyles.lastElement(); if (lastStyle.similarTo(style) && (lastStyle.start + lastStyle.length == style.start)) { lastStyle.length++; } else { cachedStyles.addElement(style); } } else { cachedStyles.addElement(style); } } } } public void modifyText(final ExtendedModifyEvent event){ StyledText text = (StyledText) event.widget; if (event.length == 0) { return; } StyleRange style; if ((event.length == 1) || text.getTextRange(event.start, event.length).equals(text.getLineDelimiter())) { // Have the new text take on the style of the text to its right // (during // typing) if no style information is active. int caretOffset = text.getCaretOffset() - 1; style = null; if (caretOffset < text.getCharCount()) { style = text.getStyleRangeAtOffset(caretOffset); } if (style != null) { style = (StyleRange) style.clone(); style.start = event.start; style.length = event.length; } else { style = new StyleRange(event.start, event.length, null, null, SWT.NORMAL); } if (isBold) { style.fontStyle |= SWT.BOLD; } if (isItalic) { style.fontStyle |= SWT.ITALIC; } style.underline = isUnderline; style.font = new Font(getDisplay(), fontName, fontHeight, style.fontStyle); if (!style.isUnstyled()) { text.setStyleRange(style); } } else { // pasteToolItem occurring, have text take on the styles it had when it was // cutToolItem/copied if (!cachedStyles.isEmpty()) { for (int i = 0; i < cachedStyles.size(); i++) { style = cachedStyles.elementAt(i); StyleRange newStyle = (StyleRange) style.clone(); newStyle.start = style.start + event.start; text.setStyleRange(newStyle); } } else { text.setSelection(event.start, event.start + event.length); updateStylesOnText(); } } updateControls(); } public boolean clear(){ page.clear(); return true; } } // test find/replace // System.out.println(ElexisTextPlugin.tempInstance.findOrReplace("a*b", new // ReplaceCallback() { // public String replace(String in) { // return "gaga"; // }})); // test insertText // ElexisTextPlugin.tempInstance.setFont("Courier", SWT.BOLD, 24); // ElexisTextPlugin.Pos pos = (Pos) // ElexisTextPlugin.tempInstance.insertTextAt(100, 1000, 200, 200, // "\nHello\n box\n", 0); // ElexisTextPlugin.tempInstance.setFont("Tahoma", SWT.ITALIC, 8); // ElexisTextPlugin.tempInstance.insertText(pos, "Tahoma text", 0); // test storeToByteArray() // byte[] array = // ElexisTextPlugin.tempInstance.storeToByteArray(); // try { // FileOutputStream fout = new // FileOutputStream("./test.dat"); // fout.write(array); // fout.close(); // } catch (Exception ex) { // ex.printStackTrace(); // } // test load from byte array // try { // FileInputStream fin = new FileInputStream("./test.dat"); // ByteArrayOutputStream bout = new ByteArrayOutputStream(); // byte[] buff = new byte[4096]; // int len = 0; // while ((len = fin.read(buff)) > 0) { // bout.write(buff, 0, len); // } // fin.close(); // bout.close(); // ElexisTextPlugin.tempInstance.loadFromByteArray(bout.toByteArray(), // false); // } catch (Exception ex) { // ex.printStackTrace(); // }