/******************************************************************************* * Copyright (c) MOBAC developers * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package mobac.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.GraphicsEnvironment; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Image; import java.awt.Insets; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.xml.bind.JAXBException; import mobac.externaltools.ExternalToolDef; import mobac.externaltools.ExternalToolsLoader; import mobac.gui.actions.AddGpxTrackAreaPolygonMap; import mobac.gui.actions.AddGpxTrackPolygonMap; import mobac.gui.actions.AddMapLayer; import mobac.gui.actions.AtlasConvert; import mobac.gui.actions.AtlasCreate; import mobac.gui.actions.AtlasNew; import mobac.gui.actions.BookmarkAdd; import mobac.gui.actions.BookmarkManage; import mobac.gui.actions.DebugSetLogLevel; import mobac.gui.actions.DebugShowLogFile; import mobac.gui.actions.DebugShowMapSourceNames; import mobac.gui.actions.DebugShowMapTileGrid; import mobac.gui.actions.DebugShowReport; import mobac.gui.actions.HelpLicenses; import mobac.gui.actions.PanelShowHide; import mobac.gui.actions.RefreshCustomMapsources; import mobac.gui.actions.SelectionModeCircle; import mobac.gui.actions.SelectionModePolygon; import mobac.gui.actions.SelectionModeRectangle; import mobac.gui.actions.ShowAboutDialog; import mobac.gui.actions.ShowHelpAction; import mobac.gui.actions.ShowReadme; import mobac.gui.atlastree.JAtlasTree; import mobac.gui.components.FilledLayeredPane; import mobac.gui.components.JAtlasNameField; import mobac.gui.components.JBookmarkMenuItem; import mobac.gui.components.JCollapsiblePanel; import mobac.gui.components.JMenuItem2; import mobac.gui.components.JZoomCheckBox; import mobac.gui.listeners.AtlasModelListener; import mobac.gui.mapview.GridZoom; import mobac.gui.mapview.JMapViewer; import mobac.gui.mapview.PreviewMap; import mobac.gui.mapview.WgsGrid.WgsDensity; import mobac.gui.mapview.controller.JMapController; import mobac.gui.mapview.controller.PolygonCircleSelectionMapController; import mobac.gui.mapview.controller.PolygonSelectionMapController; import mobac.gui.mapview.controller.RectangleSelectionMapController; import mobac.gui.mapview.interfaces.MapEventListener; import mobac.gui.panels.JCoordinatesPanel; import mobac.gui.panels.JGpxPanel; import mobac.gui.panels.JProfilesPanel; import mobac.gui.panels.JTileImageParametersPanel; import mobac.gui.panels.JTileStoreCoveragePanel; import mobac.gui.settings.SettingsGUI; import mobac.mapsources.MapSourcesManager; import mobac.program.ProgramInfo; import mobac.program.interfaces.AtlasInterface; import mobac.program.interfaces.InitializableMapSource; import mobac.program.interfaces.MapSource; import mobac.program.model.Bookmark; import mobac.program.model.MapSelection; import mobac.program.model.MercatorPixelCoordinate; import mobac.program.model.Profile; import mobac.program.model.SelectedZoomLevels; import mobac.program.model.Settings; import mobac.program.model.SettingsWgsGrid; import mobac.program.model.TileImageParameters; import mobac.utilities.GBC; import mobac.utilities.GUIExceptionHandler; import mobac.utilities.I18nUtils; import mobac.utilities.Utilities; import org.apache.log4j.Level; import org.apache.log4j.Logger; public class MainGUI extends JFrame implements MapEventListener { private static final long serialVersionUID = 1L; private static Logger log = Logger.getLogger(MainGUI.class); private static Color labelBackgroundColor = new Color(0, 0, 0, 127); private static Color checkboxBackgroundColor = new Color(0, 0, 0, 40); private static Color labelForegroundColor = Color.WHITE; private static MainGUI mainGUI = null; public static final ArrayList<Image> MOBAC_ICONS = new ArrayList<Image>(3); static { MOBAC_ICONS.add(Utilities.loadResourceImageIcon("mobac48.png").getImage()); MOBAC_ICONS.add(Utilities.loadResourceImageIcon("mobac32.png").getImage()); MOBAC_ICONS.add(Utilities.loadResourceImageIcon("mobac16.png").getImage()); } protected JMenuBar menuBar; protected JMenu toolsMenu = null; private JMenu bookmarkMenu = null; public final PreviewMap previewMap = new PreviewMap(); public final JAtlasTree jAtlasTree = new JAtlasTree(previewMap); private JCheckBox wgsGridCheckBox; private JComboBox wgsGridCombo; private JLabel zoomLevelText; private JComboBox gridZoomCombo; private JSlider zoomSlider; private JComboBox mapSourceCombo; private JButton settingsButton; private JAtlasNameField atlasNameTextField; private JButton createAtlasButton; private JPanel zoomLevelPanel; private JZoomCheckBox[] cbZoom = new JZoomCheckBox[0]; private JLabel amountOfTilesLabel; private AtlasCreate atlasCreateAction = new AtlasCreate(jAtlasTree); private JCoordinatesPanel coordinatesPanel; private JProfilesPanel profilesPanel; public JTileImageParametersPanel tileImageParametersPanel; private JTileStoreCoveragePanel tileStoreCoveragePanel; public JGpxPanel gpxPanel; private JPanel mapControlPanel = new JPanel(new BorderLayout()); private JPanel leftPanel = new JPanel(new GridBagLayout()); private JPanel leftPanelContent = null; private JPanel rightPanel = new JPanel(new GridBagLayout()); public JMenu logLevelMenu; private JMenuItem smRectangle; private JMenuItem smPolygon; private JMenuItem smCircle; private MercatorPixelCoordinate mapSelectionMax = null; private MercatorPixelCoordinate mapSelectionMin = null; public static void createMainGui() { if (mainGUI != null) return; mainGUI = new MainGUI(); mainGUI.setVisible(true); log.trace("MainGUI now visible"); } public static MainGUI getMainGUI() { return mainGUI; } // MP: get custom font static Font sCustomFont = null; public static Font customFont() { if (sCustomFont == null) { // force to use Chinese font sCustomFont = new Font("宋体", 9, 13); } return sCustomFont; } // MP: update all UI components' default font to custom font public static void setDefaultFontOfAllUIComponents(Font defaultFont) { if (defaultFont != null) { // register custom font to application,system font will return false GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); ge.registerFont(defaultFont); // update all UI's font settings javax.swing.plaf.FontUIResource fontRes = new javax.swing.plaf.FontUIResource(defaultFont); Enumeration<Object> keys = UIManager.getDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object value = UIManager.get(key); if (value instanceof javax.swing.plaf.FontUIResource) { UIManager.put(key, fontRes); } } } } private MainGUI() { super(); mainGUI = this; setIconImages(MOBAC_ICONS); GUIExceptionHandler.registerForCurrentThread(); setTitle(ProgramInfo.getCompleteTitle()); log.trace("Creating main dialog - " + getTitle()); setResizable(true); Dimension dScreen = Toolkit.getDefaultToolkit().getScreenSize(); setMinimumSize(new Dimension(Math.min(800, dScreen.width), Math.min(590, dScreen.height))); setSize(getMinimumSize()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addWindowListener(new WindowDestroyer()); addComponentListener(new MainWindowListener()); previewMap.addMapEventListener(this); createControls(); calculateNrOfTilesToDownload(); setLayout(new BorderLayout()); add(leftPanel, BorderLayout.WEST); add(rightPanel, BorderLayout.EAST); JLayeredPane layeredPane = new FilledLayeredPane(); layeredPane.add(previewMap, Integer.valueOf(0)); layeredPane.add(mapControlPanel, Integer.valueOf(1)); add(layeredPane, BorderLayout.CENTER); updateMapControlsPanel(); updateLeftPanel(); updateRightPanel(); updateZoomLevelCheckBoxes(); calculateNrOfTilesToDownload(); menuBar = new JMenuBar(); prepareMenuBar(); setJMenuBar(menuBar); loadSettings(); profilesPanel.initialize(); mapSourceChanged(previewMap.getMapSource()); updateZoomLevelCheckBoxes(); updateGridSizeCombo(); tileImageParametersPanel.updateControlsState(); zoomChanged(previewMap.getZoom()); gridZoomChanged(previewMap.getGridZoom()); previewMap.updateMapSelection(); previewMap.grabFocus(); } private void createControls() { // zoom slider zoomSlider = new JSlider(JMapViewer.MIN_ZOOM, previewMap.getMapSource().getMaxZoom()); zoomSlider.setOrientation(JSlider.HORIZONTAL); zoomSlider.setMinimumSize(new Dimension(50, 10)); zoomSlider.setSize(50, zoomSlider.getPreferredSize().height); zoomSlider.addChangeListener(new ZoomSliderListener()); zoomSlider.setOpaque(false); // zoom level text zoomLevelText = new JLabel(" 00 "); zoomLevelText.setOpaque(true); zoomLevelText.setBackground(labelBackgroundColor); zoomLevelText.setForeground(labelForegroundColor); zoomLevelText.setToolTipText(I18nUtils.localizedStringForKey("map_ctrl_zoom_level_title_tips")); // grid zoom combo gridZoomCombo = new JComboBox(); gridZoomCombo.setEditable(false); gridZoomCombo.addActionListener(new GridZoomComboListener()); gridZoomCombo.setToolTipText(I18nUtils.localizedStringForKey("map_ctrl_zoom_grid_tips")); SettingsWgsGrid s = Settings.getInstance().wgsGrid; // WGS Grid label wgsGridCheckBox = new JCheckBox(I18nUtils.localizedStringForKey("map_ctrl_wgs_grid_title"), s.enabled); // wgsGridCheckBox.setOpaque(true); wgsGridCheckBox.setOpaque(true); wgsGridCheckBox.setBackground(checkboxBackgroundColor); wgsGridCheckBox.setForeground(labelForegroundColor); wgsGridCheckBox.setToolTipText(I18nUtils.localizedStringForKey("map_ctrl_wgs_grid_tips")); wgsGridCheckBox.setMargin(new Insets(0, 0, 0, 0)); wgsGridCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean enabled = wgsGridCheckBox.isSelected(); Settings.getInstance().wgsGrid.enabled = enabled; wgsGridCombo.setVisible(enabled); previewMap.repaint(); } }); // WGS Grid combo wgsGridCombo = new JComboBox(WgsDensity.values()); wgsGridCombo.setMaximumRowCount(WgsDensity.values().length); wgsGridCombo.setVisible(s.enabled); wgsGridCombo.setSelectedItem(s.density); wgsGridCombo.setToolTipText(I18nUtils.localizedStringForKey("map_ctrl_wgs_grid_density_tips")); wgsGridCombo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { WgsDensity d = (WgsDensity) wgsGridCombo.getSelectedItem(); Settings.getInstance().wgsGrid.density = d; previewMap.repaint(); } }); // map source combo mapSourceCombo = new JComboBox(MapSourcesManager.getInstance().getEnabledOrderedMapSources()); mapSourceCombo.setMaximumRowCount(20); mapSourceCombo.addActionListener(new MapSourceComboListener()); mapSourceCombo.setToolTipText(I18nUtils.localizedStringForKey("lp_map_source_combo_tips")); // settings button settingsButton = new JButton(I18nUtils.localizedStringForKey("lp_main_setting_button_title")); settingsButton.addActionListener(new SettingsButtonListener()); settingsButton.setToolTipText(I18nUtils.localizedStringForKey("lp_main_setting_button_tips")); // atlas name text field atlasNameTextField = new JAtlasNameField(); atlasNameTextField.setColumns(12); atlasNameTextField.setActionCommand("atlasNameTextField"); atlasNameTextField.setToolTipText(I18nUtils.localizedStringForKey("lp_atlas_name_field_tips")); // main button createAtlasButton = new JButton(I18nUtils.localizedStringForKey("lp_mian_create_btn_title")); createAtlasButton.addActionListener(atlasCreateAction); createAtlasButton.setToolTipText(I18nUtils.localizedStringForKey("lp_main_create_btn_tips")); // zoom level check boxes zoomLevelPanel = new JPanel(); zoomLevelPanel.setBorder(BorderFactory.createEmptyBorder()); zoomLevelPanel.setOpaque(false); // amount of tiles to download amountOfTilesLabel = new JLabel(); amountOfTilesLabel.setToolTipText(I18nUtils.localizedStringForKey("lp_zoom_total_tile_count_tips")); amountOfTilesLabel.setOpaque(true); amountOfTilesLabel.setBackground(labelBackgroundColor); amountOfTilesLabel.setForeground(labelForegroundColor); coordinatesPanel = new JCoordinatesPanel(); tileImageParametersPanel = new JTileImageParametersPanel(); profilesPanel = new JProfilesPanel(jAtlasTree); profilesPanel.getLoadButton().addActionListener(new LoadProfileListener()); tileStoreCoveragePanel = new JTileStoreCoveragePanel(previewMap); } private void prepareMenuBar() { // Atlas menu JMenu atlasMenu = new JMenu(I18nUtils.localizedStringForKey("menu_atlas")); atlasMenu.setMnemonic(KeyEvent.VK_A); JMenuItem newAtlas = new JMenuItem(I18nUtils.localizedStringForKey("menu_atlas_new")); newAtlas.setMnemonic(KeyEvent.VK_N); newAtlas.addActionListener(new AtlasNew()); atlasMenu.add(newAtlas); JMenuItem convertAtlas = new JMenuItem(I18nUtils.localizedStringForKey("menu_atlas_convert_format")); convertAtlas.setMnemonic(KeyEvent.VK_V); convertAtlas.addActionListener(new AtlasConvert()); atlasMenu.add(convertAtlas); atlasMenu.addSeparator(); JMenuItem createAtlas = new JMenuItem(I18nUtils.localizedStringForKey("menu_atlas_create")); createAtlas.setMnemonic(KeyEvent.VK_C); createAtlas.addActionListener(atlasCreateAction); atlasMenu.add(createAtlas); // Maps menu JMenu mapsMenu = new JMenu(I18nUtils.localizedStringForKey("menu_maps")); mapsMenu.setMnemonic(KeyEvent.VK_M); JMenu selectionModeMenu = new JMenu(I18nUtils.localizedStringForKey("menu_maps_selection")); selectionModeMenu.setMnemonic(KeyEvent.VK_M); mapsMenu.add(selectionModeMenu); smRectangle = new JRadioButtonMenuItem(I18nUtils.localizedStringForKey("menu_maps_selection_rect")); smRectangle.addActionListener(new SelectionModeRectangle()); smRectangle.setSelected(true); selectionModeMenu.add(smRectangle); smPolygon = new JRadioButtonMenuItem(I18nUtils.localizedStringForKey("menu_maps_selection_polygon")); smPolygon.addActionListener(new SelectionModePolygon()); selectionModeMenu.add(smPolygon); smCircle = new JRadioButtonMenuItem(I18nUtils.localizedStringForKey("menu_maps_selection_circle")); smCircle.addActionListener(new SelectionModeCircle()); selectionModeMenu.add(smCircle); JMenuItem addSelection = new JMenuItem(I18nUtils.localizedStringForKey("menu_maps_selection_add")); addSelection.addActionListener(AddMapLayer.INSTANCE); addSelection.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK)); addSelection.setMnemonic(KeyEvent.VK_A); mapsMenu.add(addSelection); JMenuItem addGpxTrackSelection = new JMenuItem2( I18nUtils.localizedStringForKey("menu_maps_selection_add_around_gpx"), AddGpxTrackPolygonMap.class); mapsMenu.add(addGpxTrackSelection); JMenuItem addGpxTrackAreaSelection = new JMenuItem2( I18nUtils.localizedStringForKey("menu_maps_selection_add_by_gpx"), AddGpxTrackAreaPolygonMap.class); mapsMenu.add(addGpxTrackAreaSelection); // Bookmarks menu bookmarkMenu = new JMenu(I18nUtils.localizedStringForKey("menu_bookmark")); bookmarkMenu.setMnemonic(KeyEvent.VK_B); JMenuItem addBookmark = new JMenuItem(I18nUtils.localizedStringForKey("menu_bookmark_save")); addBookmark.setMnemonic(KeyEvent.VK_S); addBookmark.addActionListener(new BookmarkAdd(previewMap)); bookmarkMenu.add(addBookmark); JMenuItem manageBookmarks = new JMenuItem2(I18nUtils.localizedStringForKey("menu_bookmark_manage"), BookmarkManage.class); manageBookmarks.setMnemonic(KeyEvent.VK_S); bookmarkMenu.add(addBookmark); bookmarkMenu.add(manageBookmarks); bookmarkMenu.addSeparator(); // Panels menu JMenu panelsMenu = new JMenu(I18nUtils.localizedStringForKey("menu_panels")); panelsMenu.setMnemonic(KeyEvent.VK_P); JMenuItem showLeftPanel = new JMenuItem(I18nUtils.localizedStringForKey("menu_show_hide_left_panel")); showLeftPanel.addActionListener(new PanelShowHide(leftPanel)); JMenuItem showRightPanel = new JMenuItem(I18nUtils.localizedStringForKey("menu_show_hide_gpx_panel")); showRightPanel.addActionListener(new PanelShowHide(rightPanel)); panelsMenu.add(showLeftPanel); panelsMenu.add(showRightPanel); menuBar.add(atlasMenu); menuBar.add(mapsMenu); menuBar.add(bookmarkMenu); menuBar.add(panelsMenu); loadToolsMenu(); menuBar.add(Box.createHorizontalGlue()); // Debug menu JMenu debugMenu = new JMenu(I18nUtils.localizedStringForKey("menu_debug")); JMenuItem mapGrid = new JCheckBoxMenuItem(I18nUtils.localizedStringForKey("menu_debug_show_hide_tile_border"), false); mapGrid.addActionListener(new DebugShowMapTileGrid()); debugMenu.add(mapGrid); debugMenu.addSeparator(); debugMenu.setMnemonic(KeyEvent.VK_D); JMenuItem mapSourceNames = new JMenuItem2(I18nUtils.localizedStringForKey("menu_debug_show_all_map_source"), DebugShowMapSourceNames.class); mapSourceNames.setMnemonic(KeyEvent.VK_N); debugMenu.add(mapSourceNames); debugMenu.addSeparator(); JMenuItem refreshCustomMapSources = new JMenuItem2( I18nUtils.localizedStringForKey("menu_debug_refresh_map_source"), RefreshCustomMapsources.class); debugMenu.add(refreshCustomMapSources); debugMenu.addSeparator(); JMenuItem showLog = new JMenuItem2(I18nUtils.localizedStringForKey("menu_debug_show_log_file"), DebugShowLogFile.class); showLog.setMnemonic(KeyEvent.VK_S); debugMenu.add(showLog); logLevelMenu = new JMenu(I18nUtils.localizedStringForKey("menu_debug_log_level")); logLevelMenu.setMnemonic(KeyEvent.VK_L); Level[] list = new Level[] { Level.TRACE, Level.DEBUG, Level.INFO, Level.ERROR, Level.FATAL, Level.OFF }; ActionListener al = new DebugSetLogLevel(); Level rootLogLevel = Logger.getRootLogger().getLevel(); for (Level level : list) { String name = level.toString(); JRadioButtonMenuItem item = new JRadioButtonMenuItem(name, (rootLogLevel.toString().equals(name))); item.setName(name); item.addActionListener(al); logLevelMenu.add(item); } debugMenu.add(logLevelMenu); debugMenu.addSeparator(); JMenuItem report = new JMenuItem2(I18nUtils.localizedStringForKey("menu_debug_system_report"), DebugShowReport.class); report.setMnemonic(KeyEvent.VK_R); debugMenu.add(report); menuBar.add(debugMenu); // Help menu JMenu help = new JMenu(I18nUtils.localizedStringForKey("menu_help")); JMenuItem readme = new JMenuItem(I18nUtils.localizedStringForKey("menu_help_readme")); JMenuItem howToMap = new JMenuItem(I18nUtils.localizedStringForKey("menu_help_how_to_preview")); JMenuItem licenses = new JMenuItem(I18nUtils.localizedStringForKey("menu_help_licenses")); JMenuItem about = new JMenuItem(I18nUtils.localizedStringForKey("menu_help_about")); readme.addActionListener(new ShowReadme()); about.addActionListener(new ShowAboutDialog()); howToMap.addActionListener(new ShowHelpAction()); licenses.addActionListener(new HelpLicenses()); help.add(readme); help.add(howToMap); help.addSeparator(); help.add(licenses); help.addSeparator(); help.add(about); menuBar.add(help); } public void loadToolsMenu() { if (ExternalToolsLoader.load()) { if (toolsMenu == null) { toolsMenu = new JMenu(I18nUtils.localizedStringForKey("menu_tool")); toolsMenu.addMenuListener(new MenuListener() { public void menuSelected(MenuEvent e) { loadToolsMenu(); log.debug("Tools menu Loaded"); } public void menuDeselected(MenuEvent e) { } public void menuCanceled(MenuEvent e) { } }); menuBar.add(toolsMenu); } toolsMenu.removeAll(); for (ExternalToolDef t : ExternalToolsLoader.tools) { JMenuItem m = new JMenuItem(t.name); m.addActionListener(t); toolsMenu.add(m); } } } private void updateLeftPanel() { leftPanel.removeAll(); coordinatesPanel.addButtonActionListener(new ApplySelectionButtonListener()); JCollapsiblePanel mapSourcePanel = new JCollapsiblePanel( I18nUtils.localizedStringForKey("lp_map_source_title"), new GridBagLayout()); mapSourcePanel.addContent(mapSourceCombo, GBC.std().insets(2, 2, 2, 2).fill()); JCollapsiblePanel zoomLevelsPanel = new JCollapsiblePanel(I18nUtils.localizedStringForKey("lp_zoom_title"), new GridBagLayout()); zoomLevelsPanel.addContent(zoomLevelPanel, GBC.eol().insets(2, 4, 2, 0)); zoomLevelsPanel.addContent(amountOfTilesLabel, GBC.std().anchor(GBC.WEST).insets(0, 5, 0, 2)); GBC gbc_std = GBC.std().insets(5, 2, 5, 3); GBC gbc_eol = GBC.eol().insets(5, 2, 5, 3); JCollapsiblePanel atlasContentPanel = new JCollapsiblePanel(I18nUtils.localizedStringForKey("lp_atlas_title"), new GridBagLayout()); JScrollPane treeScrollPane = new JScrollPane(jAtlasTree, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); jAtlasTree.getTreeModel().addTreeModelListener(new AtlasModelListener(jAtlasTree, profilesPanel)); treeScrollPane.setMinimumSize(new Dimension(100, 150)); treeScrollPane.setPreferredSize(new Dimension(100, 200)); treeScrollPane.setAutoscrolls(true); atlasContentPanel.addContent(treeScrollPane, GBC.eol().fill().insets(0, 1, 0, 0)); JButton clearAtlas = new JButton(I18nUtils.localizedStringForKey("lp_atlas_new_btn_title")); atlasContentPanel.addContent(clearAtlas, GBC.std()); clearAtlas.addActionListener(new AtlasNew()); JButton addLayers = new JButton(I18nUtils.localizedStringForKey("lp_atlas_add_selection_btn_title")); atlasContentPanel.addContent(addLayers, GBC.eol()); addLayers.addActionListener(AddMapLayer.INSTANCE); atlasContentPanel.addContent(new JLabel(I18nUtils.localizedStringForKey("lp_atlas_name_label_title")), gbc_std); atlasContentPanel.addContent(atlasNameTextField, gbc_eol.fill(GBC.HORIZONTAL)); gbc_eol = GBC.eol().insets(5, 2, 5, 2).fill(GBC.HORIZONTAL); leftPanelContent = new JPanel(new GridBagLayout()); leftPanelContent.add(coordinatesPanel, gbc_eol); leftPanelContent.add(mapSourcePanel, gbc_eol); leftPanelContent.add(zoomLevelsPanel, gbc_eol); leftPanelContent.add(tileImageParametersPanel, gbc_eol); leftPanelContent.add(atlasContentPanel, gbc_eol); leftPanelContent.add(profilesPanel, gbc_eol); leftPanelContent.add(createAtlasButton, gbc_eol); leftPanelContent.add(settingsButton, gbc_eol); leftPanelContent.add(tileStoreCoveragePanel, gbc_eol); leftPanelContent.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL)); JScrollPane scrollPane = new JScrollPane(leftPanelContent); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBorder(BorderFactory.createEmptyBorder()); // Set the scroll pane width large enough so that the // scroll bar has enough space to appear right to it Dimension d = scrollPane.getPreferredSize(); d.width += 5 + scrollPane.getVerticalScrollBar().getWidth(); // scrollPane.setPreferredSize(d); scrollPane.setMinimumSize(d); leftPanel.add(scrollPane, GBC.std().fill()); // leftPanel.add(leftPanelContent, GBC.std().fill()); } private void updateRightPanel() { GBC gbc_eol = GBC.eol().insets(5, 2, 5, 2).fill(); gpxPanel = new JGpxPanel(previewMap); rightPanel.add(gpxPanel, gbc_eol); } private JPanel updateMapControlsPanel() { mapControlPanel.removeAll(); mapControlPanel.setOpaque(false); // zoom label JLabel zoomLabel = new JLabel(I18nUtils.localizedStringForKey("map_ctrl_zoom_level_title")); zoomLabel.setOpaque(true); zoomLabel.setBackground(labelBackgroundColor); zoomLabel.setForeground(labelForegroundColor); // top panel JPanel topControls = new JPanel(new GridBagLayout()); topControls.setOpaque(false); topControls.add(zoomLabel, GBC.std().insets(5, 5, 0, 0)); topControls.add(zoomSlider, GBC.std().insets(0, 5, 0, 0)); topControls.add(zoomLevelText, GBC.std().insets(0, 5, 0, 0)); topControls.add(gridZoomCombo, GBC.std().insets(10, 5, 0, 0)); topControls.add(wgsGridCheckBox, GBC.std().insets(10, 5, 0, 0)); topControls.add(wgsGridCombo, GBC.std().insets(5, 5, 0, 0)); topControls.add(Box.createHorizontalGlue(), GBC.std().fillH()); mapControlPanel.add(topControls, BorderLayout.NORTH); // bottom panel // JPanel bottomControls = new JPanel(new GridBagLayout()); // bottomControls.setOpaque(false); // bottomControls.add(Box.createHorizontalGlue(), // GBC.std().fill(GBC.HORIZONTAL)); // mapControlPanel.add(bottomControls, BorderLayout.SOUTH); return mapControlPanel; } public void updateMapSourcesList() { MapSource ms = (MapSource) mapSourceCombo.getSelectedItem(); mapSourceCombo .setModel(new DefaultComboBoxModel(MapSourcesManager.getInstance().getEnabledOrderedMapSources())); mapSourceCombo.setSelectedItem(ms); MapSource ms2 = (MapSource) mapSourceCombo.getSelectedItem(); if (!ms.equals(ms2)) previewMap.setMapSource(ms2); } public void updateBookmarksMenu() { LinkedList<JMenuItem> items = new LinkedList<JMenuItem>(); for (int i = 0; i < bookmarkMenu.getMenuComponentCount(); i++) { JMenuItem item = bookmarkMenu.getItem(i); if (!(item instanceof JBookmarkMenuItem)) items.add(item); } bookmarkMenu.removeAll(); for (JMenuItem item : items) { if (item != null) bookmarkMenu.add(item); else bookmarkMenu.addSeparator(); } for (Bookmark b : Settings.getInstance().placeBookmarks) { bookmarkMenu.add(new JBookmarkMenuItem(b)); } } private void loadSettings() { if (Profile.DEFAULT.exists()) { try { jAtlasTree.load(Profile.DEFAULT); } catch (Exception e) { log.error("Failed to load atlas", e); GUIExceptionHandler.processException(e); new AtlasNew().actionPerformed(null); } } else new AtlasNew().actionPerformed(null); Settings settings = Settings.getInstance(); atlasNameTextField.setText(settings.elementName); previewMap.settingsLoad(); int nextZoom = 0; List<Integer> zoomList = settings.selectedZoomLevels; if (zoomList != null) { for (JZoomCheckBox currentZoomCb : cbZoom) { for (int i = nextZoom; i < zoomList.size(); i++) { int currentListZoom = zoomList.get(i); if (currentZoomCb.getZoomLevel() == currentListZoom) { currentZoomCb.setSelected(true); nextZoom = 1; break; } } } } coordinatesPanel.setNumberFormat(settings.coordinateNumberFormat); tileImageParametersPanel.loadSettings(); tileImageParametersPanel.atlasFormatChanged(jAtlasTree.getAtlas().getOutputFormat()); // mapSourceCombo // .setSelectedItem(MapSourcesManager.getSourceByName(settings. // mapviewMapSource)); setSize(settings.mainWindow.size); Point windowLocation = settings.mainWindow.position; if (windowLocation.x == -1 && windowLocation.y == -1) { setLocationRelativeTo(null); } else { setLocation(windowLocation); } if (settings.mainWindow.maximized) setExtendedState(Frame.MAXIMIZED_BOTH); leftPanel.setVisible(settings.mainWindow.leftPanelVisible); rightPanel.setVisible(settings.mainWindow.rightPanelVisible); if (leftPanelContent != null) { for (Component c : leftPanelContent.getComponents()) { if (c instanceof JCollapsiblePanel) { JCollapsiblePanel cp = (JCollapsiblePanel) c; String name = cp.getName(); if (name != null && settings.mainWindow.collapsedPanels.contains(name)) cp.setCollapsed(true); } } } updateBookmarksMenu(); } private void saveSettings() { try { jAtlasTree.save(Profile.DEFAULT); Settings s = Settings.getInstance(); previewMap.settingsSave(); s.mapviewMapSource = previewMap.getMapSource().getName(); s.selectedZoomLevels = new SelectedZoomLevels(cbZoom).getZoomLevelList(); s.elementName = atlasNameTextField.getText(); s.coordinateNumberFormat = coordinatesPanel.getNumberFormat(); tileImageParametersPanel.saveSettings(); boolean maximized = (getExtendedState() & Frame.MAXIMIZED_BOTH) != 0; s.mainWindow.maximized = maximized; if (!maximized) { s.mainWindow.size = getSize(); s.mainWindow.position = getLocation(); } s.mainWindow.collapsedPanels.clear(); if (leftPanelContent != null) { for (Component c : leftPanelContent.getComponents()) { if (c instanceof JCollapsiblePanel) { JCollapsiblePanel cp = (JCollapsiblePanel) c; if (cp.isCollapsed()) s.mainWindow.collapsedPanels.add(cp.getName()); } } } s.mainWindow.leftPanelVisible = leftPanel.isVisible(); s.mainWindow.rightPanelVisible = rightPanel.isVisible(); checkAndSaveSettings(); } catch (Exception e) { GUIExceptionHandler.showExceptionDialog(e); JOptionPane.showMessageDialog(null, I18nUtils.localizedStringForKey("msg_settings_write_error"), I18nUtils.localizedStringForKey("Error"), JOptionPane.ERROR_MESSAGE); } } public void checkAndSaveSettings() throws JAXBException { if (Settings.checkSettingsFileModified()) { int x = JOptionPane.showConfirmDialog(this, I18nUtils.localizedStringForKey("msg_setting_file_is_changed_by_other"), I18nUtils.localizedStringForKey("msg_setting_file_is_changed_by_other_title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (x != JOptionPane.YES_OPTION) return; } Settings.save(); } public JTileImageParametersPanel getParametersPanel() { return tileImageParametersPanel; } public String getUserText() { return atlasNameTextField.getText(); } public void refreshPreviewMap() { previewMap.refreshMap(); } private class ZoomSliderListener implements ChangeListener { public void stateChanged(ChangeEvent e) { previewMap.setZoom(zoomSlider.getValue()); } } private class GridZoomComboListener implements ActionListener { public void actionPerformed(ActionEvent e) { if (!gridZoomCombo.isEnabled()) return; GridZoom g = (GridZoom) gridZoomCombo.getSelectedItem(); if (g == null) return; log.debug("Selected grid zoom combo box item has changed: " + g.getZoom()); previewMap.setGridZoom(g.getZoom()); repaint(); previewMap.updateMapSelection(); } } private void updateGridSizeCombo() { int maxZoom = previewMap.getMapSource().getMaxZoom(); int minZoom = previewMap.getMapSource().getMinZoom(); GridZoom lastGridZoom = (GridZoom) gridZoomCombo.getSelectedItem(); gridZoomCombo.setEnabled(false); gridZoomCombo.removeAllItems(); gridZoomCombo.setMaximumRowCount(maxZoom - minZoom + 2); gridZoomCombo.addItem(new GridZoom(-1) { @Override public String toString() { return I18nUtils.localizedStringForKey("map_ctrl_zoom_grid_disable"); } }); for (int i = maxZoom; i >= minZoom; i--) { gridZoomCombo.addItem(new GridZoom(i)); } if (lastGridZoom != null) gridZoomCombo.setSelectedItem(lastGridZoom); gridZoomCombo.setEnabled(true); } private class ApplySelectionButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { setSelectionByEnteredCoordinates(); } } private class MapSourceComboListener implements ActionListener { public void actionPerformed(ActionEvent e) { MapSource mapSource = (MapSource) mapSourceCombo.getSelectedItem(); if (mapSource == null) { mapSourceCombo.setSelectedIndex(0); mapSource = (MapSource) mapSourceCombo.getSelectedItem(); } if (mapSource instanceof InitializableMapSource) // initialize the map source e.g. detect available zoom levels ((InitializableMapSource) mapSource).initialize(); previewMap.setMapSource(mapSource); zoomSlider.setMinimum(previewMap.getMapSource().getMinZoom()); zoomSlider.setMaximum(previewMap.getMapSource().getMaxZoom()); updateGridSizeCombo(); updateZoomLevelCheckBoxes(); calculateNrOfTilesToDownload(); } } private class LoadProfileListener implements ActionListener { public void actionPerformed(ActionEvent e) { Profile profile = profilesPanel.getSelectedProfile(); profilesPanel.getDeleteButton().setEnabled(profile != null); if (profile == null) return; jAtlasTree.load(profile); previewMap.repaint(); tileImageParametersPanel.atlasFormatChanged(jAtlasTree.getAtlas().getOutputFormat()); } } private class SettingsButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { SettingsGUI.showSettingsDialog(MainGUI.this); } } private void updateZoomLevelCheckBoxes() { MapSource tileSource = previewMap.getMapSource(); int zoomLevels = tileSource.getMaxZoom() - tileSource.getMinZoom() + 1; zoomLevels = Math.max(zoomLevels, 0); JCheckBox oldZoomLevelCheckBoxes[] = cbZoom; int oldMinZoom = 0; if (cbZoom.length > 0) oldMinZoom = cbZoom[0].getZoomLevel(); cbZoom = new JZoomCheckBox[zoomLevels]; zoomLevelPanel.removeAll(); zoomLevelPanel.setLayout(new GridLayout(0, 10, 1, 2)); ZoomLevelCheckBoxListener cbl = new ZoomLevelCheckBoxListener(); for (int i = cbZoom.length - 1; i >= 0; i--) { int cbz = i + tileSource.getMinZoom(); JZoomCheckBox cb = new JZoomCheckBox(cbz); cb.setPreferredSize(new Dimension(22, 11)); cb.setMinimumSize(cb.getPreferredSize()); cb.setOpaque(false); cb.setFocusable(false); cb.setName(Integer.toString(cbz)); int oldCbIndex = cbz - oldMinZoom; if (oldCbIndex >= 0 && oldCbIndex < (oldZoomLevelCheckBoxes.length)) cb.setSelected(oldZoomLevelCheckBoxes[oldCbIndex].isSelected()); cb.addActionListener(cbl); // cb.setToolTipText("Select zoom level " + cbz + " for atlas"); zoomLevelPanel.add(cb); cbZoom[i] = cb; JLabel l = new JLabel(Integer.toString(cbz)); zoomLevelPanel.add(l); } amountOfTilesLabel.setOpaque(false); amountOfTilesLabel.setForeground(Color.black); } private class ZoomLevelCheckBoxListener implements ActionListener { public void actionPerformed(ActionEvent e) { calculateNrOfTilesToDownload(); } } public void selectionChanged(MercatorPixelCoordinate max, MercatorPixelCoordinate min) { mapSelectionMax = max; mapSelectionMin = min; coordinatesPanel.setSelection(max, min); calculateNrOfTilesToDownload(); } public void zoomChanged(int zoomLevel) { zoomLevelText.setText(" " + zoomLevel + " "); zoomSlider.setValue(zoomLevel); } public void gridZoomChanged(int newGridZoomLevel) { gridZoomCombo.setSelectedItem(new GridZoom(newGridZoomLevel)); } public MapSource getSelectedMapSource() { return (MapSource) mapSourceCombo.getSelectedItem(); } public SelectedZoomLevels getSelectedZoomLevels() { return new SelectedZoomLevels(cbZoom); } public void selectNextMapSource() { if (mapSourceCombo.getSelectedIndex() == mapSourceCombo.getItemCount() - 1) { Toolkit.getDefaultToolkit().beep(); } else { mapSourceCombo.setSelectedIndex(mapSourceCombo.getSelectedIndex() + 1); } } public void selectPreviousMapSource() { if (mapSourceCombo.getSelectedIndex() == 0) { Toolkit.getDefaultToolkit().beep(); } else { mapSourceCombo.setSelectedIndex(mapSourceCombo.getSelectedIndex() - 1); } } public void mapSourceChanged(MapSource newMapSource) { // TODO update selected area if new map source has different projectionCategory calculateNrOfTilesToDownload(); // if (newMapSource != null && newMapSource.equals(mapSourceCombo.getSelectedItem())) // return; mapSourceCombo.setSelectedItem(newMapSource); } public void mapSelectionControllerChanged(JMapController newMapController) { smPolygon.setSelected(false); smCircle.setSelected(false); smRectangle.setSelected(false); if (newMapController instanceof PolygonSelectionMapController) smPolygon.setSelected(true); else if (newMapController instanceof PolygonCircleSelectionMapController) smCircle.setSelected(true); else if (newMapController instanceof RectangleSelectionMapController) smRectangle.setSelected(true); } private void setSelectionByEnteredCoordinates() { coordinatesPanel.correctMinMax(); MapSelection ms = coordinatesPanel.getMapSelection(previewMap.getMapSource()); mapSelectionMax = ms.getBottomRightPixelCoordinate(); mapSelectionMin = ms.getTopLeftPixelCoordinate(); previewMap.setSelectionAndZoomTo(ms, false); } public MapSelection getMapSelectionCoordinates() { if (mapSelectionMax == null || mapSelectionMin == null) return null; return new MapSelection(previewMap.getMapSource(), mapSelectionMax, mapSelectionMin); } public TileImageParameters getSelectedTileImageParameters() { return tileImageParametersPanel.getSelectedTileImageParameters(); } private void calculateNrOfTilesToDownload() { MapSelection ms = getMapSelectionCoordinates(); String baseText; baseText = I18nUtils.localizedStringForKey("lp_zoom_total_tile_title"); if (ms == null || !ms.isAreaSelected()) { amountOfTilesLabel.setText(String.format(baseText, "0")); amountOfTilesLabel.setToolTipText(""); } else { try { SelectedZoomLevels sZL = new SelectedZoomLevels(cbZoom); int[] zoomLevels = sZL.getZoomLevels(); long totalNrOfTiles = 0; StringBuilder hint = new StringBuilder(1024); hint.append(I18nUtils.localizedStringForKey("lp_zoom_total_tile_hint_head")); for (int i = 0; i < zoomLevels.length; i++) { int zoom = zoomLevels[i]; long[] info = ms.calculateNrOfTilesEx(zoom); totalNrOfTiles += info[0]; hint.append(String.format(I18nUtils.localizedStringForKey("lp_zoom_total_tile_hint_row"), zoomLevels[i], info[0], info[1], info[2])); // hint.append("<br>Level " + zoomLevels[i] + ": " + info[0] + " (" + info[1] + "*" + info[2] + // ")"); } String hintText = "<html>" + hint.toString() + "</html>"; amountOfTilesLabel.setText(String.format(baseText, Long.toString(totalNrOfTiles))); amountOfTilesLabel.setToolTipText(hintText); } catch (Exception e) { amountOfTilesLabel.setText(String.format(baseText, "?")); log.error("", e); } } } public AtlasInterface getAtlas() { return jAtlasTree.getAtlas(); } private class WindowDestroyer extends WindowAdapter { @Override public void windowOpened(WindowEvent e) { SwingUtilities.invokeLater(new Runnable() { public void run() { previewMap.setEnabled(true); } }); } public void windowClosing(WindowEvent event) { saveSettings(); } } /** * Saves the window position and size when window is moved or resized. This is necessary because of the maximized * state. If a window is maximized it is impossible to retrieve the window size & position of the non-maximized * window - therefore we have to collect the information every time they change. */ private class MainWindowListener extends ComponentAdapter { public void componentResized(ComponentEvent event) { // log.debug(event.paramString()); updateValues(); } public void componentMoved(ComponentEvent event) { // log.debug(event.paramString()); updateValues(); } private void updateValues() { // only update old values while window is in NORMAL state // Note(Java bug): Sometimes getExtendedState() says the window is // not maximized but maximizing is already in progress and therefore // the window bounds are already changed. if ((getExtendedState() & MAXIMIZED_BOTH) != 0) return; Settings s = Settings.getInstance(); s.mainWindow.size = getSize(); s.mainWindow.position = getLocation(); } } }