001/* 002 * $Id: McvHelpTipDialog.java,v 1.10 2011/03/24 16:06:34 davep Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2011 007 * Space Science and Engineering Center (SSEC) 008 * University of Wisconsin - Madison 009 * 1225 W. Dayton Street, Madison, WI 53706, USA 010 * https://www.ssec.wisc.edu/mcidas 011 * 012 * All Rights Reserved 013 * 014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 015 * some McIDAS-V source code is based on IDV and VisAD source code. 016 * 017 * McIDAS-V is free software; you can redistribute it and/or modify 018 * it under the terms of the GNU Lesser Public License as published by 019 * the Free Software Foundation; either version 3 of the License, or 020 * (at your option) any later version. 021 * 022 * McIDAS-V is distributed in the hope that it will be useful, 023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 025 * GNU Lesser Public License for more details. 026 * 027 * You should have received a copy of the GNU Lesser Public License 028 * along with this program. If not, see http://www.gnu.org/licenses. 029 */ 030 031package edu.wisc.ssec.mcidasv.ui; 032 033 034import java.awt.Color; 035import java.awt.Dimension; 036import java.awt.Font; 037import java.awt.Insets; 038import java.awt.Toolkit; 039import java.awt.event.ActionEvent; 040import java.awt.event.ActionListener; 041import java.util.ArrayList; 042import java.util.Hashtable; 043import java.util.List; 044import java.util.Random; 045 046import javax.swing.BorderFactory; 047import javax.swing.JButton; 048import javax.swing.JCheckBox; 049import javax.swing.JDialog; 050import javax.swing.JEditorPane; 051import javax.swing.JLabel; 052import javax.swing.JMenu; 053import javax.swing.JMenuBar; 054import javax.swing.JMenuItem; 055import javax.swing.JPanel; 056import javax.swing.JScrollPane; 057import javax.swing.border.BevelBorder; 058import javax.swing.event.HyperlinkEvent; 059import javax.swing.event.HyperlinkListener; 060import javax.swing.text.html.HTMLDocument; 061 062import org.w3c.dom.Element; 063import org.w3c.dom.Node; 064 065import edu.wisc.ssec.mcidasv.Constants; 066import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 067 068import ucar.unidata.util.GuiUtils; 069import ucar.unidata.util.ObjectListener; 070import ucar.unidata.xml.XmlObjectStore; 071import ucar.unidata.xml.XmlResourceCollection; 072import ucar.unidata.xml.XmlUtil; 073 074 075/** 076 * Represents a dialog that holds {@literal "help tips"}. This class is based 077 * upon {@link ucar.unidata.ui.HelpTipDialog}, but adds new functionality: 078 * <ul> 079 * <li>tip counter</li> 080 * <li>formatting</li> 081 * <li>random tips</li> 082 * </ul> 083 */ 084@SuppressWarnings("serial") 085public class McvHelpTipDialog extends JDialog implements Constants, 086 HyperlinkListener 087{ 088 089 /** help tip preference */ 090 public static final String PREF_HELPTIPSHOW = "help.helptip.Show"; 091 092 /** help tip index */ 093 public static final String PREF_HELPTIPIDX = "help.helptip.Index"; 094 095 /** list of tips */ 096 private List helpTips = new ArrayList(); 097 098 /** resources */ 099 private XmlResourceCollection resources; 100 101 /** index */ 102 private int idx = 0; 103 104 /** count */ 105 private JLabel counterText; 106 107 /** label */ 108 private JLabel titleText; 109 110 /** message */ 111 private JEditorPane messageText; 112 113 /** checkbox */ 114 private JCheckBox showCbx; 115 116 /** store */ 117 private XmlObjectStore store; 118 119 /** action listener */ 120 private ActionListener actionListener; 121 122 /** 123 * Create the HelpTipDialog 124 * 125 * @param resources list of XML resources 126 * @param actionListener listener for changes 127 * @param store store for persistence 128 * @param origin calling class 129 * @param showByDefault true to show by default 130 * 131 */ 132 public McvHelpTipDialog(XmlResourceCollection resources, 133 ActionListener actionListener, XmlObjectStore store, 134 Class origin, boolean showByDefault) { 135 136 this.actionListener = actionListener; 137 this.resources = resources; 138 if ((resources == null) || (resources.size() == 0)) { 139 return; 140 } 141 this.store = store; 142 143 String title = null; 144 String icon = null; 145 146 for (int i = 0; i < resources.size(); i++) { 147 Element helpTipRoot = resources.getRoot(i); 148 if (helpTipRoot == null) { 149 continue; 150 } 151 if (title == null) { 152 title = XmlUtil.getAttribute(helpTipRoot, "title", (String) null); 153 } 154 if (icon == null) { 155 icon = XmlUtil.getAttribute(helpTipRoot, "icon", (String) null); 156 } 157 helpTips.addAll(XmlUtil.findChildren(helpTipRoot, "helptip")); 158 } 159 160 if (title == null) { 161 title = "McIDAS-V Help Tips"; 162 } 163 setTitle(title); 164 if (icon == null) { 165 icon = "/edu/wisc/ssec/mcidasv/resources/icons/toolbar/dialog-information32.png"; 166 } 167 JLabel imageLabel = GuiUtils.getImageLabel(icon); 168 169 // Build the "Tips" menu 170 JMenu topMenu = new JMenu("Tips"); 171 Hashtable menus = new Hashtable(); 172 menus.put("top", topMenu); 173 for (int i = 0; i < helpTips.size(); i++) { 174 Element helpTip = (Element) helpTips.get(i); 175 String tipTitle = XmlUtil.getAttribute(helpTip, "title", (String) null); 176 if (tipTitle == null) { 177 tipTitle = getMessage(helpTip).substring(0, 20); 178 } 179 if (tipTitle.trim().length() == 0) { 180 continue; 181 } 182 183 String category = XmlUtil.getAttribute(helpTip, "category", "None"); 184 JMenu m = (JMenu) menus.get(category); 185 if (m == null) { 186 m = new JMenu(category); 187 menus.put(category, m); 188 topMenu.add(m); 189 } 190 JMenuItem mi = new JMenuItem(tipTitle); 191 mi.addActionListener(new ObjectListener(new Integer(i)) { 192 public void actionPerformed(ActionEvent ae) { 193 idx = ((Integer) theObject).intValue(); 194 showTip(); 195 } 196 }); 197 m.add(mi); 198 } 199 200 titleText = new JLabel("Title"); 201 counterText = McVGuiUtils.makeLabelRight("0/0"); 202 203 JPanel topPanel = GuiUtils.left( 204 GuiUtils.hbox(imageLabel, titleText, GAP_RELATED) 205 ); 206 207 Dimension helpDimension = new Dimension(400, 200); 208 messageText = new JEditorPane(); 209 messageText.setMinimumSize(helpDimension); 210 messageText.setPreferredSize(helpDimension); 211 messageText.setEditable(false); 212 messageText.addHyperlinkListener(this); 213 messageText.setContentType("text/html"); 214 Font font = javax.swing.UIManager.getFont("Label.font"); 215 String rule = "body { font-family:"+font.getFamily()+"; font-size:"+font.getSize()+"pt; }"; 216 ((HTMLDocument)messageText.getDocument()).getStyleSheet().addRule(rule); 217 // messageText.setBackground(new JPanel().getBackground()); 218 JScrollPane scroller = GuiUtils.makeScrollPane(messageText, 0, 0); 219 scroller.setBorder(BorderFactory.createLoweredBevelBorder()); 220 scroller.setPreferredSize(helpDimension); 221 scroller.setMinimumSize(helpDimension); 222 223 showCbx = new JCheckBox("Show tips on startup", showByDefault); 224 showCbx.addActionListener(new ActionListener() { 225 public void actionPerformed(ActionEvent ae) { 226 writeShowNextTime(); 227 } 228 }); 229 230 JPanel centerPanel = GuiUtils.center(scroller); 231 232 JButton prevBtn = McVGuiUtils.makeImageButton(ICON_PREVIOUS_SMALL, "Previous"); 233 prevBtn.addActionListener(new ActionListener() { 234 public void actionPerformed(ActionEvent event) { 235 previous(); 236 } 237 }); 238 239 JButton nextBtn = McVGuiUtils.makeImageButton(ICON_NEXT_SMALL, "Next"); 240 nextBtn.addActionListener(new ActionListener() { 241 public void actionPerformed(ActionEvent event) { 242 next(); 243 } 244 }); 245 246 JButton randBtn = McVGuiUtils.makeImageButton(ICON_RANDOM_SMALL, "Random"); 247 randBtn.addActionListener(new ActionListener() { 248 public void actionPerformed(ActionEvent event) { 249 random(); 250 } 251 }); 252 253 JButton closeBtn = McVGuiUtils.makePrettyButton("Close"); 254 closeBtn.addActionListener(new ActionListener() { 255 public void actionPerformed(ActionEvent event) { 256 close(); 257 } 258 }); 259 260// JPanel navBtns = GuiUtils.hbox(prevBtn, randBtn, nextBtn, GAP_RELATED); 261 JPanel navBtns = GuiUtils.hbox(counterText, prevBtn, nextBtn, GAP_RELATED); 262 JPanel bottomPanel = GuiUtils.leftRight(showCbx, navBtns); 263 264 JMenuBar bar = new JMenuBar(); 265 bar.add(topMenu); 266 add("North", bar); 267 268 JPanel contents = GuiUtils.topCenterBottom( 269 GuiUtils.inset(topPanel, GAP_RELATED), 270 GuiUtils.inset(centerPanel, new Insets(0, GAP_RELATED, 0, GAP_RELATED)), 271 GuiUtils.inset(bottomPanel, GAP_RELATED) 272 ); 273 contents.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED, 274 Color.gray, Color.gray)); 275 276 JPanel bottom = new JPanel(); 277 bottom.add(closeBtn); 278 add(GuiUtils.centerBottom(contents, bottom)); 279 pack(); 280 281 random(); 282 Dimension size = getSize(); 283 Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); 284 setLocation(ss.width / 2 - size.width / 2, ss.height / 2 - size.height / 2); 285 286 setMinimumSize(helpDimension); 287 setVisible(true); 288 } 289 290 /** 291 * Write show next time 292 */ 293 public void writeShowNextTime() { 294 if (getStore().get(PREF_HELPTIPSHOW, true) != showCbx.isSelected()) { 295 getStore().put(PREF_HELPTIPSHOW, showCbx.isSelected()); 296 getStore().save(); 297 } 298 } 299 300 /** 301 * Close the dialog 302 */ 303 public void close() { 304 writeShowNextTime(); 305 setVisible(false); 306 } 307 308 /** 309 * Get the persistence store 310 * @return the persistence 311 */ 312 public XmlObjectStore getStore() { 313 return store; 314 } 315 316 /** 317 * Go to the next tip. 318 */ 319 private void previous() { 320 idx--; 321 showTip(); 322 } 323 324 /** 325 * Go to the next tip. 326 */ 327 private void next() { 328 idx++; 329 showTip(); 330 } 331 332 /** 333 * Go to the next tip. 334 */ 335 private void random() { 336 Random rand = new Random(); 337 idx = rand.nextInt(helpTips.size()); 338 showTip(); 339 } 340 341 /** 342 * Handle a change to a link 343 * 344 * @param e the link's event 345 */ 346 public void hyperlinkUpdate(HyperlinkEvent e) { 347 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 348 if (e.getURL() == null) { 349 click(e.getDescription()); 350 } else { 351 click(e.getURL().toString()); 352 } 353 } 354 } 355 356 /** 357 * Handle a click on a link 358 * 359 * @param url the link definition 360 */ 361 public void click(String url) { 362 actionListener.actionPerformed(new ActionEvent(this, 0, url)); 363 } 364 365 /** 366 * Get the title for this tip 367 * 368 * @param helpTip the tip node 369 * @return the title 370 */ 371 private String getTitle(Node helpTip) { 372 String title = XmlUtil.getAttribute(helpTip, "title", (String) null); 373 if (title == null) { 374 title = ""; 375 } 376 return "<html><h2>" + title + "</h2></html>"; 377 } 378 379 /** 380 * Get the message for this tip 381 * 382 * @param helpTip the tip node 383 * @return the message 384 */ 385 private String getMessage(Node helpTip) { 386 String message = XmlUtil.getAttribute(helpTip, "message", (String) null); 387 if (message == null) { 388 message = XmlUtil.getChildText(helpTip); 389 } 390 return message; 391 } 392 393 /** 394 * Show the current tip. 395 */ 396 private void showTip() { 397 398 // Show the first tip if we have no tip history 399 if (getStore().get(PREF_HELPTIPIDX, -1) < 0) idx=0; 400 401 if (helpTips.size() == 0) { 402 return; 403 } 404 if (idx >= helpTips.size()) { 405 idx = 0; 406 getStore().put(PREF_HELPTIPIDX, idx); 407 } else if (idx < 0) { 408 idx = helpTips.size() - 1; 409 } 410 Node helpTip = (Node) helpTips.get(idx); 411 412 counterText.setText((int)(idx+1) + "/" + helpTips.size()); 413 titleText.setText(getTitle(helpTip)); 414 messageText.setText(getMessage(helpTip)); 415 416 getStore().put(PREF_HELPTIPIDX, idx); 417 getStore().save(); 418 } 419 420}