錯誤標識(Error Marking)
Error Marking用來對編輯的文檔根據一定的規則進行驗證,比如對于XML文檔來說,可能是XML DTD或者XML Schema.其實現跟內容大綱比較類似,首先在解析文檔的時候對error加以標識.這里我們使用了SAX ErrorHandler來收集和定位所有的error, 接著在生成內容大綱的同時進行驗證和error marking,這個工作在文檔被加載和文檔保存的時候都會進行.
在XMLEditor的validateAndMark()方法中完成對error marking的初始化:
- protected void validateAndMark()
- {
- IDocument document = getInputDocument();
- MarkingErrorHandler markingErrorHandler =
- new MarkingErrorHandler(getInputFile(), document);
- markingErrorHandler.removeExistingMarkers();
- XMLParser parser = new XMLParser();
- parser.setErrorHandler(markingErrorHandler);
- String text = document.get();
- parser.doParse(text);
- }
MarkingErrorHandler的實例化需要兩個參數:一個是IFile實例,用來執行marking(Eclipse Marker API將通過IFile來引用底層的Resource對象),另一個是編輯的IDocument實例(用來確定插入到文檔中的marker的位置)
在文檔被解析之前,已有的error marker都必須先清掉, 在解析文檔的時候如果發現錯誤,將調用MarkingErrorHandler的handleError()方法:
- protected void handleError(SAXParseException e, boolean isFatal)
- {
- int lineNumber = e.getLineNumber();
- int columnNumber = e.getColumnNumber();
- Map map = new HashMap();
- MarkerUtilities.setLineNumber(map, lineNumber);
- MarkerUtilities.setMessage(map, e.getMessage());
- map.put(IMarker.MESSAGE, e.getMessage());
- map.put(IMarker.LOCATION, file.getFullPath().toString());
- Integer charStart = getCharStart(lineNumber, columnNumber);
- if (charStart != null)
- map.put(IMarker.CHAR_START, charStart);
- Integer charEnd = getCharEnd(lineNumber, columnNumber);
- if (charEnd != null)
- map.put(IMarker.CHAR_END, charEnd);
- map.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
- try
- {
- MarkerUtilities.createMarker(file, map, ERROR_MARKER_ID);
- }
- catch (CoreException ee)
- {
- ee.printStackTrace();
- }
- }
這里我們的編輯器通過XML解析器(Xerces)不僅取得了error信息,而且還得到了發生錯誤的位置信息,因此上面的代碼看起來非常的清晰:首先取得錯誤信息的行號和列號,然后使用Eclipse Marker API創建一個Error Marker
內容輔助
最后我們將要介紹的一個功能是內容輔助, 下圖是我們的實現效果, 這里我們只是一個簡單的實現,對于一個商業的XML編輯器來說,更強悍的就是能夠根據當前光標的位置以及定義的DTD做更精確的內容輔助
為了讓我們的內容輔助功能做的更智能,我們需要知道當前文檔的結構以及當前光標在文檔結構中的位置
跟其他功能類似,內容輔助功能也是通過SourceViewerConfiguration來提供的,下面是我們的實現代碼:
- public IContentAssistant getContentAssistant(ISourceViewer sourceViewer)
- {
- ContentAssistant assistant = new ContentAssistant();
- IContentAssistProcessor tagContentAssistProcessor
- = new TagContentAssistProcessor(getXMLTagScanner());
- assistant.setContentAssistProcessor(tagContentAssistProcessor,
- XMLPartitionScanner.XML_START_TAG);
- assistant.enableAutoActivation(true);
- assistant.setAutoActivationDelay(500);
- assistant.setProposalPopupOrientation(IContentAssistant.CONTEXT_INFO_BELOW);
- assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_BELOW);
- return assistant;
- }
上面的代碼比較簡單,首先創建一個ContentAssistant實例,然后設置一些UI屬性,這里主要注意IContentAssistProcessor的實現,我們實現的內容輔助只是針對節點,而且內容輔助也是建立在對編輯文檔的分割處理的基礎上.分割處理我們前面已經講的夠多了,這里我們就不再做說明
內容輔助的UI處理都在ContentAssistant中實現,一般情況下我們不需要子類化,除非當前的功能無法滿足我們的要求
內容輔助的智能之處主要體現IContentAssistProcessor的實現上,而一般我們最感興趣的就是ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset);方法,內容輔助的提示內容列表就是在該方法中提供,這里是我們的代碼實現:
- public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset)
- {
- IDocument document = viewer.getDocument();
- boolean isAttribute = isAttribute(offset, document);
- TextInfo currentText = currentText(document, offset);
- if (!isAttribute)
- {
- List allElements = dtdTree.getAllElements();
- ICompletionProposal[] result = new ICompletionProposal[allElements.size()];
- int i = 0;
- for (Iterator iter = allElements.iterator(); iter.hasNext();)
- {
- XMLElement element = (XMLElement) iter.next();
- String name = element.getName();
- String text = "" + name + ">" + "</" + name + ">";
- }
- result[i++] = new CompletionProposal(text,
- currentText.documentOffset,
- currentText.text.length(),
- text.length());
- }
- return result;
- }
- else
- {
- List allAttributes = dtdTree.getAllAttributes();
- ICompletionProposal[] result = new ICompletionProposal[allAttributes.size()];
- int i = 0;
- for (Iterator iter = allAttributes.iterator(); iter.hasNext();)
- {
- String name = (String) iter.next();
- String text = name + "= \"\" ";
- result[i++] = new CompletionProposal(text,
- currentText.documentOffset,
- currentText.text.length(),
- text.length());
- }
- return result;
- }
- }
上面的代碼非常的簡單,首先根據當前位置是否為屬性,是則列出已知的所有屬性名,否則列出所有的節點名.
當然這里我們的做法非常簡單,更高級的實現是對整個文檔進行掃描來確定當前光標在整個文檔結構中所處的位置, 然后使用DTD驗證計算當前需要提示的更精確的內容列表, 這就需要根據DTD來理解我們的文檔
總結
構建一個強大的文本編輯器在Eclipse插件開發中常常會碰到, 而JFace Text Editor是我們展開工作的基礎, 它是Eclipse非常強大,非常重要的一套API, 同時也是非常復雜的一套API.
這里我們從Eclipse PDE提供的XML Editor向導例子入手,通過對其進行擴展, 演示了高亮顯示, 內容格式化, 內容大綱, 錯誤標記, 內容輔助幾個功能的實現, 希望這篇文章對你來實現自己強大的文本編輯器能有所幫助
安徽新華電腦學校專業職業規劃師為你提供更多幫助【在線咨詢】