示例#1
0
  /** Construct a ToDo tab for the property panel. */
  public TabToDo() {
    super("tab.todo-item");
    setIcon(new LeftArrowIcon());

    String position = Configuration.getString(Configuration.makeKey("layout", "tabtodo"));
    setOrientation(
        ((position.equals("West") || position.equals("East"))
            ? Vertical.getInstance()
            : Horizontal.getInstance()));

    setLayout(new BorderLayout());

    Object[] actions = {actionNewToDoItem, actionResolve, actionSnooze};
    ToolBarFactory factory = new ToolBarFactory(actions);
    factory.setRollover(true);
    factory.setFloatable(false);
    factory.setOrientation(SwingConstants.VERTICAL);
    JToolBar toolBar = factory.createToolBar();
    toolBar.setName(getTitle());
    add(toolBar, BorderLayout.WEST);

    splitPane = new BorderSplitPane();
    add(splitPane, BorderLayout.CENTER);
    setTarget(null);

    addComponentListener(this);

    // TODO: Register listener for target ToDo item changes
    // and for new showStep() requests
  }
  /**
   * Manages the selection of the default tool in a popup tool in the toolbar.
   *
   * <p>I.e. in a toolbar, you can have tools that can be opened, into a grid of tools. The last
   * used tool is remembered, and put at the top when the popup is closed, i.e. is the only tool
   * that remains visible. This remembering is persistent, hence stored in the configuration file,
   * under a certain key (i.e. name).
   *
   * @param actions the array of actions that make up the popup
   * @param key appendix for the key for the configuration file
   */
  public static void manageDefault(Object[] actions, String key) {
    Action defaultAction = null;
    ConfigurationKey k = Configuration.makeKey("default", "popupactions", key);
    String defaultName = Configuration.getString(k);
    PopupActionsListener listener = new PopupActionsListener(k);
    for (int i = 0; i < actions.length; ++i) {
      if (actions[i] instanceof Action) {
        Action a = (Action) actions[i];
        if (a.getValue(Action.NAME).equals(defaultName)) {
          defaultAction = a;
        }
        a.addPropertyChangeListener(listener);
      } else if (actions[i] instanceof Object[]) {
        Object[] actionRow = (Object[]) actions[i];
        for (int j = 0; j < actionRow.length; ++j) {
          Action a = (Action) actionRow[j];
          if (a.getValue(Action.NAME).equals(defaultName)) {
            defaultAction = a;
          }
          a.addPropertyChangeListener(listener);
        }
      }
    }

    if (defaultAction != null) {
      defaultAction.putValue("isDefault", Boolean.valueOf(true));
    }
  }
 /**
  * Send all events when the settings are changed to refresh anything rendered with these settings.
  */
 public void notifyOfChangedSettings() {
   /*
    * Since body ever looks
    * at the type of the diagram appearance event, we can simplify from
    * sending every existing event to one event only. But since there is no
    * catch-all event defined, we just use one. Rationale: reduce the
    * number of total refreshes of the drawing.
    */
   ConfigurationKey key = Configuration.makeKey("diagramappearance", "all");
   ArgoEventPump.fireEvent(
       new ArgoDiagramAppearanceEvent(
           ArgoEventTypes.DIAGRAM_FONT_CHANGED,
           new PropertyChangeEvent(this, key.getKey(), "0", "0")));
 }
示例#4
0
/**
 * This class shall be the only one that knows in which file formats ArgoUML is able to save and
 * load. And all that knowledge is concentrated in the constructor...
 *
 * <p>The PersisterManager manages the list of persisters.
 *
 * <p>This class is a singleton, since this allows external modules to add extra persisters to the
 * ArgoUML application.
 *
 * @author [email protected]
 */
public final class PersistenceManager {
  /** The singleton instance. */
  private static final PersistenceManager INSTANCE = new PersistenceManager();

  private AbstractFilePersister defaultPersister;
  private List<AbstractFilePersister> otherPersisters = new ArrayList<AbstractFilePersister>();
  private UmlFilePersister quickViewDump;
  private XmiFilePersister xmiPersister;
  private XmiFilePersister xmlPersister;
  private UmlFilePersister umlPersister;
  private ZipFilePersister zipPersister;

  private AbstractFilePersister savePersister;

  /** The configuration key for the project file location. */
  public static final ConfigurationKey KEY_PROJECT_NAME_PATH =
      Configuration.makeKey("project", "name", "path");

  /** The configuration key for the "open project" file location. */
  public static final ConfigurationKey KEY_OPEN_PROJECT_PATH =
      Configuration.makeKey("project", "open", "path");

  /** The configuration key for the "import xmi" file location. */
  public static final ConfigurationKey KEY_IMPORT_XMI_PATH =
      Configuration.makeKey("xmi", "import", "path");

  /** Create the default diagram persister. */
  private DiagramMemberFilePersister diagramMemberFilePersister = new DiagramMemberFilePersister();

  /** @return returns the singleton */
  public static PersistenceManager getInstance() {
    return INSTANCE;
  }

  /** The constructor. */
  private PersistenceManager() {
    // These are the file formats I know about:
    defaultPersister = new OldZargoFilePersister();
    quickViewDump = new UmlFilePersister();
    xmiPersister = new XmiFilePersister();
    otherPersisters.add(xmiPersister);
    xmlPersister = new XmlFilePersister();
    otherPersisters.add(xmlPersister);
    umlPersister = new UmlFilePersister();
    otherPersisters.add(umlPersister);
    zipPersister = new ZipFilePersister();
    otherPersisters.add(zipPersister);
  }

  /**
   * This function allows to add new persisters. This can be done e.g. by plugins/modules.
   *
   * @param fp the persister
   */
  public void register(AbstractFilePersister fp) {
    otherPersisters.add(fp);
  }

  /**
   * @param name the filename
   * @return the persister
   */
  public AbstractFilePersister getPersisterFromFileName(String name) {
    if (defaultPersister.isFileExtensionApplicable(name)) {
      return defaultPersister;
    }
    for (AbstractFilePersister persister : otherPersisters) {
      if (persister.isFileExtensionApplicable(name)) {
        return persister;
      }
    }
    return null;
  }

  /**
   * @param chooser the filechooser of which the filters will be set
   * @param fileName the filename of the file to be saved (optional)
   */
  public void setSaveFileChooserFilters(JFileChooser chooser, String fileName) {

    chooser.addChoosableFileFilter(defaultPersister);
    AbstractFilePersister defaultFileFilter = defaultPersister;

    for (AbstractFilePersister fp : otherPersisters) {
      if (fp.isSaveEnabled() && !fp.equals(xmiPersister) && !fp.equals(xmlPersister)) {
        chooser.addChoosableFileFilter(fp);
        if (fileName != null && fp.isFileExtensionApplicable(fileName)) {
          defaultFileFilter = fp;
        }
      }
    }
    chooser.setFileFilter(defaultFileFilter);
  }

  /** @param chooser the filechooser of which the filters will be set */
  public void setOpenFileChooserFilter(JFileChooser chooser) {
    MultitypeFileFilter mf = new MultitypeFileFilter();
    mf.add(defaultPersister);
    chooser.addChoosableFileFilter(mf);
    chooser.addChoosableFileFilter(defaultPersister);
    Iterator iter = otherPersisters.iterator();
    while (iter.hasNext()) {
      AbstractFilePersister ff = (AbstractFilePersister) iter.next();
      if (ff.isLoadEnabled()) {
        mf.add(ff);
        chooser.addChoosableFileFilter(ff);
      }
    }
    chooser.setFileFilter(mf);
  }

  /** @param chooser the filechooser of which the filters will be set */
  public void setXmiFileChooserFilter(JFileChooser chooser) {
    chooser.addChoosableFileFilter(xmiPersister);
    chooser.setFileFilter(xmiPersister);
  }

  /** @return the extension of the default persister (just the text, not the ".") */
  public String getDefaultExtension() {
    return defaultPersister.getExtension();
  }

  /** @return the extension of the xmi persister (just the text, not the ".") */
  public String getXmiExtension() {
    return xmiPersister.getExtension();
  }

  /**
   * @param in the input file or path name which may or may not have a recognised extension
   * @return the amended file or pathname, guaranteed to have a recognised extension
   */
  public String fixExtension(String in) {
    if (getPersisterFromFileName(in) == null) {
      in += "." + getDefaultExtension();
    }
    return in;
  }

  /**
   * @param in the input file or path name which may or may not have a "xmi" extension
   * @return the amended file or pathname, guaranteed to have a "xmi" extension
   */
  public String fixXmiExtension(String in) {
    if (getPersisterFromFileName(in) != xmiPersister) {
      in += "." + getXmiExtension();
    }
    return in;
  }

  /**
   * @param in the input uri which may or may not have a recognised extension
   * @return the uri with default extension added, if it did not have a valid extension yet
   */
  public URI fixUriExtension(URI in) {
    URI newUri;
    String n = in.toString();
    n = fixExtension(n);
    try {
      newUri = new URI(n);
    } catch (java.net.URISyntaxException e) {
      throw new UnexpectedException(e);
    }
    return newUri;
  }

  /**
   * Find the base name of the given filename.
   *
   * <p>This is the name minus any valid file extension. Invalid extensions are left alone.
   *
   * @param n the given file name
   * @return the name (a String) without extension
   */
  public String getBaseName(String n) {
    AbstractFilePersister p = getPersisterFromFileName(n);
    if (p == null) {
      return n;
    }
    int extLength = p.getExtension().length() + 1;
    return n.substring(0, n.length() - extLength);
  }

  /**
   * @param p the project
   * @return the basename of the project
   */
  public String getProjectBaseName(Project p) {
    URI uri = p.getUri();
    String name = Translator.localize("label.projectbrowser-title");
    if (uri != null) {
      name = new File(uri).getName();
    }
    return getBaseName(name);
  }

  /**
   * @param n the new project name
   * @param p the project that receives the name
   * @throws URISyntaxException if the URI is malformed
   */
  public void setProjectName(final String n, Project p) throws URISyntaxException {
    String s = "";
    if (p.getURI() != null) {
      s = p.getURI().toString();
    }
    s = s.substring(0, s.lastIndexOf("/") + 1) + n;
    setProjectURI(new URI(s), p);
  }

  /**
   * @param theUri the URI for the project
   * @param p the project that receives the URI
   */
  public void setProjectURI(URI theUri, Project p) {
    if (theUri != null) {
      theUri = fixUriExtension(theUri);
    }
    p.setUri(theUri);
  }

  /**
   * Generates a String dump of the current model for quick viewing.
   *
   * @param project The project to generate.
   * @return The whole model in a String.
   */
  public String getQuickViewDump(Project project) {
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    try {
      quickViewDump.writeProject(project, stream, null);
    } catch (Exception e) {
      // If anything goes wrong return the stack
      // trace as a string so that we get some
      // useful feedback.
      e.printStackTrace(new PrintStream(stream));
    }
    try {
      return stream.toString(Argo.getEncoding());
    } catch (UnsupportedEncodingException e) {
      return e.toString();
    }
  }

  /**
   * Get the file persister for diagrams.
   *
   * @return the diagram file persister.
   */
  DiagramMemberFilePersister getDiagramMemberFilePersister() {
    return diagramMemberFilePersister;
  }

  /**
   * Set an alternative file persister for diagrams.
   *
   * @param persister the persister to use instead of the default
   */
  public void setDiagramMemberFilePersister(DiagramMemberFilePersister persister) {
    diagramMemberFilePersister = persister;
  }

  /**
   * Returns true if we are allowed to overwrite the given file.
   *
   * @param overwrite if true, then the user is not asked
   * @param file the given file
   * @return true if we are allowed to overwrite the given file
   * @param frame the Component to display the confirmation dialog on
   */
  public boolean confirmOverwrite(Component frame, boolean overwrite, File file) {
    if (file.exists() && !overwrite) {
      String sConfirm =
          Translator.messageFormat("optionpane.confirm-overwrite", new Object[] {file});
      int nResult =
          JOptionPane.showConfirmDialog(
              frame,
              sConfirm,
              Translator.localize("optionpane.confirm-overwrite-title"),
              JOptionPane.YES_NO_OPTION,
              JOptionPane.QUESTION_MESSAGE);
      if (nResult != JOptionPane.YES_OPTION) {
        return false;
      }
    }
    return true;
  }

  /**
   * Sets the currently used persister for saving.
   *
   * @param persister the persister
   */
  public void setSavePersister(AbstractFilePersister persister) {
    savePersister = persister;
  }

  /**
   * Gets the currently used persister for saving.
   *
   * @return the persister or null
   */
  public AbstractFilePersister getSavePersister() {
    return savePersister;
  }

  /**
   * Figs are stored by class name and recreated by reflection. If the class name changes or moves
   * this provides a simple way of translating from class name at time of save to the current class
   * name without need for XSL.
   *
   * @param originalClassName The class name that may be in the save file
   * @param newClassName The class name to use in preference
   */
  public void addTranslation(final String originalClassName, final String newClassName) {
    getDiagramMemberFilePersister().addTranslation(originalClassName, newClassName);
  }
}
示例#5
0
/**
 * Default <code>ProfileManager</code> implementation
 *
 * @author Marcos Aurelio
 */
public class ProfileManagerImpl implements ProfileManager {

  private static final Logger LOG = Logger.getLogger(ProfileManagerImpl.class);

  private static final String DIRECTORY_SEPARATOR = "*";

  /** The configuration key for the default profiles. */
  public static final ConfigurationKey KEY_DEFAULT_PROFILES =
      Configuration.makeKey("profiles", "default");

  /** The configuration key for the search directories. */
  public static final ConfigurationKey KEY_DEFAULT_DIRECTORIES =
      Configuration.makeKey("profiles", "directories");

  /** Avoids recursive configuration update when loading configuration */
  private boolean disableConfigurationUpdate = false;

  private List<Profile> profiles = new ArrayList<Profile>();

  private List<Profile> defaultProfiles = new ArrayList<Profile>();

  private List<String> searchDirectories = new ArrayList<String>();

  private ProfileUML profileUML;

  private ProfileGoodPractices profileGoodPractices;

  private ProfileCodeGeneration profileCodeGeneration;

  private DependencyResolver<File> resolver;

  /** Constructor - includes initialization of built-in default profiles. */
  public ProfileManagerImpl() {
    try {
      disableConfigurationUpdate = true;

      profileUML = new ProfileUML();
      profileGoodPractices = new ProfileGoodPractices();
      profileCodeGeneration = new ProfileCodeGeneration(profileGoodPractices);

      registerProfileInternal(profileUML);
      addToDefaultProfiles(profileUML);
      // the UML Profile is always present and default

      // register the built-in profiles
      registerProfileInternal(profileGoodPractices);
      registerProfileInternal(profileCodeGeneration);
      registerProfileInternal(new ProfileMeta());

    } catch (ProfileException e) {
      // TODO: Why is this throwing a generic runtime exception?!?!
      throw new RuntimeException(e);
    } finally {
      disableConfigurationUpdate = false;
    }
    createUserDefinedProfilesDependencyResolver();
    loadDirectoriesFromConfiguration();
    refreshRegisteredProfiles();
    loadDefaultProfilesfromConfiguration();
  }

  private void createUserDefinedProfilesDependencyResolver() {
    final ProfileManager profileManager = this;
    DependencyChecker<File> checker =
        new DependencyChecker<File>() {
          public boolean check(File file) {
            boolean found = findUserDefinedProfile(file) != null;
            if (!found) {
              UserDefinedProfile udp = null;
              try {
                udp = new UserDefinedProfile(file, profileManager);
                registerProfileInternal(udp);
                found = true;
                LOG.debug("UserDefinedProfile for file " + file.getAbsolutePath() + " registered.");
              } catch (ProfileException e) {
                // if an exception is raised file is unusable
                LOG.info("Failed to load user defined profile " + file.getAbsolutePath() + ".", e);
              }
            }
            return found;
          }
        };
    resolver = new DependencyResolver<File>(checker);
  }

  private void loadDefaultProfilesfromConfiguration() {
    if (!disableConfigurationUpdate) {
      disableConfigurationUpdate = true;

      String defaultProfilesList = Configuration.getString(KEY_DEFAULT_PROFILES);
      if (defaultProfilesList.equals("")) {
        // if the list does not exist add the code generation and
        // good practices profiles as default
        addToDefaultProfiles(profileGoodPractices);
        addToDefaultProfiles(profileCodeGeneration);
      } else {
        StringTokenizer tokenizer =
            new StringTokenizer(defaultProfilesList, DIRECTORY_SEPARATOR, false);

        while (tokenizer.hasMoreTokens()) {
          String desc = tokenizer.nextToken();
          Profile p = null;

          if (desc.charAt(0) == 'U') {
            String fileName = desc.substring(1);
            File file;
            try {
              file = new File(new URI(fileName));

              p = findUserDefinedProfile(file);

              if (p == null) {
                try {
                  p = new UserDefinedProfile(file, this);
                  registerProfileInternal(p);
                } catch (ProfileException e) {
                  LOG.error("Error loading profile: " + file, e);
                }
              }
            } catch (URISyntaxException e1) {
              LOG.error("Invalid path for Profile: " + fileName, e1);
            } catch (Throwable e2) {
              LOG.error("Error loading profile: " + fileName, e2);
            }
          } else if (desc.charAt(0) == 'C') {
            String profileIdentifier = desc.substring(1);
            p = lookForRegisteredProfile(profileIdentifier);
          }
          if (p != null) {
            addToDefaultProfiles(p);
          }
        }
      }
      disableConfigurationUpdate = false;
    }
  }

  private void updateDefaultProfilesConfiguration() {
    if (!disableConfigurationUpdate) {
      StringBuffer buf = new StringBuffer();
      for (Profile p : defaultProfiles) {
        if (p instanceof UserDefinedProfile) {
          buf.append("U" + ((UserDefinedProfile) p).getModelFile().toURI().toASCIIString());
        } else {
          buf.append("C" + p.getProfileIdentifier());
        }
        buf.append(DIRECTORY_SEPARATOR);
      }
      Configuration.setString(KEY_DEFAULT_PROFILES, buf.toString());
    }
  }

  private void loadDirectoriesFromConfiguration() {
    disableConfigurationUpdate = true;
    StringTokenizer tokenizer =
        new StringTokenizer(
            Configuration.getString(KEY_DEFAULT_DIRECTORIES), DIRECTORY_SEPARATOR, false);
    while (tokenizer.hasMoreTokens()) {
      searchDirectories.add(tokenizer.nextToken());
    }
    disableConfigurationUpdate = false;
  }

  private void updateSearchDirectoriesConfiguration() {
    if (!disableConfigurationUpdate) {
      StringBuffer buf = new StringBuffer();
      for (String s : searchDirectories) {
        buf.append(s).append(DIRECTORY_SEPARATOR);
      }
      Configuration.setString(KEY_DEFAULT_DIRECTORIES, buf.toString());
    }
  }

  public List<Profile> getRegisteredProfiles() {
    return profiles;
  }

  public void registerProfile(Profile p) {
    if (registerProfileInternal(p)) {
      // this profile could have not been loaded when
      // the default profile configuration
      // was loaded at first, so we need to do it again
      loadDefaultProfilesfromConfiguration();
    }
    resolver.resolve();
  }

  /**
   * @param p the profile to register.
   * @return true if there should be an attempt to load the default profiles from the configuration.
   */
  private boolean registerProfileInternal(Profile p) {

    try {
      boolean loadDefaultProfilesFromConfiguration = false;
      if (p != null && !profiles.contains(p)) {
        if (p instanceof UserDefinedProfile || getProfileForClass(p.getClass().getName()) == null) {
          loadDefaultProfilesFromConfiguration = true;
          profiles.add(p);
          for (Critic critic : p.getCritics()) {
            for (Object meta : critic.getCriticizedDesignMaterials()) {
              Agency.register(critic, meta);
            }
            critic.setEnabled(false);
          }
        }
      }
      return loadDefaultProfilesFromConfiguration;
    } catch (RuntimeException e) {
      // TODO: Better if we wrap in a ProfileException and throw that
      LOG.error("Error registering profile " + p.getDisplayName());
      throw e;
    }
  }

  public void removeProfile(Profile p) {
    if (p != null && p != profileUML) {
      profiles.remove(p);
      defaultProfiles.remove(p);
    }
    try {
      Collection packages = p.getLoadedPackages();
      if (packages != null && !packages.isEmpty()) {
        // We assume profile is contained in a single extent
        Model.getUmlFactory().deleteExtent(packages.iterator().next());
      }
    } catch (ProfileException e) {
      // Nothing to delete if we couldn't get the packages
    }
  }

  private static final String OLD_PROFILE_PACKAGE = "org.argouml.uml.profile";

  private static final String NEW_PROFILE_PACKAGE = "org.argouml.profile.internal";

  public Profile getProfileForClass(String profileClass) {
    Profile found = null;

    // If we found an old-style name, update it to the new package name
    if (profileClass != null && profileClass.startsWith(OLD_PROFILE_PACKAGE)) {
      profileClass = profileClass.replace(OLD_PROFILE_PACKAGE, NEW_PROFILE_PACKAGE);
    }

    // Make sure the names didn't change again
    assert profileUML.getClass().getName().startsWith(NEW_PROFILE_PACKAGE);

    for (Profile p : profiles) {
      if (p.getClass().getName().equals(profileClass)) {
        found = p;
        break;
      }
    }
    return found;
  }

  public void addToDefaultProfiles(Profile p) {
    if (p != null && profiles.contains(p) && !defaultProfiles.contains(p)) {
      defaultProfiles.add(p);
      updateDefaultProfilesConfiguration();
    }
  }

  public List<Profile> getDefaultProfiles() {
    return Collections.unmodifiableList(defaultProfiles);
  }

  public void removeFromDefaultProfiles(Profile p) {
    if (p != null && p != profileUML && profiles.contains(p)) {
      defaultProfiles.remove(p);
      updateDefaultProfilesConfiguration();
    }
  }

  public void addSearchPathDirectory(String path) {
    if (path != null && !searchDirectories.contains(path)) {
      searchDirectories.add(path);
      updateSearchDirectoriesConfiguration();
      try {
        Model.getXmiReader().addSearchPath(path);
      } catch (UmlException e) {
        LOG.error("Couldn't retrive XMI Reader from Model.", e);
      }
    }
  }

  public List<String> getSearchPathDirectories() {
    return Collections.unmodifiableList(searchDirectories);
  }

  public void removeSearchPathDirectory(String path) {
    if (path != null) {
      searchDirectories.remove(path);
      updateSearchDirectoriesConfiguration();
      try {
        Model.getXmiReader().removeSearchPath(path);
      } catch (UmlException e) {
        LOG.error("Couldn't retrive XMI Reader from Model.", e);
      }
    }
  }

  public void refreshRegisteredProfiles() {
    ArrayList<File> dirs = new ArrayList<File>();
    for (String dirName : searchDirectories) {
      File dir = new File(dirName);
      if (dir.exists()) {
        dirs.add(dir);
      }
    }
    if (!dirs.isEmpty()) {
      // TODO: Allow .zargo as profile as well?
      List<File> profileFiles = UserDefinedProfileHelper.getFileList(dirs.toArray(new File[0]));
      loadProfiles(profileFiles);
    }
  }

  void loadProfiles(List<File> profileFiles) {
    resolver.resolve(profileFiles);
  }

  private Profile findUserDefinedProfile(File file) {
    for (Profile p : profiles) {
      if (p instanceof UserDefinedProfile) {
        UserDefinedProfile udp = (UserDefinedProfile) p;
        if (file.equals(udp.getModelFile())) {
          return udp;
        }
      }
    }
    return null;
  }

  public Profile getUMLProfile() {
    return profileUML;
  }

  /*
   * @see org.argouml.profile.ProfileManager#lookForRegisteredProfile(java.lang.String)
   */
  public Profile lookForRegisteredProfile(String value) {
    if (value != null) {
      List<Profile> registeredProfiles = getRegisteredProfiles();
      for (Profile profile : registeredProfiles) {
        if (value.equalsIgnoreCase(profile.getProfileIdentifier())) {
          return profile;
        }
      }
    }
    return null;
  }

  /*
   * @param pc
   * @see org.argouml.profile.ProfileManager#applyConfiguration(org.argouml.kernel.ProfileConfiguration)
   */
  public void applyConfiguration(ProfileConfiguration pc) {
    for (Profile p : this.profiles) {
      for (Critic c : p.getCritics()) {
        c.setEnabled(false);
        Configuration.setBoolean(c.getCriticKey(), false);
      }
    }
    for (Profile p : pc.getProfiles()) {
      for (Critic c : p.getCritics()) {
        c.setEnabled(true);
        Configuration.setBoolean(c.getCriticKey(), true);
      }
    }
  }
}
/**
 * This class captures represents the unique access point for the configurability allowed by the use
 * of profiles.
 *
 * @author maurelio1234
 */
public class ProfileConfiguration extends AbstractProjectMember {
  /** Logger. */
  private static final Logger LOG = Logger.getLogger(ProfileConfiguration.class);

  private FormatingStrategy formatingStrategy;

  private DefaultTypeStrategy defaultTypeStrategy;

  private List figNodeStrategies = new ArrayList();

  private List<Profile> profiles = new ArrayList<Profile>();

  private List<Object> profileModels = new ArrayList<Object>();

  /** The extension used in serialization and returned by {@link #getType()} */
  public static final String EXTENSION = "profile";

  /** The configuration key for the default stereotype view. */
  public static final ConfigurationKey KEY_DEFAULT_STEREOTYPE_VIEW =
      Configuration.makeKey("profiles", "stereotypeView");

  /**
   * The default constructor for this class. Sets the default profiles as given by {@link
   * org.argouml.profile.ProfileManager} as the profiles of the project.
   *
   * @param project the project that contains this configuration
   */
  public ProfileConfiguration(Project project) {
    super(EXTENSION, project);
    for (Profile p : ProfileFacade.getManager().getDefaultProfiles()) {
      addProfile(p);
    }

    updateStrategies();
  }

  /**
   * The constructor for pre-defined profile configurations, such as when a project is read from a
   * saved file.
   *
   * @param project the project that contains this configuration
   * @param configuredProfiles the {@link Profile}s that will be the project profiles
   */
  public ProfileConfiguration(Project project, Collection<Profile> configuredProfiles) {
    super(EXTENSION, project);
    for (Profile profile : configuredProfiles) {
      addProfile(profile);
    }
    updateStrategies();
  }

  private void updateStrategies() {
    for (Profile profile : profiles) {
      activateFormatingStrategy(profile);
      activateDefaultTypeStrategy(profile);
    }
  }

  /** @return the current formating strategy */
  public FormatingStrategy getFormatingStrategy() {
    return formatingStrategy;
  }

  /** @return the current default type strategy */
  public DefaultTypeStrategy getDefaultTypeStrategy() {
    return defaultTypeStrategy;
  }

  /**
   * Updates the current strategy to the strategy provided by the passed profile. The profile should
   * have been previously registered.
   *
   * @param profile the profile providing the current default type strategy
   */
  public void activateDefaultTypeStrategy(Profile profile) {
    if (profile != null
        && profile.getDefaultTypeStrategy() != null
        && getProfiles().contains(profile)) {
      this.defaultTypeStrategy = profile.getDefaultTypeStrategy();
    }
  }

  /**
   * Updates the current strategy to the strategy provided by the passed profile. The profile should
   * have been previously registered.
   *
   * @param profile the profile providing the current formating strategy
   */
  public void activateFormatingStrategy(Profile profile) {
    if (profile != null
        && profile.getFormatingStrategy() != null
        && getProfiles().contains(profile)) {
      this.formatingStrategy = profile.getFormatingStrategy();
    }
  }

  /** @return the list of applied profiles */
  public List<Profile> getProfiles() {
    return profiles;
  }

  /**
   * Applies a new profile to this configuration
   *
   * @param p the profile to be applied
   */
  @SuppressWarnings("unchecked")
  public void addProfile(Profile p) {
    if (!profiles.contains(p)) {
      profiles.add(p);
      try {
        profileModels.addAll(p.getProfilePackages());
      } catch (ProfileException e) {
        LOG.warn("Error retrieving profile's " + p + " packages.", e);
      }

      FigNodeStrategy fns = p.getFigureStrategy();
      if (fns != null) {
        figNodeStrategies.add(fns);
      }

      for (Profile dependency : p.getDependencies()) {
        addProfile(dependency);
      }

      updateStrategies();
      ArgoEventPump.fireEvent(
          new ArgoProfileEvent(
              ArgoEventTypes.PROFILE_ADDED, new PropertyChangeEvent(this, "profile", null, p)));
    }
  }

  /** @return the list of models of the currently applied profile. */
  private List getProfileModels() {
    return profileModels;
  }

  /**
   * Removes the passed profile from the configuration.
   *
   * @param p the profile to be removed
   */
  public void removeProfile(Profile p) {
    profiles.remove(p);
    try {
      profileModels.removeAll(p.getProfilePackages());
    } catch (ProfileException e) {
      LOG.error("Exception", e);
    }

    FigNodeStrategy fns = p.getFigureStrategy();
    if (fns != null) {
      figNodeStrategies.remove(fns);
    }

    if (formatingStrategy == p.getFormatingStrategy()) {
      formatingStrategy = null;
    }

    List<Profile> markForRemoval = new ArrayList<Profile>();
    for (Profile profile : profiles) {
      if (profile.getDependencies().contains(p)) {
        markForRemoval.add(profile);
      }
    }

    for (Profile profile : markForRemoval) {
      removeProfile(profile);
    }

    updateStrategies();
    ArgoEventPump.fireEvent(
        new ArgoProfileEvent(
            ArgoEventTypes.PROFILE_REMOVED, new PropertyChangeEvent(this, "profile", p, null)));
  }

  private FigNodeStrategy compositeFigNodeStrategy =
      new FigNodeStrategy() {

        public Image getIconForStereotype(Object element) {
          Iterator it = figNodeStrategies.iterator();

          while (it.hasNext()) {
            FigNodeStrategy strat = (FigNodeStrategy) it.next();
            Image extra = strat.getIconForStereotype(element);

            if (extra != null) {
              return extra;
            }
          }
          return null;
        }
      };

  /** @return the current FigNodeStrategy */
  public FigNodeStrategy getFigNodeStrategy() {
    return compositeFigNodeStrategy;
  }

  /**
   * @return the extension for this project member
   * @see org.argouml.kernel.AbstractProjectMember#getType()
   */
  public String getType() {
    return EXTENSION;
  }

  /**
   * Objects of this class are always consistent, there's no need to repair them.
   *
   * @return the empty string.
   * @see org.argouml.kernel.ProjectMember#repair()
   */
  public String repair() {
    return "";
  }

  /**
   * @return the "Profile Configuration" string
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString() {
    return "Profile Configuration";
  }

  /**
   * Find a stereotype with the given name which is applicable to the given element.
   *
   * @param name name of stereotype to look for
   * @param element model element to which the stereotype must be applicable
   * @return the stereotype or null if none found
   */
  public Object findStereotypeForObject(String name, Object element) {
    Iterator iter = null;

    for (Object model : profileModels) {
      iter = Model.getFacade().getOwnedElements(model).iterator();

      while (iter.hasNext()) {
        Object stereo = iter.next();
        if (!Model.getFacade().isAStereotype(stereo)
            || !name.equals(Model.getFacade().getName(stereo))) {
          continue;
        }

        if (Model.getExtensionMechanismsHelper().isValidStereotype(element, stereo)) {
          return stereo;
        }
      }
    }

    return null;
  }

  /**
   * Search for the given type in all of the profile models.
   *
   * @param name name of type to be found
   * @return the type or null
   */
  public Object findType(String name) {
    for (Object model : getProfileModels()) {
      Object result = findTypeInModel(name, model);
      if (result != null) {
        return result;
      }
    }
    return null;
  }

  /**
   * Finds a type in a model by name
   *
   * <p>FIXME: duplicated from the method with the same name in
   * org.argouml.profile.internal.ModelUtils.
   *
   * @param s the type name
   * @param model the model
   * @return the type or <code>null</code> if the type has not been found.
   */
  public static Object findTypeInModel(String s, Object model) {

    if (!Model.getFacade().isANamespace(model)) {
      throw new IllegalArgumentException(
          "Looking for the classifier "
              + s
              + " in a non-namespace object of "
              + model
              + ". A namespace was expected.");
    }

    Collection allClassifiers =
        Model.getModelManagementHelper()
            .getAllModelElementsOfKind(model, Model.getMetaTypes().getClassifier());

    Object[] classifiers = allClassifiers.toArray();
    Object classifier = null;

    for (int i = 0; i < classifiers.length; i++) {

      classifier = classifiers[i];
      if (Model.getFacade().getName(classifier) != null
          && Model.getFacade().getName(classifier).equals(s)) {
        return classifier;
      }
    }

    return null;
  }

  /**
   * Find all the model elements in the configured {@link Profile}s of the given meta type.
   *
   * @param metaType the meta type of the model elements to find
   * @return a {@link Collection} containing the model elements that are of the given meta type
   */
  @SuppressWarnings("unchecked")
  public Collection findByMetaType(Object metaType) {
    Set elements = new HashSet();

    Iterator it = getProfileModels().iterator();
    while (it.hasNext()) {
      Object model = it.next();
      elements.addAll(Model.getModelManagementHelper().getAllModelElementsOfKind(model, metaType));
    }
    return elements;
  }

  /**
   * @param modelElement ModelElement for which find possible stereotypes
   * @return collection of stereotypes which are valid for the given model element.
   */
  public Collection findAllStereotypesForModelElement(Object modelElement) {
    return Model.getExtensionMechanismsHelper()
        .getAllPossibleStereotypes(getProfileModels(), modelElement);
  }
}