001/* 002 * $Id: BasicTipOfTheDayUI.java 3927 2011-02-22 16:34:11Z kleopatra $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jdesktop.swingx.plaf.basic; 022 023import java.awt.BorderLayout; 024import java.awt.Component; 025import java.awt.Dialog; 026import java.awt.Dimension; 027import java.awt.Font; 028import java.awt.Frame; 029import java.awt.GridLayout; 030import java.awt.Window; 031import java.awt.event.ActionEvent; 032import java.awt.event.ActionListener; 033import java.awt.event.KeyEvent; 034import java.awt.event.WindowAdapter; 035import java.awt.event.WindowEvent; 036import java.beans.PropertyChangeEvent; 037import java.beans.PropertyChangeListener; 038import java.util.Locale; 039 040import javax.swing.AbstractAction; 041import javax.swing.ActionMap; 042import javax.swing.BorderFactory; 043import javax.swing.Icon; 044import javax.swing.JButton; 045import javax.swing.JCheckBox; 046import javax.swing.JComponent; 047import javax.swing.JDialog; 048import javax.swing.JEditorPane; 049import javax.swing.JLabel; 050import javax.swing.JOptionPane; 051import javax.swing.JPanel; 052import javax.swing.JScrollPane; 053import javax.swing.JTextArea; 054import javax.swing.KeyStroke; 055import javax.swing.LookAndFeel; 056import javax.swing.SwingUtilities; 057import javax.swing.UIManager; 058import javax.swing.plaf.ActionMapUIResource; 059import javax.swing.plaf.ComponentUI; 060import javax.swing.plaf.basic.BasicHTML; 061import javax.swing.text.html.HTMLDocument; 062 063import org.jdesktop.swingx.JXTipOfTheDay; 064import org.jdesktop.swingx.SwingXUtilities; 065import org.jdesktop.swingx.JXTipOfTheDay.ShowOnStartupChoice; 066import org.jdesktop.swingx.plaf.TipOfTheDayUI; 067import org.jdesktop.swingx.plaf.UIManagerExt; 068import org.jdesktop.swingx.tips.TipOfTheDayModel.Tip; 069 070/** 071 * Base implementation of the <code>JXTipOfTheDay</code> UI. 072 * 073 * @author <a href="mailto:fred@L2FProd.com">Frederic Lavigne</a> 074 */ 075public class BasicTipOfTheDayUI extends TipOfTheDayUI { 076 077 public static ComponentUI createUI(JComponent c) { 078 return new BasicTipOfTheDayUI((JXTipOfTheDay)c); 079 } 080 081 protected JXTipOfTheDay tipPane; 082 protected JPanel tipArea; 083 protected Component currentTipComponent; 084 085 protected Font tipFont; 086 protected PropertyChangeListener changeListener; 087 088 public BasicTipOfTheDayUI(JXTipOfTheDay tipPane) { 089 this.tipPane = tipPane; 090 } 091 092 @Override 093 public JDialog createDialog(Component parentComponent, 094 final ShowOnStartupChoice choice) { 095 return createDialog(parentComponent, choice, true); 096 } 097 098 protected JDialog createDialog(Component parentComponent, 099 final ShowOnStartupChoice choice, 100 boolean showPreviousButton) { 101 Locale locale = parentComponent==null ? null : parentComponent.getLocale(); 102 String title = UIManagerExt.getString("TipOfTheDay.dialogTitle", locale); 103 104 final JDialog dialog; 105 106 Window window; 107 if (parentComponent == null) { 108 window = JOptionPane.getRootFrame(); 109 } else { 110 window = (parentComponent instanceof Window)?(Window)parentComponent 111 :SwingUtilities.getWindowAncestor(parentComponent); 112 } 113 114 if (window instanceof Frame) { 115 dialog = new JDialog((Frame)window, title, true); 116 } else { 117 dialog = new JDialog((Dialog)window, title, true); 118 } 119 120 dialog.getContentPane().setLayout(new BorderLayout(10, 10)); 121 dialog.getContentPane().add(tipPane, BorderLayout.CENTER); 122 ((JComponent)dialog.getContentPane()).setBorder(BorderFactory 123 .createEmptyBorder(10, 10, 10, 10)); 124 125 final JCheckBox showOnStartupBox; 126 127 // tip controls 128 JPanel controls = new JPanel(new BorderLayout()); 129 dialog.add("South", controls); 130 131 if (choice != null) { 132 showOnStartupBox = new JCheckBox(UIManagerExt 133 .getString("TipOfTheDay.showOnStartupText", locale), choice 134 .isShowingOnStartup()); 135 controls.add(showOnStartupBox, BorderLayout.CENTER); 136 } else { 137 showOnStartupBox = null; 138 } 139 140 JPanel buttons = 141 new JPanel(new GridLayout(1, showPreviousButton?3:2, 9, 0)); 142 controls.add(buttons, BorderLayout.LINE_END); 143 144 if (showPreviousButton) { 145 JButton previousTipButton = new JButton(UIManagerExt 146 .getString("TipOfTheDay.previousTipText", locale)); 147 buttons.add(previousTipButton); 148 previousTipButton.addActionListener(getActionMap().get("previousTip")); 149 } 150 151 JButton nextTipButton = new JButton(UIManagerExt 152 .getString("TipOfTheDay.nextTipText", locale)); 153 buttons.add(nextTipButton); 154 nextTipButton.addActionListener(getActionMap().get("nextTip")); 155 156 JButton closeButton = new JButton(UIManagerExt 157 .getString("TipOfTheDay.closeText", locale)); 158 buttons.add(closeButton); 159 160 final ActionListener saveChoice = new ActionListener() { 161 @Override 162 public void actionPerformed(ActionEvent e) { 163 if (choice != null) { 164 choice.setShowingOnStartup(showOnStartupBox.isSelected()); 165 } 166 dialog.setVisible(false); 167 } 168 }; 169 170 closeButton.addActionListener(new ActionListener() { 171 @Override 172 public void actionPerformed(ActionEvent e) { 173 dialog.setVisible(false); 174 saveChoice.actionPerformed(null); 175 } 176 }); 177 dialog.getRootPane().setDefaultButton(closeButton); 178 179 dialog.addWindowListener(new WindowAdapter() { 180 @Override 181 public void windowClosing(WindowEvent e) { 182 saveChoice.actionPerformed(null); 183 } 184 }); 185 186 ((JComponent)dialog.getContentPane()).registerKeyboardAction(saveChoice, 187 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 188 JComponent.WHEN_IN_FOCUSED_WINDOW); 189 190 dialog.pack(); 191 dialog.setLocationRelativeTo(parentComponent); 192 193 return dialog; 194 } 195 196 @Override 197 public void installUI(JComponent c) { 198 super.installUI(c); 199 installDefaults(); 200 installKeyboardActions(); 201 installComponents(); 202 installListeners(); 203 204 showCurrentTip(); 205 } 206 207 protected void installKeyboardActions() { 208 ActionMap map = getActionMap(); 209 if (map != null) { 210 SwingUtilities.replaceUIActionMap(tipPane, map); 211 } 212 } 213 214 ActionMap getActionMap() { 215 ActionMap map = new ActionMapUIResource(); 216 map.put("previousTip", new PreviousTipAction()); 217 map.put("nextTip", new NextTipAction()); 218 return map; 219 } 220 221 protected void installListeners() { 222 changeListener = createChangeListener(); 223 tipPane.addPropertyChangeListener(changeListener); 224 } 225 226 protected PropertyChangeListener createChangeListener() { 227 return new ChangeListener(); 228 } 229 230 protected void installDefaults() { 231 LookAndFeel.installColorsAndFont(tipPane, "TipOfTheDay.background", 232 "TipOfTheDay.foreground", "TipOfTheDay.font"); 233 LookAndFeel.installBorder(tipPane, "TipOfTheDay.border"); 234 LookAndFeel.installProperty(tipPane, "opaque", Boolean.TRUE); 235 tipFont = UIManager.getFont("TipOfTheDay.tipFont"); 236 } 237 238 protected void installComponents() { 239 tipPane.setLayout(new BorderLayout()); 240 241 // tip icon 242 JLabel tipIcon = new JLabel(UIManagerExt 243 .getString("TipOfTheDay.didYouKnowText", tipPane.getLocale())); 244 tipIcon.setIcon(UIManager.getIcon("TipOfTheDay.icon")); 245 tipIcon.setBorder(BorderFactory.createEmptyBorder(22, 15, 22, 15)); 246 tipPane.add("North", tipIcon); 247 248 // tip area 249 tipArea = new JPanel(new BorderLayout(2, 2)); 250 tipArea.setOpaque(false); 251 tipArea.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); 252 tipPane.add("Center", tipArea); 253 } 254 255 @Override 256 public Dimension getPreferredSize(JComponent c) { 257 return new Dimension(420, 175); 258 } 259 260 protected void showCurrentTip() { 261 if (currentTipComponent != null) { 262 tipArea.remove(currentTipComponent); 263 } 264 265 int currentTip = tipPane.getCurrentTip(); 266 if (currentTip == -1) { 267 JLabel label = new JLabel(); 268 label.setOpaque(true); 269 label.setBackground(UIManager.getColor("TextArea.background")); 270 currentTipComponent = label; 271 tipArea.add("Center", currentTipComponent); 272 return; 273 } 274 275 // tip does not fall in current tip range 276 if (tipPane.getModel() == null || tipPane.getModel().getTipCount() == 0 277 || (currentTip < 0 && currentTip >= tipPane.getModel().getTipCount())) { 278 currentTipComponent = new JLabel(); 279 } else { 280 Tip tip = tipPane.getModel().getTipAt(currentTip); 281 282 Object tipObject = tip.getTip(); 283 if (tipObject instanceof Component) { 284 currentTipComponent = (Component)tipObject; 285 } else if (tipObject instanceof Icon) { 286 currentTipComponent = new JLabel((Icon)tipObject); 287 } else { 288 JScrollPane tipScroll = new JScrollPane(); 289 tipScroll.setBorder(null); 290 tipScroll.setOpaque(false); 291 tipScroll.getViewport().setOpaque(false); 292 tipScroll.setBorder(null); 293 294 String text = tipObject == null?"":tipObject.toString(); 295 296 if (BasicHTML.isHTMLString(text)) { 297 JEditorPane editor = new JEditorPane("text/html", text); 298 editor.setFont(tipPane.getFont()); 299// BasicHTML.updateRenderer(editor, text); 300 SwingXUtilities.setHtmlFont( 301 (HTMLDocument) editor.getDocument(), tipPane.getFont()); 302 editor.setEditable(false); 303 editor.setBorder(null); 304 editor.setMargin(null); 305 editor.setOpaque(false); 306 tipScroll.getViewport().setView(editor); 307 } else { 308 JTextArea area = new JTextArea(text); 309 area.setFont(tipPane.getFont()); 310 area.setEditable(false); 311 area.setLineWrap(true); 312 area.setWrapStyleWord(true); 313 area.setBorder(null); 314 area.setMargin(null); 315 area.setOpaque(false); 316 tipScroll.getViewport().setView(area); 317 } 318 319 currentTipComponent = tipScroll; 320 } 321 } 322 323 tipArea.add("Center", currentTipComponent); 324 tipArea.revalidate(); 325 tipArea.repaint(); 326 } 327 328 @Override 329 public void uninstallUI(JComponent c) { 330 uninstallListeners(); 331 uninstallComponents(); 332 uninstallDefaults(); 333 super.uninstallUI(c); 334 } 335 336 protected void uninstallListeners() { 337 tipPane.removePropertyChangeListener(changeListener); 338 } 339 340 protected void uninstallComponents() {} 341 342 protected void uninstallDefaults() {} 343 344 class ChangeListener implements PropertyChangeListener { 345 @Override 346 public void propertyChange(PropertyChangeEvent evt) { 347 if (JXTipOfTheDay.CURRENT_TIP_CHANGED_KEY.equals(evt.getPropertyName())) { 348 showCurrentTip(); 349 } 350 } 351 } 352 353 class PreviousTipAction extends AbstractAction { 354 public PreviousTipAction() { 355 super("previousTip"); 356 } 357 @Override 358 public void actionPerformed(ActionEvent e) { 359 tipPane.previousTip(); 360 } 361 @Override 362 public boolean isEnabled() { 363 return tipPane.isEnabled(); 364 } 365 } 366 367 class NextTipAction extends AbstractAction { 368 public NextTipAction() { 369 super("nextTip"); 370 } 371 @Override 372 public void actionPerformed(ActionEvent e) { 373 tipPane.nextTip(); 374 } 375 @Override 376 public boolean isEnabled() { 377 return tipPane.isEnabled(); 378 } 379 } 380 381}