ProjectType initial clion/138.1944
authorDmitry Avdeev <Dmitry.Avdeev@jetbrains.com>
Fri, 29 Aug 2014 13:25:04 +0000 (17:25 +0400)
committerDmitry Avdeev <Dmitry.Avdeev@jetbrains.com>
Fri, 29 Aug 2014 13:29:19 +0000 (17:29 +0400)
platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionManager.java
platform/platform-api/src/com/intellij/openapi/actionSystem/ActionStub.java
platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/config/ActionBean.java
platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
platform/platform-resources/src/META-INF/PlatformExtensions.xml
platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeProvider.java [new file with mode: 0644]
platform/projectModel-api/src/com/intellij/openapi/project/ProjectType.java [new file with mode: 0644]
platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java [new file with mode: 0644]

index 5577664bf9f7d9911d2656144a5dc57f61813682..ee850c3fe060994a11bfcea69e652d9aae000eda 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.ex.AnActionListener;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.components.ApplicationComponent;
 import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.project.ProjectType;
 import com.intellij.openapi.util.ActionCallback;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
@@ -80,7 +81,7 @@ public abstract class ActionManager implements ApplicationComponent {
    * @param actionId Id of the registered action
    *
    * @return Action associated with the specified actionId, <code>null</code> if
-   *  there is no actions associated with the speicified actionId
+   *  there is no actions associated with the specified actionId
    *
    * @exception java.lang.IllegalArgumentException if <code>actionId</code> is <code>null</code>
    *
@@ -89,6 +90,20 @@ public abstract class ActionManager implements ApplicationComponent {
   public abstract AnAction getAction(@NonNls @NotNull String actionId);
 
   /**
+   * Returns action associated with the specified actionId.
+   *
+   * @param actionId Id of the registered action
+   *
+   * @return Action associated with the specified actionId, <code>null</code> if
+   *  there is no actions associated with the specified actionId
+   *
+   * @exception java.lang.IllegalArgumentException if <code>actionId</code> is <code>null</code>
+   *
+   * @see com.intellij.openapi.actionSystem.IdeActions
+   */
+  public abstract AnAction getAction(@NonNls @NotNull String actionId, @Nullable ProjectType projectType);
+
+  /**
    * Returns actionId associated with the specified action.
    *
    * @return id associated with the specified action, <code>null</code> if action
index 09896aaf0da8ec94f4a391c5861232b98c2be089..c96ce2aa3371cc1b26ab6ba3822b6f10b8fe2cc0 100644 (file)
@@ -29,6 +29,7 @@ public class ActionStub extends AnAction{
   private static final Logger LOG=Logger.getInstance("#com.intellij.openapi.actionSystem.ActionStub");
 
   private final String myClassName;
+  private final String myProjectType;
   private final String myId;
   private final String myText;
   private final ClassLoader myLoader;
@@ -40,9 +41,10 @@ public class ActionStub extends AnAction{
                     @NotNull String text,
                     ClassLoader loader,
                     PluginId pluginId,
-                    String iconPath) {
+                    String iconPath, String projectType) {
     myLoader = loader;
     myClassName=actionClass;
+    myProjectType = projectType;
     LOG.assertTrue(!id.isEmpty());
     myId=id;
     myText=text;
@@ -102,4 +104,7 @@ public class ActionStub extends AnAction{
     targetAction.setShortcutSet(getShortcutSet());
   }
 
+  public String getProjectType() {
+    return myProjectType;
+  }
 }
index 723956ef9daab49c7a8c836e7723d6e408a6902c..c5a9b01c4d21627fe6ecbddf75f0e8ef5dccb17a 100644 (file)
@@ -39,6 +39,7 @@ import com.intellij.openapi.keymap.KeymapManager;
 import com.intellij.openapi.keymap.KeymapUtil;
 import com.intellij.openapi.keymap.ex.KeymapManagerEx;
 import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.ProjectType;
 import com.intellij.openapi.util.ActionCallback;
 import com.intellij.openapi.util.Computable;
 import com.intellij.openapi.util.Disposer;
@@ -71,28 +72,6 @@ import java.util.*;
 import java.util.List;
 
 public final class ActionManagerImpl extends ActionManagerEx implements ApplicationComponent {
-  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.actionSystem.impl.ActionManagerImpl");
-  private static final int DEACTIVATED_TIMER_DELAY = 5000;
-  private static final int TIMER_DELAY = 500;
-  private static final int UPDATE_DELAY_AFTER_TYPING = 500;
-
-  private final Object myLock = new Object();
-  private final Map<String,Object> myId2Action = new THashMap<String, Object>();
-  private final Map<PluginId, THashSet<String>> myPlugin2Id = new THashMap<PluginId, THashSet<String>>();
-  private final TObjectIntHashMap<String> myId2Index = new TObjectIntHashMap<String>();
-  private final Map<Object,String> myAction2Id = new THashMap<Object, String>();
-  private final MultiMap<String,String> myId2GroupId = new MultiMap<String, String>();
-  private final List<String> myNotRegisteredInternalActionIds = new ArrayList<String>();
-  private MyTimer myTimer;
-
-  private int myRegisteredActionsCount;
-  private final List<AnActionListener> myActionListeners = ContainerUtil.createLockFreeCopyOnWriteList();
-  private String myLastPreformedActionId;
-  private final KeymapManager myKeymapManager;
-  private final DataManager myDataManager;
-  private String myPrevPerformedActionId;
-  private long myLastTimeEditorWasTypedIn = 0;
-
   @NonNls public static final String ACTION_ELEMENT_NAME = "action";
   @NonNls public static final String GROUP_ELEMENT_NAME = "group";
   @NonNls public static final String ACTIONS_ELEMENT_NAME = "actions";
@@ -130,14 +109,32 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
   @NonNls public static final String USE_SHORTCUT_OF_ATTR_NAME = "use-shortcut-of";
   @NonNls public static final String OVERRIDES_ATTR_NAME = "overrides";
   @NonNls public static final String KEEP_CONTENT_ATTR_NAME = "keep-content";
-
+  @NonNls public static final String PROJECT_TYPE = "project-type";
+  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.actionSystem.impl.ActionManagerImpl");
+  private static final int DEACTIVATED_TIMER_DELAY = 5000;
+  private static final int TIMER_DELAY = 500;
+  private static final int UPDATE_DELAY_AFTER_TYPING = 500;
+  private final Object myLock = new Object();
+  private final Map<String,AnAction> myId2Action = new THashMap<String, AnAction>();
+  private final Map<PluginId, THashSet<String>> myPlugin2Id = new THashMap<PluginId, THashSet<String>>();
+  private final TObjectIntHashMap<String> myId2Index = new TObjectIntHashMap<String>();
+  private final Map<Object,String> myAction2Id = new THashMap<Object, String>();
+  private final MultiMap<String,String> myId2GroupId = new MultiMap<String, String>();
+  private final List<String> myNotRegisteredInternalActionIds = new ArrayList<String>();
+  private final List<AnActionListener> myActionListeners = ContainerUtil.createLockFreeCopyOnWriteList();
+  private final KeymapManager myKeymapManager;
+  private final DataManager myDataManager;
   private final List<ActionPopupMenuImpl> myPopups = new ArrayList<ActionPopupMenuImpl>();
-
   private final Map<AnAction, DataContext> myQueuedNotifications = new LinkedHashMap<AnAction, DataContext>();
   private final Map<AnAction, AnActionEvent> myQueuedNotificationsEvents = new LinkedHashMap<AnAction, AnActionEvent>();
-
+  private MyTimer myTimer;
+  private int myRegisteredActionsCount;
+  private String myLastPreformedActionId;
+  private String myPrevPerformedActionId;
+  private long myLastTimeEditorWasTypedIn = 0;
   private Runnable myPreloadActionsRunnable;
   private boolean myTransparentOnlyUpdate;
+  private int myActionsPreloaded = 0;
 
   ActionManagerImpl(KeymapManager keymapManager, DataManager dataManager) {
     myKeymapManager = keymapManager;
@@ -146,6 +143,257 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     registerPluginActions();
   }
 
+  static AnAction convertStub(ActionStub stub) {
+    Object obj;
+    String className = stub.getClassName();
+    try {
+      Class<?> aClass = Class.forName(className, true, stub.getLoader());
+      obj = ReflectionUtil.newInstance(aClass);
+    }
+    catch (ClassNotFoundException e) {
+      PluginId pluginId = stub.getPluginId();
+      if (pluginId != null) {
+        throw new PluginException("class with name \"" + className + "\" not found", e, pluginId);
+      }
+      else {
+        throw new IllegalStateException("class with name \"" + className + "\" not found");
+      }
+    }
+    catch(UnsupportedClassVersionError e) {
+      PluginId pluginId = stub.getPluginId();
+      if (pluginId != null) {
+        throw new PluginException(e, pluginId);
+      }
+      else {
+        throw new IllegalStateException(e);
+      }
+    }
+    catch (Exception e) {
+      PluginId pluginId = stub.getPluginId();
+      if (pluginId != null) {
+        throw new PluginException("cannot create class \"" + className + "\"", e, pluginId);
+      }
+      else {
+        throw new IllegalStateException("cannot create class \"" + className + "\"", e);
+      }
+    }
+
+    if (!(obj instanceof AnAction)) {
+      throw new IllegalStateException("class with name '" + className + "' must be an instance of '" + AnAction.class.getName()+"'; got "+obj);
+    }
+
+    AnAction anAction = (AnAction)obj;
+    stub.initAction(anAction);
+    if (StringUtil.isNotEmpty(stub.getText())) {
+      anAction.getTemplatePresentation().setText(stub.getText());
+    }
+    String iconPath = stub.getIconPath();
+    if (iconPath != null) {
+      Class<? extends AnAction> actionClass = anAction.getClass();
+      setIconFromClass(actionClass, actionClass.getClassLoader(), iconPath, anAction.getTemplatePresentation(), stub.getPluginId());
+    }
+    return anAction;
+  }
+
+  private static void processAbbreviationNode(Element e, String id) {
+    final String abbr = e.getAttributeValue(VALUE_ATTR_NAME);
+    if (!StringUtil.isEmpty(abbr)) {
+      final AbbreviationManagerImpl abbreviationManager = ((AbbreviationManagerImpl)AbbreviationManager.getInstance());
+      abbreviationManager.register(abbr, id, true);
+    }
+  }
+
+  @Nullable
+  private static ResourceBundle getActionsResourceBundle(ClassLoader loader, IdeaPluginDescriptor plugin) {
+    @NonNls final String resBundleName = plugin != null && !"com.intellij".equals(plugin.getPluginId().getIdString())
+                                         ? plugin.getResourceBundleBaseName() : ACTIONS_BUNDLE;
+    ResourceBundle bundle = null;
+    if (resBundleName != null) {
+      bundle = AbstractBundle.getResourceBundle(resBundleName, loader);
+    }
+    return bundle;
+  }
+
+  private static boolean isSecondary(Element element) {
+    return "true".equalsIgnoreCase(element.getAttributeValue(SECONDARY));
+  }
+
+  private static void setIcon(@Nullable final String iconPath,
+                              @NotNull String className,
+                              @NotNull ClassLoader loader,
+                              @NotNull Presentation presentation,
+                              final PluginId pluginId) {
+    if (iconPath == null) return;
+
+    try {
+      final Class actionClass = Class.forName(className, true, loader);
+      setIconFromClass(actionClass, loader, iconPath, presentation, pluginId);
+    }
+    catch (ClassNotFoundException e) {
+      LOG.error(e);
+      reportActionError(pluginId, "class with name \"" + className + "\" not found");
+    }
+    catch (NoClassDefFoundError e) {
+      LOG.error(e);
+      reportActionError(pluginId, "class with name \"" + className + "\" not found");
+    }
+  }
+
+  private static void setIconFromClass(@NotNull final Class actionClass,
+                                       @NotNull final ClassLoader classLoader,
+                                       @NotNull final String iconPath,
+                                       @NotNull Presentation presentation,
+                                       final PluginId pluginId) {
+    final IconLoader.LazyIcon lazyIcon = new IconLoader.LazyIcon() {
+      @Override
+      protected Icon compute() {
+        //try to find icon in idea class path
+        Icon icon = IconLoader.findIcon(iconPath, actionClass, true);
+        if (icon == null) {
+          icon = IconLoader.findIcon(iconPath, classLoader);
+        }
+
+        if (icon == null) {
+          reportActionError(pluginId, "Icon cannot be found in '" + iconPath + "', action '" + actionClass + "'");
+        }
+
+        return icon;
+      }
+
+      @Override
+      public String toString() {
+        return "LazyIcon@ActionManagerImpl (path: " + iconPath + ", action class: " + actionClass + ")";
+      }
+    };
+
+    if (!Registry.is("ide.lazyIconLoading")) {
+      lazyIcon.load();
+    }
+
+    presentation.setIcon(lazyIcon);
+  }
+
+  private static String loadDescriptionForElement(final Element element, final ResourceBundle bundle, final String id, String elementType) {
+    final String value = element.getAttributeValue(DESCRIPTION);
+    if (bundle != null) {
+      @NonNls final String key = elementType + "." + id + ".description";
+      return CommonBundle.messageOrDefault(bundle, key, value == null ? "" : value);
+    } else {
+      return value;
+    }
+  }
+
+  private static String loadTextForElement(final Element element, final ResourceBundle bundle, final String id, String elementType) {
+    final String value = element.getAttributeValue(TEXT_ATTR_NAME);
+    return CommonBundle.messageOrDefault(bundle, elementType + "." + id + "." + TEXT_ATTR_NAME, value == null ? "" : value);
+  }
+
+  public static boolean checkRelativeToAction(final String relativeToActionId,
+                                       @NotNull final Anchor anchor,
+                                       @NotNull final String actionName,
+                                       @Nullable final PluginId pluginId) {
+    if ((Anchor.BEFORE == anchor || Anchor.AFTER == anchor) && relativeToActionId == null) {
+      reportActionError(pluginId, actionName + ": \"relative-to-action\" cannot be null if anchor is \"after\" or \"before\"");
+      return false;
+    }
+    return true;
+  }
+
+  @Nullable
+  public static Anchor parseAnchor(final String anchorStr,
+                            @Nullable final String actionName,
+                            @Nullable final PluginId pluginId) {
+    if (anchorStr == null) {
+      return Anchor.LAST;
+    }
+
+    if (FIRST.equalsIgnoreCase(anchorStr)) {
+      return Anchor.FIRST;
+    }
+    else if (LAST.equalsIgnoreCase(anchorStr)) {
+      return Anchor.LAST;
+    }
+    else if (BEFORE.equalsIgnoreCase(anchorStr)) {
+      return Anchor.BEFORE;
+    }
+    else if (AFTER.equalsIgnoreCase(anchorStr)) {
+      return Anchor.AFTER;
+    }
+    else {
+      reportActionError(pluginId, actionName + ": anchor should be one of the following constants: \"first\", \"last\", \"before\" or \"after\"");
+      return null;
+    }
+  }
+
+  private static void processMouseShortcutNode(Element element, String actionId, PluginId pluginId) {
+    String keystrokeString = element.getAttributeValue(KEYSTROKE_ATTR_NAME);
+    if (keystrokeString == null || keystrokeString.trim().isEmpty()) {
+      reportActionError(pluginId, "\"keystroke\" attribute must be specified for action with id=" + actionId);
+      return;
+    }
+    MouseShortcut shortcut;
+    try {
+      shortcut = KeymapUtil.parseMouseShortcut(keystrokeString);
+    }
+    catch (Exception ex) {
+      reportActionError(pluginId, "\"keystroke\" attribute has invalid value for action with id=" + actionId);
+      return;
+    }
+
+    String keymapName = element.getAttributeValue(KEYMAP_ATTR_NAME);
+    if (keymapName == null || keymapName.isEmpty()) {
+      reportActionError(pluginId, "attribute \"keymap\" should be defined");
+      return;
+    }
+    Keymap keymap = KeymapManager.getInstance().getKeymap(keymapName);
+    if (keymap == null) {
+      reportActionError(pluginId, "keymap \"" + keymapName + "\" not found");
+      return;
+    }
+
+    final String removeOption = element.getAttributeValue(REMOVE_SHORTCUT_ATTR_NAME);
+    if (Boolean.valueOf(removeOption)) {
+      keymap.removeShortcut(actionId, shortcut);
+    } else {
+      keymap.addShortcut(actionId, shortcut);
+    }
+  }
+
+  private static void assertActionIsGroupOrStub(final AnAction action) {
+    if (!(action instanceof ActionGroup || action instanceof ActionStub)) {
+      LOG.error("Action : " + action + "; class: " + action.getClass());
+    }
+  }
+
+  private static void reportActionError(final PluginId pluginId, @NonNls @NotNull String message) {
+    if (pluginId == null) {
+      LOG.error(message);
+    }
+    else {
+      LOG.error(new PluginException(message, null, pluginId));
+    }
+  }
+
+  @NonNls
+  private static String getPluginInfo(@Nullable PluginId id) {
+    if (id != null) {
+      final IdeaPluginDescriptor plugin = PluginManager.getPlugin(id);
+      if (plugin != null) {
+        String name = plugin.getName();
+        if (name == null) {
+          name = id.getIdString();
+        }
+        return " Plugin: " + name;
+      }
+    }
+    return "";
+  }
+
+  private static DataContext getContextBy(Component contextComponent) {
+    final DataManager dataManager = DataManager.getInstance();
+    return contextComponent != null ? dataManager.getDataContext(contextComponent) : dataManager.getDataContext();
+  }
+
   @Override
   public void initComponent() {}
 
@@ -213,7 +461,6 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     return new ActionToolbarImpl(place, group, horizontal, decorateButtons, myDataManager, this, (KeymapManagerEx)myKeymapManager);
   }
 
-
   private void registerPluginActions() {
     final IdeaPluginDescriptor[] plugins = PluginManagerCore.getPlugins();
     for (IdeaPluginDescriptor plugin : plugins) {
@@ -229,12 +476,28 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
 
   @Override
   public AnAction getAction(@NotNull String id) {
-    return getActionImpl(id, false);
+    return getActionImpl(id, false, null);
+  }
+
+  @Override
+  public AnAction getAction(@NonNls @NotNull String actionId, @Nullable ProjectType projectType) {
+    return getActionImpl(actionId, false, projectType);
   }
 
-  private AnAction getActionImpl(String id, boolean canReturnStub) {
+  private AnAction getActionImpl(String id, boolean canReturnStub, ProjectType projectType) {
     synchronized (myLock) {
-      AnAction action = (AnAction)myId2Action.get(id);
+      AnAction action;
+      Object o = myId2Action.get(id);
+      if (o == null) {
+        return null;
+      }
+      if (o instanceof AnAction) {
+        action = (AnAction)o;
+      }
+      else {
+        //noinspection unchecked
+        action = ((Map<ProjectType, AnAction>)o).get(projectType);
+      }
       if (!canReturnStub && action instanceof ActionStub) {
         action = convert((ActionStub)action);
       }
@@ -252,61 +515,14 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
 
     LOG.assertTrue(myId2Action.containsKey(stub.getId()));
 
-    AnAction action = (AnAction)myId2Action.remove(stub.getId());
+    AnAction action = myId2Action.remove(stub.getId());
     LOG.assertTrue(action != null);
     LOG.assertTrue(action.equals(stub));
 
-    Object obj;
-    String className = stub.getClassName();
-    try {
-      Class<?> aClass = Class.forName(className, true, stub.getLoader());
-      obj = ReflectionUtil.newInstance(aClass);
-    }
-    catch (ClassNotFoundException e) {
-      PluginId pluginId = stub.getPluginId();
-      if (pluginId != null) {
-        throw new PluginException("class with name \"" + className + "\" not found", e, pluginId);
-      }
-      else {
-        throw new IllegalStateException("class with name \"" + className + "\" not found");
-      }
-    }
-    catch(UnsupportedClassVersionError e) {
-      PluginId pluginId = stub.getPluginId();
-      if (pluginId != null) {
-        throw new PluginException(e, pluginId);
-      }
-      else {
-        throw new IllegalStateException(e);
-      }
-    }
-    catch (Exception e) {
-      PluginId pluginId = stub.getPluginId();
-      if (pluginId != null) {
-        throw new PluginException("cannot create class \"" + className + "\"", e, pluginId);
-      }
-      else {
-        throw new IllegalStateException("cannot create class \"" + className + "\"", e);
-      }
-    }
+    AnAction anAction = convertStub(stub);
 
-    if (!(obj instanceof AnAction)) {
-      throw new IllegalStateException("class with name '" + className + "' must be an instance of '" + AnAction.class.getName()+"'; got "+obj);
-    }
-
-    AnAction anAction = (AnAction)obj;
-    stub.initAction(anAction);
-    if (StringUtil.isNotEmpty(stub.getText())) {
-      anAction.getTemplatePresentation().setText(stub.getText());
-    }
-    String iconPath = stub.getIconPath();
-    if (iconPath != null) {
-      Class<? extends AnAction> actionClass = anAction.getClass();
-      setIconFromClass(actionClass, actionClass.getClassLoader(), iconPath, anAction.getTemplatePresentation(), stub.getPluginId());
-    }
-
-    myId2Action.put(stub.getId(), obj);
-    myAction2Id.put(obj, stub.getId());
+    addToMap(stub.getId(), anAction, stub.getPluginId(), stub.getProjectType() == null ? null : new ProjectType(stub.getProjectType()));
+    myAction2Id.put(anAction, stub.getId());
 
     return anAction;
   }
@@ -334,7 +550,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
 
   @Override
   public boolean isGroup(@NotNull String actionId) {
-    return getActionImpl(actionId, true) instanceof ActionGroup;
+    return getActionImpl(actionId, true, null) instanceof ActionGroup;
   }
 
   @Override
@@ -344,7 +560,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
 
   @Override
   public AnAction getActionOrStub(String id) {
-    return getActionImpl(id, true);
+    return getActionImpl(id, true, null);
   }
 
   /**
@@ -386,7 +602,8 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
       return null;
     }
 
-    ActionStub stub = new ActionStub(className, id, text, loader, pluginId, iconPath);
+    String projectType = element.getAttributeValue(PROJECT_TYPE);
+    ActionStub stub = new ActionStub(className, id, text, loader, pluginId, iconPath, projectType);
     Presentation presentation = stub.getTemplatePresentation();
     presentation.setText(text);
 
@@ -441,99 +658,6 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
-  private static void processAbbreviationNode(Element e, String id) {
-    final String abbr = e.getAttributeValue(VALUE_ATTR_NAME);
-    if (!StringUtil.isEmpty(abbr)) {
-      final AbbreviationManagerImpl abbreviationManager = ((AbbreviationManagerImpl)AbbreviationManager.getInstance());
-      abbreviationManager.register(abbr, id, true);
-    }
-  }
-
-  @Nullable
-  private static ResourceBundle getActionsResourceBundle(ClassLoader loader, IdeaPluginDescriptor plugin) {
-    @NonNls final String resBundleName = plugin != null && !"com.intellij".equals(plugin.getPluginId().getIdString())
-                                         ? plugin.getResourceBundleBaseName() : ACTIONS_BUNDLE;
-    ResourceBundle bundle = null;
-    if (resBundleName != null) {
-      bundle = AbstractBundle.getResourceBundle(resBundleName, loader);
-    }
-    return bundle;
-  }
-
-  private static boolean isSecondary(Element element) {
-    return "true".equalsIgnoreCase(element.getAttributeValue(SECONDARY));
-  }
-
-  private static void setIcon(@Nullable final String iconPath,
-                              @NotNull String className,
-                              @NotNull ClassLoader loader,
-                              @NotNull Presentation presentation,
-                              final PluginId pluginId) {
-    if (iconPath == null) return;
-
-    try {
-      final Class actionClass = Class.forName(className, true, loader);
-      setIconFromClass(actionClass, loader, iconPath, presentation, pluginId);
-    }
-    catch (ClassNotFoundException e) {
-      LOG.error(e);
-      reportActionError(pluginId, "class with name \"" + className + "\" not found");
-    }
-    catch (NoClassDefFoundError e) {
-      LOG.error(e);
-      reportActionError(pluginId, "class with name \"" + className + "\" not found");
-    }
-  }
-
-  private static void setIconFromClass(@NotNull final Class actionClass,
-                                       @NotNull final ClassLoader classLoader,
-                                       @NotNull final String iconPath,
-                                       @NotNull Presentation presentation,
-                                       final PluginId pluginId) {
-    final IconLoader.LazyIcon lazyIcon = new IconLoader.LazyIcon() {
-      @Override
-      protected Icon compute() {
-        //try to find icon in idea class path
-        Icon icon = IconLoader.findIcon(iconPath, actionClass, true);
-        if (icon == null) {
-          icon = IconLoader.findIcon(iconPath, classLoader);
-        }
-
-        if (icon == null) {
-          reportActionError(pluginId, "Icon cannot be found in '" + iconPath + "', action '" + actionClass + "'");
-        }
-
-        return icon;
-      }
-
-      @Override
-      public String toString() {
-        return "LazyIcon@ActionManagerImpl (path: " + iconPath + ", action class: " + actionClass + ")";
-      }
-    };
-
-    if (!Registry.is("ide.lazyIconLoading")) {
-      lazyIcon.load();
-    }
-
-    presentation.setIcon(lazyIcon);
-  }
-
-  private static String loadDescriptionForElement(final Element element, final ResourceBundle bundle, final String id, String elementType) {
-    final String value = element.getAttributeValue(DESCRIPTION);
-    if (bundle != null) {
-      @NonNls final String key = elementType + "." + id + ".description";
-      return CommonBundle.messageOrDefault(bundle, key, value == null ? "" : value);
-    } else {
-      return value;
-    }
-  }
-
-  private static String loadTextForElement(final Element element, final ResourceBundle bundle, final String id, String elementType) {
-    final String value = element.getAttributeValue(TEXT_ATTR_NAME);
-    return CommonBundle.messageOrDefault(bundle, elementType + "." + id + "." + TEXT_ATTR_NAME, value == null ? "" : value);
-  }
-
   private AnAction processGroupElement(Element element, final ClassLoader loader, PluginId pluginId) {
     final IdeaPluginDescriptor plugin = PluginManager.getPlugin(pluginId);
     ResourceBundle bundle = getActionsResourceBundle(loader, plugin);
@@ -710,54 +834,17 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     if (anchor == null) {
       return;
     }
-
-    final String relativeToActionId = element.getAttributeValue(RELATIVE_TO_ACTION_ATTR_NAME);
-    if (!checkRelativeToAction(relativeToActionId, anchor, actionName, pluginId)) {
-      return;
-    }
-    addToGroupInner(parentGroup, action, new Constraints(anchor, relativeToActionId), secondary);
-  }
-
-  private void addToGroupInner(AnAction group, AnAction action, Constraints constraints, boolean secondary) {
-    ((DefaultActionGroup)group).addAction(action, constraints, this).setAsSecondary(secondary);
-    myId2GroupId.putValue(myAction2Id.get(action), myAction2Id.get(group));
-  }
-
-  public static boolean checkRelativeToAction(final String relativeToActionId,
-                                       @NotNull final Anchor anchor,
-                                       @NotNull final String actionName,
-                                       @Nullable final PluginId pluginId) {
-    if ((Anchor.BEFORE == anchor || Anchor.AFTER == anchor) && relativeToActionId == null) {
-      reportActionError(pluginId, actionName + ": \"relative-to-action\" cannot be null if anchor is \"after\" or \"before\"");
-      return false;
-    }
-    return true;
-  }
-
-  @Nullable
-  public static Anchor parseAnchor(final String anchorStr,
-                            @Nullable final String actionName,
-                            @Nullable final PluginId pluginId) {
-    if (anchorStr == null) {
-      return Anchor.LAST;
-    }
-
-    if (FIRST.equalsIgnoreCase(anchorStr)) {
-      return Anchor.FIRST;
-    }
-    else if (LAST.equalsIgnoreCase(anchorStr)) {
-      return Anchor.LAST;
-    }
-    else if (BEFORE.equalsIgnoreCase(anchorStr)) {
-      return Anchor.BEFORE;
-    }
-    else if (AFTER.equalsIgnoreCase(anchorStr)) {
-      return Anchor.AFTER;
-    }
-    else {
-      reportActionError(pluginId, actionName + ": anchor should be one of the following constants: \"first\", \"last\", \"before\" or \"after\"");
-      return null;
+
+    final String relativeToActionId = element.getAttributeValue(RELATIVE_TO_ACTION_ATTR_NAME);
+    if (!checkRelativeToAction(relativeToActionId, anchor, actionName, pluginId)) {
+      return;
     }
+    addToGroupInner(parentGroup, action, new Constraints(anchor, relativeToActionId), secondary);
+  }
+
+  private void addToGroupInner(AnAction group, AnAction action, Constraints constraints, boolean secondary) {
+    ((DefaultActionGroup)group).addAction(action, constraints, this).setAsSecondary(secondary);
+    myId2GroupId.putValue(myAction2Id.get(action), myAction2Id.get(group));
   }
 
   @Nullable
@@ -768,10 +855,10 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
       reportActionError(pluginId, actionName + ": attribute \"group-id\" should be defined");
       return null;
     }
-    AnAction parentGroup = getActionImpl(groupId, true);
+    AnAction parentGroup = getActionImpl(groupId, true, null);
     if (parentGroup == null) {
       reportActionError(pluginId, actionName + ": group with id \"" + groupId + "\" isn't registered; action will be added to the \"Other\" group");
-      parentGroup = getActionImpl(IdeActions.GROUP_OTHER_MENU, true);
+      parentGroup = getActionImpl(IdeActions.GROUP_OTHER_MENU, true, null);
     }
     if (!(parentGroup instanceof DefaultActionGroup)) {
       reportActionError(pluginId, actionName + ": group with id \"" + groupId + "\" should be instance of " + DefaultActionGroup.class.getName() +
@@ -850,40 +937,6 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
-  private static void processMouseShortcutNode(Element element, String actionId, PluginId pluginId) {
-    String keystrokeString = element.getAttributeValue(KEYSTROKE_ATTR_NAME);
-    if (keystrokeString == null || keystrokeString.trim().isEmpty()) {
-      reportActionError(pluginId, "\"keystroke\" attribute must be specified for action with id=" + actionId);
-      return;
-    }
-    MouseShortcut shortcut;
-    try {
-      shortcut = KeymapUtil.parseMouseShortcut(keystrokeString);
-    }
-    catch (Exception ex) {
-      reportActionError(pluginId, "\"keystroke\" attribute has invalid value for action with id=" + actionId);
-      return;
-    }
-
-    String keymapName = element.getAttributeValue(KEYMAP_ATTR_NAME);
-    if (keymapName == null || keymapName.isEmpty()) {
-      reportActionError(pluginId, "attribute \"keymap\" should be defined");
-      return;
-    }
-    Keymap keymap = KeymapManager.getInstance().getKeymap(keymapName);
-    if (keymap == null) {
-      reportActionError(pluginId, "keymap \"" + keymapName + "\" not found");
-      return;
-    }
-
-    final String removeOption = element.getAttributeValue(REMOVE_SHORTCUT_ATTR_NAME);
-    if (Boolean.valueOf(removeOption)) {
-      keymap.removeShortcut(actionId, shortcut);
-    } else {
-      keymap.addShortcut(actionId, shortcut);
-    }
-  }
-
   @Nullable
   private AnAction processReferenceElement(Element element, PluginId pluginId) {
     if (!REFERENCE_ELEMENT_NAME.equals(element.getName())) {
@@ -902,7 +955,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
       return null;
     }
 
-    AnAction action = getActionImpl(ref, true);
+    AnAction action = getActionImpl(ref, true, null);
 
     if (action == null) {
       if (!myNotRegisteredInternalActionIds.contains(ref)) {
@@ -936,27 +989,15 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
-  private static void assertActionIsGroupOrStub(final AnAction action) {
-    if (!(action instanceof ActionGroup || action instanceof ActionStub)) {
-      LOG.error("Action : " + action + "; class: " + action.getClass());
-    }
-  }
-
   @Override
   public void registerAction(@NotNull String actionId, @NotNull AnAction action, @Nullable PluginId pluginId) {
     synchronized (myLock) {
-      if (myId2Action.containsKey(actionId)) {
-        reportActionError(pluginId, "action with the ID \"" + actionId + "\" was already registered. Action being registered is " + action +
-                                    "; Registered action is " +
-                                       myId2Action.get(actionId) + getPluginInfo(pluginId));
-        return;
-      }
+      if (!addToMap(actionId, action, pluginId, null)) return;
       if (myAction2Id.containsKey(action)) {
         reportActionError(pluginId, "action was already registered for another ID. ID is " + myAction2Id.get(action) +
                                     getPluginInfo(pluginId));
         return;
       }
-      myId2Action.put(actionId, action);
       myId2Index.put(actionId, myRegisteredActionsCount++);
       myAction2Id.put(action, actionId);
       if (pluginId != null && !(action instanceof ActionGroup)){
@@ -971,28 +1012,31 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
-  private static void reportActionError(final PluginId pluginId, @NonNls @NotNull String message) {
-    if (pluginId == null) {
-      LOG.error(message);
+  public boolean addToMap(String actionId, AnAction action, PluginId pluginId, ProjectType projectType) {
+    if (myId2Action.containsKey(actionId)) {
+      // make sure id+projectType is unique
+      AnAction o = myId2Action.get(actionId);
+      ChameleonAction chameleonAction;
+      if (o instanceof ChameleonAction) {
+        chameleonAction = (ChameleonAction)o;
+      }
+      else {
+        chameleonAction = new ChameleonAction(o, projectType);
+        myId2Action.put(actionId, chameleonAction);
+      }
+      AnAction old = chameleonAction.addAction(action, projectType);
+      if (old != null) {
+        reportActionError(pluginId,
+                          "action with the ID \"" + actionId + "\" was already registered. Action being registered is " + action +
+                          "; Registered action is " +
+                          myId2Action.get(actionId) + getPluginInfo(pluginId));
+        return false;
+      }
     }
     else {
-      LOG.error(new PluginException(message, null, pluginId));
-    }
-  }
-
-  @NonNls
-  private static String getPluginInfo(@Nullable PluginId id) {
-    if (id != null) {
-      final IdeaPluginDescriptor plugin = PluginManager.getPlugin(id);
-      if (plugin != null) {
-        String name = plugin.getName();
-        if (name == null) {
-          name = id.getIdString();
-        }
-        return " Plugin: " + name;
-      }
+      myId2Action.put(actionId, action);
     }
-    return "";
+    return true;
   }
 
   @Override
@@ -1067,6 +1111,12 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
+  //@Override
+  //public AnAction replaceAction(String actionId, @NotNull AnAction newAction) {
+  //  synchronized (myLock) {
+  //    return replaceAction(actionId, newAction, null);
+  //  }
+  //}
 
   @Override
   public boolean isActionPopupStackEmpty() {
@@ -1078,13 +1128,6 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     return myTransparentOnlyUpdate;
   }
 
-  //@Override
-  //public AnAction replaceAction(String actionId, @NotNull AnAction newAction) {
-  //  synchronized (myLock) {
-  //    return replaceAction(actionId, newAction, null);
-  //  }
-  //}
-
   private AnAction replaceAction(@NotNull String actionId, @NotNull AnAction newAction, @Nullable PluginId pluginId) {
     AnAction oldAction = getActionOrStub(actionId);
     if (oldAction != null) {
@@ -1208,8 +1251,6 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
-  private int myActionsPreloaded = 0;
-
   public void preloadActions() {
     if (myPreloadActionsRunnable == null) {
       myPreloadActionsRunnable = new Runnable() {
@@ -1281,6 +1322,85 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
+  @Override
+  public ActionCallback tryToExecute(@NotNull final AnAction action, @NotNull final InputEvent inputEvent, @Nullable final Component contextComponent, @Nullable final String place,
+                                     boolean now) {
+
+    final Application app = ApplicationManager.getApplication();
+    assert app.isDispatchThread();
+
+    final ActionCallback result = new ActionCallback();
+    final Runnable doRunnable = new Runnable() {
+      @Override
+      public void run() {
+        tryToExecuteNow(action, inputEvent, contextComponent, place, result);
+      }
+    };
+
+    if (now) {
+      doRunnable.run();
+    } else {
+      //noinspection SSBasedInspection
+      SwingUtilities.invokeLater(doRunnable);
+    }
+
+    return result;
+  }
+
+  private void tryToExecuteNow(final AnAction action, final InputEvent inputEvent, final Component contextComponent, final String place, final ActionCallback result) {
+    final Presentation presentation = action.getTemplatePresentation().clone();
+
+    IdeFocusManager.findInstanceByContext(getContextBy(contextComponent)).doWhenFocusSettlesDown(new Runnable() {
+      @Override
+      public void run() {
+        final DataContext context = getContextBy(contextComponent);
+
+        AnActionEvent event = new AnActionEvent(
+          inputEvent, context,
+          place != null ? place : ActionPlaces.UNKNOWN,
+          presentation, ActionManagerImpl.this,
+          inputEvent.getModifiersEx()
+        );
+
+        ActionUtil.performDumbAwareUpdate(action, event, false);
+        if (!event.getPresentation().isEnabled()) {
+          result.setRejected();
+          return;
+        }
+
+        ActionUtil.lastUpdateAndCheckDumb(action, event, false);
+        if (!event.getPresentation().isEnabled()) {
+          result.setRejected();
+          return;
+        }
+
+        Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(context);
+        if (component != null && !component.isShowing()) {
+          result.setRejected();
+          return;
+        }
+
+        fireBeforeActionPerformed(action, context, event);
+
+        UIUtil.addAwtListener(new AWTEventListener() {
+          @Override
+          public void eventDispatched(AWTEvent event) {
+            if (event.getID() == WindowEvent.WINDOW_OPENED ||event.getID() == WindowEvent.WINDOW_ACTIVATED) {
+              if (!result.isProcessed()) {
+                final WindowEvent we = (WindowEvent)event;
+                IdeFocusManager.findInstanceByComponent(we.getWindow()).doWhenFocusSettlesDown(result.createSetDoneRunnable());
+              }
+            }
+          }
+        }, AWTEvent.WINDOW_EVENT_MASK, result);
+
+        ActionUtil.performActionDumbAware(action, event);
+        result.setDone();
+        queueActionPerformedEvent(action, context, event);
+      }
+    });
+  }
+
   private class MyTimer extends Timer implements ActionListener {
     private final List<TimerListener> myTimerListeners = ContainerUtil.createLockFreeCopyOnWriteList();
     private final List<TimerListener> myTransparentTimerListeners = ContainerUtil.createLockFreeCopyOnWriteList();
@@ -1371,88 +1491,4 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
       }
     }
   }
-
-  @Override
-  public ActionCallback tryToExecute(@NotNull final AnAction action, @NotNull final InputEvent inputEvent, @Nullable final Component contextComponent, @Nullable final String place,
-                                     boolean now) {
-
-    final Application app = ApplicationManager.getApplication();
-    assert app.isDispatchThread();
-
-    final ActionCallback result = new ActionCallback();
-    final Runnable doRunnable = new Runnable() {
-      @Override
-      public void run() {
-        tryToExecuteNow(action, inputEvent, contextComponent, place, result);
-      }
-    };
-
-    if (now) {
-      doRunnable.run();
-    } else {
-      //noinspection SSBasedInspection
-      SwingUtilities.invokeLater(doRunnable);
-    }
-
-    return result;
-  }
-
-  private void tryToExecuteNow(final AnAction action, final InputEvent inputEvent, final Component contextComponent, final String place, final ActionCallback result) {
-    final Presentation presentation = action.getTemplatePresentation().clone();
-
-    IdeFocusManager.findInstanceByContext(getContextBy(contextComponent)).doWhenFocusSettlesDown(new Runnable() {
-      @Override
-      public void run() {
-        final DataContext context = getContextBy(contextComponent);
-
-        AnActionEvent event = new AnActionEvent(
-          inputEvent, context,
-          place != null ? place : ActionPlaces.UNKNOWN,
-          presentation, ActionManagerImpl.this,
-          inputEvent.getModifiersEx()
-        );
-
-        ActionUtil.performDumbAwareUpdate(action, event, false);
-        if (!event.getPresentation().isEnabled()) {
-          result.setRejected();
-          return;
-        }
-
-        ActionUtil.lastUpdateAndCheckDumb(action, event, false);
-        if (!event.getPresentation().isEnabled()) {
-          result.setRejected();
-          return;
-        }
-
-        Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(context);
-        if (component != null && !component.isShowing()) {
-          result.setRejected();
-          return;
-        }
-
-        fireBeforeActionPerformed(action, context, event);
-
-        UIUtil.addAwtListener(new AWTEventListener() {
-          @Override
-          public void eventDispatched(AWTEvent event) {
-            if (event.getID() == WindowEvent.WINDOW_OPENED ||event.getID() == WindowEvent.WINDOW_ACTIVATED) {
-              if (!result.isProcessed()) {
-                final WindowEvent we = (WindowEvent)event;
-                IdeFocusManager.findInstanceByComponent(we.getWindow()).doWhenFocusSettlesDown(result.createSetDoneRunnable());
-              }
-            }
-          }
-        }, AWTEvent.WINDOW_EVENT_MASK, result);
-
-        ActionUtil.performActionDumbAware(action, event);
-        result.setDone();
-        queueActionPerformedEvent(action, context, event);
-      }
-    });
-  }
-
-  private static DataContext getContextBy(Component contextComponent) {
-    final DataManager dataManager = DataManager.getInstance();
-    return contextComponent != null ? dataManager.getDataContext(contextComponent) : dataManager.getDataContext();
-  }
 }
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java
new file mode 100644 (file)
index 0000000..4b46dc1
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.actionSystem.impl;
+
+import com.intellij.openapi.actionSystem.ActionStub;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectType;
+import com.intellij.openapi.project.ProjectTypeService;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Dmitry Avdeev
+ */
+public class ChameleonAction extends AnAction {
+
+  private final Map<ProjectType, AnAction> myActions = new HashMap<ProjectType, AnAction>();
+
+  public ChameleonAction(@NotNull AnAction first, ProjectType projectType) {
+    addAction(first, projectType);
+  }
+
+  public AnAction addAction(AnAction action, ProjectType projectType) {
+    if (action instanceof ActionStub) {
+      String type = ((ActionStub)action).getProjectType();
+      action = ActionManagerImpl.convertStub((ActionStub)action);
+      projectType = type == null ? null : new ProjectType(type);
+    }
+    return myActions.put(projectType, action);
+  }
+
+  @Override
+  public void actionPerformed(AnActionEvent e) {
+    getAction(e).actionPerformed(e);
+  }
+
+  @Override
+  public void update(AnActionEvent e) {
+    super.update(e);
+  }
+
+  private AnAction getAction(AnActionEvent e) {
+    Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
+    ProjectType projectType = ProjectTypeService.getProjectType(project);
+    AnAction action = myActions.get(projectType);
+    if (action == null) action = myActions.get(null);
+    if (action == null) action = myActions.values().iterator().next();
+    return action;
+  }
+}
index 01aa0ff4c49ea4df12425ac55f01c0924f0a6a49..4de847213103a04fadcf94ee7ca969947bb2638f 100644 (file)
@@ -40,7 +40,6 @@ public class ActionBean {
   @Attribute(ActionManagerImpl.ICON_ATTR_NAME)
   public String icon;
 
-
   @Attribute(ActionManagerImpl.POPUP_ATTR_NAME)
   public String isPopup;
 
@@ -58,4 +57,7 @@ public class ActionBean {
 
   @Attribute(ActionManagerImpl.OVERRIDES_ATTR_NAME)
   public boolean overrides;
+
+  @Attribute(ActionManagerImpl.PROJECT_TYPE)
+  public String projectType;
 }
index a4dfd49a71a8f1e05235d655000bf8587ebe838c..baea70a67c7aab4e3d212a4c45e70f84cc9306e2 100644 (file)
@@ -9,6 +9,9 @@
     <extensionPoint name="postStartupActivity"
                     interface="com.intellij.openapi.startup.StartupActivity"/>
 
+    <extensionPoint name="defaultProjectTypeProvider"
+                    interface="com.intellij.openapi.project.DefaultProjectTypeProvider"/>
+
     <extensionPoint name="errorHandler"
                     interface="com.intellij.openapi.diagnostic.ErrorReportSubmitter"/>
 
index aa3ee139c1d387dfdff4beb42016220638feb6aa..51028d93edac0a15f9a460fd76c4a56776da8697 100644 (file)
                     serviceImplementation="com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl"/>
     <projectService serviceInterface="com.intellij.openapi.startup.StartupManager"
                     serviceImplementation="com.intellij.ide.startup.impl.StartupManagerImpl"/>
+    <projectService serviceImplementation="com.intellij.openapi.project.ProjectTypeService"/>
     <projectService serviceInterface="com.intellij.openapi.ui.MasterDetailsStateService" serviceImplementation="com.intellij.openapi.ui.MasterDetailsStateService"/>
     <projectService serviceInterface="com.intellij.ide.SelectInManager" serviceImplementation="com.intellij.ide.SelectInManager"/>
 
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeProvider.java b/platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeProvider.java
new file mode 100644 (file)
index 0000000..81887eb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.project;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Dmitry Avdeev
+ */
+public abstract class DefaultProjectTypeProvider {
+
+  private final static ExtensionPointName<DefaultProjectTypeProvider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.defaultProjectTypeProvider");
+
+  @Nullable
+  public static ProjectType getDefaultProjectType() {
+    DefaultProjectTypeProvider[] extensions = EXTENSION_POINT_NAME.getExtensions();
+    return extensions.length > 0 ? extensions[0].getProjectType() : null;
+  }
+
+  protected abstract ProjectType getProjectType();
+}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectType.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectType.java
new file mode 100644 (file)
index 0000000..f096e67
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.project;
+
+/**
+ * @author Dmitry Avdeev
+ */
+public class ProjectType {
+
+  private String id;
+
+  /**
+   * For serialization.
+   */
+  public ProjectType() {
+  }
+
+  public ProjectType(String id) {
+    this.id = id;
+  }
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ProjectType type = (ProjectType)o;
+
+    if (id != null ? !id.equals(type.id) : type.id != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return id != null ? id.hashCode() : 0;
+  }
+}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java
new file mode 100644 (file)
index 0000000..e430593
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.project;
+
+import com.intellij.openapi.components.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Dmitry Avdeev
+ */
+
+@State(
+  name = "ProjectType",
+  storages = {
+    @Storage(file = StoragePathMacros.PROJECT_FILE),
+    @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/misc.xml", scheme = StorageScheme.DIRECTORY_BASED)
+  }
+)
+public class ProjectTypeService implements PersistentStateComponent<ProjectType> {
+
+  private ProjectType myProjectType;
+
+  @Nullable
+  public static ProjectType getProjectType(@Nullable Project project) {
+    ProjectType projectType;
+    if (project != null) {
+      projectType = getInstance(project).myProjectType;
+      if (projectType != null) return projectType;
+    }
+    return DefaultProjectTypeProvider.getDefaultProjectType();
+  }
+
+  public static ProjectTypeService getInstance(@NotNull Project project) {
+    return ServiceManager.getService(project, ProjectTypeService.class);
+  }
+
+  @Nullable
+  @Override
+  public ProjectType getState() {
+    return myProjectType;
+  }
+
+  @Override
+  public void loadState(ProjectType state) {
+    myProjectType = state;
+  }
+}