![JAR search and dependency download from the Maven repository](/logo.png)
com.sun.electric.tool.user.UserInterfaceMain Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: UserInterfaceMain.java
*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
*
* 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;
import com.sun.electric.StartupPrefs;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.Environment;
import com.sun.electric.database.Snapshot;
import com.sun.electric.database.change.DatabaseChangeEvent;
import com.sun.electric.database.change.DatabaseChangeListener;
import com.sun.electric.database.change.Undo;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.text.Pref;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.variable.EditWindow_;
import com.sun.electric.technology.TechPool;
import com.sun.electric.tool.AbstractUserInterface;
import com.sun.electric.tool.Client;
import com.sun.electric.tool.EJob;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.Listener;
import com.sun.electric.tool.Tool;
import com.sun.electric.tool.ToolSettings;
import com.sun.electric.tool.user.dialogs.Progress;
import com.sun.electric.tool.user.ui.ClickZoomWireListener;
import com.sun.electric.tool.user.ui.EditWindow;
import com.sun.electric.tool.user.ui.ErrorLoggerTree;
import com.sun.electric.tool.user.ui.JobTree;
import com.sun.electric.tool.user.ui.LayerVisibility;
import com.sun.electric.tool.user.ui.MessagesWindow;
import com.sun.electric.tool.user.ui.ToolBar;
import com.sun.electric.tool.user.ui.TopLevel;
import com.sun.electric.tool.user.ui.WindowContent;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.math.FixpTransform;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.EventListenerList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to build the UserInterface for the main GUI version of the user interface.
*/
public class UserInterfaceMain extends AbstractUserInterface {
static final Logger logger = LoggerFactory.getLogger("com.sun.electric.tool.user");
/**
* Describe the windowing mode. The current modes are MDI and SDI.
*/
public static enum Mode {
MDI, SDI
}
// /** Property fired if ability to Undo changes */ public static final String propUndoEnabled = "UndoEnabled";
// /** Property fired if ability to Redo changes */ public static final String propRedoEnabled = "RedoEnabled";
static volatile boolean initializationFinished = false;
private static volatile boolean undoEnabled = false;
private static volatile boolean redoEnabled = false;
// private static final EventListenerList undoRedoListenerList = new EventListenerList();
private static EventListenerList listenerList = new EventListenerList();
private static Snapshot currentSnapshot = IdManager.stdIdManager.getInitialSnapshot();
private static GraphicsPreferences currentGraphicsPreferences = null;
// private static EDatabase database = EDatabase.clientDatabase();
/** The progress during input. */
protected static Progress progress = null;
private SplashWindow sw = null;
// private PrintStream stdout = System.out;
public UserInterfaceMain(List argsList, Mode mode, boolean showSplash) {
// Pushing new EventQueue failes on JDK 7
// sometimes failes if old EventQueue hasn't init EventDispatchThread
// So we push a dummy Runnable to init it
logger.trace("enter UserInterfaceMain constructor");
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
logger.trace("init original EventDispatchThread {}", Thread.currentThread().getId());
assert SwingUtilities.isEventDispatchThread();
}
});
} catch (Exception e) {
logger.error("Error initing original EventDispatchThread", e);
}
// Push a new EventQueue that catches all Throwables
logger.trace("before pushing new EventQueue");
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue() {
@Override
protected void dispatchEvent(AWTEvent e) {
if (logger.isTraceEnabled()) {
logger.trace("enter dispatchEvent {} in thread {}", e, Thread.currentThread().getId());
}
try {
super.dispatchEvent(e);
} catch (Throwable ex) {
logger.error("dispatchEvent", ex);
ActivityLogger.logException(ex);
// if (ex instanceof Error && (!(ex instanceof AssertionError))) {
// throw (Error)ex;
// }
}
if (logger.isTraceEnabled()) {
logger.trace("exiting dispatchEvent");
}
}
});
logger.trace("after pushing new EventQueue");
// JDK 6 creates a new EventDispatchThread on the new EventQueue
// JDK 7 reuses the original EventDispatchThread on the new EventQueue
// Anyway, set client thread to EventDispatchThread of the new EventQueue
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
logger.trace("set client thread to the new EventDispatchThread {}", Thread.currentThread().getId());
assert SwingUtilities.isEventDispatchThread();
setClientThread();
Environment.setThreadEnvironment(IdManager.stdIdManager.getInitialEnvironment());
}
});
} catch (Exception e) {
logger.error("Error checking client thread", e);
}
logger.trace("after setting client thread");
if (mode == null) {
int defMode = StartupPrefs.getDisplayStyle();
if (defMode == 1) {
mode = UserInterfaceMain.Mode.MDI;
} else if (defMode == 2) {
mode = UserInterfaceMain.Mode.SDI;
}
}
SwingUtilities.invokeLater(new InitializationRun(argsList, mode, showSplash));
}
private Snapshot oldUndoSnapshot = null;
@Override
protected void showSnapshot(Snapshot newSnapshot) {
if (oldUndoSnapshot == null) {
oldUndoSnapshot = currentSnapshot;
}
showSnapshot(newSnapshot, true);
}
@Override
protected void terminateJob(Job.Key jobKey, String jobName, Tool tool,
Job.Type jobType, byte[] serializedJob,
boolean doItOk, byte[] serializedResult, Snapshot newSnapshot) {
boolean undoRedo = jobType == Job.Type.UNDO;
if (jobType != Job.Type.SERVER_EXAMINE && jobType != Job.Type.CLIENT_EXAMINE) {
Snapshot oldSnapshot = currentSnapshot;
if (oldUndoSnapshot != null) {
oldSnapshot = oldUndoSnapshot;
oldUndoSnapshot = null;
}
int restoredHighlights = Undo.endChanges(oldSnapshot, tool, jobName, newSnapshot);
showSnapshot(newSnapshot, undoRedo);
restoreHighlights(restoredHighlights);
}
if (jobKey.clientId != getConnectionId()) {
return;
}
EJob ejob;
Throwable jobException = null;
if (jobKey.startedByServer()) {
ejob = new EJob(this, jobKey.jobId, jobType, jobName, serializedJob);
jobException = ejob.deserializeToClient();
} else {
ejob = removeProcessingEJob(jobKey);
}
if (jobException != null) {
System.out.println("Error deserializing " + jobName);
ActivityLogger.logException(jobException);
return;
}
ejob.serializedResult = serializedResult;
jobException = ejob.deserializeResult();
Job job = ejob.clientJob;
if (job == null) {
ActivityLogger.logException(jobException);
return;
}
try {
job.terminateIt(jobException);
} catch (Throwable ex) {
System.out.println("Exception executing terminateIt");
ex.printStackTrace(System.out);
}
job.timer.end();
job.finished = true; // is this redundant with Thread.isAlive()?
// say something if it took more than a minute by default
if (job.reportExecution || job.timer.getTime() >= Job.MIN_NUM_SECONDS) {
if (User.isBeepAfterLongJobs()) {
Job.getExtendedUserInterface().beep();
}
System.out.println(job.getInfo());
}
}
@Override
protected void showJobQueue(final Job.Inform[] jobQueue) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showJobQueue(jobQueue);
}
});
return;
}
boolean busyCursor = false;
for (Job.Inform jobInform : jobQueue) {
if (jobInform.isChangeJobQueuedOrRunning()) {
busyCursor = true;
}
}
JobTree.update(Arrays.asList(jobQueue));
TopLevel.setBusyCursor(busyCursor);
}
public void addEvent(Client.ServerEvent serverEvent) {
SwingUtilities.invokeLater(serverEvent);
}
private static String getMacClassName() {
return "com.sun.electric.tool.user.MacOSXInterface";
}
// private class InitializationSetJob implements Runnable {
// Job initJob;
// public InitializationSetJob(Job job)
// {
// this.initJob = job;
// }
// public void run()
// {
// if (!Client.isOSMac()) return;
//
// try {
// Class> osXClass = Class.forName(getMacClassName());
// Method osXSetJobMethod = null;
//
// // find the necessary methods on the Mac OS/X class
// try {
// osXSetJobMethod = osXClass.getMethod("setInitJob", new Class[] {Job.class});
// } catch (NoSuchMethodException e) {
// osXSetJobMethod = null;
// }
// if (osXSetJobMethod != null) {
// try {
// osXSetJobMethod.invoke(osXClass, new Object[] {initJob});
// } catch (Exception e) {
// System.out.println("Error initializing Mac OS/X interface");
// }
// }
// } catch (ClassNotFoundException e) {}
// }
// }
private class InitializationRun implements Runnable {
List argsList;
Mode mode;
boolean showSplash;
InitializationRun(List argsList, Mode mode, boolean showSplash) {
this.argsList = argsList;
this.mode = mode;
this.showSplash = showSplash;
}
public void run() {
assert Job.isClientThread();
Pref.setCachedObjsFromPreferences();
lastSavedEp = new EditingPreferences(true, null);
currentGraphicsPreferences = new GraphicsPreferences(true, new TechPool(IdManager.stdIdManager));
// see if there is a Macintosh OS/X interface
if (Client.isOSMac()) {
try {
Class> osXClass = Class.forName(getMacClassName());
Method osXRegisterMethod = null;
// find the necessary methods on the Macintosh OS/X class
try {
osXRegisterMethod = osXClass.getMethod("registerMacOSXApplication", new Class[]{List.class});
} catch (NoSuchMethodException e) {
osXRegisterMethod = null;
}
if (osXRegisterMethod != null) {
try {
osXRegisterMethod.invoke(osXClass, new Object[]{argsList});
} catch (Exception e) {
System.out.println("Error initializing Mac OS/X interface");
}
}
} catch (ClassNotFoundException e) {
}
}
//runThreadStatusTimer();
if (showSplash) {
sw = new SplashWindow();
}
TopLevel.OSInitialize(mode);
TopLevel.InitializeMessagesWindow();
}
}
/**
* Method is called when initialization was finished.
*/
public void finishInitialization() {
initializationFinished = true;
if (sw != null) {
sw.removeNotify();
sw = null;
}
TopLevel.InitializeWindows();
WindowFrame.wantToOpenCurrentLibrary(true, null);
// report on missing components
if (Job.getDebug()) {
Set missingComponents = TextUtils.getMissingComponentNames();
String errorMsg = null;
for (String comp : missingComponents) {
if (errorMsg == null) {
errorMsg = "Warning: optional components not found: ";
} else {
errorMsg += ", ";
}
errorMsg += comp;
}
if (errorMsg != null) {
System.out.println(errorMsg);
}
missingComponents = TextUtils.getMissingPrivateComponentNames();
errorMsg = null;
for (String comp : missingComponents) {
if (errorMsg == null) {
errorMsg = "Warning: private components not found: ";
} else {
errorMsg += ", ";
}
errorMsg += comp;
}
if (errorMsg != null) {
System.out.println(errorMsg);
}
}
}
public EDatabase getDatabase() {
return EDatabase.clientDatabase();
}
public EditWindow_ getCurrentEditWindow_() {
return EditWindow.getCurrent();
}
public EditWindow_ needCurrentEditWindow_() {
return EditWindow.needCurrent();
}
public Cell getCurrentCell() {
return WindowFrame.getCurrentCell();
}
public Cell needCurrentCell() {
return WindowFrame.needCurCell();
}
/**
* Method to adjust reference point in WindowFrame containing the cell
*/
public void adjustReferencePoint(Cell theCell, double cX, double cY) {
// adjust all windows showing this cell
for (Iterator it = WindowFrame.getWindows(); it.hasNext();) {
WindowFrame wf = it.next();
WindowContent content = wf.getContent();
if (!(content instanceof EditWindow_)) {
continue;
}
Cell cell = content.getCell();
if (cell != theCell) {
continue;
}
EditWindow_ wnd = (EditWindow_) content;
Point2D off = wnd.getOffset();
off.setLocation(off.getX() - cX, off.getY() - cY);
wnd.setOffset(off);
}
}
public void repaintAllWindows() {
WindowFrame.repaintAllWindows();
}
// public void loadComponentMenuForTechnology()
// {
// WindowFrame wf = WindowFrame.getCurrentWindowFrame(false);
// if (wf != null) wf.loadComponentMenuForTechnology();
// }
public int getDefaultTextSize() {
return EditWindow.getDefaultFontSize();
}
public EditWindow_ displayCell(Cell cell) {
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (User.isShowCellsInNewWindow()) {
wf = null;
}
if (wf == null) {
wf = WindowFrame.createEditWindow(cell);
}
wf.setCellWindow(cell, null);
if (wf.getContent() instanceof EditWindow_) {
return (EditWindow_) wf.getContent();
}
return null;
}
// ErrorLogger functions
public void termLogging(final ErrorLogger log, boolean explain, boolean terminate) {
if (!log.isPersistent() && log.getNumLogs() == 0) {
return;
}
ErrorLoggerTree.addLogger(log, explain, terminate);
}
public void updateNetworkErrors(Cell cell, List errors) {
ErrorLoggerTree.updateNetworkErrors(cell, errors);
}
public void updateIncrementalDRCErrors(Cell cell, List newErrors,
List delErrors) {
ErrorLoggerTree.updateDrcErrors(cell, newErrors, delErrors);
}
/**
* Method to return the error message associated with the current error.
* Highlights associated graphics if "showhigh" is nonzero.
*/
public String reportLog(ErrorLogger.MessageLog log, boolean showhigh, boolean separateWindow, int position) {
EDatabase database = EDatabase.clientDatabase();
// show the error
if (showhigh) {
// in case multiple windows are involved in the action so all will be brought up
// and properly terminated for display
Set updatedWindows = new HashSet();
// clear all highlighting
for (Iterator it = WindowFrame.getWindows(); it.hasNext();) {
WindowFrame wf = it.next();
if (wf.getContent() instanceof EditWindow) {
EditWindow wnd = (EditWindow) wf.getContent();
Highlighter highlighter = wnd.getHighlighter();
highlighter.clear();
}
}
// first show the geometry associated with this error
int pos = -1;
for (Iterator it = log.getHighlights(); it.hasNext();) {
ErrorHighlight eh = it.next();
Highlighter highlighter = null;
// Checking whether a specific geometry is displayed
pos++;
if (position != -1 && pos != position) {
continue; // not this one
}
Cell cell = eh.getCell(database);
// validate the cell (it may have been deleted)
if (cell != null) {
if (!cell.isLinked()) {
return "(cell deleted): " + log.getMessageString();
}
// make sure it is shown
EditWindow wnd;
if (separateWindow) {
wnd = EditWindow.showEditWindowForCell(cell, eh.getVarContext());
} else {
wnd = EditWindow.getCurrent();
if (wnd != null) {
if (wnd.getCell() != cell) {
wnd.setCell(cell, eh.getVarContext(), null);
}
} else {
wnd = EditWindow.showEditWindowForCell(cell, eh.getVarContext());
}
}
// nothing clean yet
highlighter = wnd.getHighlighter();
updatedWindows.add(wnd);
} else {
System.out.println("No cell associated with this error");
}
if (highlighter == null) {
continue;
}
eh.addToHighlighter(highlighter, database);
}
// finish all open windows
boolean nothingDone = true;
for (EditWindow wnd : updatedWindows) {
Highlighter highlighter = wnd.getHighlighter();
// Something found to highlight
if (highlighter != null) {
highlighter.finished();
if (User.isShiftWindowToErrors()) {
Rectangle2D bounds = highlighter.getHighlightedArea(wnd);
Rectangle2D displayBounds = wnd.displayableBounds();
if (wnd.isInPlaceEdit()) {
Point2D llPt = new Point2D.Double(displayBounds.getMinX(), displayBounds.getMinY());
Point2D urPt = new Point2D.Double(displayBounds.getMaxX(), displayBounds.getMaxY());
FixpTransform intoCell = wnd.getInPlaceTransformIn();
intoCell.transform(llPt, llPt);
intoCell.transform(urPt, urPt);
double lX = Math.min(llPt.getX(), urPt.getX());
double hX = Math.max(llPt.getX(), urPt.getX());
double lY = Math.min(llPt.getY(), urPt.getY());
double hY = Math.max(llPt.getY(), urPt.getY());
displayBounds = new Rectangle2D.Double(lX, lY, hX - lX, hY - lY);
}
if (bounds.getMinX() >= displayBounds.getMaxX()
|| bounds.getMaxX() <= displayBounds.getMinX()
|| bounds.getMinY() >= displayBounds.getMaxY()
|| bounds.getMaxY() <= displayBounds.getMinY()) {
Rectangle2D newBounds = highlighter.getHighlightedArea(wnd);
double newLX = newBounds.getMinX() - newBounds.getWidth() / 2;
double newHX = newBounds.getMaxX() + newBounds.getWidth() / 2;
double newLY = newBounds.getMinY() - newBounds.getHeight() / 2;
double newHY = newBounds.getMaxY() + newBounds.getHeight() / 2;
newBounds.setRect(newLX, newLY, newHX - newLX, newHY - newLY);
wnd.focusScreen(newBounds);
} else {
highlighter.ensureHighlightingSeen();
}
} else {
highlighter.ensureHighlightingSeen();
}
// // make sure the selection is visible
// Rectangle2D hBounds = highlighter.getHighlightedArea(wnd);
// Rectangle2D shown = wnd.getDisplayedBounds();
// if (wnd.isInPlaceEdit())
// {
// Point2D llPt = new Point2D.Double(shown.getMinX(), shown.getMinY());
// Point2D urPt = new Point2D.Double(shown.getMaxX(), shown.getMaxY());
// AffineTransform intoCell = wnd.getInPlaceTransformIn();
// intoCell.transform(llPt, llPt);
// intoCell.transform(urPt, urPt);
// double lX = Math.min(llPt.getX(), urPt.getX());
// double hX = Math.max(llPt.getX(), urPt.getX());
// double lY = Math.min(llPt.getY(), urPt.getY());
// double hY = Math.max(llPt.getY(), urPt.getY());
// shown = new Rectangle2D.Double(lX, lY, hX-lX, hY-lY);
// }
// if (!shown.intersects(hBounds))
// {
// wnd.focusOnHighlighted();
// }
}
nothingDone = false;
}
if (nothingDone) {
Cell logCell = log.getCell();
// Checking also that the cell hasn't been removed yet
if (logCell != null && logCell.isLinked()) {
// in case of errors or warnings with only cell information
// This would bring the EditWindow to the front.
EditWindow.showEditWindowForCell(logCell, null);
}
}
}
// return the error message
return log.getMessageString();
}
/**
* Method to show an error message.
* @param message the error message to show.
* @param title the title of a dialog with the error message.
*/
public void showErrorMessage(final String message, final String title) {
if (Job.isClientThread()) {
JFrame wf = TopLevel.getCurrentJFrame(false);
if (wf == null) {
System.err.println(message);
}
JOptionPane.showMessageDialog(wf, message, title, JOptionPane.ERROR_MESSAGE);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showErrorMessage(message, title);
}
});
}
}
/**
* Method to show an informational message.
* @param message the message to show.
* @param title the title of a dialog with the message.
*/
public void showInformationMessage(final String message, final String title) {
if (Job.isClientThread()) {
JOptionPane.showMessageDialog(TopLevel.getCurrentJFrame(), message, title, JOptionPane.INFORMATION_MESSAGE);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showInformationMessage(message, title);
}
});
}
}
/**
* Method print a message.
* @param message the message to show.
* @param newLine add new line after the message
*/
public void printMessage(String message, boolean newLine) {
final String s = newLine ? message + "\n" : message;
if (Job.isClientThread()) {
appendString(s);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MessagesWindow.appendString(s);
}
});
}
}
/**
* Method to start saving messages.
* @param filePath file to save
*/
public void saveMessages(final String filePath) {
if (!Job.isClientThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
saveMessages(filePath);
}
});
}
try {
if (printWriter != null) {
printWriter.close();
printWriter = null;
}
if (filePath == null) {
return;
}
printWriter = new PrintWriter(new BufferedWriter(new FileWriter(filePath)));
} catch (IOException e) {
System.err.println("Error creating " + filePath);
System.out.println("Error creating " + filePath);
return;
}
System.out.println("Messages will be saved to " + filePath);
}
private static PrintWriter printWriter = null;
private static boolean newCommand = true;
private static int commandNumber = 1;
/**
* Method to report that the user issued a new command (click, keystroke, pulldown menu).
* The messages window separates output by command so that each command's results
* can be distinguished from others.
*/
public static void userCommandIssued() {
newCommand = true;
}
public void appendString(String str) {
if (str.length() == 0) {
return;
}
if (newCommand) {
newCommand = false;
str = "=================================" + (commandNumber++) + "=================================\n" + str;
}
if (printWriter != null) {
printWriter.print(str);
printWriter.flush();
}
MessagesWindow.appendString(str);
}
/**
* Method to show a message and ask for confirmation.
* @param message the message to show.
* @return true if "yes" was selected, false if "no" was selected.
*/
public boolean confirmMessage(Object message) {
int response = JOptionPane.showConfirmDialog(TopLevel.getCurrentJFrame(), message);
return response == JOptionPane.YES_OPTION;
}
/**
* Method to ask for a choice among possibilities.
* @param message the message to show.
* @param title the title of the dialog with the query.
* @param choices an array of choices to present, each in a button.
* @param defaultChoice the default choice.
* @return the index into the choices array that was selected.
*/
public int askForChoice(String message, String title, String[] choices, String defaultChoice) {
// make sure the message is not too long and add \n if necessary
String msg = message;
int size = msg.length();
int pos = 0;
int lineNumber = 0;
String newMsg = "";
while (pos < size && lineNumber < 10) {
int endIndex = pos + 256;
if (endIndex > size) {
endIndex = size;
}
newMsg += msg.substring(pos, endIndex);
newMsg += "\n";
pos += 256;
lineNumber++;
}
if (pos < size) // too many lines
{
newMsg += "........\n";
// adding the end of the message. If end of message is close then add the remainder otherwise
// print the last 256 characters.
int index = (size - pos > 256) ? (size - 256) : (pos);
newMsg += msg.substring(index, size);
}
msg = newMsg;
message = msg;
int val = JOptionPane.showOptionDialog(TopLevel.getCurrentJFrame(), message, title,
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, choices, defaultChoice);
return val;
}
/**
* Method to ask for a line of text.
* @param message the prompt message.
* @param title the title of a dialog with the message.
* @param def the default response.
* @return the string (null if canceled).
*/
public String askForInput(Object message, String title, String def) {
Object ret = JOptionPane.showInputDialog(TopLevel.getCurrentJFrame(), message, title, JOptionPane.QUESTION_MESSAGE, null, null, def);
if (ret == null) {
return null;
}
return ret.toString();
}
/** For Preference */
public static void importPrefs(URL fileURL) {
assert Job.isClientThread();
if (fileURL == null) {
return;
}
System.out.println("Importing preferences...");
Pref.importPrefs(fileURL);
Environment env = EDatabase.clientDatabase().getEnvironment();
// Mirror Settings in Preferences
env.saveToPreferences();
// recache all preferences
loadPreferences(env.techPool);
TopLevel.getCurrentJFrame().getEMenuBar().restoreSavedBindings(false); //trying to cache again
User.technologyChanged();
WindowFrame.repaintAllWindows();
System.out.println("...preferences imported from " + fileURL.getFile());
}
// ExtendedUserInterface
/**
* Save current state of highlights and return its ID.
*/
@Override
public int saveHighlights() {
EditWindow_ wnd = getCurrentEditWindow_();
if (wnd == null) {
return -1;
}
SavedHighlights sh = new SavedHighlights(lastId++, wnd);
while (savedHighlights.size() >= User.getMaxUndoHistory() && !savedHighlights.isEmpty()) {
savedHighlights.remove(0);
}
savedHighlights.add(sh);
return sh.id;
}
/**
* Restore state of highlights by its ID.
*/
@Override
public void restoreHighlights(int highlightsId) {
for (SavedHighlights sh : savedHighlights) {
if (sh.id == highlightsId) {
sh.restore();
break;
}
}
}
/**
* Show status of undo/redo buttons
* @param newUndoEnabled new status of undo button.
* @param newRedoEnabled new status of redo button.
*/
@Override
public void showUndoRedoStatus(boolean newUndoEnabled, boolean newRedoEnabled) {
PropertyChangeEvent e = null;
if (undoEnabled != newUndoEnabled) {
// PropertyChangeEvent e = new PropertyChangeEvent(this, propUndoEnabled, undoEnabled, newUndoEnabled);
undoEnabled = newUndoEnabled;
SwingUtilities.invokeLater(new PropertyChangeRun(e));
}
if (redoEnabled != newRedoEnabled) {
// PropertyChangeEvent e = new PropertyChangeEvent(this, propRedoEnabled, redoEnabled, newRedoEnabled);
redoEnabled = newRedoEnabled;
SwingUtilities.invokeLater(new PropertyChangeRun(e));
}
}
/**
* Show new database snapshot.saveh
* @param newSnapshot new snapshot.
*/
public void showSnapshot(Snapshot newSnapshot, boolean undoRedo) {
assert Job.isClientThread();
DatabaseChangeEvent event = new DatabaseChangeEvent(currentSnapshot, newSnapshot);
Snapshot oldSnapshot = currentSnapshot;
EDatabase database = EDatabase.clientDatabase();
database.lock(true);
try {
// database.checkFresh(oldSnapshot);
database.lowLevelSetCanUndoing(true);
try {
database.undo(newSnapshot);
} catch (Throwable e) {
ActivityLogger.logException(e);
database.recover(newSnapshot);
}
database.lowLevelSetCanUndoing(false);
} finally {
database.unlock();
endChanging();
}
currentSnapshot = newSnapshot;
if (newSnapshot.environment != oldSnapshot.environment) {
Environment.setThreadEnvironment(newSnapshot.environment);
if (newSnapshot.environment.toolSettings != oldSnapshot.environment.toolSettings) {
ToolSettings.attachToGroup(newSnapshot.environment.toolSettings);
}
if (newSnapshot.techPool != oldSnapshot.techPool) {
LayerVisibility.preserveVisibility();
loadPreferences(newSnapshot.techPool);
User.technologyChanged();
WindowFrame.repaintAllWindows();
}
}
for (Iterator it = Tool.getListeners(); it.hasNext();) {
Listener listener = it.next();
listener.endBatch(oldSnapshot, newSnapshot, undoRedo);
}
fireDatabaseChangeEvent(event);
// SwingUtilities.invokeLater(new DatabaseChangeRun(newSnapshot, undoRedo));
}
@Override
public void beep() {
if (Job.isClientThread()) {
User.playSound();
// Toolkit.getDefaultToolkit().beep();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
beep();
}
});
}
}
/**
* Method to tell whether undo can be done.
* This is used by the tool bar to determine whether the undo button should be available.
* @return true if undo can be done.
*/
public static boolean getUndoEnabled() {
return undoEnabled;
}
/**
* Method to tell whether redo can be done.
* This is used by the tool bar to determine whether the undo button should be available.
* @return true if redo can be done.
*/
public static boolean getRedoEnabled() {
return redoEnabled;
}
// /** Add a property change listener. This generates Undo and Redo enabled property changes */
// public static synchronized void addUndoRedoListener(PropertyChangeListener l)
// {
// assert SwingUtilities.isEventDispatchThread();
// undoRedoListenerList.add(PropertyChangeListener.class, l);
// }
//
// /** Remove a property change listener. */
// public static synchronized void removeUndoRedoListener(PropertyChangeListener l)
// {
// assert SwingUtilities.isEventDispatchThread();
// undoRedoListenerList.remove(PropertyChangeListener.class, l);
// }
private static void firePropertyChange(PropertyChangeEvent e) {
assert Job.isClientThread();
ToolBar.updateUndoRedoButtons(getUndoEnabled(), getRedoEnabled());
// Check all current WindowFrames and determine if displayed cells are still valid
// close windows that reference this cell
for (Iterator it = WindowFrame.getWindows(); it.hasNext();) {
WindowFrame wf = it.next();
WindowContent content = wf.getContent();
if (content == null) {
continue;
}
Cell c = content.getCell();
if (c != null && !c.isLinked()) // got removed in undo
{
wf.setCellWindow(null, null);
content.fullRepaint();
}
}
// Object[] listeners;
// synchronized (UserInterfaceMain.class) {
// listeners = undoRedoListenerList.getListenerList();
// }
// // Process the listeners last to first, notifying those that are interested in this event
// for (int i = listeners.length-2; i>=0; i-=2) {
// if (listeners[i] == PropertyChangeListener.class)
// ((PropertyChangeListener)listeners[i+1]).propertyChange(e);
// }
}
private static class PropertyChangeRun implements Runnable {
private PropertyChangeEvent e;
private PropertyChangeRun(PropertyChangeEvent e) {
this.e = e;
}
public void run() {
firePropertyChange(e);
}
}
/** Add a DatabaseChangeListener. It will be notified when
* state of the database changes.
* @param l the listener
*/
public static synchronized void addDatabaseChangeListener(DatabaseChangeListener l) {
listenerList.add(DatabaseChangeListener.class, l);
}
/** Remove a DatabaseChangeListener. */
public static synchronized void removeDatabaseChangeListener(DatabaseChangeListener l) {
listenerList.remove(DatabaseChangeListener.class, l);
}
/**
* Fire DatabaseChangeEvent to DatabaseChangeListeners.
* @param e DatabaseChangeEvent.
*/
public static void fireDatabaseChangeEvent(DatabaseChangeEvent e) {
Object[] listeners;
synchronized (User.class) {
listeners = listenerList.getListenerList();
}
// Process the listeners last to first, notifying those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == DatabaseChangeListener.class) {
((DatabaseChangeListener) listeners[i + 1]).databaseChanged(e);
}
}
}
private static void loadPreferences(TechPool techPool) {
assert techPool == Environment.getThreadEnvironment().techPool;
Pref.setCachedObjsFromPreferences();
lastSavedEp = new EditingPreferences(false, techPool);
currentGraphicsPreferences = new GraphicsPreferences(false, techPool);
EditWindow.setLayerVisibilityAll(LayerVisibility.loadPreferences());
ClickZoomWireListener.theOne.readPrefs();
}
@Override
public EditingPreferences lowLevelGetEditingPreferences() {
return getEditingPreferences();
}
public static EditingPreferences getEditingPreferences() {
assert Job.isClientThread();
return lastSavedEp;
}
private static EditingPreferences lastSavedEp;
public static void setEditingPreferences(EditingPreferences newEp) {
EditingPreferences oldEp = getEditingPreferences();
if (newEp.equals(oldEp)) {
return;
}
Pref.delayPrefFlushing();
newEp.putPrefs(Pref.getPrefRoot(), true, lastSavedEp);
lastSavedEp = newEp;
ClickZoomWireListener.theOne.readPrefs();
Pref.resumePrefFlushing();
}
private static boolean badAccessReported = false;
public static GraphicsPreferences getGraphicsPreferences() {
if (!badAccessReported && !Job.isClientThread()) {
String msg = "GraphicsPreferences is accessed from " + Job.getRunningJob();
if (Job.getDebug()) {
ActivityLogger.logMessage(msg);
System.out.println(msg);
}
badAccessReported = true;
}
return currentGraphicsPreferences;
}
public static void setGraphicsPreferences(GraphicsPreferences gp) {
assert Job.isClientThread();
if (gp.equals(currentGraphicsPreferences)) {
return;
}
Pref.delayPrefFlushing();
gp.putPrefs(Pref.getPrefRoot(), true, currentGraphicsPreferences);
Pref.resumePrefFlushing();
currentGraphicsPreferences = gp;
}
private int lastId = 0;
private ArrayList savedHighlights = new ArrayList();
private static class SavedHighlights {
/** id of this saved state */
private final int id;
/** EditWindow_ of highlights */
private final EditWindow_ wnd;
/** list of saved Highlights */
private final List savedHighlights;
/** saved Highlight offset */
private final Point2D savedHighlightsOffset;
private SavedHighlights(int id, EditWindow_ wnd) {
this.id = id;
this.wnd = wnd;
savedHighlights = wnd.saveHighlightList();
savedHighlightsOffset = wnd.getHighlightOffset();
}
private void restore() {
wnd.restoreHighlightList(savedHighlights);
wnd.setHighlightOffset((int) savedHighlightsOffset.getX(), (int) savedHighlightsOffset.getY());
wnd.finishedHighlighting();
}
}
/**
* Class to display a Splash Screen at the start of the program.
*/
private static class SplashWindow extends JFrame {
public SplashWindow() {
super();
setUndecorated(true);
setTitle("Electric Splash");
setIconImage(TopLevel.getFrameIcon().getImage());
JPanel whole = new JPanel();
whole.setBorder(BorderFactory.createLineBorder(new Color(0, 170, 0), 5));
whole.setLayout(new BorderLayout());
ImageIcon splashImage = Resources.getResource(TopLevel.class, "SplashImage.gif");
JLabel l = new JLabel(splashImage);
whole.add(l, BorderLayout.CENTER);
JLabel v = new JLabel("Version " + Version.getVersion(), JLabel.CENTER);
whole.add(v, BorderLayout.SOUTH);
String fontName = User.getFactoryDefaultFont();
//String fontName = User.getDefaultFont();
Font font = new Font(fontName, Font.BOLD, 24);
v.setFont(font);
v.setForeground(Color.BLACK);
v.setBackground(Color.WHITE);
getContentPane().add(whole, BorderLayout.SOUTH);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = getPreferredSize();
setLocation(screenSize.width / 2 - (labelSize.width / 2),
screenSize.height / 2 - (labelSize.height / 2));
addWindowListener(new WindowsEvents(this));
setVisible(true);
toFront();
paint(getGraphics());
}
}
/**
* This class handles deactivation of the splash screen and forces it back to the top.
*/
private static class WindowsEvents implements WindowListener {
SplashWindow sw;
WindowsEvents(SplashWindow sw) {
super();
this.sw = sw;
}
public void windowActivated(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
TopLevel tl = TopLevel.getCurrentJFrame(false);
Window w = e.getOppositeWindow();
if (tl == w) {
sw.toFront();
}
}
}
// private static void runThreadStatusTimer() {
// int delay = 1000*60*10; // milliseconds
// ElapseTimer timer = new ElapseTimer(delay, new ThreadStatusTask());
// timer.start();
// }
//
// private static class ThreadStatusTask implements ActionListener {
// public void actionPerformed(ActionEvent e) {
// Thread t = Thread.currentThread();
// ThreadGroup group = t.getThreadGroup();
// // get the top level group
// while (group.getParent() != null)
// group = group.getParent();
// Thread [] threads = new Thread[200];
// int numThreads = group.enumerate(threads, true);
// StringBuffer buf = new StringBuffer();
// for (int i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy