diff --git a/datafiles-src/tours/convert-images.sh b/datafiles-src/tours/convert-images.sh
new file mode 100755
index 000000000..f9fa53c15
--- /dev/null
+++ b/datafiles-src/tours/convert-images.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+#
+# A script to batch-convert all source image files into suitable
+# slideset image files. It converts all *.png, *.jpg and *.xcf.gz
+# files into the suitably sized jpg images in the datafiles directory.
+#
+
+DEST=../../datafiles/tours
+
+CONVERSION="-background #ececec -flatten -geometry 600x400 -quality 85"
+
+
+# Convert all xcf files
+find -iname "*.xcf.gz" | grep -v MANUAL | while read FILE; do
+
+ echo Converting $FILE
+ BASE="$(echo $FILE | sed 's/\.xcf\.gz$//')"
+ xcf2png "$FILE" | convert $CONVERSION - $DEST/$BASE.jpg
+
+done
+
+# Convert all png and jpg files
+find -iname "*.png" -o -iname "*.jpg" | grep -v MANUAL | while read FILE; do
+
+ echo Converting $FILE
+ BASE="$(echo $FILE | sed 's/\.png$//' | sed 's/\.jpg$//')"
+ convert $CONVERSION $FILE $DEST/$BASE.jpg
+
+done
\ No newline at end of file
diff --git a/datafiles-src/tours/introduction/advanced_features.xcf.gz b/datafiles-src/tours/introduction/advanced_features.xcf.gz
new file mode 100644
index 000000000..5c687d33d
Binary files /dev/null and b/datafiles-src/tours/introduction/advanced_features.xcf.gz differ
diff --git a/datafiles-src/tours/introduction/flight_simulations.xcf.gz b/datafiles-src/tours/introduction/flight_simulations.xcf.gz
new file mode 100644
index 000000000..e3fb8adfe
Binary files /dev/null and b/datafiles-src/tours/introduction/flight_simulations.xcf.gz differ
diff --git a/datafiles-src/tours/introduction/logo-MANUAL.xcf.gz b/datafiles-src/tours/introduction/logo-MANUAL.xcf.gz
new file mode 100644
index 000000000..910c4f3ce
Binary files /dev/null and b/datafiles-src/tours/introduction/logo-MANUAL.xcf.gz differ
diff --git a/datafiles-src/tours/introduction/main_window.png b/datafiles-src/tours/introduction/main_window.png
new file mode 100644
index 000000000..8a217a99b
Binary files /dev/null and b/datafiles-src/tours/introduction/main_window.png differ
diff --git a/datafiles-src/tours/introduction/main_window_bottom.xcf.gz b/datafiles-src/tours/introduction/main_window_bottom.xcf.gz
new file mode 100644
index 000000000..3a2f23e44
Binary files /dev/null and b/datafiles-src/tours/introduction/main_window_bottom.xcf.gz differ
diff --git a/datafiles-src/tours/introduction/main_window_top.xcf.gz b/datafiles-src/tours/introduction/main_window_top.xcf.gz
new file mode 100644
index 000000000..ba0820685
Binary files /dev/null and b/datafiles-src/tours/introduction/main_window_top.xcf.gz differ
diff --git a/datafiles/tours/designed_rocket.png b/datafiles/tours/designed_rocket.png
deleted file mode 100644
index 0accfa23b..000000000
Binary files a/datafiles/tours/designed_rocket.png and /dev/null differ
diff --git a/datafiles/tours/introduction/advanced_features.jpg b/datafiles/tours/introduction/advanced_features.jpg
new file mode 100644
index 000000000..24cc9b1aa
Binary files /dev/null and b/datafiles/tours/introduction/advanced_features.jpg differ
diff --git a/datafiles/tours/introduction/flight_simulations.jpg b/datafiles/tours/introduction/flight_simulations.jpg
new file mode 100644
index 000000000..0d112dbba
Binary files /dev/null and b/datafiles/tours/introduction/flight_simulations.jpg differ
diff --git a/datafiles/tours/introduction/introduction.tour b/datafiles/tours/introduction/introduction.tour
new file mode 100644
index 000000000..48386f36b
--- /dev/null
+++ b/datafiles/tours/introduction/introduction.tour
@@ -0,0 +1,84 @@
+
+Introduction
+
+
This first tour provides a quick overview of OpenRocket screens and
+features.
+
+
+[logo.png]
+# TODO: Add "Welcome to OpenRocket" text to image.
+
+
OpenRocket is a versatile application for designing,
+simulating and optimizing model rockets. This first tour provides an
+overview of the OpenRocket screens and features.
+
+
You can browse through the tour using the Next and
+Previous buttons, or using the left and right
+arrows on your keyboard.
+
+
+[none]
+
+
This is the startup screen from which you can create a new rocket
+design or open existing designs.
+
+
For this tour, let's open an example design called A simple model
+rocket.
+
+
+[main_window.jpg]
+
+
This is the main screen of OpenRocket. It is divided horizontally
+into two parts: the rocket design / flight simulation section and the
+rocket design view.
+
+
+[main_window_top.jpg]
+
+
On the top left is the component tree of the rocket design.
+It displays which components are attached to what components.
+
+
Next to it are buttons which allow adding new components to the
+rocket.
+
+
+[main_window_bottom.jpg]
+
+
The bottom half of the window contains a diagram of the current
+rocket design.
+
+
The different viewing options are described in detail in the
+Viewing options tour.
+
+
+[flight_simulations.jpg]
+
+
When you select the Flight simulations tab, the top part of
+the window changes to show the simulations that have been defined for
+the rocket.
+
+
You can define various simulations with different motor
+configurations and differing launch conditions, such as wind and
+launch rod angle.
+
+
+[simulation_edit.png]
+
+
By double-clicking on a simulation you open the Simulation edit
+dialog. On the first two tabs you can define simulation options,
+on the last two tabs you can plot or export the results.
+
+
Simulating a rocket is described in detail in the
+Simulating a flight tour.
+
+
+[advanced_features.jpg]
+
+
Other advanced features include component analysis and automatic
+design optimization, which are covered by separate tours.
+
+
Next you can take a tour on Creating a rocket
+design, browse other tours or start experimenting with the
+software.
+
+
diff --git a/datafiles/tours/introduction/logo.png b/datafiles/tours/introduction/logo.png
new file mode 100644
index 000000000..9946c41f6
Binary files /dev/null and b/datafiles/tours/introduction/logo.png differ
diff --git a/datafiles/tours/introduction/main_window.jpg b/datafiles/tours/introduction/main_window.jpg
new file mode 100644
index 000000000..8f6713ba6
Binary files /dev/null and b/datafiles/tours/introduction/main_window.jpg differ
diff --git a/datafiles/tours/introduction/main_window_bottom.jpg b/datafiles/tours/introduction/main_window_bottom.jpg
new file mode 100644
index 000000000..1a38592b2
Binary files /dev/null and b/datafiles/tours/introduction/main_window_bottom.jpg differ
diff --git a/datafiles/tours/introduction/main_window_top.jpg b/datafiles/tours/introduction/main_window_top.jpg
new file mode 100644
index 000000000..aef896480
Binary files /dev/null and b/datafiles/tours/introduction/main_window_top.jpg differ
diff --git a/datafiles/tours/introduction/simulation_edit.png b/datafiles/tours/introduction/simulation_edit.png
new file mode 100644
index 000000000..552a414c4
Binary files /dev/null and b/datafiles/tours/introduction/simulation_edit.png differ
diff --git a/datafiles/tours/rocket_configuration.png b/datafiles/tours/rocket_configuration.png
deleted file mode 100644
index e2ddd7e16..000000000
Binary files a/datafiles/tours/rocket_configuration.png and /dev/null differ
diff --git a/datafiles/tours/style.css b/datafiles/tours/style.css
index 4aa6f5506..59c62b8e1 100644
--- a/datafiles/tours/style.css
+++ b/datafiles/tours/style.css
@@ -11,10 +11,14 @@ div.base {
}
p {
- margin: 0 0 5px;
+ margin: 0 0 8px;
}
a {
color: #0000dd;
text-decoration: underline;
}
+
+em {
+ font-style: italics;
+}
\ No newline at end of file
diff --git a/datafiles/tours/left_design.png b/datafiles/tours/test1/left_design.png
similarity index 100%
rename from datafiles/tours/left_design.png
rename to datafiles/tours/test1/left_design.png
diff --git a/datafiles/tours/main_window.png b/datafiles/tours/test1/main_window.png
similarity index 100%
rename from datafiles/tours/main_window.png
rename to datafiles/tours/test1/main_window.png
diff --git a/datafiles/tours/test.tour b/datafiles/tours/test1/test.tour
similarity index 73%
rename from datafiles/tours/test.tour
rename to datafiles/tours/test1/test.tour
index 978771cd1..f5a278b86 100644
--- a/datafiles/tours/test.tour
+++ b/datafiles/tours/test1/test.tour
@@ -11,7 +11,8 @@ This is the description.
This is the first slide — the left_design file.
It's nifty. It can also contain links (though they don't work yet).
-
+
Tour2: Test2
+
Hyperlink: google
[main_window.png]
diff --git a/datafiles/tours/test_de.tour b/datafiles/tours/test1/test_de.tour
similarity index 100%
rename from datafiles/tours/test_de.tour
rename to datafiles/tours/test1/test_de.tour
diff --git a/datafiles/tours/test2/left_design.png b/datafiles/tours/test2/left_design.png
new file mode 100644
index 000000000..4c496d50c
Binary files /dev/null and b/datafiles/tours/test2/left_design.png differ
diff --git a/datafiles/tours/test2/main_window.png b/datafiles/tours/test2/main_window.png
new file mode 100644
index 000000000..d6f7f70cd
Binary files /dev/null and b/datafiles/tours/test2/main_window.png differ
diff --git a/datafiles/tours/test2.tour b/datafiles/tours/test2/test2.tour
similarity index 100%
rename from datafiles/tours/test2.tour
rename to datafiles/tours/test2/test2.tour
diff --git a/datafiles/tours/tours.txt b/datafiles/tours/tours.txt
index 79242c079..200e9d111 100644
--- a/datafiles/tours/tours.txt
+++ b/datafiles/tours/tours.txt
@@ -1,6 +1,9 @@
# This file lists all the available tours.
-test.tour
-test2.tour
+introduction/introduction.tour
+
+
+test1/test.tour
+test2/test2.tour
diff --git a/src/net/sf/openrocket/gui/help/tours/GuidedTourSelectionDialog.java b/src/net/sf/openrocket/gui/help/tours/GuidedTourSelectionDialog.java
index c2ede5e2d..baff4a5bb 100644
--- a/src/net/sf/openrocket/gui/help/tours/GuidedTourSelectionDialog.java
+++ b/src/net/sf/openrocket/gui/help/tours/GuidedTourSelectionDialog.java
@@ -5,8 +5,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
-import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.List;
import javax.swing.AbstractListModel;
@@ -29,16 +27,14 @@ import net.sf.openrocket.gui.components.StyledLabel.Style;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Named;
public class GuidedTourSelectionDialog extends JDialog {
private static final Translator trans = Application.getTranslator();
- private static final String TOURS_BASE_DIR = "datafiles/tours";
-
+
private final SlideSetManager slideSetManager;
private final List tourNames;
@@ -52,21 +48,9 @@ public class GuidedTourSelectionDialog extends JDialog {
public GuidedTourSelectionDialog(Window parent) {
super(parent, trans.get("title"), ModalityType.MODELESS);
- try {
-
- slideSetManager = new SlideSetManager(TOURS_BASE_DIR);
- slideSetManager.load();
-
- tourNames = slideSetManager.getSlideSetNames();
- if (tourNames.isEmpty()) {
- throw new FileNotFoundException("No tours found.");
- }
-
- } catch (IOException e) {
- throw new BugException(e);
- }
+ slideSetManager = SlideSetManager.getSlideSetManager();
+ tourNames = slideSetManager.getSlideSetNames();
-
JPanel panel = new JPanel(new MigLayout("fill"));
panel.add(new StyledLabel(trans.get("lbl.selectTour"), Style.BOLD), "spanx, wrap rel");
@@ -87,10 +71,10 @@ public class GuidedTourSelectionDialog extends JDialog {
}
}
});
- panel.add(new JScrollPane(tourList), "grow, gapright unrel, w 200lp, h 150lp");
+ panel.add(new JScrollPane(tourList), "grow, gapright unrel, w 200lp, h 250lp");
+
+
-
-
// Sub-panel containing description and start button
JPanel sub = new JPanel(new MigLayout("fill, ins 0"));
sub.add(new StyledLabel(trans.get("lbl.description"), -1), "wrap rel");
@@ -113,10 +97,10 @@ public class GuidedTourSelectionDialog extends JDialog {
});
sub.add(start, "growx");
- panel.add(sub, "grow, wrap para, w 200lp, h 150lp");
+ panel.add(sub, "grow, wrap para, w 350lp, h 250lp");
+
+
-
-
JButton close = new JButton(trans.get("button.close"));
close.addActionListener(new ActionListener() {
@Override
@@ -128,6 +112,7 @@ public class GuidedTourSelectionDialog extends JDialog {
this.add(panel);
GUIUtil.setDisposableDialogOptions(this, close);
+ GUIUtil.rememberWindowPosition(this);
tourList.setSelectedIndex(0);
}
@@ -192,6 +177,6 @@ public class GuidedTourSelectionDialog extends JDialog {
}
-
-
+
+
}
diff --git a/src/net/sf/openrocket/gui/help/tours/Slide.java b/src/net/sf/openrocket/gui/help/tours/Slide.java
index 7ac4212b0..c3c1fab87 100644
--- a/src/net/sf/openrocket/gui/help/tours/Slide.java
+++ b/src/net/sf/openrocket/gui/help/tours/Slide.java
@@ -14,6 +14,7 @@ import javax.imageio.ImageIO;
* @author Sampo Niskanen
*/
public class Slide {
+ private static final String NO_IMAGE = "none";
private final String imageFile;
private SoftReference imageReference = null;
@@ -21,16 +22,20 @@ public class Slide {
private final String text;
-
+
public Slide(String imageFile, String text) {
this.imageFile = imageFile;
this.text = text;
}
-
+
public BufferedImage getImage() {
+ if (imageFile.equals(NO_IMAGE)) {
+ return new BufferedImage(0, 0, BufferedImage.TYPE_INT_ARGB);
+ }
+
// Check the cache
if (imageReference != null) {
BufferedImage image = imageReference.get();
@@ -51,7 +56,7 @@ public class Slide {
}
-
+
private BufferedImage loadImage() {
BufferedImage img;
diff --git a/src/net/sf/openrocket/gui/help/tours/SlideSetManager.java b/src/net/sf/openrocket/gui/help/tours/SlideSetManager.java
index abf5e74b8..0d9e38155 100644
--- a/src/net/sf/openrocket/gui/help/tours/SlideSetManager.java
+++ b/src/net/sf/openrocket/gui/help/tours/SlideSetManager.java
@@ -11,6 +11,8 @@ import java.util.Map;
import javax.swing.text.html.StyleSheet;
+import net.sf.openrocket.util.BugException;
+
/**
* A manager that loads a number of slide sets from a defined base directory
* and provides access to them.
@@ -18,11 +20,14 @@ import javax.swing.text.html.StyleSheet;
* @author Sampo Niskanen
*/
public class SlideSetManager {
+ private static final String TOURS_BASE_DIR = "datafiles/tours";
private static final String TOURS_FILE = "tours.txt";
private static final String STYLESHEET_FILE = "style.css";
-
+ private static SlideSetManager slideSetManager = null;
+
+
private final String baseDir;
private final Map slideSets = new LinkedHashMap();
@@ -49,20 +54,24 @@ public class SlideSetManager {
List tours = loadTourList();
StyleSheet styleSheet = loadStyleSheet();
- for (String file : tours) {
+ for (String fileAndDir : tours) {
+ String base;
+ String file;
- String base = baseDir + file;
- int index = base.lastIndexOf('/');
+ String fullFileAndDir = baseDir + fileAndDir;
+ int index = fullFileAndDir.lastIndexOf('/');
if (index >= 0) {
- base = base.substring(0, index);
+ base = fullFileAndDir.substring(0, index);
+ file = fullFileAndDir.substring(index + 1);
} else {
base = "";
+ file = "";
}
SlideSetLoader loader = new SlideSetLoader(base);
SlideSet set = loader.load(file);
set.setStyleSheet(styleSheet);
- slideSets.put(file, set);
+ slideSets.put(fileAndDir, set);
}
}
@@ -131,4 +140,26 @@ public class SlideSetManager {
}
+
+
+ /**
+ * Return a singleton implementation that has loaded the default tours.
+ */
+ public static SlideSetManager getSlideSetManager() {
+ if (slideSetManager == null) {
+ try {
+ SlideSetManager ssm = new SlideSetManager(TOURS_BASE_DIR);
+ ssm.load();
+
+ if (ssm.getSlideSetNames().isEmpty()) {
+ throw new FileNotFoundException("No tours found.");
+ }
+
+ slideSetManager = ssm;
+ } catch (IOException e) {
+ throw new BugException(e);
+ }
+ }
+ return slideSetManager;
+ }
}
diff --git a/src/net/sf/openrocket/gui/help/tours/SlideShowComponent.java b/src/net/sf/openrocket/gui/help/tours/SlideShowComponent.java
index 4e11d252b..236f9cc89 100644
--- a/src/net/sf/openrocket/gui/help/tours/SlideShowComponent.java
+++ b/src/net/sf/openrocket/gui/help/tours/SlideShowComponent.java
@@ -19,6 +19,10 @@ import net.sf.openrocket.gui.components.ImageDisplayComponent;
*/
public class SlideShowComponent extends JSplitPane {
+ private final int WIDTH = 600;
+ private final int HEIGHT_IMAGE = 400;
+ private final int HEIGHT_TEXT = 100;
+
private final ImageDisplayComponent imageDisplay;
private final JEditorPane textPane;
@@ -27,21 +31,21 @@ public class SlideShowComponent extends JSplitPane {
super(VERTICAL_SPLIT);
imageDisplay = new ImageDisplayComponent();
- imageDisplay.setPreferredSize(new Dimension(600, 350));
+ imageDisplay.setPreferredSize(new Dimension(WIDTH, HEIGHT_IMAGE));
this.setLeftComponent(imageDisplay);
textPane = new JEditorPane("text/html", "");
textPane.setEditable(false);
- textPane.setPreferredSize(new Dimension(600, 100));
+ textPane.setPreferredSize(new Dimension(WIDTH, HEIGHT_TEXT));
JScrollPane scrollPanel = new JScrollPane(textPane);
this.setRightComponent(scrollPanel);
- this.setResizeWeight(0.7);
+ this.setResizeWeight(((double) HEIGHT_IMAGE) / (HEIGHT_IMAGE + HEIGHT_TEXT));
}
-
+
public void setSlide(Slide slide) {
this.imageDisplay.setImage(slide.getImage());
this.textPane.setText(slide.getText());
diff --git a/src/net/sf/openrocket/gui/help/tours/SlideShowDialog.java b/src/net/sf/openrocket/gui/help/tours/SlideShowDialog.java
index ca97e2e63..61936b911 100644
--- a/src/net/sf/openrocket/gui/help/tours/SlideShowDialog.java
+++ b/src/net/sf/openrocket/gui/help/tours/SlideShowDialog.java
@@ -3,24 +3,28 @@ package net.sf.openrocket.gui.help.tours;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.util.Locale;
+import java.awt.event.KeyEvent;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.JButton;
+import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.HyperlinkEvent;
-import javax.swing.event.HyperlinkListener;
+import javax.swing.JRootPane;
+import javax.swing.KeyStroke;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Chars;
public class SlideShowDialog extends JDialog {
+ private static final LogHelper log = Application.getLogger();
private static final Translator trans = Application.getTranslator();
private SlideShowComponent slideShowComponent;
@@ -38,35 +42,38 @@ public class SlideShowDialog extends JDialog {
JPanel panel = new JPanel(new MigLayout("fill"));
slideShowComponent = new SlideShowComponent();
+ slideShowComponent.addHyperlinkListener(new SlideShowLinkListener(parent));
panel.add(slideShowComponent, "spanx, grow, wrap para");
-
+
JPanel sub = new JPanel(new MigLayout("ins 0, fill"));
prevButton = new JButton(Chars.LEFT_ARROW + " " + trans.get("btn.prev"));
prevButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
+ log.user("Clicked previous button");
setPosition(position - 1);
}
});
sub.add(prevButton, "left");
-
-
+
+
nextButton = new JButton(trans.get("btn.next") + " " + Chars.RIGHT_ARROW);
nextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
+ log.user("Clicked next button");
setPosition(position + 1);
}
});
sub.add(nextButton, "left, gapleft para");
-
+
sub.add(new JPanel(), "growx");
-
+
closeButton = new JButton(trans.get("button.close"));
closeButton.addActionListener(new ActionListener() {
@Override
@@ -76,12 +83,16 @@ public class SlideShowDialog extends JDialog {
});
sub.add(closeButton, "right");
-
+
panel.add(sub, "growx");
this.add(panel);
updateEnabled();
+ addKeyActions();
GUIUtil.setDisposableDialogOptions(this, nextButton);
+ nextButton.grabFocus();
+ GUIUtil.rememberWindowPosition(this);
+ GUIUtil.rememberWindowSize(this);
this.setAlwaysOnTop(true);
}
@@ -120,41 +131,43 @@ public class SlideShowDialog extends JDialog {
}
- public static void main(String[] args) throws Exception {
-
- Locale.setDefault(new Locale("de", "DE", ""));
-
- SlideSetManager manager = new SlideSetManager("datafiles/tours");
- manager.load();
-
- final SlideSet set = manager.getSlideSet("test.tour");
-
- SwingUtilities.invokeAndWait(new Runnable() {
+
+
+
+ private void addKeyActions() {
+ Action next = new AbstractAction() {
@Override
- public void run() {
-
- SlideShowDialog ssd = new SlideShowDialog(null);
-
- ssd.slideShowComponent.addHyperlinkListener(new HyperlinkListener() {
- @Override
- public void hyperlinkUpdate(HyperlinkEvent e) {
- System.out.println("Hyperlink event: " + e);
- System.out.println("Event type: " + e.getEventType());
- System.out.println("Description: " + e.getDescription());
- System.out.println("URL: " + e.getURL());
- System.out.println("Source element: " + e.getSourceElement());
-
- }
- });
-
- ssd.setSize(500, 500);
- ssd.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- ssd.setVisible(true);
-
- ssd.setSlideSet(set, 0);
+ public void actionPerformed(ActionEvent event) {
+ log.user("Key action for next slide");
+ if (position < slideSet.getSlideCount() - 1) {
+ setPosition(position + 1);
+ }
}
- });
+ };
+
+ Action previous = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ log.user("Key action for previous slide");
+ if (position > 0) {
+ setPosition(position - 1);
+ }
+ }
+ };
+
+ String nextKey = "slide:next";
+ String prevKey = "slide:previous";
+
+ JRootPane root = this.getRootPane();
+ root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), nextKey);
+ root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, 0), nextKey);
+ root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), prevKey);
+ root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, 0), prevKey);
+
+ root.getActionMap().put(nextKey, next);
+ root.getActionMap().put(prevKey, previous);
}
-
+
+
}
diff --git a/src/net/sf/openrocket/gui/help/tours/SlideShowLinkListener.java b/src/net/sf/openrocket/gui/help/tours/SlideShowLinkListener.java
new file mode 100644
index 000000000..5fc1d888a
--- /dev/null
+++ b/src/net/sf/openrocket/gui/help/tours/SlideShowLinkListener.java
@@ -0,0 +1,55 @@
+package net.sf.openrocket.gui.help.tours;
+
+import java.awt.Desktop;
+import java.awt.Window;
+import java.net.URL;
+
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkEvent.EventType;
+import javax.swing.event.HyperlinkListener;
+
+import net.sf.openrocket.startup.Application;
+
+public class SlideShowLinkListener implements HyperlinkListener {
+
+ private final Window parent;
+
+ public SlideShowLinkListener(Window parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent event) {
+
+ if (event.getEventType() != EventType.ACTIVATED) {
+ return;
+ }
+
+ URL url = event.getURL();
+ if (url != null && (url.getProtocol().equalsIgnoreCase("http") || url.getProtocol().equals("https"))) {
+
+ if (Desktop.isDesktopSupported()) {
+ try {
+ Desktop.getDesktop().browse(url.toURI());
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+
+ } else {
+
+ String name = event.getDescription();
+ try {
+ SlideSet ss = SlideSetManager.getSlideSetManager().getSlideSet(name);
+
+ SlideShowDialog dialog = new SlideShowDialog(parent);
+ dialog.setSlideSet(ss, 0);
+ dialog.setVisible(true);
+ } catch (IllegalArgumentException e) {
+ Application.getExceptionHandler().handleErrorCondition("Guided tour '" + name + "' not found.");
+ }
+
+ }
+
+ }
+}
diff --git a/src/net/sf/openrocket/gui/util/GUIUtil.java b/src/net/sf/openrocket/gui/util/GUIUtil.java
index c796405c8..4ee74ba4e 100644
--- a/src/net/sf/openrocket/gui/util/GUIUtil.java
+++ b/src/net/sf/openrocket/gui/util/GUIUtil.java
@@ -127,8 +127,8 @@ public class GUIUtil {
}
-
-
+
+
/**
* Set suitable options for a single-use disposable dialog. This includes
* setting ESC to close the dialog, adding the appropriate window icons and
@@ -153,7 +153,7 @@ public class GUIUtil {
}
-
+
/**
* Add the correct action to close a JDialog when the ESC key is pressed.
* The dialog is closed by sending is a WINDOW_CLOSING event.
@@ -192,7 +192,7 @@ public class GUIUtil {
}
-
+
/**
* Change the behavior of a component so that TAB and Shift-TAB cycles the focus of
* the components. This is necessary for e.g. JTextArea
.
@@ -207,7 +207,7 @@ public class GUIUtil {
}
-
+
/**
* Set the OpenRocket icons to the window icons.
*
@@ -236,7 +236,7 @@ public class GUIUtil {
}
-
+
/**
* Set the best available look-and-feel into use.
*/
@@ -294,7 +294,7 @@ public class GUIUtil {
}
-
+
/**
* Automatically remember the size of a window. This stores the window size in the user
* preferences when resizing/maximizing the window and sets the state on the first call.
@@ -377,7 +377,7 @@ public class GUIUtil {
}
-
+
/**
* Traverses recursively the component tree, and sets all applicable component
* models to null, so as to remove the listener connections. After calling this
@@ -519,7 +519,7 @@ public class GUIUtil {
}
-
+
/**
* A mouse listener that toggles the state of a boolean value in a table model
* when clicked on another column of the table.