Package org.sylfra.idea.plugins.revu.ui.projectView

Source Code of org.sylfra.idea.plugins.revu.ui.projectView.RevuProjectViewPane

/*
* Copyright 2000-2009 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 org.sylfra.idea.plugins.revu.ui.projectView;

import com.intellij.ide.SelectInTarget;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.ide.projectView.ProjectViewNodeDecorator;
import com.intellij.ide.projectView.impl.AbstractProjectViewPane;
import com.intellij.ide.scopeView.nodes.BasePsiNode;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packageDependencies.ui.PackageDependenciesNode;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
import com.intellij.psi.search.scope.packageSet.PackageSet;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.sylfra.idea.plugins.revu.RevuBundle;
import org.sylfra.idea.plugins.revu.RevuDataKeys;
import org.sylfra.idea.plugins.revu.business.IReviewListener;
import org.sylfra.idea.plugins.revu.business.ReviewManager;
import org.sylfra.idea.plugins.revu.model.Review;
import org.sylfra.idea.plugins.revu.model.ReviewStatus;
import org.sylfra.idea.plugins.revu.settings.IRevuSettingsListener;
import org.sylfra.idea.plugins.revu.settings.project.workspace.RevuWorkspaceSettings;
import org.sylfra.idea.plugins.revu.settings.project.workspace.RevuWorkspaceSettingsComponent;
import org.sylfra.idea.plugins.revu.utils.RevuUtils;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;

/**
* @author <a href="mailto:syllant@gmail.com">Sylvain FRANCOIS</a>
* @version $Id$
*/
public class RevuProjectViewPane extends AbstractProjectViewPane
{
  private final static ReviewStatus[] VISIBLE_STATUSES_ARRAY
    = {ReviewStatus.DRAFT, ReviewStatus.FIXING, ReviewStatus.REVIEWING};
  private static final List<ReviewStatus> VISIBLE_STATUSES_LIST = Arrays.asList(VISIBLE_STATUSES_ARRAY);

  @NonNls
  public static final String ID = "Revu";
  public static final Icon ICON = IconLoader.getIcon("/org/sylfra/idea/plugins/revu/resources/icons/revu.png");

  private final ProjectView myProjectView;
  private RevuScopeTreeViewPanel myViewPanel;
  private final IdentityHashMap<Review, NamedScope> scopes;

  public RevuProjectViewPane(Project project, ProjectView projectView)
  {
    super(project);
    myProjectView = projectView;
    scopes = new IdentityHashMap<Review, NamedScope>();

    installListeners();
  }

  private void installListeners()
  {
    ReviewManager reviewManager = myProject.getComponent(ReviewManager.class);
    CustomReviewListener reviewListener = new CustomReviewListener();
    reviewManager.addReviewListener(reviewListener);
    for (Review review : reviewManager.getReviews(RevuUtils.getCurrentUserLogin(), VISIBLE_STATUSES_ARRAY))
    {
      reviewListener.reviewAdded(review);
    }

    myProject.getComponent(RevuWorkspaceSettingsComponent.class).addListener(new CustomWorkspaceSettingsListener());
  }

  public String getTitle()
  {
    return RevuBundle.message("general.plugin.title");
  }

  public Icon getIcon()
  {
    return ICON;
  }

  @NotNull
  public String getId()
  {
    return ID;
  }

  public JComponent createComponent()
  {
    myViewPanel = new RevuScopeTreeViewPanel(myProject);
    Disposer.register(this, myViewPanel);
    myViewPanel.initListeners();

    myTree = myViewPanel.getTree();
    PopupHandler.installPopupHandler(myTree, "RevuProjectViewPopupMenu", "RevuProjectViewPopup");
    enableDnD();

    myTree.setCellRenderer(new CustomTreeCellRenderer(myProject, myViewPanel));

    updateFromRoot(true);

    return myViewPanel.getPanel();
  }

  public void dispose()
  {
    myViewPanel = null;
    super.dispose();
  }

  @NotNull
  public String[] getSubIds()
  {
    String[] ids = new String[scopes.size()];
    int i = 0;
    for (NamedScope namedScope : scopes.values())
    {
      ids[i++] = namedScope.getName();
    }

    return ids;
  }

  @NotNull
  public String getPresentableSubIdName(@NotNull final String subId)
  {
    return subId;
  }

  public void addToolbarActions(DefaultActionGroup actionGroup)
  {
    actionGroup.add(ActionManager.getInstance().getAction("revu.ProjectView.ToggleFilterIssues"));
    actionGroup.add(ActionManager.getInstance().getAction("revu.ShowProjectSettings"));
  }

  public ActionCallback updateFromRoot(boolean restoreExpandedPaths)
  {
    saveExpandedPaths();
//    myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId()));
    for (NamedScope namedScope : scopes.values())
    {
      if (namedScope.getName().equals(getSubId()))
      {
        myViewPanel.selectScope(namedScope);
        break;
      }
    }

    if (myTree != null)
    {
      restoreExpandedPaths();
    }

    return new ActionCallback.Done();
  }

  public void select(Object element, VirtualFile file, boolean requestFocus)
  {
    if (file == null)
    {
      return;
    }
    PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
    if (psiFile == null)
    {
      return;
    }
    if (!(element instanceof PsiElement))
    {
      return;
    }

    List<NamedScope> allScopes = new ArrayList<NamedScope>(scopes.values());
    for (int i = 0; i < allScopes.size(); i++)
    {
      final NamedScope scope = allScopes.get(i);
      String name = scope.getName();
      if (name.equals(getSubId()))
      {
        allScopes.set(i, allScopes.get(0));
        allScopes.set(0, scope);
        break;
      }
    }
    for (NamedScope scope : allScopes)
    {
      String name = scope.getName();
      PackageSet packageSet = scope.getValue();
      if (packageSet == null)
      {
        continue;
      }
      if (changeView(packageSet, ((PsiElement) element), psiFile, name, requestFocus))
      {
        break;
      }
    }
  }

  private boolean changeView(final PackageSet packageSet, final PsiElement element, final PsiFile psiFile,
    final String name, boolean requestFocus)
  {
    // Does not work anymore with IDEA 11
    //NamedScopesHolder holder = NamedScopesHolder.getHolder(myProject, name, null);
    NamedScopesHolder holder = NamedScopesHolder.getAllNamedScopeHolders(myProject)[0];
    if ((holder == null) || packageSet.contains(psiFile, holder))
    {
      if (!name.equals(getSubId()))
      {
        myProjectView.changeView(getId(), name);
      }
      myViewPanel.selectNode(element, psiFile, requestFocus);
      return true;
    }

    return false;
  }

  public int getWeight()
  {
    // http://code.google.com/p/idea-revu/issues/detail?id=18
    // bug when 2 panes have same weight?!
    return Integer.MAX_VALUE - 1;
  }

  public void installComparator()
  {
    myViewPanel.setSortByType();
  }

  public SelectInTarget createSelectInTarget()
  {
    return new RevuPaneSelectInTarget(myProject);
  }

  protected Object exhumeElementFromNode(final DefaultMutableTreeNode node)
  {
    if (node instanceof PackageDependenciesNode)
    {
      return ((PackageDependenciesNode) node).getPsiElement();
    }
    return super.exhumeElementFromNode(node);
  }

  public Object getData(final String dataId)
  {
    if (RevuDataKeys.REVIEW.is(dataId))
    {
      return getSelectedReview();
    }

    final Object data = super.getData(dataId);
    if (data != null)
    {
      return data;
    }

    return myViewPanel != null ? myViewPanel.getData(dataId) : null;
  }

  private boolean isVisible(Review review)
  {
    String currentUserLogin = RevuUtils.getCurrentUserLogin();
    return (currentUserLogin != null)
      && VISIBLE_STATUSES_LIST.contains(review.getStatus())
      && review.getDataReferential().getUser(currentUserLogin, true) != null;
  }

  public void rebuildPane()
  {
    Alarm refreshProjectViewAlarm = new Alarm();
    // amortize batch scope changes
    refreshProjectViewAlarm.cancelAllRequests();
    refreshProjectViewAlarm.addRequest(new Runnable()
    {
      public void run()
      {
        if (myProject.isDisposed())
        {
          return;
        }
        myProjectView.removeProjectPane(RevuProjectViewPane.this);
        myProjectView.addProjectPane(RevuProjectViewPane.this);
      }
    }, 10);
  }

  private String getScopeName(Review review)
  {
    return review.getName();
  }

  @Nullable
  public Review getSelectedReview()
  {
    String reviewName = getSubId();
    return reviewName == null ? null : myProject.getComponent(ReviewManager.class).getReviewByName(reviewName);
  }

  // See com.intellij.ide.scopeView.ScopeTreeViewPanel.MyTreeCellRenderer
  private class CustomTreeCellRenderer extends ColoredTreeCellRenderer
  {
    private final Project project;
    private final RevuScopeTreeViewPanel scopeTreeViewPanel;

    public CustomTreeCellRenderer(Project project, RevuScopeTreeViewPanel scopeTreeViewPanel)
    {
      this.project = project;
      this.scopeTreeViewPanel = scopeTreeViewPanel;
    }

    public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf,
      int row, boolean hasFocus)
    {
      if (value instanceof PackageDependenciesNode)
      {
        PackageDependenciesNode node = (PackageDependenciesNode) value;
        try
        {
            setIcon(node.getIcon());
        }
        catch (IndexNotReadyException ignored)
        {
        }

        final SimpleTextAttributes regularAttributes = SimpleTextAttributes.REGULAR_ATTRIBUTES;
        TextAttributes textAttributes = regularAttributes.toTextAttributes();
        if (node instanceof BasePsiNode && ((BasePsiNode) node).isDeprecated())
        {
          textAttributes =
            EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.DEPRECATED_ATTRIBUTES)
              .clone();
        }

        PsiElement psiElement = node.getPsiElement();
        VirtualFile vFile = (psiElement == null)
          ? null
            : ((psiElement instanceof PsiDirectory)
              ? ((PsiDirectory) psiElement).getVirtualFile()
                : (psiElement.getContainingFile() == null) ? null : psiElement.getContainingFile().getVirtualFile());

        String reviewName = scopeTreeViewPanel.getCurrentScopeName();
        if (reviewName == null)
        {
          return;
        }

        Review review = project.getComponent(ReviewManager.class).getReviewByName(reviewName);
        if (review != null)
        {
          FileStatus fileStatus = retrieveFileStatus(review, vFile);
          textAttributes.setForegroundColor(fileStatus.getColor());
        }

        append(node.toString(), SimpleTextAttributes.fromTextAttributes(textAttributes));

        String oldToString = toString();
        for (ProjectViewNodeDecorator decorator : Extensions.getExtensions(ProjectViewNodeDecorator.EP_NAME, myProject))
        {
          decorator.decorate(node, this);
        }

        if (review != null)
        {
          int issueCount = retrieveIssueCount(review, vFile);
          if (issueCount > 0)
          {
            append(" [" + RevuBundle.message("projectView.issueCount.text", issueCount) + "]",
              SimpleTextAttributes.GRAY_ATTRIBUTES);
          }
        }

        if (toString().equals(oldToString))
        {   // nothing was decorated
          final String locationString = node.getComment();
          if (locationString != null && locationString.length() > 0)
          {
            append(" (" + locationString + ")", SimpleTextAttributes.GRAY_ATTRIBUTES);
          }
        }
      }
    }

    private FileStatus retrieveFileStatus(Review review, VirtualFile vFile)
    {
      if (review.getFileScope().getVcsAfterRev() != null)
      {
        // @TODO: handle ADDED/MODIFIED
        return FileStatus.MODIFIED;
      }

      if (vFile == null)
      {
        return FileStatus.NOT_CHANGED;
      }

      FileStatus fileStatus = FileStatusManager.getInstance(project).getStatus(vFile);
      return (fileStatus == null) ? FileStatus.NOT_CHANGED : fileStatus;
    }

    private int retrieveIssueCount(Review review, VirtualFile vFile)
    {
      return ((vFile == null) || (review == null)) ? 0 : review.getIssues(vFile).size();
    }
  }

  private class CustomReviewListener implements IReviewListener
  {
    public void reviewChanged(Review review)
    {
      if (isVisible(review))
      {
        scopes.put(review, new NamedScope(getScopeName(review), new RevuPackageSet(myProject, review)));
      }
      else
      {
        scopes.remove(review);
      }

      // @TODO refresh only current tree
      updateFromRoot(true);
    }

    public void reviewAdded(Review review)
    {
      if (isVisible(review))
      {
        scopes.put(review, new NamedScope(getScopeName(review), new RevuPackageSet(myProject, review)));
        rebuildPane();
      }
    }

    public void reviewDeleted(Review review)
    {
      scopes.remove(review);
      rebuildPane();
    }
  }

  private class CustomWorkspaceSettingsListener implements IRevuSettingsListener<RevuWorkspaceSettings>
  {
    public void settingsChanged(RevuWorkspaceSettings oldSettings, RevuWorkspaceSettings newSettings)
    {
      if (newSettings.isFilterFilesWithIssues() != oldSettings.isFilterFilesWithIssues())
      {
        updateFromRoot(true);
      }
    }
  }
}
TOP

Related Classes of org.sylfra.idea.plugins.revu.ui.projectView.RevuProjectViewPane

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.