package com.kartoflane.superluminal2.ui; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Dialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import com.kartoflane.superluminal2.components.Hotkey; import com.kartoflane.superluminal2.components.enums.Hotkeys; import com.kartoflane.superluminal2.components.interfaces.Action; import com.kartoflane.superluminal2.components.interfaces.Predicate; import com.kartoflane.superluminal2.core.Database; import com.kartoflane.superluminal2.core.Manager; import com.kartoflane.superluminal2.mvc.views.Preview; import com.kartoflane.superluminal2.utils.UIUtils; import com.kartoflane.superluminal2.utils.Utils; import com.kartoflane.superluminal2.utils.Utils.AlphanumComparator; public class DatabaseFileDialog extends Dialog implements SelectionListener { private final Predicate<String> defaultFilter = new Predicate<String>() { public boolean accept(String s) { if (filterExtensions == null) return true; for (int i = 0; i < filterExtensions.length; i++) { if (filterExtensions[i] == null || s.matches(regexize(filterExtensions[i]))) return true; } return false; } }; private String result = null; private String[] filterExtensions = new String[0]; private Map<String, TreeItem> itemMap = new HashMap<String, TreeItem>(); private Predicate<String> filter = defaultFilter; private Shell shell; private Button btnConfirm; private Button btnCancel; private Tree tree; private Composite composite; private Combo cmbExtensions; private Text txtFile; private Canvas canvas; private Preview preview; private SashForm sashForm; private Button btnSearch; public DatabaseFileDialog(Shell parent, int style) { super(parent, style); } public DatabaseFileDialog(Shell parent) { this(parent, SWT.NONE); } public String open() { createGUI(); loadItems(regexize(cmbExtensions.getText())); shell.open(); Display display = shell.getDisplay(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } return result; } public void setFilterExtensions(String[] ext) { filterExtensions = ext; } private void createGUI() { Shell parent = getParent(); shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); shell.setSize(500, 350); shell.setText(getText()); shell.setLayout(new GridLayout(2, false)); sashForm = new SashForm(shell, SWT.SMOOTH); sashForm.setSashWidth(5); sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); tree = new Tree(sashForm, SWT.BORDER); tree.addSelectionListener(this); canvas = new Canvas(sashForm, SWT.NONE); preview = new Preview(); RGB rgb = canvas.getBackground().getRGB(); preview.setBackgroundColor((int) (0.9 * rgb.red), (int) (0.9 * rgb.green), (int) (0.9 * rgb.blue)); preview.setDrawBackground(true); canvas.addPaintListener(preview); sashForm.setWeights(new int[] { 3, 2 }); txtFile = new Text(shell, SWT.BORDER); txtFile.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); if (filterExtensions == null) filterExtensions = new String[0]; cmbExtensions = new Combo(shell, SWT.READ_ONLY); GridData gd_cmbExtensions = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); gd_cmbExtensions.widthHint = 80; cmbExtensions.setLayoutData(gd_cmbExtensions); for (int i = 0; i < filterExtensions.length; i++) cmbExtensions.add(filterExtensions[i]); cmbExtensions.select(0); cmbExtensions.addSelectionListener(this); composite = new Composite(shell, SWT.NONE); GridLayout gl_composite = new GridLayout(3, false); gl_composite.marginWidth = 0; gl_composite.marginHeight = 0; composite.setLayout(gl_composite); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); btnSearch = new Button(composite, SWT.NONE); GridData gd_btnSearch = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); gd_btnSearch.widthHint = 80; btnSearch.setLayoutData(gd_btnSearch); btnSearch.setText("Search"); btnSearch.addSelectionListener(this); btnConfirm = new Button(composite, SWT.NONE); GridData gd_btnConfirm = new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1); gd_btnConfirm.widthHint = 80; btnConfirm.setLayoutData(gd_btnConfirm); btnConfirm.setText("Confirm"); btnConfirm.addSelectionListener(this); btnCancel = new Button(composite, SWT.NONE); GridData gd_btnCancel = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1); gd_btnCancel.widthHint = 80; btnCancel.setLayoutData(gd_btnCancel); btnCancel.setText("Cancel"); btnCancel.addSelectionListener(this); shell.addListener(SWT.Close, new Listener() { public void handleEvent(Event e) { btnCancel.notifyListeners(SWT.Selection, null); e.doit = false; } }); tree.addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { if (e.button == 1 && tree.getSelectionCount() != 0) { TreeItem selectedItem = tree.getSelection()[0]; if (selectedItem.getItemCount() == 0 && btnConfirm.isEnabled()) btnConfirm.notifyListeners(SWT.Selection, null); else if (selectedItem.getBounds().contains(e.x, e.y)) selectedItem.setExpanded(!selectedItem.getExpanded()); } } }); canvas.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { updatePreview(); canvas.redraw(); } }); txtFile.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { String text = txtFile.getText(); boolean found = itemMap.containsKey(text) && itemMap.get(text).getItemCount() == 0; btnConfirm.setEnabled(found); if (found && text.endsWith(".png")) { preview.setImage("db:" + text); preview.setDrawBackground(true); } else { preview.setImage(null); preview.setDrawBackground(false); } updatePreview(); canvas.redraw(); } }); // Register hotkeys Hotkey h = new Hotkey(); h.setOnPress(new Action() { public void execute() { if (tree.getSelectionCount() != 0) { TreeItem selectedItem = tree.getSelection()[0]; if (selectedItem.getItemCount() == 0 && btnConfirm.isEnabled()) btnConfirm.notifyListeners(SWT.Selection, null); else selectedItem.setExpanded(!selectedItem.getExpanded()); } } }); h.setKey(SWT.CR); Manager.hookHotkey(shell, h); h = new Hotkey(Manager.getHotkey(Hotkeys.SEARCH)); h.addNotifyAction(btnSearch, true); Manager.hookHotkey(shell, h); } private void loadItems(String ext) { for (TreeItem item : itemMap.values()) item.dispose(); itemMap.clear(); tree.removeAll(); List<String> pathlist = Database.getInstance().listFiles(filter); Collections.sort(pathlist, new AlphanumComparator()); for (String ipath : pathlist) { if (ipath.matches(ext)) createItems(ipath); } if (filter != defaultFilter) { for (TreeItem item : itemMap.values()) item.setExpanded(true); } } private void createItems(String ipath) { String[] dirs = ipath.split("/"); String bs = dirs[0]; if (!itemMap.containsKey(bs)) { TreeItem item = new TreeItem(tree, SWT.NONE); item.setText(dirs[0]); itemMap.put(bs, item); } for (int i = 1; i < dirs.length; i++) { String ps = bs; bs = bs + "/" + dirs[i]; if (!itemMap.containsKey(bs)) { TreeItem item = null; if (i == dirs.length - 1) { item = new TreeItem(itemMap.get(ps), SWT.NONE); } else { item = new TreeItem(itemMap.get(ps), SWT.NONE, findPos(itemMap.get(ps), dirs[i])); } item.setText(dirs[i]); itemMap.put(bs, item); } } } /** * Find the index at which a new item with the given name should be inserted in the parent. * Allows to sort items that have children before ones that have none. */ private int findPos(TreeItem parent, String insertee) { int result = parent.getItemCount() - 1; int comp = 1; for (; comp == 1 && result >= 0; result--) { TreeItem item = parent.getItem(result); if (item.getItemCount() == 0) continue; comp = item.getText().compareTo(insertee); } if (result < 0) result = 0; return result; } private String regexize(String ext) { ext = ext.replace(".", "\\."); ext = ext.replace("*", ".*?"); return ext; } private String reconstructPath(TreeItem item) { StringBuilder sb = new StringBuilder(); sb.append(item.getText()); TreeItem parent = item.getParentItem(); while (parent != null) { sb.insert(0, "/"); sb.insert(0, parent.getText()); parent = parent.getParentItem(); } return sb.toString(); } private void updatePreview() { Point iSize = preview.getImageSize(); Point cSize = canvas.getSize(); double ratio = (double) iSize.y / iSize.x; int w = (int) (cSize.y / ratio); int h = (int) (cSize.x * ratio); preview.setSize(Utils.min(w, cSize.x, iSize.x), Utils.min(h, cSize.y, iSize.y)); preview.setLocation(cSize.x / 2, cSize.y / 2); } protected void dispose() { itemMap.clear(); preview.dispose(); shell.dispose(); } public void widgetSelected(SelectionEvent e) { Object source = e.getSource(); if (source == btnConfirm) { result = txtFile.getText(); if (Database.getInstance().contains(result)) { dispose(); } else { UIUtils.showWarningDialog(EditorWindow.getInstance().getShell(), null, "The file you have selected does not exist."); } } else if (source == btnCancel) { result = null; dispose(); } else if (source == btnSearch) { DatabaseSearchDialog dbsDialog = new DatabaseSearchDialog(shell); Predicate<String> resultFilter = dbsDialog.open(); if (resultFilter == AbstractSearchDialog.RESULT_DEFAULT) { if (filter == defaultFilter) return; filter = defaultFilter; } else if (resultFilter == AbstractSearchDialog.RESULT_UNCHANGED) { // Do nothing return; } else { filter = resultFilter; } loadItems(regexize(cmbExtensions.getText())); tree.notifyListeners(SWT.Selection, null); } else if (source == tree) { if (tree.getSelectionCount() > 0) txtFile.setText(reconstructPath(tree.getSelection()[0])); } else if (source == cmbExtensions) { btnConfirm.setEnabled(false); loadItems(regexize(cmbExtensions.getText())); } } public void widgetDefaultSelected(SelectionEvent e) { } }