/** * Copyright 2008 Studio Melipone * * This file is part of "Smash Uploader". * * Smash Uploader is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Foobar 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Foobar. If not, see <http://www.gnu.org/licenses/>. * * * plugin for UpShot (c) * http://www.upshotit.com * */ package main; import java.awt.Color; import java.awt.Cursor; import java.awt.Desktop; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.Insets; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.TransferHandler; import javax.swing.table.TableColumn; import table.DataModel; import table.DeleteCellEditor; import table.DeleteCellRender; import table.EditCellEditor; import table.EditCellRender; import connect.Login; import connect.UpConnection; /** * UpShot plugin application * Smash Uploader uses a JDesktopPane to transfert from desktop to application * then list it in a JTable, and send it to a distant host through http requests. * @author Gregory Durelle * */ public class Smash extends JFrame implements ActionListener{ private static final long serialVersionUID = 1L;//useless but avoid warning ;) private JPanel flags, pane; private JDesktopPane desk; private DataModel model; private JTable table; private DeleteCellRender delCellRender; private EditCellRender editCellRender; private EditCellEditor editCellEditor; private JScrollPane scroll; private JButton sender, logger, abouter, helper, fr, en; private JLabel title,format, size;; private TransferHandler handler; private UpConnection uc; private Login log; private String home, folder, file, languages; private About about; private final Color background = Color.decode("#656565"); private final Color foreground = Color.WHITE; private Locale locale = Locale.getDefault(); private ResourceBundle msg; public Smash(){ super("Smash Uploader"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setResizable(false); this.getContentPane().setBackground(background); this.getContentPane().setForeground(foreground); this.setIconImage(getIcon("upshot_logo.png").getImage()); //TODO Try to use SwingWorker to load ALL images needed in the application languages = "doc/languages/trans"; msg = ResourceBundle.getBundle(languages, locale); /* * STEP 0: prepare folders and files needed * for user's preferences * */ home = System.getProperty("user.home");//users'main folder, MyDocuments or /home... folder = "/Smash/"; file = "smash.config"; File f = new File(home+folder);//create the folder at the right place f.mkdir(); /* * STEP 1: we prepare the visual aspect of the application * * send, login, help, * the desk pane, * the list of dropped images, */ Cursor hand = new Cursor(Cursor.HAND_CURSOR); ImageIcon lfr = Smash.getIcon("fr.png"); ImageIcon len = Smash.getIcon("enus.png"); flags = new JPanel(); flags.setBackground(Color.BLACK); flags.setBorder(BorderFactory.createEmptyBorder()); fr = new JButton(lfr); fr.setActionCommand("fr"); fr.addActionListener(this); fr.setOpaque(false); fr.setBorder(BorderFactory.createEmptyBorder()); fr.setFocusable(false); fr.setCursor(hand); en = new JButton(len); en.setActionCommand("en"); en.addActionListener(this); en.setOpaque(false); en.setBorder(BorderFactory.createEmptyBorder()); en.setFocusable(false); en.setCursor(hand); GridBagLayout flagbl = new GridBagLayout(); GridBagConstraints flagbc = new GridBagConstraints(); flags.setLayout(flagbl); flagbc.gridx=0; flagbc.gridy=0; flagbc.fill=GridBagConstraints.NONE; flagbc.anchor=GridBagConstraints.WEST; flagbc.insets=new Insets(5, 20, 5, 2); flagbl.setConstraints(fr, flagbc); flagbc.gridx=1; flagbc.insets=new Insets(5, 2, 5, 624); flagbl.setConstraints(en, flagbc); flags.add(fr); flags.add(en); pane = new JPanel(); pane.setOpaque(false); pane.setBorder(BorderFactory.createEmptyBorder()); final Image back = getIcon("dropzone.png").getImage(); desk = new JDesktopPane(){ private static final long serialVersionUID = 1L; public void paint(Graphics g){ super.paintComponents(g); g.drawImage(back, 0, g.getClipBounds().y, g.getClipBounds().width, g.getClipBounds().height, null); } }; desk.setOpaque(false); model = new DataModel(); table = new JTable(model); scroll = new JScrollPane(table); Dimension dim = new Dimension(back.getWidth(null),back.getHeight(null)); desk.setSize(dim); desk.setPreferredSize(dim); desk.setRequestFocusEnabled(true); desk.requestFocus(); desk.setBorder(BorderFactory.createEmptyBorder()); scroll.setPreferredSize(new Dimension(back.getWidth(null),150)); scroll.setBackground(background); scroll.setForeground(foreground); scroll.setOpaque(false); scroll.getViewport().setOpaque(false); scroll.setBorder(BorderFactory.createEmptyBorder()); table.setAutoCreateRowSorter(false);//no sorting by clicking the headers table.setColumnSelectionAllowed(false);//no dragging table.setRowSelectionAllowed(false); table.setAutoscrolls(true); table.setDoubleBuffered(true); table.setShowGrid(false); table.setBackground(background);// used cells background table.setForeground(foreground); table.setSelectionBackground(background);// when you select a cell table.setSelectionForeground(foreground); Font font = new Font("Verdana",Font.BOLD,12); table.setFont(font); table.setTableHeader(null); /* FIXME customize the header correctly to obtain same effect as with the JPanel myHead * The header of the table is quite independant * so we have to customize it singly BUT as it was too ugly, * we replaced it with the JPanel myHead defined further . * * DO NOT FORGET to comment line : table.setTableHeader(null); before uncommenting those lines */ // JTableHeader jth = table.getTableHeader(); // jth.setBackground(background); // jth.setForeground(foreground); // font = new Font("Verdana",Font.BOLD,10); // jth.setFont(font); // jth.setOpaque(false); // jth.setResizingAllowed(false); // jth.enableInputMethods(false); // jth.setReorderingAllowed(false); /*Column Delete*/ TableColumn column = table.getColumnModel().getColumn(0); column.setPreferredWidth(10); delCellRender = new DeleteCellRender(); DeleteCellEditor delCellEditor = new DeleteCellEditor(model); column.setCellRenderer(delCellRender); column.setCellEditor(delCellEditor); column.setResizable(false); /*Column Title*/ column = table.getColumnModel().getColumn(1); column.setPreferredWidth(180); column.setResizable(false); /*Column Format*/ column = table.getColumnModel().getColumn(2); column.setPreferredWidth(60); column.setResizable(false); /*Column Size*/ column = table.getColumnModel().getColumn(3); column.setPreferredWidth(70); column.setResizable(false); /*Column Edit*/ column = table.getColumnModel().getColumn(4); column.setPreferredWidth(55); column.setResizable(false); editCellRender = new EditCellRender(); editCellEditor = new EditCellEditor(model); column.setCellRenderer(editCellRender); column.setCellEditor(editCellEditor); /* Now let's display our elements as we want */ Dimension dimBtn = new Dimension(32, 32); logger = new JButton(Smash.getIcon("user.png")); logger.setActionCommand("login"); logger.addActionListener(this); logger.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); logger.setOpaque(false); logger.setBackground(background); logger.setFocusPainted(false); logger.setPreferredSize(dimBtn); helper = new JButton(Smash.getIcon("help.png")); helper.setActionCommand("help"); helper.addActionListener(this); helper.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); helper.setOpaque(false); helper.setBackground(background); helper.setFocusPainted(false); helper.setPreferredSize(dimBtn); abouter = new JButton(Smash.getIcon("upshot_logo.png")); abouter.setActionCommand("about"); abouter.addActionListener(this); abouter.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); abouter.setOpaque(false); abouter.setBackground(background); abouter.setFocusPainted(false); abouter.setPreferredSize(dimBtn); sender = new JButton(); sender.setActionCommand("SEND"); sender.addActionListener(this); sender.setEnabled(false); sender.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); sender.setOpaque(false); sender.setBackground(background); sender.setForeground(foreground); Font fontBig = new Font("Verdana",Font.BOLD,28); sender.setFont(fontBig); /* * Wiredly ugly coded customized header * */ title=new JLabel(); title.setBackground(background); title.setForeground(foreground); format=new JLabel(); format.setBackground(background); format.setForeground(foreground); size=new JLabel(); size.setBackground(background); size.setForeground(foreground); JPanel myHead = new JPanel(); myHead.setFont(font); myHead.setBackground(background); myHead.setForeground(foreground); myHead.add(title); myHead.add(format); myHead.add(size); /* Do not forget to display labels and buttons text * in the wanted language * */ // For the button and labels in this frame sender.setText(msg.getString("send")); title.setText(msg.getString("title")+" "); format.setText(" "+msg.getString("format")+" "); size.setText(msg.getString("size")+" "); // For all other components delCellRender.setResourceBundle(msg); editCellRender.setResourceBundle(msg); editCellEditor.setResourceBundle(msg); GridBagLayout pgbl = new GridBagLayout(); GridBagConstraints pgbc = new GridBagConstraints(); pgbc.gridx=0; pgbc.gridy=0; pgbc.gridwidth=2; pgbc.fill=GridBagConstraints.HORIZONTAL; pgbc.anchor=GridBagConstraints.NORTH; pgbl.setConstraints(desk, pgbc); pgbc.gridy=1; pgbc.anchor=GridBagConstraints.CENTER; pgbl.setConstraints(myHead, pgbc); pgbc.gridy=2; pgbl.setConstraints(scroll, pgbc); pgbc.gridy=3; pgbc.gridwidth=1; pgbc.insets=new Insets(0,1,2,1); pgbc.anchor=GridBagConstraints.SOUTHWEST; pgbl.setConstraints(logger, pgbc); pgbc.gridy=4;; pgbl.setConstraints(helper, pgbc); pgbc.gridy=5; pgbl.setConstraints(abouter, pgbc); pgbc.gridx=1; pgbc.gridy=3; pgbc.gridheight=3; pgbc.gridwidth=2; pgbc.fill=GridBagConstraints.BOTH; pgbl.setConstraints(sender, pgbc); pane.setLayout(pgbl); pane.add(desk); pane.add(myHead); pane.add(scroll); pane.add(logger); pane.add(helper); pane.add(abouter); pane.add(sender); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); this.getContentPane().setLayout(gbl); gbc.gridx=0; gbc.gridy=0; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.fill = GridBagConstraints.NONE; gbl.setConstraints(flags, gbc); gbc.gridy=1; gbc.anchor = GridBagConstraints.SOUTH; gbl.setConstraints(pane, gbc); this.add(flags); this.add(pane); this.pack(); /* * STEP 2 : The transferHandler * * One of the fundamental functionnality of the application is this transferHandler * * see http://java.sun.com/docs/books/tutorial/uiswing/dnd/intro.html for details */ handler = new TransferHandler() { private static final long serialVersionUID = 1L; public boolean canImport(TransferHandler.TransferSupport support) { if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { return false; } support.setDropAction(COPY); return true; } @SuppressWarnings("unchecked") public boolean importData(TransferHandler.TransferSupport support) { if (!canImport(support)) { return false; } Transferable t = support.getTransferable(); try { DataFlavor df = DataFlavor.javaFileListFlavor; List<File> localList = (List<File>)t.getTransferData(df);//list of the items we have just dropped for (File f : localList) { ImageFile imf = new ImageFile(f); model.add(imf); table.repaint(); } if (localList.size()>0 && log.getAnswer()>0) sender.setEnabled(true); } catch (UnsupportedFlavorException e) { JOptionPane.showMessageDialog(Smash.getFrames()[0], "Smash.handler.importData() UnsupportedFlavorException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); return false; } catch (IOException e) { JOptionPane.showMessageDialog(Smash.getFrames()[0], "Smash.handler.importData() IOException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); return false; } return true; } }; desk.setTransferHandler(handler); /* * STEP 3 : Logging in * Retrieve the user's id by sending its email+password * throught simple GET HTTP request * The id is needed for future request paths */ uc = new UpConnection(); /* * check if login information already given in the past * and load it if yes * */ File fconfig = new File(home+folder+file); if(fconfig.exists()) load(); else{ log = new Login(this, uc); log.setResourceBundle(msg); log.setVisible(true); } if(log.getAnswer()>0){ save(); if(model.getImages().size()>0) sender.setEnabled(true); } else sender.setEnabled(false); this.setLocationRelativeTo(null); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Smash up = new Smash(); up.setVisible(true); } }); } /** * Set the language resource from About * @param rb the ResourceBundle representing the language */ public void setResourceBundle(ResourceBundle rb){ msg=rb; this.displayLanguage(); } /** * Redraw all labels and buttons in the appropriate language */ private void displayLanguage(){ // For the button and labels in this frame sender.setText(msg.getString("send")); title.setText(msg.getString("title")+" "); format.setText(" "+msg.getString("format")+" "); size.setText(msg.getString("size")+" "); // For all other components log.setResourceBundle(msg); delCellRender.setResourceBundle(msg); editCellRender.setResourceBundle(msg); editCellEditor.setResourceBundle(msg); table.repaint(); } @Override public void actionPerformed(ActionEvent ae) { String s = ae.getActionCommand(); if(s.equals("SEND")){ if(model.getRowCount()==0) JOptionPane.showMessageDialog(this, "Nothing to send !\nAdd image files and try again.", "Send what ?", JOptionPane.WARNING_MESSAGE); else{ sender.setEnabled(false); /* * DO THE HTTP JOB * send each file with its informations to create drafts upshots * and refresh the list at the same time... * */ uc.setModel(model); Thread t = new Thread(uc); t.start(); this.repaint(); } } else if(s.equals("login")){ log.setVisible(true); if(log.getAnswer()>0){ save(); if(model.getImages().size()>0) sender.setEnabled(true); } else sender.setEnabled(false); } else if(s.equals("about")){ if(about==null){ about = new About(this); about.setResourceBundle(msg); about.setVisible(true); } else { about.setResourceBundle(msg); about.setVisible(true); } } else if(s.equals("help")){ try { if ( Desktop.isDesktopSupported() ) {//Test if the class Desktop is supported on the OS Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(Desktop.Action.BROWSE)) {//test if the browse method is also supported desktop.browse(new URI("http://smashuploader.com/help")); } } } catch (MalformedURLException e) { JOptionPane.showMessageDialog(Smash.getFrames()[0], "About.actionPerformed() MalformedURException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(Smash.getFrames()[0], "About.actionPerformed() IOException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } catch (URISyntaxException e) { JOptionPane.showMessageDialog(Smash.getFrames()[0], "About.actionPerformed() URISyntaxException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } } else if(s.equals("fr")){ locale = new Locale("fr","FR"); msg = ResourceBundle.getBundle(languages, locale); this.displayLanguage(); } else if(s.equals("en")){ locale = new Locale("en","US"); msg = ResourceBundle.getBundle(languages, locale); this.displayLanguage(); } } /** * Save login information in serialized file */ private void save(){ FileOutputStream fos = null; ObjectOutputStream out = null; try { fos = new FileOutputStream(home+folder+file); out = new ObjectOutputStream(fos); out.writeObject(log); out.close(); } catch (IOException e) { JOptionPane.showMessageDialog(Smash.getFrames()[0], "Smash.save() IOException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } } /** * Load serialized file * and recreate login object thanks to it */ private void load(){ FileInputStream fis = null; ObjectInputStream in = null; try{ fis = new FileInputStream(home+folder+file); in = new ObjectInputStream(fis); log = (Login)in.readObject(); in.close(); } catch(IOException e){ JOptionPane.showMessageDialog(Smash.getFrames()[0], "Smash.load() IOException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } catch(ClassNotFoundException e){ JOptionPane.showMessageDialog(Smash.getFrames()[0], "Smash.load() ClassNotFoundException : "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } log.setConnectionConfig(uc); log.setResourceBundle(msg); } /** * Helping method to get an image * @return ImageIcon using the package path */ public static ImageIcon getIcon(String name){ URL url = Smash.class.getResource("/images/"+name); return new ImageIcon(url); } }