public void updateModel(
      List<? extends ChangeList> changeLists,
      Trinity<List<VirtualFile>, Integer, Integer> unversionedFiles,
      final List<LocallyDeletedChange> locallyDeletedFiles,
      List<VirtualFile> modifiedWithoutEditing,
      MultiMap<String, VirtualFile> switchedFiles,
      @Nullable Map<VirtualFile, String> switchedRoots,
      @Nullable List<VirtualFile> ignoredFiles,
      final List<VirtualFile> lockedFolders,
      @Nullable final Map<VirtualFile, LogicalLock> logicallyLockedFiles) {
    TreeModelBuilder builder = new TreeModelBuilder(myProject, isShowFlatten());
    final DefaultTreeModel model =
        builder.buildModel(
            changeLists,
            unversionedFiles,
            locallyDeletedFiles,
            modifiedWithoutEditing,
            switchedFiles,
            switchedRoots,
            ignoredFiles,
            lockedFolders,
            logicallyLockedFiles);

    storeState();
    DefaultTreeModel oldModel = getModel();
    setModel(model);
    setCellRenderer(new ChangesBrowserNodeRenderer(myProject, isShowFlatten(), true));
    ChangesBrowserNode root = (ChangesBrowserNode) model.getRoot();
    expandPath(new TreePath(root.getPath()));
    restoreState();
    expandDefaultChangeList(oldModel, root);
  }
  @NotNull
  public Change[] getSelectedChanges() {
    Set<Change> changes = new LinkedHashSet<Change>();

    final TreePath[] paths = getSelectionPaths();
    if (paths == null) {
      return new Change[0];
    }

    for (TreePath path : paths) {
      ChangesBrowserNode<?> node = (ChangesBrowserNode) path.getLastPathComponent();
      changes.addAll(node.getAllChangesUnder());
    }

    if (changes.isEmpty()) {
      final List<VirtualFile> selectedModifiedWithoutEditing = getSelectedModifiedWithoutEditing();
      if (selectedModifiedWithoutEditing != null && !selectedModifiedWithoutEditing.isEmpty()) {
        for (VirtualFile file : selectedModifiedWithoutEditing) {
          AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file);
          if (vcs == null) continue;
          final VcsCurrentRevisionProxy before =
              VcsCurrentRevisionProxy.create(file, myProject, vcs.getKeyInstanceMethod());
          if (before != null) {
            ContentRevision afterRevision = new CurrentContentRevision(new FilePathImpl(file));
            changes.add(new Change(before, afterRevision, FileStatus.HIJACKED));
          }
        }
      }
    }

    return changes.toArray(new Change[changes.size()]);
  }
 @Override
 public void calcData(DataKey key, DataSink sink) {
   if (key == VcsDataKeys.CHANGES) {
     sink.put(VcsDataKeys.CHANGES, getSelectedChanges());
   } else if (key == VcsDataKeys.CHANGE_LEAD_SELECTION) {
     sink.put(VcsDataKeys.CHANGE_LEAD_SELECTION, getLeadSelection());
   } else if (key == VcsDataKeys.CHANGE_LISTS) {
     sink.put(VcsDataKeys.CHANGE_LISTS, getSelectedChangeLists());
   } else if (key == PlatformDataKeys.VIRTUAL_FILE_ARRAY) {
     sink.put(PlatformDataKeys.VIRTUAL_FILE_ARRAY, getSelectedFiles());
   } else if (key == PlatformDataKeys.NAVIGATABLE) {
     final VirtualFile[] files = getSelectedFiles();
     if (files.length == 1 && !files[0].isDirectory()) {
       sink.put(PlatformDataKeys.NAVIGATABLE, new OpenFileDescriptor(myProject, files[0], 0));
     }
   } else if (key == PlatformDataKeys.NAVIGATABLE_ARRAY) {
     sink.put(
         PlatformDataKeys.NAVIGATABLE_ARRAY,
         ChangesUtil.getNavigatableArray(myProject, getSelectedFiles()));
   } else if (key == PlatformDataKeys.DELETE_ELEMENT_PROVIDER) {
     final TreePath[] paths = getSelectionPaths();
     if (paths != null) {
       for (TreePath path : paths) {
         ChangesBrowserNode node = (ChangesBrowserNode) path.getLastPathComponent();
         if (!(node.getUserObject() instanceof ChangeList)) {
           sink.put(PlatformDataKeys.DELETE_ELEMENT_PROVIDER, new VirtualFileDeleteProvider());
           break;
         }
       }
     }
   } else if (key == PlatformDataKeys.COPY_PROVIDER) {
     sink.put(PlatformDataKeys.COPY_PROVIDER, myCopyProvider);
   } else if (key == UNVERSIONED_FILES_DATA_KEY) {
     sink.put(UNVERSIONED_FILES_DATA_KEY, getSelectedUnversionedFiles());
   } else if (key == VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY) {
     sink.put(VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY, getSelectedModifiedWithoutEditing());
   } else if (key == LOCALLY_DELETED_CHANGES) {
     sink.put(LOCALLY_DELETED_CHANGES, getSelectedLocallyDeletedChanges());
   } else if (key == MISSING_FILES_DATA_KEY) {
     sink.put(MISSING_FILES_DATA_KEY, getSelectedMissingFiles());
   } else if (VcsDataKeys.HAVE_LOCALLY_DELETED == key) {
     sink.put(VcsDataKeys.HAVE_LOCALLY_DELETED, haveLocallyDeleted());
   } else if (VcsDataKeys.HAVE_MODIFIED_WITHOUT_EDITING == key) {
     sink.put(VcsDataKeys.HAVE_MODIFIED_WITHOUT_EDITING, haveLocallyModified());
   } else if (VcsDataKeys.HAVE_SELECTED_CHANGES == key) {
     sink.put(VcsDataKeys.HAVE_SELECTED_CHANGES, haveSelectedChanges());
   } else if (key == HELP_ID_DATA_KEY) {
     sink.put(HELP_ID_DATA_KEY, ourHelpId);
   } else if (key == VcsDataKeys.CHANGES_IN_LIST_KEY) {
     final TreePath selectionPath = getSelectionPath();
     if (selectionPath != null && selectionPath.getPathCount() > 1) {
       ChangesBrowserNode<?> firstNode = (ChangesBrowserNode) selectionPath.getPathComponent(1);
       if (firstNode instanceof ChangesBrowserChangeListNode) {
         final List<Change> list = firstNode.getAllChangesUnder();
         sink.put(VcsDataKeys.CHANGES_IN_LIST_KEY, list);
       }
     }
   }
 }
    @Override
    public void drop(DnDEvent aEvent) {
      Object attached = aEvent.getAttachedObject();
      if (!(attached instanceof ChangeListDragBean)) return;

      final ChangeListDragBean dragBean = (ChangeListDragBean) attached;
      final ChangesBrowserNode changesBrowserNode = dragBean.getTargetNode();
      if (changesBrowserNode != null) {
        changesBrowserNode.acceptDrop(myDragOwner, dragBean);
      }
    }
 protected boolean haveSelectedFileType(final Object tag) {
   final TreePath[] paths = getSelectionPaths();
   if (paths != null) {
     for (TreePath path : paths) {
       if (path.getPathCount() > 1) {
         ChangesBrowserNode firstNode = (ChangesBrowserNode) path.getPathComponent(1);
         if ((tag == null || firstNode.getUserObject() == tag) && path.getPathCount() > 2) {
           return true;
         }
       }
     }
   }
   return false;
 }
 private List<FilePath> getSelectedFilePaths(final Object tag) {
   Set<FilePath> files = new HashSet<FilePath>();
   final TreePath[] paths = getSelectionPaths();
   if (paths != null) {
     for (TreePath path : paths) {
       if (path.getPathCount() > 1) {
         ChangesBrowserNode firstNode = (ChangesBrowserNode) path.getPathComponent(1);
         if (tag == null || firstNode.getUserObject() == tag) {
           ChangesBrowserNode<?> node = (ChangesBrowserNode) path.getLastPathComponent();
           files.addAll(node.getAllFilePathsUnder());
         }
       }
     }
   }
   return new ArrayList<FilePath>(files);
 }
  @NotNull
  private ChangeList[] getSelectedChangeLists() {
    Set<ChangeList> lists = new HashSet<ChangeList>();

    final TreePath[] paths = getSelectionPaths();
    if (paths == null) return new ChangeList[0];

    for (TreePath path : paths) {
      ChangesBrowserNode node = (ChangesBrowserNode) path.getLastPathComponent();
      final Object userObject = node.getUserObject();
      if (userObject instanceof ChangeList) {
        lists.add((ChangeList) userObject);
      }
    }

    return lists.toArray(new ChangeList[lists.size()]);
  }
 private List<LocallyDeletedChange> getSelectedLocallyDeletedChanges() {
   Set<LocallyDeletedChange> files = new HashSet<LocallyDeletedChange>();
   final TreePath[] paths = getSelectionPaths();
   if (paths != null) {
     for (TreePath path : paths) {
       if (path.getPathCount() > 1) {
         ChangesBrowserNode firstNode = (ChangesBrowserNode) path.getPathComponent(1);
         if (firstNode.getUserObject() == TreeModelBuilder.LOCALLY_DELETED_NODE) {
           ChangesBrowserNode<?> node = (ChangesBrowserNode) path.getLastPathComponent();
           final List<LocallyDeletedChange> objectsUnder =
               node.getAllObjectsUnder(LocallyDeletedChange.class);
           files.addAll(objectsUnder);
         }
       }
     }
   }
   return new ArrayList<LocallyDeletedChange>(files);
 }
    public static Image createImage(final JTree tree) {
      final TreeSelectionModel model = tree.getSelectionModel();
      final TreePath[] paths = model.getSelectionPaths();

      int count = 0;
      final List<ChangesBrowserNode> nodes = new ArrayList<ChangesBrowserNode>();
      for (final TreePath path : paths) {
        final ChangesBrowserNode node = (ChangesBrowserNode) path.getLastPathComponent();
        if (!node.isLeaf()) {
          nodes.add(node);
          count += node.getCount();
        }
      }

      for (TreePath path : paths) {
        final ChangesBrowserNode element = (ChangesBrowserNode) path.getLastPathComponent();
        boolean child = false;
        for (final ChangesBrowserNode node : nodes) {
          if (node.isNodeChild(element)) {
            child = true;
            break;
          }
        }

        if (!child) {
          if (element.isLeaf()) count++;
        } else if (!element.isLeaf()) {
          count -= element.getCount();
        }
      }

      final JLabel label = new JLabel(VcsBundle.message("changes.view.dnd.label", count));
      label.setOpaque(true);
      label.setForeground(tree.getForeground());
      label.setBackground(tree.getBackground());
      label.setFont(tree.getFont());
      label.setSize(label.getPreferredSize());
      final BufferedImage image =
          new BufferedImage(label.getWidth(), label.getHeight(), BufferedImage.TYPE_INT_ARGB);

      Graphics2D g2 = (Graphics2D) image.getGraphics();
      g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f));
      label.paint(g2);
      g2.dispose();

      return image;
    }
    @Override
    public boolean update(DnDEvent aEvent) {
      aEvent.hideHighlighter();
      aEvent.setDropPossible(false, "");

      Object attached = aEvent.getAttachedObject();
      if (!(attached instanceof ChangeListDragBean)) return false;

      final ChangeListDragBean dragBean = (ChangeListDragBean) attached;
      if (dragBean.getSourceComponent() != ChangesListView.this) return false;
      dragBean.setTargetNode(null);

      RelativePoint dropPoint = aEvent.getRelativePoint();
      Point onTree = dropPoint.getPoint(ChangesListView.this);
      final TreePath dropPath = getPathForLocation(onTree.x, onTree.y);

      if (dropPath == null) return false;

      ChangesBrowserNode dropNode = (ChangesBrowserNode) dropPath.getLastPathComponent();
      while (!((ChangesBrowserNode) dropNode.getParent()).isRoot()) {
        dropNode = (ChangesBrowserNode) dropNode.getParent();
      }

      if (!dropNode.canAcceptDrop(dragBean)) {
        return false;
      }

      final Rectangle tableCellRect = getPathBounds(new TreePath(dropNode.getPath()));
      if (fitsInBounds(tableCellRect)) {
        aEvent.setHighlighting(
            new RelativeRectangle(ChangesListView.this, tableCellRect),
            DnDEvent.DropTargetHighlightingType.RECTANGLE);
      }

      aEvent.setDropPossible(true);
      dragBean.setTargetNode(dropNode);

      return false;
    }
  private void expandDefaultChangeList(DefaultTreeModel oldModel, ChangesBrowserNode root) {
    if (((ChangesBrowserNode) oldModel.getRoot()).getCount() == 0
        && TreeUtil.collectExpandedPaths(this).size() == 1) {
      TreeNode toExpand = null;
      for (int i = 0; i < root.getChildCount(); i++) {
        TreeNode node = root.getChildAt(i);
        if (node instanceof ChangesBrowserChangeListNode && node.getChildCount() > 0) {
          ChangeList object = ((ChangesBrowserChangeListNode) node).getUserObject();
          if (object instanceof LocalChangeList) {
            if (((LocalChangeList) object).isDefault()) {
              toExpand = node;
              break;
            }
          }
        }
      }

      if (toExpand != null) {
        expandPath(new TreePath(new Object[] {root, toExpand}));
      }
    }
  }
  public ChangesListView(final Project project) {
    myProject = project;

    getModel().setRoot(ChangesBrowserNode.create(myProject, TreeModelBuilder.ROOT_NODE_VALUE));

    setShowsRootHandles(true);
    setRootVisible(false);

    new TreeSpeedSearch(this, new NodeToTextConvertor());
    SmartExpander.installOn(this);
    myCopyProvider = new TreeCopyProvider(this);
    new TreeLinkMouseListener(new ChangesBrowserNodeRenderer(myProject, false, false))
        .installOn(this);
  }
 @Override
 public String convert(final TreePath path) {
   ChangesBrowserNode node = (ChangesBrowserNode) path.getLastPathComponent();
   return node.getTextPresentation();
 }