package de.onyxbits.raccoon.gui; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.net.URL; import java.util.List; import java.util.StringTokenizer; import java.util.Vector; import java.util.prefs.Preferences; import javax.swing.ImageIcon; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTabbedPane; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import de.onyxbits.raccoon.App; import de.onyxbits.raccoon.BrowseUtil; import de.onyxbits.raccoon.Messages; import de.onyxbits.raccoon.io.Archive; import de.onyxbits.raccoon.io.DownloadLogger; /** * The main UI. This class must be started by creating an object and passing it * to SwingUtils.invokeLater() * * @author patrick * */ public class MainActivity extends JFrame implements ActionListener, WindowListener, Runnable { private static final long serialVersionUID = 1L; /** * Preferences key for storing the last opened archive directory. */ public static final String LASTARCHIVE = "lastarchive"; //$NON-NLS-1$ /** * Preferences key for whether or not to fetch icons. */ public static final String FETCHICONS = "fetchicons"; //$NON-NLS-1$ private JMenuItem quit; private JMenuItem open; private JMenuItem search; private JMenuItem close; private JMenuItem update; private JMenuItem exportArchive; private JMenuItem importArchive; private JMenuItem downloads; private JMenuItem contents; private JMenuItem newArchive; private JRadioButtonMenuItem fetchIcons; private JTabbedPane views; private ListView downloadList; private JScrollPane downloadListScroll; private SearchView searchView; private Archive archive; private static Vector<MainActivity> all = new Vector<MainActivity>(); /** * New GUI * * @param archive * the archive to display. This may be null. */ public MainActivity(Archive archive) { this.archive = archive; views = new JTabbedPane(); downloadList = new ListView(); JMenuBar bar = new JMenuBar(); JMenu file = new JMenu(Messages.getString("MainActivity.1")); //$NON-NLS-1$ file.setMnemonic(KeyStroke.getKeyStroke(Messages.getString("MainActivity.0")).getKeyCode()); //$NON-NLS-1$ quit = new JMenuItem( Messages.getString("MainActivity.2"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.22")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); open = new JMenuItem( Messages.getString("MainActivity.3"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.23")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); close = new JMenuItem( Messages.getString("MainActivity.4"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.24")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ close.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); update = new JMenuItem( Messages.getString("MainActivity.5"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.25")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ update.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); update.setEnabled(false); newArchive = new JMenuItem( Messages.getString("MainActivity.29"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.30")) //$NON-NLS-1$ //$NON-NLS-2$ .getKeyCode()); newArchive.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); exportArchive = new JMenuItem( Messages.getString("MainActivity.33"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.35")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ importArchive = new JMenuItem( Messages.getString("MainActivity.36"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.37")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ Preferences prefs = Preferences.userNodeForPackage(getClass()); fetchIcons = new JRadioButtonMenuItem( Messages.getString("MainActivity.34"), prefs.getBoolean(FETCHICONS, true)); //$NON-NLS-1$ file.add(newArchive); file.add(open); file.add(new JSeparator()); file.add(importArchive); file.add(exportArchive); file.add(update); file.add(new JSeparator()); file.add(close); file.add(quit); bar.add(file); JMenu view = new JMenu(Messages.getString("MainActivity.6")); //$NON-NLS-1$ view.setMnemonic(KeyStroke.getKeyStroke(Messages.getString("MainActivity.15")).getKeyCode()); //$NON-NLS-1$ search = new JMenuItem( Messages.getString("MainActivity.7"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.26")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ search.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); downloads = new JMenuItem( Messages.getString("MainActivity.8"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.27")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ downloads.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask())); view.add(search); view.add(downloads); view.add(new JSeparator()); view.add(fetchIcons); search.setEnabled(false); downloads.setEnabled(false); importArchive.setEnabled(false); exportArchive.setEnabled(false); bar.add(view); JMenu help = new JMenu(Messages.getString("MainActivity.9")); //$NON-NLS-1$ help.setMnemonic(KeyStroke.getKeyStroke(Messages.getString("MainActivity.21")).getKeyCode()); //$NON-NLS-1$ contents = new JMenuItem( Messages.getString("MainActivity.10"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.28")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$ contents.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); help.add(contents); bar.add(help); setJMenuBar(bar); setContentPane(views); } public void run() { if (archive == null) { Preferences prefs = Preferences.userNodeForPackage(getClass()); String tmp = prefs.get(MainActivity.LASTARCHIVE, null); if (tmp != null) { archive = new Archive(new File(tmp)); } else { archive = new Archive(new File(App.getDir(App.ARCHIVEDIR), Messages.getString("MainActivity.11"))); //$NON-NLS-1$ } } newArchive.addActionListener(this); open.addActionListener(this); quit.addActionListener(this); close.addActionListener(this); search.addActionListener(this); contents.addActionListener(this); downloads.addActionListener(this); update.addActionListener(this); fetchIcons.addActionListener(this); exportArchive.addActionListener(this); importArchive.addActionListener(this); addWindowListener(this); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); URL img = getClass().getResource("/rsrc/icons/appicon.png"); //$NON-NLS-1$ setIconImage(new ImageIcon(img, "").getImage()); //$NON-NLS-1$ doMount(archive); pack(); setSize(1024, 768); setVisible(true); all.add(this); } public void actionPerformed(ActionEvent event) { Object src = event.getSource(); if (src == downloads) { views.setSelectedIndex(1); } if (src == search) { views.setSelectedIndex(0); } if (src == newArchive) { if (searchView != null) { searchView.doMessage(null); } doNewArchive(); } if (src == quit) { if (searchView != null) { searchView.doMessage(null); } doQuit(); } if (src == close) { if (searchView != null) { searchView.doMessage(null); } doClose(); } if (src == open) { if (searchView != null) { searchView.doMessage(null); } doOpen(); } if (src == contents) { if (searchView != null) { searchView.doMessage(null); } BrowseUtil.openUrl(Messages.getString("MainActivity.12")); //$NON-NLS-1$ } if (src == update) { views.setSelectedIndex(0); searchView.doUpdateSearch(); } if (src == fetchIcons) { Preferences prefs = Preferences.userNodeForPackage(getClass()); prefs.putBoolean(FETCHICONS, fetchIcons.isSelected()); } if (src == exportArchive) { searchView.doMessage(null); doExport(); } if (src == importArchive) { searchView.doMessage(null); doImport(); } } private void doImport() { try { String data = (String) Toolkit.getDefaultToolkit().getSystemClipboard() .getData(DataFlavor.stringFlavor); String prefix = "market://details?id="; //$NON-NLS-1$ StringTokenizer st = new StringTokenizer(data); Vector<String> lst = new Vector<String>(); int count = 0; while (st.hasMoreElements()) { // Lets first check the entire clipboard if its content is well formed. String url = st.nextToken(); if (url.startsWith(prefix) && url.length() > prefix.length()) { // Let's keep it simple. String id = url.substring(prefix.length(), url.length()); if (!lst.contains(id) && !archive.fileUnder(id, 0).getParentFile().exists()) { lst.add(id); count++; } } } // We got at least one new app id. Ask the user to confirm the list, then // create files. if (count > 0) { JList<String> all = new JList<String>(lst); all.addSelectionInterval(0, lst.size() - 1); if (JOptionPane .showConfirmDialog( this, new JScrollPane(all), Messages.getString("MainActivity.42"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null) == JOptionPane.OK_OPTION) {//$NON-NLS-1$ int[] sel = all.getSelectedIndices(); for (int idx : sel) { archive.fileUnder(all.getModel().getElementAt(idx), 0).getParentFile().mkdirs(); } searchView.doMessage(Messages.getString("MainActivity.39")); //$NON-NLS-1$ } } else { // Tell the user that no new items were found. searchView.doMessage(Messages.getString("MainActivity.43")); //$NON-NLS-1$ } } catch (Exception e) { searchView.doMessage(Messages.getString("MainActivity.40")); //$NON-NLS-1$ // e.printStackTrace(); } } private void doExport() { List<String> lst = archive.list(); StringBuilder sb = new StringBuilder(); for (String s : lst) { sb.append("market://details?id="); //$NON-NLS-1$ sb.append(s); sb.append("\n"); //$NON-NLS-1$ } StringSelection stringSelection = new StringSelection(sb.toString()); Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard(); clpbrd.setContents(stringSelection, null); searchView.doMessage(Messages.getString("MainActivity.38")); //$NON-NLS-1$ } private void doNewArchive() { String res = JOptionPane .showInputDialog( this, Messages.getString("MainActivity.32"), Messages.getString("MainActivity.31"), JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$ //$NON-NLS-2$ if (res != null && res.length() > 0) { File file = new File(App.getDir(App.ARCHIVEDIR), res); MainActivity ma = new MainActivity(new Archive(file)); SwingUtilities.invokeLater(ma); } } private void doClose() { if (isDownloading()) { int result = JOptionPane .showConfirmDialog( getRootPane(), Messages.getString("MainActivity.13"), //$NON-NLS-1$ Messages.getString("MainActivity.14"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$ if (result == JOptionPane.NO_OPTION) { return; } for (int i = 0; i < downloadList.getComponentCount(); i++) { DownloadView dv = (DownloadView) downloadList.getComponent(i); dv.stopWorker(); } } all.remove(this); setVisible(false); if (all.size() == 0) { System.exit(0); } } /** * Must be called to connect to an archive. * * @param archive * the archive to mount. */ protected void doMount(Archive archive) { this.archive = archive; archive.getRoot().mkdirs(); new DownloadLogger(archive).clear(); setTitle("Raccoon - " + archive.getRoot().getAbsolutePath()); //$NON-NLS-1$ views.removeAll(); if (archive.getAndroidId().length() == 0) { views.addTab(Messages.getString("MainActivity.16"), InitView.create(this, archive)); //$NON-NLS-1$ } else { searchView = SearchView.create(this, archive); update.setEnabled(true); views.addTab(Messages.getString("MainActivity.17"), searchView); //$NON-NLS-1$ views.addChangeListener(searchView); search.setEnabled(true); downloads.setEnabled(true); importArchive.setEnabled(true); exportArchive.setEnabled(true); downloadListScroll = new JScrollPane(); downloadListScroll.setViewportView(downloadList); downloadListScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); views.addTab(Messages.getString("MainActivity.18"), downloadListScroll); //$NON-NLS-1$ Preferences prefs = Preferences.userNodeForPackage(getClass()); prefs.put(LASTARCHIVE, archive.getRoot().getAbsolutePath()); SwingUtilities.invokeLater(searchView); } } private void doOpen() { JFileChooser chooser = new JFileChooser(App.getDir(App.ARCHIVEDIR)); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int ret = chooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { MainActivity ma = new MainActivity(new Archive(chooser.getSelectedFile())); SwingUtilities.invokeLater(ma); } } /** * Trigger a download * * @param d * packagename. */ public void doDownload(DownloadView d) { downloadList.add(d); d.startWorker(); views.setSelectedComponent(downloadListScroll); Feedback.used(this); } private boolean isDownloading() { for (int i = 0; i < downloadList.getComponentCount(); i++) { DownloadView dv = (DownloadView) downloadList.getComponent(i); if (dv.isDownloading()) { return true; } } return false; } private void doQuit() { boolean ask = false; for (MainActivity ma : all) { if (ma.isDownloading()) { ask = true; break; } } if (ask) { int result = JOptionPane .showConfirmDialog( getRootPane(), Messages.getString("MainActivity.19"), //$NON-NLS-1$ Messages.getString("MainActivity.20"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$ if (result == JOptionPane.NO_OPTION) { return; } } for (MainActivity ma : all) { for (int i = 0; i < ma.downloadList.getComponentCount(); i++) { DownloadView dv = (DownloadView) ma.downloadList.getComponent(i); dv.stopWorker(); } } System.exit(0); } public void windowClosing(WindowEvent arg0) { doClose(); } public void windowActivated(WindowEvent arg0) { } public void windowClosed(WindowEvent arg0) { } public void windowDeactivated(WindowEvent arg0) { } public void windowDeiconified(WindowEvent arg0) { } public void windowIconified(WindowEvent arg0) { } public void windowOpened(WindowEvent arg0) { } }