code: /*--------------------------------------------------------------*
    Copyright (C) 2006-2015 OpenSim Ltd.
  
    This file is distributed WITHOUT ANY WARRANTY. See the file
    'License' for details on this and other legal matters.
  *--------------------------------------------------------------*/
  
  package org.omnetpp.common.image;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.regex.Pattern;
  import java.util.regex.PatternSyntaxException;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.jface.dialogs.Dialog;
  import org.eclipse.jface.dialogs.IDialogConstants;
  import org.eclipse.jface.dialogs.IDialogSettings;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.ScrolledComposite;
  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.SelectionAdapter;
  import org.eclipse.swt.events.SelectionEvent;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.swt.graphics.Rectangle;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.layout.GridLayout;
  import org.eclipse.swt.layout.RowData;
  import org.eclipse.swt.layout.RowLayout;
  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.Display;
  import org.eclipse.swt.widgets.Label;
  import org.eclipse.swt.widgets.Shell;
  import org.omnetpp.common.CommonPlugin;
  import org.omnetpp.common.util.UIUtils;
  
  /**
   * Dialog for selecting an icon. To ensure responsiveness, dialog get filled
   * asynchronously if it would take too long.
   *
   * @author Andras
   */
  //FIXME selection==null/"" is totally confused. OK button should be disabled until user makes a choice!!!! this used to work. --Andras
  public class ImageSelectionDialog extends Dialog {
      private static final int HEIGHT = 350;
      private static final int WIDTH = 500;
      private static final int RIGHT_MARGIN = 30;
  
      private static final long TIMEOUT_MILLIS = 500;
  
      // parameters
      private final IProject project;
  
      // widgets
      private Combo filterCombo;
      private Label filterStatusLabel;
      private Label selectionStatusLabel;
      private ScrolledComposite scrolledComposite;
      private Composite imageCanvas;
      private Button okButton;
  
      // state
      private List<String> imageNames;
      private int currentPopulationNumber = 0;
  
      // result
      private String initialSelection = null;
      private String selection = null;
  
  
      public ImageSelectionDialog(Shell parentShell, String initialValue, IProject project) {
          super(parentShell);
          setShellStyle(getShellStyle() | SWT.MAX | SWT.RESIZE);
          this.project = project;
          initialSelection = "".equals(initialValue) ? null : initialValue; // store "" as null
          imageNames = new ArrayList<String>(ImageFactory.of(project).getImageNameList());
          // "" represents NO IMAGE
          imageNames.add(0, "");
      }
  
      @Override
      protected IDialogSettings getDialogBoundsSettings() {
          return UIUtils.getDialogSettings(CommonPlugin.getDefault(), getClass().getName());
      }
  
      @Override
      protected void configureShell(Shell shell) {
          super.configureShell(shell);
          shell.setText("Select Image");
      }
  
      @Override
      protected Control createDialogArea(Composite parent) {
          Composite dialogArea = (Composite) super.createDialogArea(parent);
  
          Composite composite = new Composite(dialogArea, SWT.NONE);
          composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
          composite.setLayout(new GridLayout(1,false));
  
          // label and filter combo
          Label label = new Label(composite, SWT.NONE);
          label.setText("Select Image (substring search, ? = any character, * = any string)");
          label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
          label.setFont(parent.getFont());
          filterCombo = new Combo(composite, SWT.BORDER);
          filterCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
  
          filterStatusLabel = new Label(composite, SWT.NONE);
          filterStatusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
          filterStatusLabel.setFont(parent.getFont());
  
          selectionStatusLabel = new Label(composite, SWT.NONE);
          selectionStatusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
          selectionStatusLabel.setFont(parent.getFont());
  
          // scrolled composite for the images
          scrolledComposite = new ScrolledComposite(composite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
          scrolledComposite.getVerticalBar().setIncrement(10); // mouse wheel step
          GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
          gridData.widthHint = WIDTH;
          gridData.heightHint = HEIGHT;
          scrolledComposite.setLayoutData(gridData);
  
          // create inner composite to the icons
          imageCanvas = new Composite(scrolledComposite, SWT.NONE);
          scrolledComposite.setContent(imageCanvas);
          imageCanvas.setLayout(new RowLayout());
  
          // handle resizes
          scrolledComposite.addControlListener(new ControlAdapter() {
              public void controlResized(ControlEvent e) {
                  layoutForm();
              }
          });
  
          filterCombo.setItems(getImageFilters());
          filterCombo.setVisibleItemCount(Math.min(20, filterCombo.getItemCount()));
          if (initialSelection != null)
              filterCombo.setText(initialSelection.replaceFirst("/.*", "/"));
  
          // set up validation on content changes
          filterCombo.addModifyListener(new ModifyListener() {
              public void modifyText(ModifyEvent e) {
                  populate(null);
              }
          });
  
          // focus on first field
          filterCombo.setFocus();
  
          // add the images, and make initial icon one selected
          populate(initialSelection);
  
          return dialogArea;
      }
  
      protected void layoutForm() {
          if (scrolledComposite.getSize().x != 0) {
              // reset size of content so children can be seen (method 1)
              imageCanvas.setSize(imageCanvas.computeSize(scrolledComposite.getSize().x-RIGHT_MARGIN, SWT.DEFAULT));
              imageCanvas.layout();
          }
      }
  
      protected void createButtonsForButtonBar(Composite parent) {
          okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
          createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
      }
  
      protected String[] getImageFilters() {
          ArrayList<String> result = new ArrayList<String>();
  
          // collect toplevel folders
          result.addAll(ImageFactory.of(project).getCategories());
  
          // add all concrete images as well
          result.addAll(imageNames);
  
          return result.toArray(new String[]{});
      }
  
      protected void populate(String imageToSelect) {
          // regex'ify the filter string
          String filter = filterCombo.getText().trim();
          filter = filter.replace("\\", "\\\\");
          filter = filter.replace(".", "\\.");
          filter = filter.replace("[", "\\[");
          filter = filter.replace("]", "\\]");
          filter = filter.replace("(", "\\(");
          filter = filter.replace(")", "\\)");
          filter = filter.replace("?", ".?");
          filter = filter.replace("*", ".*");
          filter = ".*" + filter + ".*";
  
          Pattern pattern = null;
          try {
              pattern = Pattern.compile(filter);
          }
          catch (PatternSyntaxException e) {
              filterStatusLabel.setText("Invalid filter string");
              CommonPlugin.logError(e);
              layoutForm();
              return;
          }
  
          // remove existing images
          for (Control c : imageCanvas.getChildren())
              c.dispose();
  
          // add new images
          int count = 0;
          String oneImage = null;
          long startTime = System.currentTimeMillis();
          currentPopulationNumber++;
          final int schedulePopulationNumber = currentPopulationNumber;
          for (final String imageName : imageNames) {
              if (pattern.matcher(imageName).matches() || imageName.equals("")) {
                  if (!imageName.equals("")) {
                      count++;
                      oneImage = imageName;
                  }
  
                  // add image to canvas: either directly, or if we're taking too much time already,
                  // defer it using Display.asyncExec(). NOTE: we use "population number" to ensure
                  // that a populate() call cancels stale asyncExec()'s still pending from the
                  // previous populate()
                  if (System.currentTimeMillis() - startTime <= TIMEOUT_MILLIS) {
                      addImageToCanvas(imageName);
                  }
                  else {
                      Display.getCurrent().asyncExec(new Runnable() {
                          public void run() {
                              if (!imageCanvas.isDisposed() && currentPopulationNumber==schedulePopulationNumber) {
                                  addImageToCanvas(imageName);
                                  layoutForm();
                              }
                          }
                      });
                  }
              }
          }
  
          layoutForm();
  
          // update status line
          filterStatusLabel.setText("Filter matches "+count+" image"+(count==1?"":"s")+" out of "+imageNames.size()+".");
  
          // if selection got narrowed down to one image: make that the user's choice;
          // otherwise invalidate user's previous selection
          final String finalImageToSelect = (count==1) ? oneImage : imageToSelect;
  
          if (finalImageToSelect != null) {
              Display.getCurrent().asyncExec(new Runnable() {
                  public void run() {
                      if (!imageCanvas.isDisposed() && currentPopulationNumber==schedulePopulationNumber) {
                          selectImage(finalImageToSelect);
                      }
                  }
              });
          }
      }
  
      protected void addImageToCanvas(final String imageName) {
          Button button = new Button(imageCanvas, SWT.PUSH);
  
          if (imageName.equals("")) {
              button.setText("NONE");
              button.setLayoutData(new RowData(50,50));
              button.setToolTipText("Clear existing image");
          }
          else {
              // produce image and tooltip
              Image image = ImageFactory.of(project).getImage(imageName);
              Rectangle bounds = image.getBounds();
              String tooltip = imageName + " (" + bounds.width + "x" + bounds.height + ")";
              if (bounds.width > 64 || bounds.height > 64) {
                  image = ImageUtils.getResampledImage(image, 64, 64);  //FIXME will have to be disposed!!!! cache it!!!
                  tooltip += " [scaled back for display]";
              }
  
              button.setImage(image);
              button.setToolTipText(tooltip);
          }
  
          button.addSelectionListener(new SelectionAdapter() {
              public void widgetSelected(SelectionEvent e) {
                  selectImage(imageName);
              }
          });
          // unfortunately, widgetDefaultSelected() does not work for a button, so:
          button.addMouseListener(new MouseAdapter() {
              public void mouseDoubleClick(MouseEvent e) {
                  selectImage(imageName);
                  okPressed();
              }
          });
      }
  
      protected void selectImage(String imageName) {
          selection = imageName;
          selectionStatusLabel.setText("Current selection: "+(selection==null ? "--" : selection));
          if (okButton != null)  // it is null initially
              okButton.setEnabled(selection != null);
      }
  
      public String getImageId() {
          return selection;
      }
  }
  