一个简单的编辑器 : 格式文本 « SWT « Java 教程

En
Java 教程
1. 语言基础
2. 数据类型
3. 操作符
4. 流程控制
5. 类定义
6. 开发相关
7. 反射
8. 正则表达式
9. 集合
10. 线
11. 文件
12. 泛型
13. 本土化
14. Swing
15. Swing事件
16. 二维图形
17. SWT
18. SWT 二维图形
19. 网络
20. 数据库
21. Hibernate
22. JPA
23. JSP
24. JSTL
25. Servlet
26. Web服务SOA
27. EJB3
28. Spring
29. PDF
30. 电子邮件
31. 基于J2ME
32. J2EE应用
33. XML
34. 设计模式
35. 日志
36. 安全
37. Apache工具
38. 蚂蚁编译
39. JUnit单元测试
Java
Java 教程 » SWT » 格式文本 
17. 42. 16. 一个简单的编辑器
一个简单的编辑器
//Code revised from
/*
The Definitive Guide to SWT and JFace
by Robert Harris and Rob Warner 
Apress 2004
*/
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Stack;
import java.util.StringTokenizer;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ExtendedModifyEvent;
import org.eclipse.swt.custom.ExtendedModifyListener;
import org.eclipse.swt.custom.LineStyleEvent;
import org.eclipse.swt.custom.LineStyleListener;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextPrintOptions;
import org.eclipse.swt.events.ArmEvent;
import org.eclipse.swt.events.ArmListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;

public class PmpEditor {
  // The number of operations that can be undone
  private static final int UNDO_LIMIT = 500;

  // Contains a reference to this application
  private static PmpEditor app;

  // Contains a reference to the main window
  private Shell shell;

  // Displays the file
  private StyledText st;

  // The full path of the current file
  private String filename;

  // The font for the StyledText
  private Font font;

  // The label to display statistics
  private Label status;

  // The print options and printer
  private StyledTextPrintOptions options;

  private Printer printer;

  // The stack used to store the undo information
  private Stack changes;

  // Flag to set before performaing an undo, so the undo
  // operation doesn't get stored with the rest of the undo
  // information
  private boolean ignoreUndo = false;

  // Syntax data for the current extension
  private SyntaxData sd;

  // Line style listener
  private PmpeLineStyleListener lineStyleListener;

  /**
   * Gets the reference to this application
   
   @return HexEditor
   */
  public static PmpEditor getApp() {
    return app;
  }

  /**
   * Constructs a PmpEditor
   */
  public PmpEditor() {
    app = this;
    changes = new Stack();

    // Set up the printing options
    options = new StyledTextPrintOptions();
    options.footer = StyledTextPrintOptions.SEPARATOR + StyledTextPrintOptions.PAGE_TAG
        + StyledTextPrintOptions.SEPARATOR + "Confidential";
  }

  /**
   * Runs the application
   */
  public void run() {
    Display display = new Display();
    shell = new Shell(display);
    // Choose a monospaced font
    font = new Font(display, "Terminal"12, SWT.NONE);

    createContents(shell);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    font.dispose();
    display.dispose();
    if (printer != null)
      printer.dispose();
  }

  /**
   * Creates the main window's contents
   
   @param shell
   *          the main window
   */
  private void createContents(Shell shell) {
    // Set the layout and the menu bar
    shell.setLayout(new FormLayout());
    shell.setMenuBar(new PmpEditorMenu(shell).getMenu());

    // Create the status bar
    status = new Label(shell, SWT.BORDER);
    FormData data = new FormData();
    data.left = new FormAttachment(00);
    data.right = new FormAttachment(1000);
    data.bottom = new FormAttachment(1000);
    data.height = status.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
    status.setLayoutData(data);

    // Create the styled text
    st = new StyledText(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
    data = new FormData();
    data.left = new FormAttachment(0);
    data.right = new FormAttachment(100);
    data.top = new FormAttachment(0);
    data.bottom = new FormAttachment(status);
    st.setLayoutData(data);

    // Set the font
    st.setFont(font);

    // Add Brief delete next word
    // Use SWT.MOD1 instead of SWT.CTRL for portability
    st.setKeyBinding('k' | SWT.MOD1, ST.DELETE_NEXT);

    // Add vi end of line (kind of)
    // Use SWT.MOD1 instead of SWT.CTRL for portability
    // Use SWT.MOD2 instead of SWT.SHIFT for portability
    // Shift+4 is $
    st.setKeyBinding('4' | SWT.MOD1 | SWT.MOD2, ST.LINE_END);

    // Handle key presses
    st.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent event) {
        // Update the status bar
        updateStatus();
      }
    });

    // Handle text modifications
    st.addModifyListener(new ModifyListener() {
      public void modifyText(ModifyEvent event) {
        // Update the status bar
        updateStatus();

        // Update the comments
        if (lineStyleListener != null) {
          lineStyleListener.refreshMultilineComments(st.getText());
          st.redraw();
        }
      }
    });

    // Store undo information
    st.addExtendedModifyListener(new ExtendedModifyListener() {
      public void modifyText(ExtendedModifyEvent event) {
        if (!ignoreUndo) {
          // Push this change onto the changes stack
          changes.push(new TextChange(event.start, event.length, event.replacedText));
          if (changes.size() > UNDO_LIMIT)
            changes.remove(0);
        }
      }
    });

    // Update the title bar and the status bar
    updateTitle();
    updateStatus();
  }

  /**
   * Opens a file
   */
  public void openFile() {
    FileDialog dlg = new FileDialog(shell);
    String temp = dlg.open();
    if (temp != null) {
      try {
        // Get the file's contents
        String text = PmpeIoManager.getFile(temp);
        // File loaded, so save the file name
        filename = temp;

        // Update the syntax properties to use
        updateSyntaxData();

        // Put the new file's data in the StyledText
        st.setText(text);

        // Update the title bar
        updateTitle();

        // Delete any undo information
        changes.clear();
      catch (IOException e) {
        showError(e.getMessage());
      }
    }
  }

  /**
   * Saves a file
   */
  public void saveFile() {
    if (filename == null) {
      saveFileAs();
    else {
      try {
        // Save the file and update the title bar based on the new file name
        PmpeIoManager.saveFile(filename, st.getText().getBytes());
        updateTitle();
      catch (IOException e) {
        showError(e.getMessage());
      }
    }
  }

  /**
   * Saves a file under a different name
   */
  public void saveFileAs() {
    FileDialog dlg = new FileDialog(shell);
    if (filename != null) {
      dlg.setFileName(filename);
    }
    String temp = dlg.open();
    if (temp != null) {
      filename = temp;

      // The extension may have changed; update the syntax data accordingly
      updateSyntaxData();
      saveFile();
    }
  }

  /**
   * Prints the document to the default printer
   */
  public void print() {
    if (printer == null)
      printer = new Printer();
    options.header = StyledTextPrintOptions.SEPARATOR + filename + StyledTextPrintOptions.SEPARATOR;
    st.print(printer, options).run();
  }

  /**
   * Cuts the current selection to the clipboard
   */
  public void cut() {
    st.cut();
  }

  /**
   * Copies the current selection to the clipboard
   */
  public void copy() {
    st.copy();
  }

  /**
   * Pastes the clipboard's contents
   */
  public void paste() {
    st.paste();
  }

  /**
   * Selects all the text
   */
  public void selectAll() {
    st.selectAll();
  }

  /**
   * Undoes the last change
   */
  public void undo() {
    // Make sure undo stack isn't empty
    if (!changes.empty()) {
      // Get the last change
      TextChange change = (TextChangechanges.pop();

      // Set the flag. Otherwise, the replaceTextRange call will get placed
      // on the undo stack
      ignoreUndo = true;
      // Replace the changed text
      st.replaceTextRange(change.getStart(), change.getLength(), change.getReplacedText());

      // Move the caret
      st.setCaretOffset(change.getStart());

      // Scroll the screen
      st.setTopIndex(st.getLineAtOffset(change.getStart()));
      ignoreUndo = false;
    }
  }

  /**
   * Toggles word wrap
   */
  public void toggleWordWrap() {
    st.setWordWrap(!st.getWordWrap());
  }

  /**
   * Gets the current word wrap settings
   
   @return boolean
   */
  public boolean getWordWrap() {
    return st.getWordWrap();
  }

  /**
   * Shows an about box
   */
  public void about() {
    MessageBox mb = new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK);
    mb.setMessage("Poor Man's Programming Editor");
    mb.open();
  }

  /**
   * Updates the title bar
   */
  private void updateTitle() {
    String fn = filename == null "Untitled" : filename;
    shell.setText(fn + " -- PmPe");
  }

  /**
   * Updates the status bar
   */
  private void updateStatus() {
    // Show the offset into the file, the total number of characters in the
    // file,
    // the current line number (1-based) and the total number of lines
    StringBuffer buf = new StringBuffer();
    buf.append("Offset: ");
    buf.append(st.getCaretOffset());
    buf.append("\tChars: ");
    buf.append(st.getCharCount());
    buf.append("\tLine: ");
    buf.append(st.getLineAtOffset(st.getCaretOffset()) 1);
    buf.append(" of ");
    buf.append(st.getLineCount());
    status.setText(buf.toString());
  }

  /**
   * Updates the syntax data based on the filename's extension
   */
  private void updateSyntaxData() {
    // Determine the extension of the current file
    String extension = "";
    if (filename != null) {
      int pos = filename.lastIndexOf(".");
      if (pos > -&& pos < filename.length() 2) {
        extension = filename.substring(pos + 1);
      }
    }

    // Get the syntax data for the extension
    sd = SyntaxManager.getSyntaxData(extension);

    // Reset the line style listener
    if (lineStyleListener != null) {
      st.removeLineStyleListener(lineStyleListener);
    }
    lineStyleListener = new PmpeLineStyleListener(sd);
    st.addLineStyleListener(lineStyleListener);

    // Redraw the contents to reflect the new syntax data
    st.redraw();
  }

  /**
   * Shows an error message
   
   @param error
   *          the text to show
   */
  private void showError(String error) {
    MessageBox mb = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
    mb.setMessage(error);
    mb.open();
  }

  /**
   * The application entry point
   
   @param args
   *          the command line arguments
   */
  public static void main(String[] args) {
    new PmpEditor().run();
  }
}

class PmpEditorMenu {
  // The underlying menu this class wraps
  Menu menu = null;

  /**
   * Constructs a PmpEditorMenu
   
   @param shell
   *          the parent shell
   */
  public PmpEditorMenu(final Shell shell) {
    // Create the menu
    menu = new Menu(shell, SWT.BAR);

    // Create the File top-level menu
    MenuItem item = new MenuItem(menu, SWT.CASCADE);
    item.setText("File");
    Menu dropMenu = new Menu(shell, SWT.DROP_DOWN);
    item.setMenu(dropMenu);

    // Create File->Open
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Open...\tCtrl+O");
    item.setAccelerator(SWT.CTRL + 'O');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().openFile();
      }
    });

    // Create File->Save
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Save\tCtrl+S");
    item.setAccelerator(SWT.CTRL + 'S');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().saveFile();
      }
    });

    // Create File->Save As
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Save As...");
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().saveFileAs();
      }
    });

    new MenuItem(dropMenu, SWT.SEPARATOR);

    // Create File->Print
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Print\tCtrl+P");
    item.setAccelerator(SWT.CTRL + 'P');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().print();
      }
    });

    new MenuItem(dropMenu, SWT.SEPARATOR);

    // Create File->Exit
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Exit\tAlt+F4");
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        shell.close();
      }
    });

    // Create Edit
    item = new MenuItem(menu, SWT.CASCADE);
    item.setText("Edit");
    dropMenu = new Menu(shell, SWT.DROP_DOWN);
    item.setMenu(dropMenu);

    // Create Edit->Cut
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Cut\tCtrl+X");
    item.setAccelerator(SWT.CTRL + 'X');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().cut();
      }
    });

    // Create Edit->Copy
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Copy\tCtrl+C");
    item.setAccelerator(SWT.CTRL + 'C');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().copy();
      }
    });

    // Create Edit->Paste
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Paste\tCtrl+V");
    item.setAccelerator(SWT.CTRL + 'V');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().paste();
      }
    });

    new MenuItem(dropMenu, SWT.SEPARATOR);

    // Create Select All
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Select All\tCtrl+A");
    item.setAccelerator(SWT.CTRL + 'A');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().selectAll();
      }
    });

    new MenuItem(dropMenu, SWT.SEPARATOR);

    // Create Undo
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("Undo\tCtrl+Z");
    item.setAccelerator(SWT.CTRL + 'Z');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().undo();
      }
    });

    new MenuItem(dropMenu, SWT.SEPARATOR);
    // Create Word Wrap
    final MenuItem wwItem = new MenuItem(dropMenu, SWT.CHECK);
    wwItem.setText("Word Wrap\tCtrl+W");
    wwItem.setAccelerator(SWT.CTRL + 'W');
    wwItem.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().toggleWordWrap();
      }
    });
    wwItem.addArmListener(new ArmListener() {
      public void widgetArmed(ArmEvent event) {
        wwItem.setSelection(PmpEditor.getApp().getWordWrap());
      }
    });

    // Create Help
    item = new MenuItem(menu, SWT.CASCADE);
    item.setText("Help");
    dropMenu = new Menu(shell, SWT.DROP_DOWN);
    item.setMenu(dropMenu);

    // Create Help->About
    item = new MenuItem(dropMenu, SWT.NULL);
    item.setText("About\tCtrl+A");
    item.setAccelerator(SWT.CTRL + 'A');
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        PmpEditor.getApp().about();
      }
    });
  }

  /**
   * Gets the underlying menu
   
   @return Menu
   */
  public Menu getMenu() {
    return menu;
  }
}

class PmpeIoManager {
  /**
   * Gets a file (loads it) from the filesystem
   
   @param filename
   *          the full path of the file
   @return String
   @throws IOException
   *           if file cannot be loaded
   */
  public static String getFile(String filenamethrows IOException {
    InputStream in = new BufferedInputStream(new FileInputStream(filename));
    StringBuffer buf = new StringBuffer();
    int c;
    while ((c = in.read()) != -1) {
      buf.append((charc);
    }
    return buf.toString();
  }

  /**
   * Saves a file
   
   @param filename
   *          the full path of the file to save
   @param data
   *          the data to save
   @throws IOException
   *           if file cannot be saved
   */
  public static void saveFile(String filename, byte[] datathrows IOException {
    File outputFile = new File(filename);
    FileOutputStream out = new FileOutputStream(outputFile);
    out.write(data);
    out.close();
  }
}

class TextChange {
  // The starting offset of the change
  private int start;

  // The length of the change
  private int length;

  // The replaced text
  String replacedText;

  /**
   * Constructs a TextChange
   
   @param start
   *          the starting offset of the change
   @param length
   *          the length of the change
   @param replacedText
   *          the text that was replaced
   */
  public TextChange(int start, int length, String replacedText) {
    this.start = start;
    this.length = length;
    this.replacedText = replacedText;
  }

  /**
   * Returns the start
   
   @return int
   */
  public int getStart() {
    return start;
  }

  /**
   * Returns the length
   
   @return int
   */
  public int getLength() {
    return length;
  }

  /**
   * Returns the replacedText
   
   @return String
   */
  public String getReplacedText() {
    return replacedText;
  }
}

/**
 * This class contains information for syntax coloring and styling for an
 * extension
 */
class SyntaxData {
  private String extension;

  private Collection keywords;

  private String punctuation;

  private String comment;

  private String multiLineCommentStart;

  private String multiLineCommentEnd;

  /**
   * Constructs a SyntaxData
   
   @param extension
   *          the extension
   */
  public SyntaxData(String extension) {
    this.extension = extension;
  }

  /**
   * Gets the extension
   
   @return String
   */
  public String getExtension() {
    return extension;
  }

  /**
   * Gets the comment
   
   @return String
   */
  public String getComment() {
    return comment;
  }

  /**
   * Sets the comment
   
   @param comment
   *          The comment to set.
   */
  public void setComment(String comment) {
    this.comment = comment;
  }

  /**
   * Gets the keywords
   
   @return Collection
   */
  public Collection getKeywords() {
    return keywords;
  }

  /**
   * Sets the keywords
   
   @param keywords
   *          The keywords to set.
   */
  public void setKeywords(Collection keywords) {
    this.keywords = keywords;
  }

  /**
   * Gets the multiline comment end
   
   @return String
   */
  public String getMultiLineCommentEnd() {
    return multiLineCommentEnd;
  }

  /**
   * Sets the multiline comment end
   
   @param multiLineCommentEnd
   *          The multiLineCommentEnd to set.
   */
  public void setMultiLineCommentEnd(String multiLineCommentEnd) {
    this.multiLineCommentEnd = multiLineCommentEnd;
  }

  /**
   * Gets the multiline comment start
   
   @return String
   */
  public String getMultiLineCommentStart() {
    return multiLineCommentStart;
  }

  /**
   * Sets the multiline comment start
   
   @param multiLineCommentStart
   *          The multiLineCommentStart to set.
   */
  public void setMultiLineCommentStart(String multiLineCommentStart) {
    this.multiLineCommentStart = multiLineCommentStart;
  }

  /**
   * Gets the punctuation
   
   @return String
   */
  public String getPunctuation() {
    return punctuation;
  }

  /**
   * Sets the punctuation
   
   @param punctuation
   *          The punctuation to set.
   */
  public void setPunctuation(String punctuation) {
    this.punctuation = punctuation;
  }
}

/**
 * This class manages the syntax coloring and styling data
 */
class SyntaxManager {
  // Lazy cache of SyntaxData objects
  private static Map data = new Hashtable();

  /**
   * Gets the syntax data for an extension
   */
  public static synchronized SyntaxData getSyntaxData(String extension) {
    // Check in cache
    SyntaxData sd = (SyntaxDatadata.get(extension);
    if (sd == null) {
      // Not in cache; load it and put in cache
      sd = loadSyntaxData(extension);
      if (sd != null)
        data.put(sd.getExtension(), sd);
    }
    return sd;
  }

  /**
   * Loads the syntax data for an extension
   
   @param extension
   *          the extension to load
   @return SyntaxData
   */
  private static SyntaxData loadSyntaxData(String extension) {
    SyntaxData sd = null;
    try {
      ResourceBundle rb = ResourceBundle.getBundle("examples.ch11." + extension);
      sd = new SyntaxData(extension);
      sd.setComment(rb.getString("comment"));
      sd.setMultiLineCommentStart(rb.getString("multilinecommentstart"));
      sd.setMultiLineCommentEnd(rb.getString("multilinecommentend"));

      // Load the keywords
      Collection keywords = new ArrayList();
      for (StringTokenizer st = new StringTokenizer(rb.getString("keywords")" "); st
          .hasMoreTokens();) {
        keywords.add(st.nextToken());
      }
      sd.setKeywords(keywords);

      // Load the punctuation
      sd.setPunctuation(rb.getString("punctuation"));
    catch (MissingResourceException e) {
      // Ignore
    }
    return sd;
  }
}

/**
 * This class performs the syntax highlighting and styling for Pmpe
 */
class PmpeLineStyleListener implements LineStyleListener {
  // Colors
  private static final Color COMMENT_COLOR = Display.getCurrent().getSystemColor(
      SWT.COLOR_DARK_GREEN);

  private static final Color COMMENT_BACKGROUND = Display.getCurrent().getSystemColor(
      SWT.COLOR_GRAY);

  private static final Color PUNCTUATION_COLOR = Display.getCurrent().getSystemColor(
      SWT.COLOR_DARK_CYAN);

  private static final Color KEYWORD_COLOR = Display.getCurrent().getSystemColor(
      SWT.COLOR_DARK_MAGENTA);

  // Holds the syntax data
  private SyntaxData syntaxData;

  // Holds the offsets for all multiline comments
  List commentOffsets;

  /**
   * PmpeLineStyleListener constructor
   
   @param syntaxData
   *          the syntax data to use
   */
  public PmpeLineStyleListener(SyntaxData syntaxData) {
    this.syntaxData = syntaxData;
    commentOffsets = new LinkedList();
  }

  /**
   * Refreshes the offsets for all multiline comments in the parent StyledText.
   * The parent StyledText should call this whenever its text is modified. Note
   * that this code doesn't ignore comment markers inside strings.
   
   @param text
   *          the text from the StyledText
   */
  public void refreshMultilineComments(String text) {
    // Clear any stored offsets
    commentOffsets.clear();

    if (syntaxData != null) {
      // Go through all the instances of COMMENT_START
      for (int pos = text.indexOf(syntaxData.getMultiLineCommentStart()); pos > -1; pos = text
          .indexOf(syntaxData.getMultiLineCommentStart(), pos)) {
        // offsets[0] holds the COMMENT_START offset
        // and COMMENT_END holds the ending offset
        int[] offsets = new int[2];
        offsets[0= pos;

        // Find the corresponding end comment.
        pos = text.indexOf(syntaxData.getMultiLineCommentEnd(), pos);

        // If no corresponding end comment, use the end of the text
        offsets[1= pos == -? text.length() : pos
            + syntaxData.getMultiLineCommentEnd().length() 1;
        pos = offsets[1];
        // Add the offsets to the collection
        commentOffsets.add(offsets);
      }
    }
  }

  /**
   * Checks to see if the specified section of text begins inside a multiline
   * comment. Returns the index of the closing comment, or the end of the line
   * if the whole line is inside the comment. Returns -1 if the line doesn't
   * begin inside a comment.
   
   @param start
   *          the starting offset of the text
   @param length
   *          the length of the text
   @return int
   */
  private int getBeginsInsideComment(int start, int length) {
    // Assume section doesn't being inside a comment
    int index = -1;

    // Go through the multiline comment ranges
    for (int i = 0, n = commentOffsets.size(); i < n; i++) {
      int[] offsets = (int[]) commentOffsets.get(i);

      // If starting offset is past range, quit
      if (offsets[0> start + length)
        break;
      // Check to see if section begins inside a comment
      if (offsets[0<= start && offsets[1>= start) {
        // It does; determine if the closing comment marker is inside
        // this section
        index = offsets[1> start + length ? start + length : offsets[1]
            + syntaxData.getMultiLineCommentEnd().length() 1;
      }
    }
    return index;
  }

  /**
   * Called by StyledText to get styles for a line
   */
  public void lineGetStyle(LineStyleEvent event) {
    // Only do styles if syntax data has been loaded
    if (syntaxData != null) {
      // Create collection to hold the StyleRanges
      List styles = new ArrayList();

      int start = 0;
      int length = event.lineText.length();

      // Check if line begins inside a multiline comment
      int mlIndex = getBeginsInsideComment(event.lineOffset, event.lineText.length());
      if (mlIndex > -1) {
        // Line begins inside multiline comment; create the range
        styles.add(new StyleRange(event.lineOffset, mlIndex - event.lineOffset, COMMENT_COLOR,
            COMMENT_BACKGROUND));
        start = mlIndex;
      }
      // Do punctuation, single-line comments, and keywords
      while (start < length) {
        // Check for multiline comments that begin inside this line
        if (event.lineText.indexOf(syntaxData.getMultiLineCommentStart(), start== start) {
          // Determine where comment ends
          int endComment = event.lineText.indexOf(syntaxData.getMultiLineCommentEnd(), start);

          // If comment doesn't end on this line, extend range to end of line
          if (endComment == -1)
            endComment = length;
          else
            endComment += syntaxData.getMultiLineCommentEnd().length();
          styles.add(new StyleRange(event.lineOffset + start, endComment - start, COMMENT_COLOR,
              COMMENT_BACKGROUND));

          // Move marker
          start = endComment;
        }
        // Check for single line comments
        else if (event.lineText.indexOf(syntaxData.getComment(), start== start) {
          // Comment rest of line
          styles.add(new StyleRange(event.lineOffset + start, length - start, COMMENT_COLOR,
              COMMENT_BACKGROUND));

          // Move marker
          start = length;
        }
        // Check for punctuation
        else if (syntaxData.getPunctuation().indexOf(event.lineText.charAt(start)) > -1) {
          // Add range for punctuation
          styles.add(new StyleRange(event.lineOffset + start, 1, PUNCTUATION_COLOR, null));
          ++start;
        else if (Character.isLetter(event.lineText.charAt(start))) {
          // Get the next word
          StringBuffer buf = new StringBuffer();
          int i = start;
          // Call any consecutive letters a word
          for (; i < length && Character.isLetter(event.lineText.charAt(i)); i++) {
            buf.append(event.lineText.charAt(i));
          }
          // See if the word is a keyword
          if (syntaxData.getKeywords().contains(buf.toString())) {
            // It's a keyword; create the StyleRange
            styles.add(new StyleRange(event.lineOffset + start, i - start, KEYWORD_COLOR, null,
                SWT.BOLD));
          }
          // Move the marker to the last char (the one that wasn't a letter)
          // so it can be retested in the next iteration through the loop
          start = i;
        else
          // It's nothing we're interested in; advance the marker
          ++start;
      }

      // Copy the StyleRanges back into the event
      event.styles = (StyleRange[]) styles.toArray(new StyleRange[0]);
    }
  }
}
17. 42. 格式文本
17. 42. 1. 创建StyledText控件
17. 42. 2. Create a StyledText that scrolls vertically, wraps text, and displays a border:Create a StyledText that scrolls vertically, wraps text, and displays a border:
17. 42. 3. 使用剪贴板使用剪贴板
17. 42. 4. 画一个文本框画一个文本框
17. 42. 5. StyledText:嵌入图像StyledText:嵌入图像
17. 42. 6. StyledText:使用梯度背景StyledText:使用梯度背景
17. 42. 7. StyledText:嵌入控件StyledText:嵌入控件
17. 42. 8. Getting Statistics: Caret Offset, Total Lines of Text, Total Characters and Current LineGetting Statistics: Caret Offset, Total Lines of Text, Total Characters and Current Line
17. 42. 9. 打印StyledText打印StyledText
17. 42. 10. 在一个单独的线程打印到默认打印机
17. 42. 11. 设置页面格式,打印
17. 42. 12. StyledText只读
17. 42. 13. 限制字符数限制字符数
17. 42. 14. 替换文字范围替换文字范围
17. 42. 15. Understanding the Repercussions
17. 42. 16. 一个简单的编辑器一个简单的编辑器
www.java2java.com | Contact Us
Copyright 2010 - 2030 Java Source and Support. All rights reserved.
All other trademarks are property of their respective owners.