package de.onyxbits.raccoon.gui;
import java.awt.Event;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultCaret;
import com.akdeniz.googleplaycrawler.GooglePlay.DocV2;
import de.onyxbits.raccoon.BrowseUtil;
import de.onyxbits.raccoon.Messages;
import de.onyxbits.raccoon.io.Archive;
/**
* Displays and handles a single search result.
*
* @author patrick
*
*/
public class ResultView extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private DocV2 doc;
private JButton download;
private JButton gplay;
private JToggleButton details;
private JToggleButton permissions;
private SearchView searchView;
private JEditorPane entry;
private HashMap<String, Object> model;
private static Icon iconNetwork;
private static Icon iconIap;
private static Icon iconLocation;
private static Icon iconMicrophone;
private static Icon iconPersonal;
private static Icon iconPhone;
private static Icon iconCamera;
private static Icon iconSystem;
private static Icon iconStorage;
private static Icon iconLicenseCheck;
private static Icon iconDownload;
static {
Class<?> clazz = new Object().getClass();
iconNetwork = new ImageIcon(clazz.getResource("/rsrc/badges/wi-fi-outline.png")); //$NON-NLS-1$
iconIap = new ImageIcon(clazz.getResource("/rsrc/badges/shopping-cart.png")); //$NON-NLS-1$
iconLocation = new ImageIcon(clazz.getResource("/rsrc/badges/location-outline.png")); //$NON-NLS-1$
iconMicrophone = new ImageIcon(clazz.getResource("/rsrc/badges/microphone-outline.png")); //$NON-NLS-1$
iconPersonal = new ImageIcon(clazz.getResource("/rsrc/badges/contacts.png")); //$NON-NLS-1$
iconPhone = new ImageIcon(clazz.getResource("/rsrc/badges/phone-outline.png")); //$NON-NLS-1$
iconCamera = new ImageIcon(clazz.getResource("/rsrc/badges/camera-outline.png")); //$NON-NLS-1$
iconSystem = new ImageIcon(clazz.getResource("/rsrc/badges/spanner-outline.png")); //$NON-NLS-1$
iconStorage = new ImageIcon(clazz.getResource("/rsrc/badges/folder.png")); //$NON-NLS-1$
iconLicenseCheck = new ImageIcon(clazz.getResource("/rsrc/badges/key-outline.png")); //$NON-NLS-1$
iconDownload = new ImageIcon(clazz.getResource("/rsrc/icons/download.png")); //$NON-NLS-1$
}
/**
* Construct a new app listing
*
* @param searchView
* the searchview that will handle button presses.
*
* @param doc
* the source from which to draw app info
*/
private ResultView(SearchView searchView, DocV2 doc) {
this.doc = doc;
this.searchView = searchView;
model = new HashMap<String, Object>();
model.put("i18n_installs", Messages.getString("ResultView.1")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_rating", Messages.getString("ResultView.3")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_price", Messages.getString("ResultView.5")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_date", Messages.getString("ResultView.7")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_version", Messages.getString("ResultView.2")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_size", Messages.getString("ResultView.9")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_permissions", Messages.getString("ResultView.27")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_permissions_none", Messages.getString("ResultView.22")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("i18n_changelog", Messages.getString("ResultView.4")); //$NON-NLS-1$ //$NON-NLS-2$
model.put("title", doc.getTitle()); //$NON-NLS-1$
model.put("installs", doc.getDetails().getAppDetails().getNumDownloads()); //$NON-NLS-1$
model.put("rating", String.format("%.2f", doc.getAggregateRating().getStarRating())); //$NON-NLS-1$ //$NON-NLS-2$
model.put("package", doc.getBackendDocid()); //$NON-NLS-1$
model.put("author", doc.getCreator()); //$NON-NLS-1$
model.put("price", doc.getOffer(0).getFormattedAmount()); //$NON-NLS-1$
model.put("date", doc.getDetails().getAppDetails().getUploadDate()); //$NON-NLS-1$
model.put("size", Archive.humanReadableByteCount(doc.getDetails().getAppDetails() //$NON-NLS-1$
.getInstallationSize(), true));
File icon = SearchWorker.getImageCacheFile(doc.getBackendDocid(), 4);
if (icon.exists()) {
model.put("icon", icon.toURI()); //$NON-NLS-1$
}
else {
model.put("icon", getClass().getResource("/rsrc/icons/icon_missing.png").toString());
}
JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout(0, 1, 0, 4));
buttons.setOpaque(false);
download = new JButton(Messages.getString("ResultView.25"), iconDownload); //$NON-NLS-1$
gplay = new JButton(Messages.getString("ResultView.26")); //$NON-NLS-1$
details = new JToggleButton(Messages.getString("ResultView.6")); //$NON-NLS-1$
permissions = new JToggleButton(Messages.getString("ResultView.27")); //$NON-NLS-1$
buttons.add(download);
buttons.add(gplay);
buttons.add(details);
buttons.add(permissions);
entry = new HypertextPane(TmplTool.transform("app.html", model)); //$NON-NLS-1$
entry.setMargin(new Insets(10, 10, 10, 10));
entry.addHyperlinkListener(new BrowseUtil());
// Keep enclosing scrollpanes steady
DefaultCaret caret = (DefaultCaret) entry.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
JPanel outer = new JPanel(); // Needed to simplify the layout code.
outer.setOpaque(false);
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
container.setOpaque(false);
container.add(buttons);
container.add(Box.createVerticalStrut(10));
container.add(createBadges(doc.getDetails().getAppDetails().getPermissionList()));
container.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
outer.add(container);
JSeparator sep = new JSeparator(JSeparator.VERTICAL);
sep.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(outer);
add(sep);
add(entry);
}
private JPanel createBadges(List<String> perms) {
JPanel ret = new JPanel();
ret.setLayout(new GridLayout(0, 3));
ret.setOpaque(false);
String[][] groups = { { "android.permission.INTERNET", //$NON-NLS-1$
"android.permission.ACCESS_NETWORK_STATE", //$NON-NLS-1$
"android.permission.CHANGE_NETWORK_STATE", //$NON-NLS-1$
"android.permission.CHANGE_WIFI_MULTICAST_STATE", //$NON-NLS-1$
"android.permission.CHANGE_WIFI_STATE", //$NON-NLS-1$
"android.permission.ACCESS_WIFI_STATE", //$NON-NLS-1$
"android.permission.BIND_VPN_SERVICE" }, //$NON-NLS-1$
{ "com.android.vending.BILLING" }, //$NON-NLS-1$
{ "com.android.vending.CHECK_LICENSE" }, //$NON-NLS-1$
{ "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION" }, //$NON-NLS-1$ //$NON-NLS-2$
{ "android.permission.RECORD_AUDIO" }, //$NON-NLS-1$
{ "android.permission.CAMERA" }, //$NON-NLS-1$
{ "android.permission.CALL_PHONE", //$NON-NLS-1$
"android.permission.PROCESS_OUTGOING_CALLS", //$NON-NLS-1$
"android.permission.READ_CALL_LOG", //$NON-NLS-1$
"android.permission.READ_PHONE_STATE", //$NON-NLS-1$
"android.permission.READ_SMS", //$NON-NLS-1$
"android.permission.RECEIVE_SMS", //$NON-NLS-1$
"android.permission.SEND_SMS", //$NON-NLS-1$
"android.permission.USE_SIP", //$NON-NLS-1$
"android.permission.WRITE_CALL_LOG", //$NON-NLS-1$
"android.permission.WRITE_SMS" }, //$NON-NLS-1$
{ "android.permission.BIND_DEVICE_ADMIN", //$NON-NLS-1$
"android.permission.CHANGE_CONFIGURATION", //$NON-NLS-1$
"android.permission.DISABLE_KEYGUARD", //$NON-NLS-1$
"android.permission.EXPAND_STATUS_BAR", //$NON-NLS-1$
"android.permission.GET_TASKS", //$NON-NLS-1$
"android.permission.KILL_BACKGROUND_PROCESSES", //$NON-NLS-1$
"android.permission.MODIFY_AUDIO_SETTINGS", //$NON-NLS-1$
"android.permission.RECEIVE_BOOT_COMPLETED", //$NON-NLS-1$
"android.permission.REORDER_TASKS", //$NON-NLS-1$
"android.permission.SYSTEM_ALERT_WINDOW", //$NON-NLS-1$
"android.permission.SET_WALLPAPER", //$NON-NLS-1$
"com.android.launcher.permission.UNINSTALL_SHORTCUT" }, //$NON-NLS-1$
{ "android.permission.GET_ACCOUNTS", //$NON-NLS-1$
"android.permission.READ_PHONE_STATE", //$NON-NLS-1$
"android.permission.GLOBAL_SEARCH", //$NON-NLS-1$
"android.permission.MANAGE_DOCUMENTS", //$NON-NLS-1$
"android.permission.READ_CALENDAR", //$NON-NLS-1$
"android.permission.READ_CALL_LOG", //$NON-NLS-1$
"android.permission.READ_CONTACTS", //$NON-NLS-1$
"com.android.browser.permission.READ_HISTORY_BOOKMARKS", //$NON-NLS-1$
"android.permission.READ_LOGS", //$NON-NLS-1$
"android.permission.READ_USER_DICTIONARY", //$NON-NLS-1$
"android.permission.USE_CREDENTIALS", //$NON-NLS-1$
"android.permission.WRITE_CALENDAR", //$NON-NLS-1$
"android.permission.WRITE_CALL_LOG", //$NON-NLS-1$
"android.permission.WRITE_CONTACTS", //$NON-NLS-1$
"com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", //$NON-NLS-1$
"android.permission.WRITE_SOCIAL_STREAM", //$NON-NLS-1$
"android.permission.READ_PROFILE", //$NON-NLS-1$
"android.permission.USE_CREDENTIALS", //$NON-NLS-1$
"android.permission.WRITE_USER_DICTIONARY" }, //$NON-NLS-1$
{ "android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE" } }; //$NON-NLS-1$ //$NON-NLS-2$
for (int x = 0; x < groups.length; x++) {
for (int y = 0; y < groups[x].length; y++) {
if (x == 0 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconNetwork);
lbl.setToolTipText(Messages.getString("ResultView.84")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 1 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconIap);
lbl.setToolTipText(Messages.getString("ResultView.85")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 2 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconLicenseCheck);
lbl.setToolTipText(Messages.getString("ResultView.0")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 3 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconLocation);
lbl.setToolTipText(Messages.getString("ResultView.86")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 4 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconMicrophone);
lbl.setToolTipText(Messages.getString("ResultView.87")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 5 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconCamera);
lbl.setToolTipText(Messages.getString("ResultView.88")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 6 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconPhone);
lbl.setToolTipText(Messages.getString("ResultView.89")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 7 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconSystem);
lbl.setToolTipText(Messages.getString("ResultView.90")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 8 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconPersonal);
lbl.setToolTipText(Messages.getString("ResultView.91")); //$NON-NLS-1$
ret.add(lbl);
break;
}
if (x == 9 && perms.contains(groups[x][y])) {
JLabel lbl = new JLabel(iconStorage);
lbl.setToolTipText(Messages.getString("ResultView.92")); //$NON-NLS-1$
ret.add(lbl);
break;
}
}
}
return ret;
}
public static ResultView create(SearchView searchView, DocV2 doc) {
ResultView ret = new ResultView(searchView, doc);
ret.setLayout(new BoxLayout(ret, BoxLayout.X_AXIS));
ret.download.addActionListener(ret);
ret.gplay.addActionListener(ret);
ret.permissions.addActionListener(ret);
ret.details.addActionListener(ret);
return ret;
}
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
if (src == download) {
DownloadView d = DownloadView.create(searchView.getArchive(), doc);
searchView.doDownload(d);
}
if (src == details) {
if ((event.getModifiers() & Event.SHIFT_MASK) == Event.SHIFT_MASK) {
// This is indented for debugging!
entry.setContentType("text/plain"); //$NON-NLS-1$
entry.setText(doc.toString());
}
else {
doToggleDetails();
}
}
if (src == gplay) {
BrowseUtil.openUrl(doc.getShareUrl());
SwingUtilities.invokeLater(searchView); // Re - focus
}
if (src == permissions) {
doTogglePermissions();
}
}
private void doTogglePermissions() {
if (model.containsKey("showpermissions")) { //$NON-NLS-1$
model.remove("permissions_list"); //$NON-NLS-1$
model.remove("showpermissions"); //$NON-NLS-1$
}
else {
List<String> perms = doc.getDetails().getAppDetails().getPermissionList();
if (perms.size() > 0) {
ArrayList<String> sortMe = new ArrayList<String>(perms);
Collections.sort(sortMe);
model.put("permissions_list", sortMe); //$NON-NLS-1$
}
model.put("showpermissions", true);
}
entry.setText(TmplTool.transform("app.html", model)); //$NON-NLS-1$
SwingUtilities.invokeLater(searchView);
}
private void doToggleDetails() {
if (model.containsKey("description")) { //$NON-NLS-1$
model.remove("version"); //$NON-NLS-1$
model.remove("vcode"); //$NON-NLS-1$
model.remove("email"); //$NON-NLS-1$
model.remove("website"); //$NON-NLS-1$
model.remove("description"); //$NON-NLS-1$
model.remove("changelog"); //$NON-NLS-1$
entry.setText(TmplTool.transform("app.html", model)); //$NON-NLS-1$
SwingUtilities.invokeLater(searchView);
}
else {
details.setEnabled(false);
new DetailsWorker(searchView.getArchive(), this, doc.getBackendDocid()).execute();
}
}
protected void updateEntry(DocV2 docV2) {
details.setEnabled(true);
doc = docV2;
model.put("version", doc.getDetails().getAppDetails().getVersionString()); //$NON-NLS-1$
model.put("vcode", doc.getDetails().getAppDetails().getVersionCode()); //$NON-NLS-1$
model.put("website", doc.getDetails().getAppDetails().getDeveloperWebsite()); //$NON-NLS-1$
model.put("email", doc.getDetails().getAppDetails().getDeveloperEmail()); //$NON-NLS-1$
model.put("description", doc.getDescriptionHtml()); //$NON-NLS-1$
model.put("changelog", doc.getDetails().getAppDetails().getRecentChangesHtml()); //$NON-NLS-1$
entry.setText(TmplTool.transform("app.html", model)); //$NON-NLS-1$
SwingUtilities.invokeLater(searchView);
}
}