package com.aptana.rdt.ui.gems; import java.util.HashSet; import java.util.Set; import java.util.SortedSet; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.progress.UIJob; import org.rubypeople.rdt.internal.ui.RubyPluginImages; import org.rubypeople.rdt.internal.ui.util.CollectionContentProvider; import org.rubypeople.rdt.ui.TableViewerSorter; import com.aptana.rdt.AptanaRDTPlugin; import com.aptana.rdt.core.gems.Gem; import com.aptana.rdt.core.gems.IGemManager; import com.aptana.rdt.core.gems.LogicalGem; /** * InstallGemDialog * * @author Kevin Sawicki (added async jobs) */ public class InstallGemDialog extends Dialog { private static final Gem LOADING_GEM = new Gem("Please wait", "N/A", "Loading remote gem listing...") { public boolean isInstallable() { return false; } }; private Text nameText; private Combo versionCombo; private String name; private String version; private boolean filterByText = true; private TableViewer gemViewer; private IStructuredContentProvider contentProvider; private Combo sourceURLCombo; private String sourceURL = IGemManager.DEFAULT_GEM_HOST; private Set<Gem> gems; private Job gemJob; private Button sourceButton; private Image refreshImage; /** * InstallGemDialog * * @param parentShell */ public InstallGemDialog(Shell parentShell) { super(parentShell); setShellStyle(getShellStyle() | SWT.RESIZE); contentProvider = new CollectionContentProvider(); } /** * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) */ protected Control createDialogArea(Composite parent) { getShell().setText(GemsMessages.InstallGemDialog_dialog_title); Composite control = new Composite(parent, SWT.NULL); GridLayout layout = new GridLayout(); layout.numColumns = 4; control.setLayout(layout); Label sourceLabel = new Label(control, SWT.LEFT); sourceLabel.setText("Source URL"); sourceURLCombo = new Combo(control, SWT.DROP_DOWN); GridData sourceTextData = new GridData(); sourceTextData.widthHint = 300; sourceTextData.horizontalSpan = 2; sourceURLCombo.setLayoutData(sourceTextData); updateSourceURLs(); sourceURLCombo.setText(sourceURL); sourceURLCombo.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { sourceURL = sourceURLCombo.getText(); } }); sourceURLCombo.addTraverseListener(new TraverseListener() { public void keyTraversed(TraverseEvent e) { if (e.keyCode == SWT.CR) { loadSourceURL(); e.doit = false; } } }); sourceButton = new Button(control, SWT.NONE); sourceButton.setToolTipText("Refresh"); refreshImage = RubyPluginImages.TOOLBAR_REFRESH.createImage(); sourceButton.setImage(refreshImage); sourceButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { loadSourceURL(); } }); Label nameLabel = new Label(control, SWT.LEFT); nameLabel.setText(GemsMessages.InstallGemDialog_name_label); nameText = new Text(control, SWT.BORDER | SWT.SEARCH); GridData nameTextData = new GridData(); nameTextData.widthHint = 150; nameText.setLayoutData(nameTextData); nameText.setEnabled(false); nameText.setMessage("Type portion of gem name to filter listing"); Label versionLabel = new Label(control, SWT.RIGHT); versionLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); versionLabel.setText(GemsMessages.InstallGemDialog_version_label); versionCombo = new Combo(control, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); GridData versionComboData = new GridData(); versionComboData.widthHint = 150; versionCombo.setLayoutData(versionComboData); versionCombo.setEnabled(false); gems = new HashSet<Gem>(); gems.add(LOADING_GEM); final Table gemsTable = new Table(parent, SWT.VIRTUAL | SWT.SINGLE | SWT.FULL_SELECTION); gemsTable.setItemCount(gems.size()); nameText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { if (filterByText) { getShell().getDisplay().asyncExec(new Runnable() { public void run() { // Filtering with the virtual table doesn't work with just using a ViewerFilter like it did // on normal table Set<Gem> filtered = filter(nameText.getText(), gems); gemsTable.setItemCount(filtered.size()); gemsTable.clearAll(); gemViewer.setInput(filtered); } private Set<Gem> filter(String filter, Set<Gem> gems) { Set<Gem> filtered = new HashSet<Gem>(); for (Gem gem : gems) { if (gem.getName().toLowerCase().startsWith(filter)) filtered.add(gem); } return filtered; } }); } filterByText = true; } }); gemViewer = new TableViewer(gemsTable); gemsTable.setHeaderVisible(true); gemsTable.setLinesVisible(false); GridData data = new GridData(GridData.FILL_HORIZONTAL); data.heightHint = 400; gemsTable.setLayoutData(data); TableColumn nameColumn = new TableColumn(gemsTable, SWT.LEFT); nameColumn.setText(GemsMessages.GemsView_NameColumn_label); nameColumn.setWidth(150); TableColumn versionColumn = new TableColumn(gemsTable, SWT.LEFT); versionColumn.setText(GemsMessages.GemsView_VersionColumn_label); versionColumn.setWidth(75); TableColumn descriptionColumn = new TableColumn(gemsTable, SWT.LEFT); descriptionColumn.setText(GemsMessages.GemsView_DescriptionColumn_label); descriptionColumn.setWidth(275); gemViewer.setLabelProvider(new GemLabelProvider()); gemViewer.setContentProvider(contentProvider); TableViewerSorter.bind(gemViewer); gemViewer.setInput(gems); gemViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection structured = (IStructuredSelection) selection; Gem gem = (Gem) structured.getFirstElement(); if (gem == null) { versionCombo.removeAll(); return; } filterByText = false; // don't filter list when I programmatically set text nameText.setText(gem.getName()); versionCombo.removeAll(); String lastVersion = null; if (gem instanceof LogicalGem) { LogicalGem logical = (LogicalGem) gem; SortedSet<String> versions = logical.getVersions(); for (String version : versions) { versionCombo.add(version); lastVersion = version; } } else { versionCombo.add(gem.getVersion()); lastVersion = gem.getVersion(); } versionCombo.setText(lastVersion); } } }); setGems(IGemManager.DEFAULT_GEM_HOST); return control; } private void updateTable() { gemViewer.setInput(gems); gemViewer.getTable().setItemCount(gems.size()); gemViewer.refresh(); } /** * Sets the gems in the table * * @param url */ protected void setGems(final String url) { if (gemJob != null) { gemJob.cancel(); } gemJob = new Job("Loading remote gem listing") { protected IStatus run(IProgressMonitor gemJobMonitor) { if (gemJobMonitor != null && gemJobMonitor.isCanceled()) { return Status.CANCEL_STATUS; } gems = AptanaRDTPlugin.getDefault().getGemManager().getRemoteGems(url, gemJobMonitor); if (gemJobMonitor != null && gemJobMonitor.isCanceled()) { return Status.CANCEL_STATUS; } UIJob updatingTable = new UIJob("Updating gem table") { public IStatus runInUIThread(IProgressMonitor monitor) { if (monitor != null && monitor.isCanceled()) { return Status.CANCEL_STATUS; } if (gemViewer != null && !gemViewer.getTable().isDisposed()) { updateTable(); } if (nameText != null && !nameText.isDisposed()) { nameText.setEnabled(true); } if (versionCombo != null && !versionCombo.isDisposed()) { versionCombo.setEnabled(true); } return Status.OK_STATUS; } }; updatingTable.schedule(); return Status.OK_STATUS; } }; gemJob.schedule(); } /** * Update the source urls */ protected void updateSourceURLs() { sourceURLCombo.removeAll(); Set<String> urls = AptanaRDTPlugin.getDefault().getGemManager().getSourceURLs(); for (String url : urls) { sourceURLCombo.add(url); } } @Override protected void okPressed() { name = nameText.getText(); version = versionCombo.getText(); super.okPressed(); } /** * Gets the gem * * @return - new gem */ public Gem getGem() { return new Gem(name, version, ""); } /** * Get source url * * @return - url */ public String getSourceURL() { return sourceURL; } @Override public boolean close() { if (refreshImage != null) refreshImage.dispose(); return super.close(); } private void loadSourceURL() { String curr = sourceURLCombo.getText(); gems = new HashSet<Gem>(); gems.add(LOADING_GEM); updateTable(); nameText.setEnabled(false); versionCombo.setEnabled(false); setGems(sourceURL); updateSourceURLs(); sourceURLCombo.setText(curr); } }