/* * @(#)Command.java * * This file is part of webCDwriter - Network CD/DVD Writing. * * Copyright (C) 1999-2006 Jörg P. M. Haeger * * webCDwriter is free software. See CDcreator.java for details. */ import java.io.*; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; /** * Execution of a command. * * @version 20060425 * @author Jörg P. M. Haeger */ public class Command implements Runnable { final JButton cancelButton = new JButton(i18n("cancel")); final Object[] cancelOption = { cancelButton }; final String okButtonText = i18n("OK"); final JButton okButton = new JButton(okButtonText); final Object[] okOption = { okButton }; public static final int INIT = 0; public static final int RUNNING = 1; public static final int ERROR = 2; public static final int SUCCESS = 3; public int status = INIT; private Window dialog; private volatile boolean dialogIsVisible = false; static Point location = new Point(-1, -1); private Point locationAtOpen; private String updateTitle = null; protected boolean cancel = false, offline = false; String infoStr; String lastResult = "unknown"; int writer = -1; private int openCommands = 0; protected final ExecSemaphore execSemaphore = new ExecSemaphore(); public Command() { cancelButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { Version.debug("show", "" + e); cancelCommand(); } }); okButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { Version.debug("show", "" + e); closeDialog(); } }); infoStr = new String(); } void cancelCommand() { if (cancel) System.exit(0); cancel = true; JPanel vp = new JPanel(); vp.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); vp.setLayout(new BoxLayout(vp, BoxLayout.Y_AXIS)); vp.add(new JLabel(i18n("waitForCancel"))); vp.add(Box.createVerticalStrut(20)); JProgressBar bar = new JProgressBar(); bar.setIndeterminate(true); vp.add(bar); showCentered(vp, i18n("titleWaitForCancel")); execSemaphore.setDone(); } protected void closeDialog() { Version.debug("show", "closeDialog()..."); invokeLater(new Runnable() { public void run() { if (dialogIsVisible) { Point locationAtClose = dialog.getLocation(); if (!locationAtClose.equals(locationAtOpen)) location = locationAtClose; dialog.setVisible(false); dialogIsVisible = false; } Version.debug("show", "closeDialog()... done"); } }); execSemaphore.setDone(); } protected JComponent createFirstDialog() { JPanel vp = new JPanel(); vp.setLayout(new BoxLayout(vp, BoxLayout.Y_AXIS)); vp.add(Box.createVerticalGlue()); vp.add(new JLabel("Please wait...")); vp.add(Box.createVerticalGlue()); return vp; } public final void exec() throws CommandError { if (!SwingUtilities.isEventDispatchThread()) Version.debug("FIXME", "Command.exec()"); if (CDcreator.frame == null) dialog = new JDialog(); else dialog = new JDialog(CDcreator.frame); initWindowListener(dialog); JDialog dialog = (JDialog) this.dialog; dialog.getContentPane().add(createFirstDialog()); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setModal(true); dialog.setSize(getPreferredSize()); if (location.x == -1 && location.y == -1) MainWin.center(dialog); else dialog.setLocation(location); locationAtOpen = dialog.getLocation(); Thread thread = new Thread(this); thread.start(); int delay = getDialogDelay(); if (delay > 0) { try { thread.join(delay); } catch (InterruptedException e) { } } if (thread.isAlive() || delay == 0) { dialogIsVisible = true; dialog.setVisible(true); } try { thread.join(); } catch (InterruptedException e) { } while (openCommands > 0) { Version.debug("command", "close " + openCommands); try { readResult(); } catch (java.io.IOException e) { } } CDcreator.setTitle(-1); if (offline) { CDcreator.closeMainWin(); return; } showResult(); if (status == ERROR) throw new CommandError(); if (cancel) throw new CommandError(); } public final void exec(RootPaneContainer pane) throws CommandError { final JFrame frame = (JFrame) pane; int closeOperation = frame.getDefaultCloseOperation(); invokeAndWait(new Runnable() { public void run() { } }); try { exec2(frame); } finally { frame.setDefaultCloseOperation(closeOperation); } } private void exec2(JFrame frame) throws CommandError { dialog = frame; frame.getContentPane().add(createFirstDialog()); frame.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); initWindowListener(frame); run(); while (openCommands > 0) { Version.debug("command", "close " + openCommands); try { readResult(); } catch (java.io.IOException e) { } } execSemaphore.setDone(false); invokeLater(new Runnable() { public void run() { CDcreator.setTitle(-1); if (offline) { CDcreator.closeMainWin(); return; } showResult(); } }); execSemaphore.untilDone(); if (status == ERROR) throw new CommandError(); if (cancel) throw new CommandError(); } protected void execCommand(String cmdStr) { try { status = INIT; writeCommand(cmdStr); status = RUNNING; readResult(); } catch (java.io.IOException e) { System.out.println("execCommand: IOException"); lastResult = "error " + e.getLocalizedMessage(); } } int getDialogDelay() { return 200; } Dimension getPreferredSize() { return new Dimension(600, 400); } protected void handleWindowEvent(WindowEvent e) { cancelCommand(); } String i18n(String key) { if (key.startsWith(".")) key = getClass().getName() + key; return CDcreator.i18n(key); } private void initWindowListener(Window window) { WindowListener[] listeners = window.getWindowListeners(); for (int i = 0; i < listeners.length; i++) window.removeWindowListener(listeners[i]); window.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Version.debug("show", "windowClosing"); handleWindowEvent(e); } }); } static void invokeAndWait(Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) runnable.run(); else try { SwingUtilities.invokeAndWait(runnable); } catch (Exception e) { } } static void invokeLater(Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) runnable.run(); else SwingUtilities.invokeLater(runnable); } boolean lastResultOK() { return status == SUCCESS; } protected void pack() { if (dialog instanceof JDialog) invokeAndWait(new Runnable() { public void run() { dialog.pack(); } }); } protected Integer parse(String str, String key) { try { StreamTokenizer tokenizer = new StreamTokenizer( new StringReader(str)); if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) return null; if (!tokenizer.sval.equals(key)) return null; if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) return null; return new Integer((int)tokenizer.nval); } catch (IOException e) { return null; } } protected Integer parse(String str, String key, int arg) { StringTokenizer t = new StringTokenizer(str, " \t"); try { String str2 = t.nextToken(); if (!str2.equals(key)) return null; for (int i = 0; i < arg; i++) str2 = t.nextToken(); return new Integer(str2); } catch (Exception e) { return null; } } int parsePairStrInt(String lineStr) throws IOException { StreamTokenizer tokenizer = new StreamTokenizer( new StringReader(lineStr)); tokenizer.nextToken(); if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) return 0; return (int)tokenizer.nval; } protected void preloadHTMLViewer() { Version.debug("show", "preloadHTMLViewer()..."); invokeAndWait(new Runnable() { public void run() { new JLabel("Preload HTML viewer"); Version.debug("show", "preloadHTMLViewer()... done"); } }); } protected void process(int code, String text) { } void processHint(String str) { } void processInfo(String str) { if (infoStr.length() > 0) infoStr += "\n"; infoStr = CDcreator.replaceAll(infoStr, "CD-R(W)", Mode.medium); infoStr += str; } protected boolean processInternal(int code, String text) { return false; } void processLog(String str) { } protected String readLine() throws java.io.IOException { StringBuffer strBuf = new StringBuffer(); while (true) { int b = CDcreator.inStream.read(); if (b < 0) break; if (b == 10) break; if (b < 32 && b != '\t') strBuf.append("(" + String.valueOf(b) + ")"); else strBuf.append((char) b); } String str = new String(strBuf); Version.debug("inStream", "<- \"" + str + "\""); return str; } void readResult() throws java.io.IOException { synchronized(CDcreator.inStream) { readResult2(); } } private void readResult2() throws java.io.IOException { Version.debug("command", "readResult() " + openCommands); openCommands--; while (true) { String line = readLine(); if (line.length() == 0) break; writer = -1; if (line.startsWith("W")) { int p = line.indexOf(" "); if (p >= 2) { try { writer = Integer.parseInt(line.substring(1, p)); p++; while (p < line.length() && line.charAt(p) <= 32) p++; line = line.substring(p); } catch (Exception e) { } } } String type = line, message = ""; int i = line.indexOf(' '); if (i >= 0) { type = line.substring(0, i); i++; while (i < line.length() && line.charAt(i) <= 32) i++; message = line.substring(i); } type = type.toUpperCase(); if (type.equals("ERR")) { status = ERROR; lastResult = i18n("error_" + message.replace(' ', '_')); if (lastResult.startsWith("error_")) { int p0 = message.indexOf("http://"); if (p0 < 0) lastResult = "\"" + message + "\""; else { int p1 = p0 + 1; while(p1 < message.length() && message.charAt(p1) != ' ') p1++; String link = message.substring(p0, p1); lastResult = "" + message.substring(0, p0) + "
" + link + "
" + message.substring(p1) + ""; } } break; } else if (type.equals("OK")) { status = SUCCESS; lastResult = i18n("success_" + message.replace(' ', '_')); break; } else if (type.equals("HINT") && this instanceof ListWriters) processHint(message); else if (type.equals("HINT")) { final String message0 = message; invokeAndWait(new Runnable() { public void run() { processHint(message0); } }); } else if (type.equals("INFO")) processInfo(message); else if (type.equals("CDRECORD") || type.equals("CDWVERIFY") || type.equals("MKISOFS") || type.equals("READCD")) { toLog(message); processLog(message); } else { try { final int code = Integer.parseInt(type); final String text = message; if (!processInternal(code, text)) invokeAndWait(new Runnable() { public void run() { process(code, text); } }); } catch (Exception e) { } } } } public static String removeEscChars(String str) { char str2[] = new char[str.length()]; int i, j; for (i = 0, j = 0; i < str.length(); j++) { if (str.charAt(i) == '%') { i++; int digits = 2; if (str.charAt(i) == 'u') { digits = 4; i++; } try { str2[j] = (char) Integer.parseInt( str.substring(i, i + digits), 16); } catch (NumberFormatException e) { str2[j] = '_'; } i += digits; } else str2[j] = str.charAt(i++); } return new String(str2, 0, j); } protected void resetOpenCommands() { openCommands = 0; } public void run() { closeDialog(); } protected void setTitle(String title) { if (!(dialog instanceof JDialog)) return; final JDialog dialog = (JDialog) this.dialog; synchronized(dialog) { if (updateTitle != null) { updateTitle = title; return; } updateTitle = title; } SwingUtilities.invokeLater(new Runnable() { public void run() { synchronized(dialog) { dialog.setTitle(Version.product + " - " + updateTitle); updateTitle = null; } } }); } protected void show(final JComponent component) { show(component, "none"); } protected void show(final JComponent component, final String title) { Version.debug("show", title + "..."); if (component instanceof JOptionPane) { JOptionPane pane = (JOptionPane) component; Object[] options = pane.getOptions(); for (int i = 0; i < options.length; i++) { if (options[i] instanceof JComponent) continue; Version.debug("show", "option: " + options[i]); options[i] = new JButton(options[i].toString()); ((JButton) options[i]).addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { Version.debug("show", "" + e); closeDialog(); } }); } pane.setOptions(options); } final RootPaneContainer dialog2 = (RootPaneContainer) dialog; invokeLater(new Runnable() { public void run() { if (!title.equals("none") && dialog instanceof JDialog) { JDialog dialog3 = (JDialog) dialog; dialog3.setTitle(Version.product + " - " + title); } dialog2.getContentPane().removeAll(); dialog2.getContentPane().add(component, BorderLayout.CENTER); // dialog.pack(); dialog.validate(); if (dialog.isVisible()) dialog.repaint(); Dimension d = component.getMinimumSize(); Dimension d2 = dialog.getSize(); if (d.height > d2.height) { d2.height = d.height; // dialog.setSize(d2); } Version.debug("show", title + "... done"); } }); } protected void showCentered(JComponent component, String title) { JPanel vp = new JPanel(); vp.setLayout(new BoxLayout(vp, BoxLayout.Y_AXIS)); vp.add(Box.createVerticalGlue()); vp.add(component); vp.add(Box.createVerticalGlue()); show(vp, title); } public int showConfirmDialog( Object message, String title, int optionType) { return JOptionPane.showConfirmDialog( dialog, message, title, optionType); } public int showOptionDialog( Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) { return JOptionPane.showOptionDialog( dialog, message, title, optionType, messageType, icon, options, initialValue); } void showResult() { execSemaphore.setDone(); } protected void sleep(int msec) { try { Thread.currentThread().sleep(msec); } catch (InterruptedException e) { } } /** * replace 0x00 to 0x20 by %00 to %20 */ public static String spaceToEsc(String str) { char str2[] = new char[6 * str.length()]; int i, j; for (i = 0, j = 0; i < str.length(); i++, j++) { char code = str.charAt(i); if (code > 0x20 && code < 0x7F && code != '%') str2[j] = code; else if (code < 0x100) { str2[j++] = '%'; String codeStr = Integer.toHexString(0x100 + code); str2[j++] = codeStr.charAt(1); str2[j] = codeStr.charAt(2); } else { str2[j++] = '%'; str2[j++] = 'u'; String codeStr = Integer.toHexString( 0x10000 + (code & 0xFFFF)); str2[j++] = codeStr.charAt(1); str2[j++] = codeStr.charAt(2); str2[j++] = codeStr.charAt(3); str2[j] = codeStr.charAt(4); } } return new String(str2, 0, j); } protected void toLog(String str) { if (writer < 0) Log.put(str); else Log.put(writer + ": " + str); } protected void validate() { invokeAndWait(new Runnable() { public void run() { dialog.validate(); dialog.repaint(); } }); } protected synchronized void writeCommand(String cmdStr) throws java.io.IOException { openCommands++; cmdStr.replace('\n', ' '); Version.debug("command", "-> \"" + cmdStr + "\"" + " " + openCommands); CDcreator.outStream.writeBytes(cmdStr + '\n'); } protected void writeCommandIgnoreException(String cmdStr) { try { writeCommand(cmdStr); } catch (java.io.IOException e) { } } protected void writeHint(String cmdStr) { writeCommandIgnoreException(cmdStr); if (openCommands > 0) openCommands--; } class ExecSemaphore { private boolean done = false; synchronized void setDone() { done = true; notify(); } synchronized void setDone(boolean done) { this.done = done; notify(); } synchronized void untilDone() { Version.debug("wait", "start"); while (!done) try { wait(); } catch (InterruptedException e) { } Version.debug("wait", "done"); } } }