001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.plugin; 020 021import icy.file.FileUtil; 022import icy.gui.component.ImageComponent; 023import icy.gui.frame.IcyFrame; 024import icy.gui.util.ComponentUtil; 025import icy.gui.util.GuiUtil; 026import icy.network.NetworkUtil; 027import icy.plugin.PluginDescriptor; 028import icy.plugin.PluginLauncher; 029import icy.plugin.PluginLoader; 030import icy.system.IcyExceptionHandler; 031import icy.system.SystemUtil; 032import icy.system.thread.ThreadUtil; 033import icy.util.EventUtil; 034import icy.util.Random; 035import icy.util.StringUtil; 036 037import java.awt.BorderLayout; 038import java.awt.Color; 039import java.awt.Dimension; 040import java.awt.Font; 041import java.awt.Image; 042import java.awt.event.ActionEvent; 043import java.awt.event.ActionListener; 044import java.awt.event.MouseAdapter; 045import java.awt.event.MouseEvent; 046import java.io.IOException; 047 048import javax.swing.BorderFactory; 049import javax.swing.Box; 050import javax.swing.BoxLayout; 051import javax.swing.JButton; 052import javax.swing.JLabel; 053import javax.swing.JPanel; 054import javax.swing.JScrollPane; 055import javax.swing.JSeparator; 056import javax.swing.JTextPane; 057import javax.swing.SwingConstants; 058import javax.swing.event.HyperlinkEvent; 059import javax.swing.event.HyperlinkListener; 060 061/** 062 * @author stephane 063 */ 064public class PluginDetailPanel extends IcyFrame implements HyperlinkListener 065{ 066 private class ExecuteActionButton extends JButton implements ActionListener 067 { 068 /** 069 * 070 */ 071 private static final long serialVersionUID = 3096619820228575930L; 072 073 public ExecuteActionButton() 074 { 075 super("Execute"); 076 077 setVisible(plugin.isActionable()); 078 079 addActionListener(this); 080 } 081 082 @Override 083 public void actionPerformed(ActionEvent e) 084 { 085 PluginLauncher.start(plugin); 086 } 087 } 088 089 private class CloseActionButton extends JButton implements ActionListener 090 { 091 /** 092 * 093 */ 094 private static final long serialVersionUID = 4912851751410749786L; 095 096 public CloseActionButton() 097 { 098 super("Close"); 099 100 addActionListener(this); 101 } 102 103 @Override 104 public void actionPerformed(ActionEvent e) 105 { 106 close(); 107 } 108 } 109 110 final PluginDescriptor plugin; 111 112 // private final ChangesLogActionButton changesLogButton; 113 private final ExecuteActionButton executeButton; 114 private final CloseActionButton closeButton; 115 116 /** 117 * gui 118 */ 119 final JPanel imagePanel; 120 final ImageComponent pluginImage; 121 final JLabel pluginPathLabel; 122 final JLabel pluginAuthorLabel; 123 final JLabel pluginWebsiteLabel; 124 final JLabel pluginEmailLabel; 125 final JTextPane pluginDescriptionText; 126 final JTextPane pluginChangeLogText; 127 128 /** 129 * @param plugin 130 */ 131 public PluginDetailPanel(PluginDescriptor plugin) 132 { 133 super(plugin.getName() + " " + plugin.getVersion(), false, true); 134 135 this.plugin = plugin; 136 137 // changesLogButton = new ChangesLogActionButton(); 138 executeButton = new ExecuteActionButton(); 139 closeButton = new CloseActionButton(); 140 141 setPreferredSize(new Dimension(640, 520)); 142 143 // build top panel 144 pluginDescriptionText = new JTextPane(); 145 pluginDescriptionText.setContentType("text/html"); 146 pluginDescriptionText.setEditable(false); 147 pluginDescriptionText.setOpaque(false); 148 pluginDescriptionText.addHyperlinkListener(this); 149 ComponentUtil.setFixedHeight(pluginDescriptionText, 256); 150 151 final JScrollPane scDescription = new JScrollPane(pluginDescriptionText); 152 scDescription.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); 153 154 pluginImage = new ImageComponent(plugin.isImageLoaded() ? plugin.getImage() : PluginDescriptor.DEFAULT_IMAGE); 155 156 imagePanel = new JPanel(new BorderLayout()); 157 imagePanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); 158 imagePanel.add(pluginImage, BorderLayout.CENTER); 159 160 final JPanel topPanel = new JPanel(new BorderLayout()); 161 162 topPanel.add(imagePanel, BorderLayout.WEST); 163 topPanel.add(scDescription, BorderLayout.CENTER); 164 165 // center panel 166 pluginPathLabel = new JLabel(); 167 pluginPathLabel.addMouseListener(new MouseAdapter() 168 { 169 @Override 170 public void mouseClicked(MouseEvent e) 171 { 172 if (e.isConsumed()) 173 return; 174 175 if (EventUtil.isLeftMouseButton(e) && (e.getClickCount() == 2)) 176 { 177 final String path = pluginPathLabel.getText(); 178 179 try 180 { 181 if (!StringUtil.isEmpty(path) && !path.equals("---")) 182 SystemUtil.openFolder(FileUtil.getDirectory(path)); 183 } 184 catch (IOException e1) 185 { 186 IcyExceptionHandler.showErrorMessage(e1, false, false); 187 } 188 189 e.consume(); 190 } 191 } 192 }); 193 pluginAuthorLabel = new JLabel(); 194 pluginWebsiteLabel = new JLabel(); 195 pluginWebsiteLabel.addMouseListener(new MouseAdapter() 196 { 197 @Override 198 public void mouseClicked(MouseEvent e) 199 { 200 if (e.isConsumed()) 201 return; 202 203 if (EventUtil.isLeftMouseButton(e) && (e.getClickCount() == 2)) 204 { 205 final String url = pluginWebsiteLabel.getText(); 206 207 if (!StringUtil.isEmpty(url) && !url.equals("---")) 208 NetworkUtil.openBrowser(url); 209 210 e.consume(); 211 } 212 } 213 }); 214 pluginEmailLabel = new JLabel(); 215 216 final JPanel infosPanel = new JPanel(); 217 infosPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); 218 infosPanel.setLayout(new BoxLayout(infosPanel, BoxLayout.PAGE_AXIS)); 219 220 infosPanel.add(GuiUtil.createTabBoldLabel("Path", 1)); 221 infosPanel.add(GuiUtil.createTabLabel(pluginPathLabel, 32)); 222 infosPanel.add(Box.createVerticalStrut(4)); 223 infosPanel.add(GuiUtil.createTabBoldLabel("Author", 1)); 224 infosPanel.add(GuiUtil.createTabLabel(pluginAuthorLabel, 32)); 225 infosPanel.add(Box.createVerticalStrut(4)); 226 infosPanel.add(GuiUtil.createTabBoldLabel("Web site", 1)); 227 infosPanel.add(GuiUtil.createTabLabel(pluginWebsiteLabel, 32)); 228 infosPanel.add(Box.createVerticalStrut(4)); 229 infosPanel.add(GuiUtil.createTabBoldLabel("Email", 1)); 230 infosPanel.add(GuiUtil.createTabLabel(pluginEmailLabel, 32)); 231 infosPanel.add(Box.createVerticalStrut(4)); 232 infosPanel.add(Box.createVerticalGlue()); 233 234 final JScrollPane scInfosPanel = new JScrollPane(infosPanel); 235 scInfosPanel.setPreferredSize(new Dimension(280, 128)); 236 scInfosPanel.setMaximumSize(new Dimension(280, 2048)); 237 scInfosPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); 238 239 pluginChangeLogText = new JTextPane(); 240 pluginChangeLogText.setContentType("text/html"); 241 pluginChangeLogText.setEditable(false); 242 pluginChangeLogText.setOpaque(false); 243 pluginChangeLogText.addHyperlinkListener(this); 244 245 final JScrollPane scChangeLog = new JScrollPane(pluginChangeLogText); 246 scChangeLog.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); 247 248 final JPanel changeLogPanel = new JPanel(new BorderLayout()); 249 changeLogPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 4, 4)); 250 251 changeLogPanel.add(GuiUtil.createTabBoldLabel("ChangeLog", 1), BorderLayout.NORTH); 252 changeLogPanel.add(GuiUtil.createLineBoxPanel(Box.createHorizontalStrut(32), scChangeLog), BorderLayout.CENTER); 253 254 final JPanel centerPanel = new JPanel(new BorderLayout()); 255 256 centerPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH); 257 centerPanel.add(scInfosPanel, BorderLayout.WEST); 258 centerPanel.add(changeLogPanel, BorderLayout.CENTER); 259 260 // bottom panel 261 final JPanel buttonsPanel = new JPanel(); 262 buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.LINE_AXIS)); 263 buttonsPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); 264 265 buttonsPanel.add(executeButton); 266 buttonsPanel.add(Box.createHorizontalGlue()); 267 buttonsPanel.add(Box.createHorizontalStrut(4)); 268 buttonsPanel.add(closeButton); 269 270 final JPanel bottomPanel = new JPanel(new BorderLayout()); 271 272 bottomPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH); 273 bottomPanel.add(buttonsPanel, BorderLayout.CENTER); 274 275 setLayout(new BorderLayout()); 276 277 add(topPanel, BorderLayout.NORTH); 278 add(centerPanel, BorderLayout.CENTER); 279 add(bottomPanel, BorderLayout.SOUTH); 280 281 updateGui(); 282 283 addToDesktopPane(); 284 // random position for more fun 285 setLocation(10 * Random.nextInt(20) + 40, 10 * Random.nextInt(10) + 40); 286 setVisible(true); 287 requestFocus(); 288 289 // some parts of the descriptor are not loaded --> async update 290 if (!plugin.isAllLoaded()) 291 { 292 ThreadUtil.bgRun(new Runnable() 293 { 294 @Override 295 public void run() 296 { 297 PluginDetailPanel.this.plugin.loadAll(); 298 299 // rebuild interface 300 ThreadUtil.invokeLater(new Runnable() 301 { 302 @Override 303 public void run() 304 { 305 updateGui(); 306 } 307 }); 308 } 309 }); 310 } 311 } 312 313 void updateGui() 314 { 315 final Font sysFont = pluginAuthorLabel.getFont(); 316 final Image img = plugin.getImage(); 317 final String description = plugin.getDescription(); 318 final String changesLog = plugin.getChangeLog(); 319 final String author = plugin.getAuthor(); 320 final String email = plugin.getEmail(); 321 final String web = plugin.getWeb(); 322 323 String jarPath = plugin.getPluginJarPath(); 324 325 // can't get JAR path ? 326 if (StringUtil.isEmpty(jarPath)) 327 { 328 // try to get the local plugin (we were probably using the online descriptor) 329 final PluginDescriptor localPlugin = PluginLoader.getPlugin(plugin.getClassName()); 330 331 if (localPlugin != null) 332 jarPath = localPlugin.getPluginJarPath(); 333 } 334 335 if (img == null) 336 pluginImage.setImage(PluginDescriptor.DEFAULT_IMAGE); 337 else 338 pluginImage.setImage(img); 339 340 if (StringUtil.isEmpty(description)) 341 pluginDescriptionText.setText("No description"); 342 else 343 { 344 if (StringUtil.containHtmlCR(description)) 345 pluginDescriptionText.setText(StringUtil.removeCR(description)); 346 else 347 pluginDescriptionText.setText(StringUtil.toHtmlCR(description)); 348 349 pluginDescriptionText.setCaretPosition(0); 350 } 351 352 ComponentUtil.setJTextPaneFont(pluginDescriptionText, sysFont, Color.black); 353 354 if (StringUtil.isEmpty(changesLog)) 355 pluginChangeLogText.setText("---"); 356 else 357 { 358 pluginChangeLogText.setText(StringUtil.toHtmlCR(changesLog)); 359 pluginChangeLogText.setCaretPosition(0); 360 } 361 ComponentUtil.setJTextPaneFont(pluginChangeLogText, new Font("courier", Font.PLAIN, 11), Color.black); 362 if (StringUtil.isEmpty(jarPath)) 363 { 364 pluginPathLabel.setText("---"); 365 pluginPathLabel.setToolTipText(""); 366 } 367 else 368 { 369 pluginPathLabel.setText(jarPath); 370 pluginPathLabel.setToolTipText(jarPath + " (double click to see file location)"); 371 } 372 if (StringUtil.isEmpty(author)) 373 { 374 pluginAuthorLabel.setText("---"); 375 pluginAuthorLabel.setToolTipText(""); 376 } 377 else 378 { 379 pluginAuthorLabel.setText(author); 380 pluginAuthorLabel.setToolTipText(author); 381 } 382 if (StringUtil.isEmpty(email)) 383 { 384 pluginEmailLabel.setText("---"); 385 pluginEmailLabel.setToolTipText(""); 386 } 387 else 388 { 389 pluginEmailLabel.setText(email); 390 pluginEmailLabel.setToolTipText(email); 391 } 392 if (StringUtil.isEmpty(web)) 393 { 394 pluginWebsiteLabel.setText("---"); 395 pluginWebsiteLabel.setToolTipText(""); 396 } 397 else 398 { 399 pluginWebsiteLabel.setText(web); 400 pluginWebsiteLabel.setToolTipText(web + " (double click to open in browser)"); 401 } 402 403 pack(); 404 } 405 406 @Override 407 public void hyperlinkUpdate(HyperlinkEvent e) 408 { 409 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) 410 NetworkUtil.openBrowser(e.getURL()); 411 } 412}