introduction tour
							
								
								
									
										30
									
								
								datafiles-src/tours/convert-images.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -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
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								datafiles-src/tours/introduction/advanced_features.xcf.gz
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								datafiles-src/tours/introduction/flight_simulations.xcf.gz
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								datafiles-src/tours/introduction/logo-MANUAL.xcf.gz
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								datafiles-src/tours/introduction/main_window.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 112 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles-src/tours/introduction/main_window_bottom.xcf.gz
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								datafiles-src/tours/introduction/main_window_top.xcf.gz
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 Before Width: | Height: | Size: 50 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/advanced_features.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 44 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/flight_simulations.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										84
									
								
								datafiles/tours/introduction/introduction.tour
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					Introduction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>This first tour provides a quick overview of OpenRocket screens and
 | 
				
			||||||
 | 
					features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[logo.png]
 | 
				
			||||||
 | 
					# TODO: Add "Welcome to OpenRocket" text to image.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p><b>OpenRocket</b> is a versatile application for designing,
 | 
				
			||||||
 | 
					simulating and optimizing model rockets.  This first tour provides an
 | 
				
			||||||
 | 
					overview of the OpenRocket screens and features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>You can browse through the tour using the <b>Next</b> and
 | 
				
			||||||
 | 
					<b>Previous</b> buttons, or using the <em>left</em> and <em>right
 | 
				
			||||||
 | 
					arrows</em> on your keyboard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[none]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>This is the startup screen from which you can create a new rocket
 | 
				
			||||||
 | 
					design or open existing designs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>For this tour, let's open an example design called <em>A simple model
 | 
				
			||||||
 | 
					rocket</em>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[main_window.jpg]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>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]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>On the top left is the component tree of the rocket design.
 | 
				
			||||||
 | 
					It displays which components are attached to what components.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>Next to it are buttons which allow adding new components to the
 | 
				
			||||||
 | 
					rocket.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[main_window_bottom.jpg]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>The bottom half of the window contains a diagram of the current
 | 
				
			||||||
 | 
					rocket design.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>The different viewing options are described in detail in the
 | 
				
			||||||
 | 
					<a href="FIXME">Viewing options</a> tour. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[flight_simulations.jpg]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>When you select the <b>Flight simulations</b> tab, the top part of
 | 
				
			||||||
 | 
					the window changes to show the simulations that have been defined for
 | 
				
			||||||
 | 
					the rocket.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>You can define various simulations with different motor
 | 
				
			||||||
 | 
					configurations and differing launch conditions, such as wind and
 | 
				
			||||||
 | 
					launch rod angle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[simulation_edit.png]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>By double-clicking on a simulation you open the <em>Simulation edit
 | 
				
			||||||
 | 
					dialog</em>.  On the first two tabs you can define simulation options,
 | 
				
			||||||
 | 
					on the last two tabs you can plot or export the results.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>Simulating a rocket is described in detail in the
 | 
				
			||||||
 | 
					<a href="FIXME">Simulating a flight</a> tour.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[advanced_features.jpg]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>Other advanced features include component analysis and automatic
 | 
				
			||||||
 | 
					design optimization, which are covered by separate tours.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>Next you can take a tour on <a href="FIXME">Creating a rocket
 | 
				
			||||||
 | 
					design</a>, browse other tours or start experimenting with the
 | 
				
			||||||
 | 
					software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 86 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/main_window.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/main_window_bottom.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/main_window_top.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/introduction/simulation_edit.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 51 KiB  | 
| 
		 Before Width: | Height: | Size: 17 KiB  | 
@ -11,10 +11,14 @@ div.base {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
p {
 | 
					p {
 | 
				
			||||||
  margin: 0 0 5px;
 | 
					  margin: 0 0 8px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
a {
 | 
					a {
 | 
				
			||||||
  color: #0000dd;
 | 
					  color: #0000dd;
 | 
				
			||||||
  text-decoration: underline;
 | 
					  text-decoration: underline;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					em {
 | 
				
			||||||
 | 
					  font-style: italics;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB  | 
| 
		 Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB  | 
@ -11,7 +11,8 @@ This is the <i>description</i>.
 | 
				
			|||||||
<p>This is the first slide — the left_design file.
 | 
					<p>This is the first slide — the left_design file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<p>It's nifty. It can also contain <a href="foobar">links</a> (though they don't work yet).
 | 
					<p>It's nifty. It can also contain <a href="foobar">links</a> (though they don't work yet).
 | 
				
			||||||
 | 
					<p>Tour2: <a href="test2/test2.tour">Test2</a>
 | 
				
			||||||
 | 
					<p>Hyperlink: <a href="http://www.google.com">google</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[main_window.png]
 | 
					[main_window.png]
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/test2/left_design.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 19 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								datafiles/tours/test2/main_window.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
@ -1,6 +1,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# This file lists all the available tours.
 | 
					# This file lists all the available tours.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test.tour
 | 
					introduction/introduction.tour
 | 
				
			||||||
test2.tour
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test1/test.tour
 | 
				
			||||||
 | 
					test2/test2.tour
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,8 +5,6 @@ import java.awt.event.ActionEvent;
 | 
				
			|||||||
import java.awt.event.ActionListener;
 | 
					import java.awt.event.ActionListener;
 | 
				
			||||||
import java.awt.event.MouseAdapter;
 | 
					import java.awt.event.MouseAdapter;
 | 
				
			||||||
import java.awt.event.MouseEvent;
 | 
					import java.awt.event.MouseEvent;
 | 
				
			||||||
import java.io.FileNotFoundException;
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.AbstractListModel;
 | 
					import javax.swing.AbstractListModel;
 | 
				
			||||||
@ -29,14 +27,12 @@ import net.sf.openrocket.gui.components.StyledLabel.Style;
 | 
				
			|||||||
import net.sf.openrocket.gui.util.GUIUtil;
 | 
					import net.sf.openrocket.gui.util.GUIUtil;
 | 
				
			||||||
import net.sf.openrocket.l10n.Translator;
 | 
					import net.sf.openrocket.l10n.Translator;
 | 
				
			||||||
import net.sf.openrocket.startup.Application;
 | 
					import net.sf.openrocket.startup.Application;
 | 
				
			||||||
import net.sf.openrocket.util.BugException;
 | 
					 | 
				
			||||||
import net.sf.openrocket.util.Named;
 | 
					import net.sf.openrocket.util.Named;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class GuidedTourSelectionDialog extends JDialog {
 | 
					public class GuidedTourSelectionDialog extends JDialog {
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private static final Translator trans = Application.getTranslator();
 | 
						private static final Translator trans = Application.getTranslator();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private static final String TOURS_BASE_DIR = "datafiles/tours";
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private final SlideSetManager slideSetManager;
 | 
						private final SlideSetManager slideSetManager;
 | 
				
			||||||
@ -52,20 +48,8 @@ public class GuidedTourSelectionDialog extends JDialog {
 | 
				
			|||||||
	public GuidedTourSelectionDialog(Window parent) {
 | 
						public GuidedTourSelectionDialog(Window parent) {
 | 
				
			||||||
		super(parent, trans.get("title"), ModalityType.MODELESS);
 | 
							super(parent, trans.get("title"), ModalityType.MODELESS);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		try {
 | 
							slideSetManager = SlideSetManager.getSlideSetManager();
 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			slideSetManager = new SlideSetManager(TOURS_BASE_DIR);
 | 
					 | 
				
			||||||
			slideSetManager.load();
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
		tourNames = slideSetManager.getSlideSetNames();
 | 
							tourNames = slideSetManager.getSlideSetNames();
 | 
				
			||||||
			if (tourNames.isEmpty()) {
 | 
					 | 
				
			||||||
				throw new FileNotFoundException("No tours found.");
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
		} catch (IOException e) {
 | 
					 | 
				
			||||||
			throw new BugException(e);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		JPanel panel = new JPanel(new MigLayout("fill"));
 | 
							JPanel panel = new JPanel(new MigLayout("fill"));
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@ -87,7 +71,7 @@ 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");
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@ -113,7 +97,7 @@ public class GuidedTourSelectionDialog extends JDialog {
 | 
				
			|||||||
		});
 | 
							});
 | 
				
			||||||
		sub.add(start, "growx");
 | 
							sub.add(start, "growx");
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		panel.add(sub, "grow, wrap para, w 200lp, h 150lp");
 | 
							panel.add(sub, "grow, wrap para, w 350lp, h 250lp");
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@ -128,6 +112,7 @@ public class GuidedTourSelectionDialog extends JDialog {
 | 
				
			|||||||
		
 | 
							
 | 
				
			||||||
		this.add(panel);
 | 
							this.add(panel);
 | 
				
			||||||
		GUIUtil.setDisposableDialogOptions(this, close);
 | 
							GUIUtil.setDisposableDialogOptions(this, close);
 | 
				
			||||||
 | 
							GUIUtil.rememberWindowPosition(this);
 | 
				
			||||||
		tourList.setSelectedIndex(0);
 | 
							tourList.setSelectedIndex(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ import javax.imageio.ImageIO;
 | 
				
			|||||||
 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
 | 
					 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class Slide {
 | 
					public class Slide {
 | 
				
			||||||
 | 
						private static final String NO_IMAGE = "none";
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private final String imageFile;
 | 
						private final String imageFile;
 | 
				
			||||||
	private SoftReference<BufferedImage> imageReference = null;
 | 
						private SoftReference<BufferedImage> imageReference = null;
 | 
				
			||||||
@ -31,6 +32,10 @@ public class Slide {
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	public BufferedImage getImage() {
 | 
						public BufferedImage getImage() {
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 | 
							if (imageFile.equals(NO_IMAGE)) {
 | 
				
			||||||
 | 
								return new BufferedImage(0, 0, BufferedImage.TYPE_INT_ARGB);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		// Check the cache
 | 
							// Check the cache
 | 
				
			||||||
		if (imageReference != null) {
 | 
							if (imageReference != null) {
 | 
				
			||||||
			BufferedImage image = imageReference.get();
 | 
								BufferedImage image = imageReference.get();
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,8 @@ import java.util.Map;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import javax.swing.text.html.StyleSheet;
 | 
					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
 | 
					 * A manager that loads a number of slide sets from a defined base directory
 | 
				
			||||||
 * and provides access to them.
 | 
					 * and provides access to them.
 | 
				
			||||||
@ -18,10 +20,13 @@ import javax.swing.text.html.StyleSheet;
 | 
				
			|||||||
 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
 | 
					 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SlideSetManager {
 | 
					public class SlideSetManager {
 | 
				
			||||||
 | 
						private static final String TOURS_BASE_DIR = "datafiles/tours";
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private static final String TOURS_FILE = "tours.txt";
 | 
						private static final String TOURS_FILE = "tours.txt";
 | 
				
			||||||
	private static final String STYLESHEET_FILE = "style.css";
 | 
						private static final String STYLESHEET_FILE = "style.css";
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						private static SlideSetManager slideSetManager = null;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private final String baseDir;
 | 
						private final String baseDir;
 | 
				
			||||||
	private final Map<String, SlideSet> slideSets = new LinkedHashMap<String, SlideSet>();
 | 
						private final Map<String, SlideSet> slideSets = new LinkedHashMap<String, SlideSet>();
 | 
				
			||||||
@ -49,20 +54,24 @@ public class SlideSetManager {
 | 
				
			|||||||
		List<String> tours = loadTourList();
 | 
							List<String> tours = loadTourList();
 | 
				
			||||||
		StyleSheet styleSheet = loadStyleSheet();
 | 
							StyleSheet styleSheet = loadStyleSheet();
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		for (String file : tours) {
 | 
							for (String fileAndDir : tours) {
 | 
				
			||||||
 | 
								String base;
 | 
				
			||||||
 | 
								String file;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			String base = baseDir + file;
 | 
								String fullFileAndDir = baseDir + fileAndDir;
 | 
				
			||||||
			int index = base.lastIndexOf('/');
 | 
								int index = fullFileAndDir.lastIndexOf('/');
 | 
				
			||||||
			if (index >= 0) {
 | 
								if (index >= 0) {
 | 
				
			||||||
				base = base.substring(0, index);
 | 
									base = fullFileAndDir.substring(0, index);
 | 
				
			||||||
 | 
									file = fullFileAndDir.substring(index + 1);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				base = "";
 | 
									base = "";
 | 
				
			||||||
 | 
									file = "";
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			SlideSetLoader loader = new SlideSetLoader(base);
 | 
								SlideSetLoader loader = new SlideSetLoader(base);
 | 
				
			||||||
			SlideSet set = loader.load(file);
 | 
								SlideSet set = loader.load(file);
 | 
				
			||||||
			set.setStyleSheet(styleSheet);
 | 
								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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,10 @@ import net.sf.openrocket.gui.components.ImageDisplayComponent;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class SlideShowComponent extends JSplitPane {
 | 
					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 ImageDisplayComponent imageDisplay;
 | 
				
			||||||
	private final JEditorPane textPane;
 | 
						private final JEditorPane textPane;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@ -27,17 +31,17 @@ public class SlideShowComponent extends JSplitPane {
 | 
				
			|||||||
		super(VERTICAL_SPLIT);
 | 
							super(VERTICAL_SPLIT);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		imageDisplay = new ImageDisplayComponent();
 | 
							imageDisplay = new ImageDisplayComponent();
 | 
				
			||||||
		imageDisplay.setPreferredSize(new Dimension(600, 350));
 | 
							imageDisplay.setPreferredSize(new Dimension(WIDTH, HEIGHT_IMAGE));
 | 
				
			||||||
		this.setLeftComponent(imageDisplay);
 | 
							this.setLeftComponent(imageDisplay);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		textPane = new JEditorPane("text/html", "");
 | 
							textPane = new JEditorPane("text/html", "");
 | 
				
			||||||
		textPane.setEditable(false);
 | 
							textPane.setEditable(false);
 | 
				
			||||||
		textPane.setPreferredSize(new Dimension(600, 100));
 | 
							textPane.setPreferredSize(new Dimension(WIDTH, HEIGHT_TEXT));
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		JScrollPane scrollPanel = new JScrollPane(textPane);
 | 
							JScrollPane scrollPanel = new JScrollPane(textPane);
 | 
				
			||||||
		this.setRightComponent(scrollPanel);
 | 
							this.setRightComponent(scrollPanel);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		this.setResizeWeight(0.7);
 | 
							this.setResizeWeight(((double) HEIGHT_IMAGE) / (HEIGHT_IMAGE + HEIGHT_TEXT));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
				
			|||||||
@ -3,24 +3,28 @@ package net.sf.openrocket.gui.help.tours;
 | 
				
			|||||||
import java.awt.Window;
 | 
					import java.awt.Window;
 | 
				
			||||||
import java.awt.event.ActionEvent;
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
import java.awt.event.ActionListener;
 | 
					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.JButton;
 | 
				
			||||||
 | 
					import javax.swing.JComponent;
 | 
				
			||||||
import javax.swing.JDialog;
 | 
					import javax.swing.JDialog;
 | 
				
			||||||
import javax.swing.JPanel;
 | 
					import javax.swing.JPanel;
 | 
				
			||||||
import javax.swing.SwingUtilities;
 | 
					import javax.swing.JRootPane;
 | 
				
			||||||
import javax.swing.event.HyperlinkEvent;
 | 
					import javax.swing.KeyStroke;
 | 
				
			||||||
import javax.swing.event.HyperlinkListener;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.miginfocom.swing.MigLayout;
 | 
					import net.miginfocom.swing.MigLayout;
 | 
				
			||||||
import net.sf.openrocket.gui.util.GUIUtil;
 | 
					import net.sf.openrocket.gui.util.GUIUtil;
 | 
				
			||||||
import net.sf.openrocket.l10n.Translator;
 | 
					import net.sf.openrocket.l10n.Translator;
 | 
				
			||||||
 | 
					import net.sf.openrocket.logging.LogHelper;
 | 
				
			||||||
import net.sf.openrocket.startup.Application;
 | 
					import net.sf.openrocket.startup.Application;
 | 
				
			||||||
import net.sf.openrocket.util.BugException;
 | 
					import net.sf.openrocket.util.BugException;
 | 
				
			||||||
import net.sf.openrocket.util.Chars;
 | 
					import net.sf.openrocket.util.Chars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class SlideShowDialog extends JDialog {
 | 
					public class SlideShowDialog extends JDialog {
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						private static final LogHelper log = Application.getLogger();
 | 
				
			||||||
	private static final Translator trans = Application.getTranslator();
 | 
						private static final Translator trans = Application.getTranslator();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private SlideShowComponent slideShowComponent;
 | 
						private SlideShowComponent slideShowComponent;
 | 
				
			||||||
@ -38,6 +42,7 @@ public class SlideShowDialog extends JDialog {
 | 
				
			|||||||
		JPanel panel = new JPanel(new MigLayout("fill"));
 | 
							JPanel panel = new JPanel(new MigLayout("fill"));
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		slideShowComponent = new SlideShowComponent();
 | 
							slideShowComponent = new SlideShowComponent();
 | 
				
			||||||
 | 
							slideShowComponent.addHyperlinkListener(new SlideShowLinkListener(parent));
 | 
				
			||||||
		panel.add(slideShowComponent, "spanx, grow, wrap para");
 | 
							panel.add(slideShowComponent, "spanx, grow, wrap para");
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@ -47,6 +52,7 @@ public class SlideShowDialog extends JDialog {
 | 
				
			|||||||
		prevButton.addActionListener(new ActionListener() {
 | 
							prevButton.addActionListener(new ActionListener() {
 | 
				
			||||||
			@Override
 | 
								@Override
 | 
				
			||||||
			public void actionPerformed(ActionEvent e) {
 | 
								public void actionPerformed(ActionEvent e) {
 | 
				
			||||||
 | 
									log.user("Clicked previous button");
 | 
				
			||||||
				setPosition(position - 1);
 | 
									setPosition(position - 1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
@ -58,6 +64,7 @@ public class SlideShowDialog extends JDialog {
 | 
				
			|||||||
		nextButton.addActionListener(new ActionListener() {
 | 
							nextButton.addActionListener(new ActionListener() {
 | 
				
			||||||
			@Override
 | 
								@Override
 | 
				
			||||||
			public void actionPerformed(ActionEvent e) {
 | 
								public void actionPerformed(ActionEvent e) {
 | 
				
			||||||
 | 
									log.user("Clicked next button");
 | 
				
			||||||
				setPosition(position + 1);
 | 
									setPosition(position + 1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
@ -81,7 +88,11 @@ public class SlideShowDialog extends JDialog {
 | 
				
			|||||||
		
 | 
							
 | 
				
			||||||
		this.add(panel);
 | 
							this.add(panel);
 | 
				
			||||||
		updateEnabled();
 | 
							updateEnabled();
 | 
				
			||||||
 | 
							addKeyActions();
 | 
				
			||||||
		GUIUtil.setDisposableDialogOptions(this, nextButton);
 | 
							GUIUtil.setDisposableDialogOptions(this, nextButton);
 | 
				
			||||||
 | 
							nextButton.grabFocus();
 | 
				
			||||||
 | 
							GUIUtil.rememberWindowPosition(this);
 | 
				
			||||||
 | 
							GUIUtil.rememberWindowSize(this);
 | 
				
			||||||
		this.setAlwaysOnTop(true);
 | 
							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");
 | 
						private void addKeyActions() {
 | 
				
			||||||
		
 | 
							Action next = new AbstractAction() {
 | 
				
			||||||
		SwingUtilities.invokeAndWait(new Runnable() {
 | 
					 | 
				
			||||||
			@Override
 | 
								@Override
 | 
				
			||||||
			public void run() {
 | 
								public void actionPerformed(ActionEvent event) {
 | 
				
			||||||
 | 
									log.user("Key action for next slide");
 | 
				
			||||||
 | 
									if (position < slideSet.getSlideCount() - 1) {
 | 
				
			||||||
 | 
										setPosition(position + 1);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
				SlideShowDialog ssd = new SlideShowDialog(null);
 | 
							Action previous = new AbstractAction() {
 | 
				
			||||||
				
 | 
					 | 
				
			||||||
				ssd.slideShowComponent.addHyperlinkListener(new HyperlinkListener() {
 | 
					 | 
				
			||||||
			@Override
 | 
								@Override
 | 
				
			||||||
					public void hyperlinkUpdate(HyperlinkEvent e) {
 | 
								public void actionPerformed(ActionEvent event) {
 | 
				
			||||||
						System.out.println("Hyperlink event: " + e);
 | 
									log.user("Key action for previous slide");
 | 
				
			||||||
						System.out.println("Event type: " + e.getEventType());
 | 
									if (position > 0) {
 | 
				
			||||||
						System.out.println("Description: " + e.getDescription());
 | 
										setPosition(position - 1);
 | 
				
			||||||
						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);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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.");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||