/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: ErrorLoggerTree.java * * Copyright (c) 2006 Sun Microsystems and Static Free Software * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.user.ui; import com.sun.electric.Main; import com.sun.electric.database.change.DatabaseChangeEvent; import com.sun.electric.database.change.DatabaseChangeListener; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.EDatabase; import com.sun.electric.database.id.CellId; import com.sun.electric.database.text.TextUtils; import com.sun.electric.tool.Job; import com.sun.electric.tool.drc.DRC; import com.sun.electric.tool.io.FileType; import com.sun.electric.tool.user.ErrorHighlight; import com.sun.electric.tool.user.ErrorLogger; import com.sun.electric.tool.user.Highlighter; import com.sun.electric.tool.user.UserInterfaceMain; import com.sun.electric.tool.user.ErrorLogger.MessageLog; import com.sun.electric.tool.user.dialogs.OpenFile; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; /** * Class to define a collection of highlighted errors in the Explorer tree. */ // ----------------------------- Explorer Tree Stuff --------------------------- public class ErrorLoggerTree { public static final String errorNode = "ERRORS"; /** Top of error tree */ private static final DefaultMutableTreeNode errorTree = new DefaultMutableTreeNode(errorNode); /** Path to error tree */ private static final TreePath errorPath = (new TreePath(ExplorerTreeModel.rootNode)).pathByAddingChild(errorTree); /** Current Logger */ static DefaultMutableTreeNode currentLogger; private static final ErrorLogger networkErrorLogger = ErrorLogger.newInstance("Network Errors"); // private static final ErrorLogger drcErrorLogger = ErrorLogger.newInstance("DRC (incremental)"); private static DefaultMutableTreeNode networkTree; private static DefaultMutableTreeNode drcTree; // public methods called from any thread public static boolean hasLogger(ErrorLogger logger) { return indexOf(logger) >= 0; }; public static void addLogger(ErrorLogger logger, boolean explain, boolean terminate) { logger.termLogging_(terminate); if (logger.getNumLogs() == 0) return; SwingUtilities.invokeLater(new AddLogger(logger, explain)); }; public static void updateNetworkErrors(Cell cell, List<ErrorLogger.MessageLog> errors) { SwingUtilities.invokeLater(new UpdateNetwork(cell.getId(), errors)); } public static void updateDrcErrors(Cell cell, List<ErrorLogger.MessageLog> newErrors, List<MessageLog> delErrors) { SwingUtilities.invokeLater(new UpdateDrc(cell.getId(), newErrors, delErrors)); } // public methods called from GUI thread public static DefaultMutableTreeNode getExplorerTree() { return errorTree; } /** * Method to advance to the next error and report it. */ public static void reportSingleGeometry(boolean separateWindow) { if (currentLogger == null) { System.out.println("No errors to report"); return; } ((ErrorLoggerTreeNode)currentLogger.getUserObject()).reportSingleGeometry_(true, separateWindow); } /** * Method to advance to the next error and report it. * @param separateWindow true to show each cell in its own window; false to show in the current window. */ public static String reportNextMessage(boolean separateWindow) { if (currentLogger == null) return "No errors to report"; return ((ErrorLoggerTreeNode)currentLogger.getUserObject()).reportNextMessage_(true, separateWindow); } /** * Method to back up to the previous error and report it. * @param separateWindow true to show each cell in its own window; false to show in the current window. */ public static String reportPrevMessage(boolean separateWindow) { if (currentLogger == null) return "No errors to report"; return ((ErrorLoggerTreeNode)currentLogger.getUserObject()).reportPrevMessage_(separateWindow); } /** * Method to show the current collection of errors. */ public static void showCurrentErrors() { WindowFrame wf = WindowFrame.getCurrentWindowFrame(); if (wf == null) return; if (currentLogger == null) return; Job.getUserInterface().getCurrentEditWindow_().clearHighlighting(); ErrorLoggerTreeNode node = (ErrorLoggerTreeNode)ErrorLoggerTree.currentLogger.getUserObject(); int index = indexOf(node); highlightLogger(index, -1); Job.getUserInterface().getCurrentEditWindow_().finishedHighlighting(); } private static class AddLogger implements Runnable { private ErrorLogger logger; private boolean explain; AddLogger(ErrorLogger logger, boolean explain) { this.logger = logger; this.explain = explain; } public void run() { int i = indexOf(logger); if (i >= 0) { updateTree((DefaultMutableTreeNode)errorTree.getChildAt(i)); } else { addLogger(errorTree.getChildCount(), logger); if (explain) explain(logger); } } } private static void explain(ErrorLogger logger) { // To print consistent message in message window String extraMsg = "errors/warnings"; if (logger.getNumErrors() == 0) extraMsg = "warnings"; else if (logger.getNumWarnings() == 0) extraMsg = "errors"; String msg = logger.getInfo(); System.out.println(msg); if (logger.getNumLogs() > 0) { System.out.println("Type > and < to step through " + extraMsg + ", or open the ERRORS view in the explorer"); } if (logger.getNumErrors() > 0) { JOptionPane.showMessageDialog(Main.getCurrentJFrame(), msg, logger.getSystem() + " finished with Errors", JOptionPane.INFORMATION_MESSAGE); } } private static class UpdateNetwork implements Runnable { private CellId cellId; private List<ErrorLogger.MessageLog> errors; UpdateNetwork(CellId cellId, List<ErrorLogger.MessageLog> errors) { this.cellId = cellId; this.errors = new ArrayList<ErrorLogger.MessageLog>(errors); } public void run() { Cell cell = EDatabase.clientDatabase().getCell(cellId); if (cell == null) return; boolean changed = networkErrorLogger.clearLogs(cell) || !errors.isEmpty(); networkErrorLogger.addMessages(errors); if (!changed) return; networkErrorLogger.termLogging_(true); if (networkErrorLogger.getNumLogs() == 0) { removeLogger(0); return; } if (networkTree == null) networkTree = addLogger(0, networkErrorLogger); updateTree(networkTree); setCurrent(0); } } private static class UpdateDrc implements Runnable { private CellId cellId; private List<ErrorLogger.MessageLog> newErrors; private List<ErrorLogger.MessageLog> delErrors; UpdateDrc(CellId cId, List<ErrorLogger.MessageLog> newErrs, List<MessageLog> delErrs) { this.cellId = cId; if (newErrs != null) this.newErrors = new ArrayList<ErrorLogger.MessageLog>(newErrs); if (delErrs != null) this.delErrors = new ArrayList<ErrorLogger.MessageLog>(delErrs); } public void run() { Cell cell = EDatabase.clientDatabase().getCell(cellId); if (cell == null) return; ErrorLogger drcErrorLogger = DRC.getDRCIncrementalLogger(); // boolean changed = drcErrorLogger.clearLogs(cell) || (newErrors != null && !newErrors.isEmpty() || // (delErrors != null && !delErrors.isEmpty())); drcErrorLogger.addMessages(newErrors); drcErrorLogger.deleteMessages(delErrors); // if (!changed) return; drcErrorLogger.termLogging_(true); int index = networkTree != null ? 1 : 0; if (drcErrorLogger.getNumLogs() == 0) { if (drcTree != null) removeLogger(errorTree.getIndex(drcTree)); return; } if (drcTree == null) drcTree = addLogger(index, drcErrorLogger); updateTree(drcTree); setCurrent(index); } } private static DefaultMutableTreeNode addLogger(int index, ErrorLogger logger) { ErrorLoggerTreeNode tn = new ErrorLoggerTreeNode(logger); UserInterfaceMain.addDatabaseChangeListener(tn); DefaultMutableTreeNode newNode = new ErrorLoggerDefaultMutableTreeNode(tn); int[] childIndices = new int[] { index }; DefaultMutableTreeNode[] children = new DefaultMutableTreeNode[] { newNode }; setCurrent(-1); errorTree.insert(newNode, index); currentLogger = newNode; ExplorerTreeModel.fireTreeNodesInserted(errorTree, errorPath, childIndices, children); updateTree(newNode); return newNode; } private static void removeLogger(int index) { if (errorTree.getChildCount() <= index) return; // nothing to remove. Case of incremental errors DefaultMutableTreeNode node = (DefaultMutableTreeNode)errorTree.getChildAt(index); ErrorLoggerTreeNode treeNode = (ErrorLoggerTreeNode)node.getUserObject(); UserInterfaceMain.removeDatabaseChangeListener(treeNode); ErrorLogger drcErrorLogger = DRC.getDRCIncrementalLogger(); // Clean DRC incremental logger if (treeNode.getLogger() == drcErrorLogger) { drcErrorLogger.clearAllLogs(); } if (node == networkTree) networkTree = null; if (node == drcTree) drcTree = null; if (node == currentLogger) currentLogger = null; int[] childIndices = new int[] { index }; DefaultMutableTreeNode[] children = new DefaultMutableTreeNode[] { node }; errorTree.remove(index); ExplorerTreeModel.fireTreeNodesRemoved(errorTree, errorPath, childIndices, children); } private static void highlightLogger(int index, int sortKey) { EditWindow ew = EditWindow.getCurrent(); if (ew == null) return; Highlighter h = ew.getHighlighter(); DefaultMutableTreeNode node = (DefaultMutableTreeNode)errorTree.getChildAt(index); ErrorLoggerTreeNode eltn = (ErrorLoggerTreeNode)node.getUserObject(); ErrorLogger el = eltn.getLogger(); EDatabase database = EDatabase.clientDatabase(); for(int i=0; i<el.getNumLogs(); i++) { MessageLog ml = el.getLog(i); if (sortKey >= 0 && ml.getSortKey() != sortKey) continue; for(Iterator<ErrorHighlight> it = ml.getHighlights(); it.hasNext(); ) { ErrorHighlight eh = it.next(); eh.addToHighlighter(h, database); } } } private static void updateTree(DefaultMutableTreeNode loggerNode) { TreePath loggerPath = errorPath.pathByAddingChild(loggerNode); int oldChildCount = loggerNode.getChildCount(); if (oldChildCount != 0) { int[] childIndex = new int[oldChildCount]; DefaultMutableTreeNode[] children = new DefaultMutableTreeNode[oldChildCount]; for (int i = 0; i < oldChildCount; i++) { childIndex[i] = i; children[i] = (DefaultMutableTreeNode)loggerNode.getChildAt(i); } loggerNode.removeAllChildren(); ExplorerTreeModel.fireTreeNodesRemoved(errorTree, loggerPath, childIndex, children); } ErrorLoggerTreeNode eltn = (ErrorLoggerTreeNode)loggerNode.getUserObject(); ErrorLogger logger = eltn.logger; if (logger.getNumLogs() == 0) return; Map<Integer,DefaultMutableTreeNode> sortKeyMap = new HashMap<Integer,DefaultMutableTreeNode>(); Map<Integer,String> sortKeyGroupNamesMap = logger.getSortKeyToGroupNames(); // Extra level for loggers if (sortKeyGroupNamesMap != null) { for (Map.Entry e : sortKeyGroupNamesMap.entrySet()) { String name = (String)e.getValue(); Integer key = (Integer)e.getKey(); DefaultMutableTreeNode grpNode = new DefaultMutableTreeNode(new ErrorLoggerGroupNode(name, key.intValue(), eltn)); loggerNode.add(grpNode); sortKeyMap.put(key, grpNode); } } for (Iterator<ErrorLogger.MessageLog> it = logger.getLogs(); it.hasNext();) { ErrorLogger.MessageLog el = it.next(); // by default, groupNode is entire loggerNode // but, groupNode could be sub-node: DefaultMutableTreeNode groupNode = loggerNode; if (logger.getSortKeyToGroupNames() != null) { groupNode = sortKeyMap.get(new Integer(el.getSortKey())); if (groupNode == null) // not found, put in loggerNode groupNode = loggerNode; } DefaultMutableTreeNode node = new DefaultMutableTreeNode(el); groupNode.add(node); } int newChildCount = loggerNode.getChildCount(); int[] childIndex = new int[newChildCount]; DefaultMutableTreeNode[] children = new DefaultMutableTreeNode[newChildCount]; for (int i = 0; i < newChildCount; i++) { childIndex[i] = i; children[i] = (DefaultMutableTreeNode)loggerNode.getChildAt(i); } ExplorerTreeModel.fireTreeNodesInserted(errorTree, loggerPath, childIndex, children); } private static void setCurrent(int index) { int oldIndex = currentLogger != null ? indexOf((ErrorLoggerTreeNode)currentLogger.getUserObject()) : -1; if (index == oldIndex) return; currentLogger = index >= 0 ? (DefaultMutableTreeNode)errorTree.getChildAt(index) : null; int l = 0; if (oldIndex >= 0) l++; if (index >= 0) l++; int[] childIndex = new int[l]; TreeNode[] children = new TreeNode[l]; l = 0; if (oldIndex >= 0 && oldIndex < index) { childIndex[l] = oldIndex; children[l] = errorTree.getChildAt(oldIndex); l++; } if (index >= 0) { childIndex[l] = index; children[l] = errorTree.getChildAt(index); l++; } if (oldIndex >= 0 && oldIndex > index) { childIndex[l] = oldIndex; children[l] = errorTree.getChildAt(oldIndex); l++; } ExplorerTreeModel.fireTreeNodesChanged(errorTree, errorPath, childIndex, children); } /** Delete this logger */ // private static void delete(ErrorLoggerTreeNode node) { // int index = indexOf(node); // if (index < 0) return; // removeLogger(index); // if (currentLogger != null && ((ErrorLoggerTreeNode)currentLogger.getUserObject()) == node) { // if (errorTree.getChildCount() != 0) // currentLogger = (DefaultMutableTreeNode)errorTree.getChildAt(0); // else // currentLogger = null; // } // } private static int indexOf(ErrorLoggerTreeNode tn) { for (int i = 0, numLoggers = errorTree.getChildCount(); i < numLoggers; i++) if (((DefaultMutableTreeNode)errorTree.getChildAt(i)).getUserObject() == tn) return i; return -1; } private static int indexOf(ErrorLogger logger) { for (int i = 0, numLoggers = errorTree.getChildCount(); i < numLoggers; i++) { DefaultMutableTreeNode defaultMutableTreeNode = (DefaultMutableTreeNode)errorTree.getChildAt(i); ErrorLoggerTreeNode errorLoggerTreeNode = (ErrorLoggerTreeNode)defaultMutableTreeNode.getUserObject(); if (errorLoggerTreeNode.logger == logger) return i; } return -1; } public static void importLogger() { String fileName = OpenFile.chooseInputFile(FileType.XML, "Read ErrorLogger"); if (fileName == null) return; // nothing to load try { ErrorLogger.XMLParser parser = new ErrorLogger.XMLParser(); ErrorLogger logger = parser.process(TextUtils.makeURLToFile(fileName), true); addLogger(logger, false, true); } catch (Exception e) { System.out.println("Error loading " + fileName); return; } } public static class ErrorLoggerDefaultMutableTreeNode extends DefaultMutableTreeNode { ErrorLoggerDefaultMutableTreeNode(ErrorLoggerTreeNode tn) { super(tn); } public boolean isLeaf() { return false; } } public static class ErrorLoggerGroupNode { private String name; private int sortKey; private ErrorLoggerTreeNode parent; ErrorLoggerGroupNode(String s, int k, ErrorLoggerTreeNode p) { name = s; sortKey = k; parent = p; } public int getSortKey() { return sortKey; } public ErrorLoggerTreeNode getParentNode() { return parent; } public boolean equals(Object x) { if (x instanceof ErrorLoggerGroupNode) { ErrorLoggerGroupNode elgn = (ErrorLoggerGroupNode)x; if (elgn.name.equals(name) && elgn.parent == parent) return true; } return false; } public String toString() { return name; } } public static class ErrorLoggerTreeNode implements DatabaseChangeListener //, ActionListener { private ErrorLogger logger; private int currentLogNumber = -1; private ErrorLogger.MessageLog currentMsgLog; private int currentMsgLogGeoIndex; ErrorLoggerTreeNode(ErrorLogger log) { this.logger = log; } public void setLogNumber(int number) { currentLogNumber = number; currentMsgLog = logger.getLog(number); } public ErrorLogger getLogger() { return logger; } public String toString() { return "ErrorLogger Information: " + logger.getInfo();} private int getNextMessageNumber() { int currentLogNumber = this.currentLogNumber; if (currentLogNumber < logger.getNumLogs()-1) { currentLogNumber++; } else { if (logger.getNumLogs() <= 0) return -1; //"No "+logger.getSystem()+" errors"; currentLogNumber = 0; } return currentLogNumber; } private void reportSingleGeometry_(boolean showHigh, boolean separateWindow) { if (currentMsgLog == null) { currentLogNumber = getNextMessageNumber(); if (currentLogNumber < 0) return; // nothing to show. currentMsgLog = logger.getLog(currentLogNumber); currentMsgLogGeoIndex = 0; } Job.getUserInterface().reportLog(currentMsgLog, showHigh, separateWindow, currentMsgLogGeoIndex); currentMsgLogGeoIndex = (currentMsgLogGeoIndex < currentMsgLog.getNumHighlights() - 1) ? currentMsgLogGeoIndex+1 : 0; } private String reportNextMessage_(boolean showHigh, boolean separateWindow) { currentLogNumber = getNextMessageNumber(); if (currentLogNumber < 0) return "No "+logger.getSystem()+" errors"; return reportLog(currentLogNumber, showHigh, separateWindow); } private String reportPrevMessage_(boolean separateWindow) { if (currentLogNumber > 0) { currentLogNumber--; } else { if (logger.getNumLogs() <= 0) return "No "+logger.getSystem()+" errors"; currentLogNumber = logger.getNumLogs() - 1; } return reportLog(currentLogNumber, true, separateWindow); } /** * Report an error */ private String reportLog(int logNumber, boolean showHigh, boolean separateWindow) { if (logNumber < 0 || (logNumber >= logger.getNumLogs())) { return logger.getSystem() + ": no such error or warning "+(logNumber+1)+", only "+logger.getNumLogs()+" errors."; } currentMsgLog = logger.getLog(logNumber); currentMsgLogGeoIndex = 0; String extraMsg = null; if (logNumber < logger.getNumErrors()) { extraMsg = " error " + (logNumber+1) + " of " + logger.getNumErrors(); } else { extraMsg = " warning " + (logNumber+1-logger.getNumErrors()) + " of " + logger.getNumWarnings(); } String message = Job.getUserInterface().reportLog(currentMsgLog, showHigh, separateWindow, -1); return (logger.getSystem() + extraMsg + ": " + message); } public void databaseChanged(DatabaseChangeEvent e) { // check if any errors need to be deleted boolean changed = false; for (int i = logger.getNumLogs() - 1; i >= 0; i--) { MessageLog err = logger.getLog(i); if (!err.isValid(EDatabase.clientDatabase())) { logger.deleteLog(i); if (i < currentLogNumber) currentLogNumber--; else if (i == currentLogNumber) currentLogNumber = 0; changed = true; } } if (!changed) return; int index = indexOf(this); if (index < 0) return; if (logger.getNumLogs() == 0) removeLogger(index); else { // remember the state of the tree WindowFrame wf = WindowFrame.getCurrentWindowFrame(); if (wf != null) { ExplorerTree tree = wf.getExplorerTab(); ExplorerTreeModel etm = tree.model(); ExplorerTree.KeepTreeExpansion kte = new ExplorerTree.KeepTreeExpansion(tree, etm.getRoot(), etm, errorPath); updateTree((DefaultMutableTreeNode)errorTree.getChildAt(index)); kte.restore(); } } } // public void actionPerformed(ActionEvent e) // { // int index = indexOf(this); // if (e.getSource() instanceof JMenuItem) // { // JMenuItem m = (JMenuItem)e.getSource(); // if (m.getText().equals("Delete")) // { // boolean removedStuff = false; // WindowFrame wf = WindowFrame.getCurrentWindowFrame(); // if (wf != null) // { // ExplorerTree ex = wf.getExplorerTab(); // TreePath [] paths = ex.getSelectionPaths(); // for(int i=0; i<paths.length; i++) // { // Object obj = paths[i].getLastPathComponent(); // if (obj instanceof DefaultMutableTreeNode) // { // Object clickedObject = ((DefaultMutableTreeNode)obj).getUserObject(); // if (clickedObject instanceof ErrorLoggerTreeNode) // { // index = indexOf((ErrorLoggerTreeNode)clickedObject); // removeLogger(index); // removedStuff = true; // } // } // } // } // if (!removedStuff) // removeLogger(index); // } else if (m.getText().equals("Export")) // { // String filePath = null; // try // { // filePath = OpenFile.chooseOutputFile(FileType.XML, null, "ErrorLoggerSave.xml"); // if (filePath == null) return; // cancel operation // logger.exportErrorLogger(filePath); // } catch (Exception se) // { // System.out.println("Error creating " + filePath); // } // } else if (m.getText().equals("Show All")) // { // WindowFrame wf = WindowFrame.getCurrentWindowFrame(); // if (wf == null) return; // Job.getUserInterface().getCurrentEditWindow_().clearHighlighting(); // ExplorerTree ex = wf.getExplorerTab(); // TreePath [] paths = ex.getSelectionPaths(); // for(int i=0; i<paths.length; i++) // { // Object obj = paths[i].getLastPathComponent(); // if (obj instanceof DefaultMutableTreeNode) // { // Object clickedObject = ((DefaultMutableTreeNode)obj).getUserObject(); // if (clickedObject instanceof ErrorLoggerTreeNode) // { // index = indexOf((ErrorLoggerTreeNode)clickedObject); // highlightLogger(index); // } // } // } // Job.getUserInterface().getCurrentEditWindow_().finishedHighlighting(); // } else if (m.getText().equals("Get Info")) // { // System.out.println("ErrorLogger Information: " + logger.getInfo()); // } else if (m.getText().equals("Set Current")) // { // setCurrent(index); // } // } // } } public static void deleteAllLoggers() { for (int i = errorTree.getChildCount() - 1; i >= 0; i--) removeLogger(i); } public static void deleteLogger(ExplorerTree ex) { TreePath [] paths = ex.getSelectionPaths(); for(int i=0; i<paths.length; i++) { Object obj = paths[i].getLastPathComponent(); if (obj instanceof DefaultMutableTreeNode) { Object clickedObject = ((DefaultMutableTreeNode)obj).getUserObject(); if (clickedObject instanceof ErrorLoggerTreeNode) { int index = indexOf((ErrorLoggerTreeNode)clickedObject); removeLogger(index); } } } } public static void exportLogger(ErrorLoggerTreeNode node) { ErrorLogger logger = node.getLogger(); String filePath = null; try { filePath = OpenFile.chooseOutputFile(FileType.XML, null, "ErrorLoggerSave.xml"); if (filePath == null) return; // cancel operation logger.exportErrorLogger(filePath); } catch (Exception se) { System.out.println("Error creating " + filePath); } } public static void showAllLogger(ExplorerTree ex) { Job.getUserInterface().getCurrentEditWindow_().clearHighlighting(); TreePath [] paths = ex.getSelectionPaths(); for(int i=0; i<paths.length; i++) { Object obj = paths[i].getLastPathComponent(); if (obj instanceof DefaultMutableTreeNode) { Object clickedObject = ((DefaultMutableTreeNode)obj).getUserObject(); if (clickedObject instanceof ErrorLoggerTreeNode) { int index = indexOf((ErrorLoggerTreeNode)clickedObject); highlightLogger(index, -1); } else if (clickedObject instanceof ErrorLoggerGroupNode) { ErrorLoggerGroupNode egn = (ErrorLoggerGroupNode)clickedObject; int sortKey = egn.getSortKey(); int index = indexOf(egn.getParentNode()); highlightLogger(index, sortKey); } else if (clickedObject instanceof ErrorLogger.MessageLog) { ErrorLogger.MessageLog ml = (ErrorLogger.MessageLog)clickedObject; EditWindow ew = EditWindow.getCurrent(); if (ew == null) return; Highlighter h = ew.getHighlighter(); EDatabase database = EDatabase.clientDatabase(); for(Iterator<ErrorHighlight> it = ml.getHighlights(); it.hasNext(); ) { ErrorHighlight eh = it.next(); eh.addToHighlighter(h, database); } } } } Job.getUserInterface().getCurrentEditWindow_().finishedHighlighting(); } public static void setCurrentLogger(ErrorLoggerTreeNode node) { int index = indexOf(node); setCurrent(index); } }