diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java index afdc835518e1..8193216423be 100644 --- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java +++ b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java @@ -67,7 +67,7 @@ public class PaletteManager implements ProjectComponent { myPaletteWindow, ToolWindowAnchor.RIGHT, myProject, - true); + true, false); myPaletteToolWindow.setIcon(IconLoader.getIcon("/general/toolWindowPalette.png")); myPaletteToolWindow.setAvailable(false, null); final MyFileEditorManagerListener myListener = new MyFileEditorManagerListener(); diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java b/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java index 219be9870c90..732d666fa136 100644 --- a/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java +++ b/platform/lang-api/src/com/intellij/psi/search/PsiSearchHelper.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.Nullable; * * @see com.intellij.psi.PsiManager#getSearchHelper() */ -public interface PsiSearchHelper { +public interface PsiSearchHelper extends PsiTodoSearchHelper { /** * Searches the specified scope for comments containing the specified identifier. * @@ -49,48 +49,6 @@ public interface PsiSearchHelper { */ boolean processCommentsContainingIdentifier(@NotNull String identifier, @NotNull SearchScope searchScope, @NotNull Processor processor); - /** - * Returns the list of all files in the project which have to do items. - * - * @return the list of files with to do items. - */ - @NotNull PsiFile[] findFilesWithTodoItems(); - - /** - * Searches the specified file for to do items. - * - * @param file the file to search for to do items. - * @return the array of found items. - */ - @NotNull TodoItem[] findTodoItems(@NotNull PsiFile file); - - /** - * Searches the specified range of text in the specified file for to do items. - * - * @param file the file to search for to do items. - * @param startOffset the start offset of the text range to search to do items in. - * @param endOffset the end offset of the text range to search to do items in. - * @return the array of found items. - */ - @NotNull TodoItem[] findTodoItems(@NotNull PsiFile file, int startOffset, int endOffset); - - /** - * Returns the number of to do items in the specified file. - * - * @param file the file to return the to do count for. - * @return the count of to do items in the file. - */ - int getTodoItemsCount(@NotNull PsiFile file); - - /** - * Returns the number of to do items matching the specified pattern in the specified file. - * - * @param file the file to return the to do count for. - * @param pattern the pattern of to do items to find. - * @return the count of to do items in the file. - */ - int getTodoItemsCount(@NotNull PsiFile file, @NotNull TodoPattern pattern); - /** * Returns the list of files which contain the specified word in "plain text" * context (for example, plain text files or attribute values in XML files). diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiTodoSearchHelper.java b/platform/lang-api/src/com/intellij/psi/search/PsiTodoSearchHelper.java new file mode 100644 index 000000000000..552b3c85c8bf --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/search/PsiTodoSearchHelper.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2011 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.psi.search; + +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author irengrig + * Date: 2/24/11 + * Time: 10:08 AM + */ +public interface PsiTodoSearchHelper { + /** + * Returns the list of all files in the project which have to do items. + * + * @return the list of files with to do items. + */ + @NotNull + PsiFile[] findFilesWithTodoItems(); + + /** + * Searches the specified file for to do items. + * + * @param file the file to search for to do items. + * @return the array of found items. + */ + @NotNull + TodoItem[] findTodoItems(@NotNull PsiFile file); + + /** + * Searches the specified range of text in the specified file for to do items. + * + * @param file the file to search for to do items. + * @param startOffset the start offset of the text range to search to do items in. + * @param endOffset the end offset of the text range to search to do items in. + * @return the array of found items. + */ + @NotNull + TodoItem[] findTodoItems(@NotNull PsiFile file, int startOffset, int endOffset); + + /** + * Returns the number of to do items in the specified file. + * + * @param file the file to return the to do count for. + * @return the count of to do items in the file. + */ + int getTodoItemsCount(@NotNull PsiFile file); + + /** + * Returns the number of to do items matching the specified pattern in the specified file. + * + * @param file the file to return the to do count for. + * @param pattern the pattern of to do items to find. + * @return the count of to do items in the file. + */ + int getTodoItemsCount(@NotNull PsiFile file, @NotNull TodoPattern pattern); +} diff --git a/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodoTreeStructure.java b/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodoTreeStructure.java new file mode 100644 index 000000000000..92d4b4faf7ab --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodoTreeStructure.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2011 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.ide.todo; + +import com.intellij.ide.todo.nodes.ToDoRootNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.PsiTodoSearchHelper; + +/** + * @author irengrig + * Date: 2/21/11 + * Time: 4:28 PM + */ +public class CustomChangelistTodoTreeStructure extends TodoTreeStructure { + private final PsiTodoSearchHelper mySearchHelper; + + public CustomChangelistTodoTreeStructure(Project project, PsiTodoSearchHelper searchHelper) { + super(project); + mySearchHelper = searchHelper; + } + + public boolean accept(final PsiFile psiFile) { + if (! psiFile.isValid()) return false; + return mySearchHelper.getTodoItemsCount(psiFile) > 0; + } + + public boolean getIsPackagesShown() { + return myArePackagesShown; + } + + Object getFirstSelectableElement() { + return ((ToDoRootNode)myRootElement).getSummaryNode(); + } + + protected AbstractTreeNode createRootElement() { + return new ToDoRootNode(myProject, new Object(), myBuilder, mySummaryElement); + } + + @Override + public PsiTodoSearchHelper getSearchHelper() { + return mySearchHelper; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java b/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java new file mode 100644 index 000000000000..55c8538271f6 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/todo/CustomChangelistTodosTreeBuilder.java @@ -0,0 +1,187 @@ +/* + * Copyright 2000-2011 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.ide.todo; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.LocalChangeList; +import com.intellij.openapi.vcs.checkin.TodoCheckinHandlerWorker; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.PsiTodoSearchHelper; +import com.intellij.psi.search.TodoItem; +import com.intellij.psi.search.TodoPattern; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.tree.DefaultTreeModel; +import java.util.*; + +/** + * @author irengrig + * Date: 2/21/11 + * Time: 5:14 PM + */ +public class CustomChangelistTodosTreeBuilder extends TodoTreeBuilder { + public static final TodoItem[] EMPTY_ITEMS = new TodoItem[0]; + private final Project myProject; + private final String myTitle; + private final MultiMap myMap; + private final Set myIncludedFiles; + private PsiTodoSearchHelper myPsiTodoSearchHelper; + private ChangeListManager myChangeListManager; + + public CustomChangelistTodosTreeBuilder(JTree tree, DefaultTreeModel treeModel, Project project, final String title, + final List list) { + super(tree, treeModel, project); + myProject = project; + myTitle = title; + myMap = new MultiMap(); + myIncludedFiles = new HashSet(); + myChangeListManager = ChangeListManager.getInstance(myProject); + initMap(list); + initHelper(); + } + + private void initMap(List list) { + buildMap(list); + myIncludedFiles.addAll(myMap.keySet()); + } + + private void buildMap(List list) { + for (TodoItem todoItem : list) { + myMap.putValue(todoItem.getFile(), todoItem); + } + } + + private void initHelper() { + myPsiTodoSearchHelper = new PsiTodoSearchHelper() { + @NotNull + @Override + public PsiFile[] findFilesWithTodoItems() { + final List changes = new ArrayList(); + final List changeLists = myChangeListManager.getChangeLists(); + final Map allChanges = new HashMap(); + for (LocalChangeList changeList : changeLists) { + final Collection currChanges = changeList.getChanges(); + for (Change currChange : currChanges) { + if (currChange.getAfterRevision() != null && currChange.getAfterRevision().getFile().getVirtualFile() != null) { + allChanges.put(currChange.getAfterRevision().getFile().getVirtualFile(), currChange); + } + } + } + for (Iterator iterator = myIncludedFiles.iterator(); iterator.hasNext(); ) { + final PsiFile next = iterator.next(); + final Change change = allChanges.get(next.getVirtualFile()); + if (change != null) { + changes.add(change); + } + } + // a hack here with _todo filter + final TodoCheckinHandlerWorker worker = new TodoCheckinHandlerWorker(myProject, changes, getTodoTreeStructure().getTodoFilter(), true); + worker.execute(); + buildMap(worker.inOneList()); + + final Set files = myMap.keySet(); + return files.toArray(new PsiFile[files.size()]); + } + + @NotNull + @Override + public TodoItem[] findTodoItems(@NotNull PsiFile file) { + if (! myIncludedFiles.contains(file)) return EMPTY_ITEMS; + if (myDirtyFileSet.contains(file.getVirtualFile())) { + myMap.remove(file); + final Change change = myChangeListManager.getChange(file.getVirtualFile()); + if (change != null) { + final TodoCheckinHandlerWorker worker = new TodoCheckinHandlerWorker(myProject, Collections.singletonList(change), getTodoTreeStructure().getTodoFilter(), true); + worker.execute(); + final List todoItems = worker.inOneList(); + if (todoItems != null && ! todoItems.isEmpty()) { + for (TodoItem todoItem : todoItems) { + myMap.putValue(file, todoItem); + } + } + } + } + final Collection todoItems = myMap.get(file); + return todoItems == null || todoItems.isEmpty() ? EMPTY_ITEMS : todoItems.toArray(new TodoItem[todoItems.size()]); + } + + @NotNull + @Override + public TodoItem[] findTodoItems(@NotNull PsiFile file, int startOffset, int endOffset) { + final TodoItem[] todoItems = findTodoItems(file); + if (todoItems.length == 0) { + return todoItems; + } + final TextRange textRange = new TextRange(startOffset, endOffset); + final List result = new ArrayList(); + for (TodoItem todoItem : todoItems) { + if (todoItem.getTextRange().contains(textRange)) { + result.add(todoItem); + } + } + return result.isEmpty() ? EMPTY_ITEMS : result.toArray(new TodoItem[result.size()]); + } + + @Override + public int getTodoItemsCount(@NotNull PsiFile file) { + return findTodoItems(file).length; + } + + @Override + public int getTodoItemsCount(@NotNull PsiFile file, @NotNull TodoPattern pattern) { + throw new UnsupportedOperationException(); + // just would not work while implemented like that + /*final TodoItem[] todoItems = findTodoItems(file); + if (todoItems.length == 0) return 0; + int cnt = 0; + for (TodoItem todoItem : todoItems) { + if (todoItem.getPattern().equals(pattern)) ++ cnt; + } + return cnt;*/ + } + }; + } + + @Override + protected TodoTreeStructure createTreeStructure() { + return new CustomChangelistTodoTreeStructure(myProject, myPsiTodoSearchHelper); + } + + @Override + void rebuildCache() { + myMap.clear(); + myFileTree.clear(); + myDirtyFileSet.clear(); + myFile2Highlighter.clear(); + + TodoTreeStructure treeStructure=getTodoTreeStructure(); + PsiFile[] psiFiles= myPsiTodoSearchHelper.findFilesWithTodoItems(); + for(int i=0;i 0 && treeStructure.accept(psiFile)){ + myFileTree.add(psiFile.getVirtualFile()); + } + } + + treeStructure.validateCache(); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/todo/SetTodoFilterAction.java b/platform/lang-impl/src/com/intellij/ide/todo/SetTodoFilterAction.java new file mode 100644 index 000000000000..53436890e5f4 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/todo/SetTodoFilterAction.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2011 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.ide.todo; + +import com.intellij.ide.IdeBundle; +import com.intellij.ide.todo.configurable.TodoConfigurable; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.actionSystem.impl.ActionButton; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.IconLoader; +import com.intellij.util.Consumer; + +import javax.swing.*; + +/** +* @author irengrig +* Date: 2/24/11 +* Time: 3:38 PM + * moved from inner class +*/ +public class SetTodoFilterAction extends AnAction implements CustomComponentAction { + private final Project myProject; + private final TodoPanelSettings myToDoSettings; + private final Consumer myTodoFilterConsumer; + + public SetTodoFilterAction(final Project project, final TodoPanelSettings toDoSettings, final Consumer todoFilterConsumer) { + super(IdeBundle.message("action.filter.todo.items"), null, IconLoader.getIcon("/ant/filter.png")); + myProject = project; + myToDoSettings = toDoSettings; + myTodoFilterConsumer = todoFilterConsumer; + } + + public void actionPerformed(AnActionEvent e) { + Presentation presentation = e.getPresentation(); + JComponent button = (JComponent)presentation.getClientProperty("button"); + DefaultActionGroup group = createPopupActionGroup(); + ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.TODO_VIEW_TOOLBAR, + group); + popupMenu.getComponent().show(button, button.getWidth(), 0); + } + + public JComponent createCustomComponent(Presentation presentation) { + ActionButton button = new ActionButton( + this, + presentation, + ActionPlaces.TODO_VIEW_TOOLBAR, + ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE + ); + presentation.putClientProperty("button", button); + return button; + } + + private DefaultActionGroup createPopupActionGroup() { + TodoFilter[] filters = TodoConfiguration.getInstance().getTodoFilters(); + DefaultActionGroup group = new DefaultActionGroup(); + group.add(new TodoFilterApplier(IdeBundle.message("action.todo.show.all"), + IdeBundle.message("action.description.todo.show.all"), null)); + for (TodoFilter filter : filters) { + group.add(new TodoFilterApplier(filter.getName(), null, filter)); + } + group.addSeparator(); + group.add( + new AnAction(IdeBundle.message("action.todo.edit.filters"), + IdeBundle.message("action.todo.edit.filters"), IconLoader.getIcon("/general/ideOptions.png")) { + public void actionPerformed(AnActionEvent e) { + final ShowSettingsUtil util = ShowSettingsUtil.getInstance(); + util.editConfigurable(myProject, new TodoConfigurable()); + } + } + ); + return group; + } + + private class TodoFilterApplier extends ToggleAction { + private final TodoFilter myFilter; + + /** + * @param text action's text. + * @param description action's description. + * @param filter filter to be applied. null value means "empty" filter. + */ + TodoFilterApplier(String text, String description, TodoFilter filter) { + super(null, description, null); + getTemplatePresentation().setText(text, false); + myFilter = filter; + } + + public void update(AnActionEvent e) { + super.update(e); + if (myFilter != null) { + e.getPresentation().setEnabled(!myFilter.isEmpty()); + } + } + + public boolean isSelected(AnActionEvent e) { + return Comparing.equal(myFilter != null ? myFilter.getName() : null, myToDoSettings.getTodoFilterName()); + } + + public void setSelected(AnActionEvent e, boolean state) { + if (state) { + myTodoFilterConsumer.consume(myFilter); + //setTodoFilter(myFilter); + } + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java b/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java index e59e4dca73e9..b1797eab8b10 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java @@ -23,21 +23,16 @@ import com.intellij.ide.TreeExpander; import com.intellij.ide.actions.ContextHelpAction; import com.intellij.ide.actions.NextOccurenceToolbarAction; import com.intellij.ide.actions.PreviousOccurenceToolbarAction; -import com.intellij.ide.todo.configurable.TodoConfigurable; import com.intellij.ide.todo.nodes.TodoFileNode; import com.intellij.ide.todo.nodes.TodoItemNode; import com.intellij.ide.todo.nodes.TodoTreeHelper; import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.CustomComponentAction; -import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.OpenFileDescriptor; -import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; @@ -52,6 +47,7 @@ import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.content.Content; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.Consumer; import com.intellij.util.EditSourceOnDoubleClickHandler; import com.intellij.util.Icons; import com.intellij.util.OpenSourceUtil; @@ -195,7 +191,12 @@ abstract class TodoPanel extends SimpleToolWindowPanel implements OccurenceNavig autoScrollToSourceHandler.install(myTree); rightGroup.add(autoScrollToSourceHandler.createToggleAction()); - MySetTodoFilterAction setTodoFilterAction = new MySetTodoFilterAction(); + SetTodoFilterAction setTodoFilterAction = new SetTodoFilterAction(myProject, mySettings, new Consumer() { + @Override + public void consume(TodoFilter todoFilter) { + setTodoFilter(todoFilter); + } + }); rightGroup.add(setTodoFilterAction); toolBarPanel.add( ActionManager.getInstance().createActionToolbar(ActionPlaces.TODO_VIEW_TOOLBAR, rightGroup, false).getComponent()); @@ -566,85 +567,6 @@ abstract class TodoPanel extends SimpleToolWindowPanel implements OccurenceNavig } } - private final class MySetTodoFilterAction extends AnAction implements CustomComponentAction { - MySetTodoFilterAction() { - super(IdeBundle.message("action.filter.todo.items"), null, IconLoader.getIcon("/ant/filter.png")); - } - - public void actionPerformed(AnActionEvent e) { - Presentation presentation = e.getPresentation(); - JComponent button = (JComponent)presentation.getClientProperty("button"); - DefaultActionGroup group = createPopupActionGroup(); - ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.TODO_VIEW_TOOLBAR, - group); - popupMenu.getComponent().show(button, button.getWidth(), 0); - } - - public JComponent createCustomComponent(Presentation presentation) { - ActionButton button = new ActionButton( - this, - presentation, - ActionPlaces.TODO_VIEW_TOOLBAR, - ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE - ); - presentation.putClientProperty("button", button); - return button; - } - - private DefaultActionGroup createPopupActionGroup() { - TodoFilter[] filters = TodoConfiguration.getInstance().getTodoFilters(); - DefaultActionGroup group = new DefaultActionGroup(); - group.add(new TodoFilterApplier(IdeBundle.message("action.todo.show.all"), - IdeBundle.message("action.description.todo.show.all"), null)); - for (TodoFilter filter : filters) { - group.add(new TodoFilterApplier(filter.getName(), null, filter)); - } - group.addSeparator(); - group.add( - new AnAction(IdeBundle.message("action.todo.edit.filters"), - IdeBundle.message("action.todo.edit.filters"), IconLoader.getIcon("/general/ideOptions.png")) { - public void actionPerformed(AnActionEvent e) { - final ShowSettingsUtil util = ShowSettingsUtil.getInstance(); - util.editConfigurable(myProject, new TodoConfigurable()); - } - } - ); - return group; - } - - private final class TodoFilterApplier extends ToggleAction { - private final TodoFilter myFilter; - - /** - * @param text action's text. - * @param description action's description. - * @param filter filter to be applied. null value means "empty" filter. - */ - TodoFilterApplier(String text, String description, TodoFilter filter) { - super(null, description, null); - getTemplatePresentation().setText(text, false); - myFilter = filter; - } - - public void update(AnActionEvent e) { - super.update(e); - if (myFilter != null) { - e.getPresentation().setEnabled(!myFilter.isEmpty()); - } - } - - public boolean isSelected(AnActionEvent e) { - return Comparing.equal(myFilter != null ? myFilter.getName() : null, mySettings.getTodoFilterName()); - } - - public void setSelected(AnActionEvent e, boolean state) { - if (state) { - setTodoFilter(myFilter); - } - } - } - } - private final class MyVisibilityWatcher extends VisibilityWatcher { public void visibilityChanged() { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); diff --git a/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeBuilderFactory.java b/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeBuilderFactory.java new file mode 100644 index 000000000000..580f950c064e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeBuilderFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2011 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.ide.todo; + +import com.intellij.openapi.project.Project; + +import javax.swing.*; +import javax.swing.tree.DefaultTreeModel; + +/** + * @author irengrig + * Date: 2/24/11 + * Time: 10:51 AM + */ +public interface TodoTreeBuilderFactory { + TodoTreeBuilder createTreeBuilder(JTree tree,DefaultTreeModel treeModel,Project project); +} diff --git a/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeStructure.java b/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeStructure.java index 36ccbc56b7eb..e0c8a4a94236 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeStructure.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/TodoTreeStructure.java @@ -25,6 +25,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.PsiTodoSearchHelper; import com.intellij.psi.search.TodoPattern; import java.util.Collections; @@ -111,10 +112,10 @@ public abstract class TodoTreeStructure extends AbstractTreeStructureBase implem if(myTodoFilter!=null){ for(Iterator i=myTodoFilter.iterator();i.hasNext();){ TodoPattern pattern=(TodoPattern)i.next(); - count+=mySearchHelper.getTodoItemsCount(psiFile,pattern); + count+=getSearchHelper().getTodoItemsCount(psiFile,pattern); } }else{ - count=mySearchHelper.getTodoItemsCount(psiFile); + count=getSearchHelper().getTodoItemsCount(psiFile); } } return count; @@ -141,7 +142,7 @@ public abstract class TodoTreeStructure extends AbstractTreeStructureBase implem return myFlattenPackages; } - public PsiSearchHelper getSearchHelper() { + public PsiTodoSearchHelper getSearchHelper() { return mySearchHelper; } diff --git a/platform/lang-impl/src/com/intellij/ide/todo/TodoView.java b/platform/lang-impl/src/com/intellij/ide/todo/TodoView.java index 31f5028634f6..566ea076569a 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/TodoView.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/TodoView.java @@ -47,6 +47,8 @@ import javax.swing.*; import javax.swing.tree.DefaultTreeModel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; /** * @author Vladimir Kondratyev @@ -67,6 +69,8 @@ public class TodoView implements PersistentStateComponent, Disposable { private CurrentFileTodosPanel myCurrentFileTodos; private TodoPanel myAllTodos; private ChangeListTodosPanel myChangeListTodos; + private final List myPanels; + private final List myNotAddedContent; private int mySelectedIndex; private final TodoPanelSettings myCurrentPanelSettings; @@ -90,6 +94,8 @@ public class TodoView implements PersistentStateComponent, Disposable { myCurrentPanelSettings=new TodoPanelSettings(); myAllPanelSettings=new TodoPanelSettings(); myChangeListTodosPanelSettings = new TodoPanelSettings(); + myPanels = new ArrayList(); + myNotAddedContent = new ArrayList(); myVCSManager.addVcsListener(myVcsListener); @@ -204,16 +210,26 @@ public class TodoView implements PersistentStateComponent, Disposable { myVcsListener.myIsVisible = true; myContentManager.addContent(myChangeListTodosContent); } + for (Content content : myNotAddedContent) { + myContentManager.addContent(content); + } + myChangeListTodosContent.setCloseable(false); + allTodosContent.setCloseable(false); + currentFileTodosContent.setCloseable(false); Content content=myContentManager.getContent(mySelectedIndex); content = content == null ? allTodosContent : content; myContentManager.setSelectedContent(content); + + myPanels.add(myAllTodos); + myPanels.add(myChangeListTodos); + myPanels.add(myCurrentFileTodos); } private final class MyVcsListener implements VcsListener { private boolean myIsVisible; - public void directoryMappingChanged() { + public void directoryMappingChanged() { // todo ? ApplicationManager.getApplication().invokeLater(new Runnable(){ public void run() { if (myContentManager == null) return; //was not initialized yet @@ -255,9 +271,9 @@ public class TodoView implements PersistentStateComponent, Disposable { } private void updateFilters(){ - myCurrentFileTodos.updateTodoFilter(); - myAllTodos.updateTodoFilter(); - myChangeListTodos.updateTodoFilter(); + for (TodoPanel panel : myPanels) { + panel.updateTodoFilter(); + } } } @@ -279,17 +295,17 @@ public class TodoView implements PersistentStateComponent, Disposable { ApplicationManager.getApplication().runReadAction( new Runnable(){ public void run(){ - myAllTodos.rebuildCache(); - myCurrentFileTodos.rebuildCache(); - myChangeListTodos.rebuildCache(); + for (TodoPanel panel : myPanels) { + panel.rebuildCache(); + } } } ); ApplicationManager.getApplication().invokeLater(new Runnable(){ public void run(){ - myAllTodos.updateTree(); - myCurrentFileTodos.updateTree(); - myChangeListTodos.updateTree(); + for (TodoPanel panel : myPanels) { + panel.updateTree(); + } } }, ModalityState.NON_MODAL); } @@ -298,4 +314,32 @@ public class TodoView implements PersistentStateComponent, Disposable { }); } } + + public void addCustomTodoView(final TodoTreeBuilderFactory factory, final String title, final TodoPanelSettings settings) { + final Content content = ContentFactory.SERVICE.getInstance().createContent(null, title, true); + final ChangeListTodosPanel panel = new ChangeListTodosPanel(myProject, settings, content) { + @Override + protected TodoTreeBuilder createTreeBuilder(JTree tree, DefaultTreeModel treeModel, Project project) { + final TodoTreeBuilder todoTreeBuilder = factory.createTreeBuilder(tree, treeModel, project); + todoTreeBuilder.init(); + return todoTreeBuilder; + } + }; + content.setComponent(panel); + Disposer.register(this, panel); + + if (myContentManager != null) { + myContentManager.addContent(content); + } else { + myNotAddedContent.add(content); + } + myPanels.add(panel); + content.setCloseable(true); + content.setDisposer(new Disposable() { + @Override + public void dispose() { + myPanels.remove(panel); + } + }); + } } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java index 89d0f3157c80..b4ef6e0cf52a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java @@ -16,52 +16,37 @@ package com.intellij.openapi.vcs.checkin; import com.intellij.CommonBundle; -import com.intellij.openapi.application.Application; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.todo.*; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.diff.ex.DiffFragment; -import com.intellij.openapi.diff.impl.ComparisonPolicy; -import com.intellij.openapi.diff.impl.DiffUtil; -import com.intellij.openapi.diff.impl.fragments.Fragment; -import com.intellij.openapi.diff.impl.fragments.LineFragment; -import com.intellij.openapi.diff.impl.highlighting.FragmentSide; -import com.intellij.openapi.diff.impl.processing.DiffCorrection; -import com.intellij.openapi.diff.impl.processing.DiffFragmentsProcessor; -import com.intellij.openapi.diff.impl.processing.DiffPolicy; -import com.intellij.openapi.diff.impl.processing.TextCompareProcessor; -import com.intellij.openapi.diff.impl.util.TextDiffType; -import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.*; +import com.intellij.openapi.vcs.CheckinProjectPanel; +import com.intellij.openapi.vcs.VcsBundle; +import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.CommitExecutor; -import com.intellij.openapi.vcs.checkin.CheckinHandler; import com.intellij.openapi.vcs.ui.RefreshableOnComponent; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileFactory; -import com.intellij.psi.PsiManager; -import com.intellij.psi.impl.search.PsiSearchHelperImpl; -import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.psi.search.TodoItem; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentManager; +import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; -import com.intellij.util.SmartList; -import com.intellij.util.containers.Convertor; +import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; -import sun.util.LocaleServiceProviderPool; import javax.swing.*; -import java.awt.*; -import java.util.*; -import java.util.List; -import java.util.concurrent.Callable; +import javax.swing.tree.DefaultTreeModel; +import java.util.Collection; /** * @author irengrig @@ -72,6 +57,7 @@ public class TodoCheckinHandler extends CheckinHandler { private final Project myProject; private final CheckinProjectPanel myCheckinProjectPanel; private VcsConfiguration myConfiguration; + private TodoFilter myTodoFilter; private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.checkin.TodoCheckinHandler"); public TodoCheckinHandler(CheckinProjectPanel checkinProjectPanel) { @@ -82,15 +68,40 @@ public class TodoCheckinHandler extends CheckinHandler { @Override public RefreshableOnComponent getBeforeCheckinConfigurationPanel() { - final JCheckBox checkBox = new JCheckBox(VcsBundle.message("before.checkin.new.todo.check")); + final JCheckBox checkBox = new JCheckBox(VcsBundle.message("before.checkin.new.todo.check", "")); return new RefreshableOnComponent() { public JComponent getComponent() { - JPanel panel = new JPanel(new BorderLayout()); + JPanel panel = new JPanel(); + final BoxLayout boxLayout = new BoxLayout(panel, BoxLayout.X_AXIS); + panel.setLayout(boxLayout); panel.add(checkBox); + setFilterText(myConfiguration.myTodoPanelSettings.getTodoFilterName()); + if (myConfiguration.myTodoPanelSettings.getTodoFilterName() != null) { + myTodoFilter = TodoConfiguration.getInstance().getTodoFilter(myConfiguration.myTodoPanelSettings.getTodoFilterName()); + } + final DefaultActionGroup group = new DefaultActionGroup(); + group.add(new SetTodoFilterAction(myProject, myConfiguration.myTodoPanelSettings, new Consumer() { + @Override + public void consume(TodoFilter todoFilter) { + myTodoFilter = todoFilter; + final String name = todoFilter == null ? null : todoFilter.getName(); + myConfiguration.myTodoPanelSettings.setTodoFilterName(name); + setFilterText(name); + } + })); + panel.add(ActionManager.getInstance().createActionToolbar("commit dialog todo handler", group, true).getComponent()); refreshEnable(checkBox); return panel; } + private void setFilterText(final String filterName) { + if (filterName == null) { + checkBox.setText(VcsBundle.message("before.checkin.new.todo.check", IdeBundle.message("action.todo.show.all"))); + } else { + checkBox.setText(VcsBundle.message("before.checkin.new.todo.check", "Filter: " + filterName)); + } + } + public void refresh() { } @@ -118,7 +129,7 @@ public class TodoCheckinHandler extends CheckinHandler { public ReturnResult beforeCheckin(@Nullable CommitExecutor executor, PairConsumer additionalDataConsumer) { if (! myConfiguration.CHECK_NEW_TODO) return ReturnResult.COMMIT; if (DumbService.getInstance(myProject).isDumb()) { - final String todoName = VcsBundle.message("before.checkin.new.todo.check"); + final String todoName = VcsBundle.message("before.checkin.new.todo.check.title"); if (Messages.showDialog(myProject, todoName + " can't be performed while IntelliJ IDEA updates the indices in background.\n" + @@ -130,11 +141,8 @@ public class TodoCheckinHandler extends CheckinHandler { return ReturnResult.COMMIT; } final Collection changes = myCheckinProjectPanel.getSelectedChanges(); - final TodoCheckinHandlerWorker worker = new TodoCheckinHandlerWorker(myProject, changes); + final TodoCheckinHandlerWorker worker = new TodoCheckinHandlerWorker(myProject, changes, myTodoFilter, true); - // todo: progress, read actions, exceptions handling (report !), report "bad" files - // todo: special pattern - // todo: report window final Runnable runnable = new Runnable() { public void run() { worker.execute(); @@ -147,34 +155,48 @@ public class TodoCheckinHandler extends CheckinHandler { return showResults(worker, executor); } - private ReturnResult showResults(TodoCheckinHandlerWorker worker, CommitExecutor executor) { + private ReturnResult showResults(final TodoCheckinHandlerWorker worker, CommitExecutor executor) { String commitButtonText = executor != null ? executor.getActionText() : myCheckinProjectPanel.getCommitActionName(); if (commitButtonText.endsWith("...")) { commitButtonText = commitButtonText.substring(0, commitButtonText.length()-3); } - final StringBuilder text = new StringBuilder(); - if (worker.getAddedOrEditedTodos().isEmpty() && worker.getInChangedTodos().isEmpty()) { - text.append("No new, edited, or located in changed fragments TODO items found.\n").append(worker.getSkipped().size()) - .append(" file(s) were skipped.\nWould you like to review them?"); - } else { - if (worker.getAddedOrEditedTodos().isEmpty()) { - text.append("There were ").append(worker.getInChangedTodos().size()).append(" located in changed fragments TODO item(s) found.\n"); - } else if (worker.getInChangedTodos().isEmpty()) { - text.append("There were ").append(worker.getAddedOrEditedTodos().size()).append(" added or edited TODO item(s) found.\n"); - } else { - text.append("There were ").append(worker.getAddedOrEditedTodos().size()).append(" added or edited,\nand ") - .append(worker.getInChangedTodos().size()).append(" located in changed fragments TODO item(s) found.\n"); - } - if (! worker.getSkipped().isEmpty()) { - text.append(worker.getSkipped().size()).append(" file(s) were skipped.\n"); - } - text.append("Would you like to review them?"); - } - - final int answer = Messages.showDialog(text.toString(), "TODO", new String[]{VcsBundle.message("todo.in.new.review.button"), - commitButtonText, CommonBundle.getCancelButtonText()}, 0, UIUtil.getWarningIcon()); + final String text = createMessage(worker); + final String[] buttons = worker.getAddedOrEditedTodos().size() + worker.getInChangedTodos().size() > 0 ? + new String[] {VcsBundle.message("todo.in.new.review.button"), commitButtonText, CommonBundle.getCancelButtonText()} : + new String[] {commitButtonText, CommonBundle.getCancelButtonText()}; + final int answer = Messages.showDialog(text, "TODO", buttons, 0, UIUtil.getWarningIcon()); if (answer == 0) { + TodoView todoView = ServiceManager.getService(myProject, TodoView.class); + final String title = "For commit (" + DateFormatUtil.formatDateTime(System.currentTimeMillis()) + ")"; + todoView.addCustomTodoView(new TodoTreeBuilderFactory() { + @Override + public TodoTreeBuilder createTreeBuilder(JTree tree, DefaultTreeModel treeModel, Project project) { + return new CustomChangelistTodosTreeBuilder(tree, treeModel, myProject, title, worker.inOneList()); + } + }, title, new TodoPanelSettings(myConfiguration.myTodoPanelSettings)); + + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final ToolWindowManager manager = ToolWindowManager.getInstance(myProject); + if (manager != null) { + final ToolWindow window = manager.getToolWindow("TODO"); + if (window != null) { + window.show(new Runnable() { + @Override + public void run() { + final ContentManager cm = window.getContentManager(); + final Content[] contents = cm.getContents(); + if (contents.length > 0) { + cm.setSelectedContent(contents[contents.length - 1], true); + } + } + }); + } + } + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); // show for review return ReturnResult.CLOSE_WINDOW; } @@ -185,4 +207,35 @@ public class TodoCheckinHandler extends CheckinHandler { return ReturnResult.COMMIT; } } + + private static String createMessage(TodoCheckinHandlerWorker worker) { + final StringBuilder text = new StringBuilder(""); + if (worker.getAddedOrEditedTodos().isEmpty() && worker.getInChangedTodos().isEmpty()) { + text.append("No new, edited, or located in changed fragments TODO items found.
").append(worker.getSkipped().size()) + .append(" file(s) were skipped."); + } else { + final int inChanged = worker.getInChangedTodos().size(); + final int added = worker.getAddedOrEditedTodos().size(); + if (added == 0) { + text.append("There ").append(wereWas(inChanged)).append(inChanged).append(" located in changed fragments TODO item(s) found.
"); + } else { + if (inChanged == 0) { + text.append("There ").append(wereWas(added)).append(added).append(" added or edited TODO item(s) found.
"); + } else { + text.append("There were ").append(added).append(" added or edited,
and ") + .append(inChanged).append(" located in changed fragments TODO item(s) found.
"); + } + } + if (! worker.getSkipped().isEmpty()) { + text.append(worker.getSkipped().size()).append(" file(s) were skipped.
"); + } + text.append("Would you like to review them?"); + } + text.append(""); + return text.toString(); + } + + private static String wereWas(final int num) { + return num == 1 ? "was " : "were "; + } } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java index 4a89f8da1d11..0479b436a1bd 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.checkin; +import com.intellij.ide.todo.TodoFilter; import com.intellij.ide.todo.TodoIndexPatternProvider; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.ex.DiffFragment; @@ -58,6 +59,8 @@ public class TodoCheckinHandlerWorker { private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.checkin.TodoCheckinHandler"); private final Collection changes; + private final TodoFilter myTodoFilter; + private final boolean myIncludePattern; private final PsiManager myPsiManager; private final PsiSearchHelper mySearchHelper; @@ -69,8 +72,11 @@ public class TodoCheckinHandlerWorker { private MyEditedFileProcessor myEditedFileProcessor; - public TodoCheckinHandlerWorker(final Project project, final Collection changes) { + public TodoCheckinHandlerWorker(final Project project, final Collection changes, final TodoFilter todoFilter, + final boolean includePattern) { this.changes = changes; + myTodoFilter = todoFilter; + myIncludePattern = includePattern; myPsiManager = PsiManager.getInstance(project); mySearchHelper = myPsiManager.getSearchHelper(); myAddedOrEditedTodos = new ArrayList(); @@ -91,7 +97,7 @@ public class TodoCheckinHandlerWorker { public void inChanged(TodoItem todoItem) { myInChangedTodos.add(todoItem); } - }); + }, myTodoFilter); } public void execute() { @@ -110,7 +116,8 @@ public class TodoCheckinHandlerWorker { continue; } - myNewTodoItems = Arrays.asList(mySearchHelper.findTodoItems(myPsiFile)); + myNewTodoItems = new ArrayList(Arrays.asList(mySearchHelper.findTodoItems(myPsiFile))); + applyFilterAndRemoveDuplicates(myNewTodoItems, myTodoFilter); if (change.getBeforeRevision() == null) { // take just all todos if (myNewTodoItems.isEmpty()) continue; @@ -122,6 +129,22 @@ public class TodoCheckinHandlerWorker { } } + private static void applyFilterAndRemoveDuplicates(final List todoItems, final TodoFilter filter) { + TodoItem previous = null; + for (Iterator iterator = todoItems.iterator(); iterator.hasNext(); ) { + final TodoItem next = iterator.next(); + if (filter != null && ! filter.contains(next.getPattern())) { + iterator.remove(); + continue; + } + if (previous != null && next.getTextRange().equals(previous.getTextRange())) { + iterator.remove(); + } else { + previous = next; + } + } + } + private static class MyEditedFileProcessor { //private String myFileText; private String myBeforeContent; @@ -133,9 +156,11 @@ public class TodoCheckinHandlerWorker { private final PsiFileFactory myPsiFileFactory; private FilePath myAfterFile; private final Acceptor myAcceptor; + private final TodoFilter myTodoFilter; - private MyEditedFileProcessor(final Project project, Acceptor acceptor) { + private MyEditedFileProcessor(final Project project, Acceptor acceptor, final TodoFilter todoFilter) { myAcceptor = acceptor; + myTodoFilter = todoFilter; myPsiFileFactory = PsiFileFactory.getInstance(project); } @@ -209,6 +234,7 @@ public class TodoCheckinHandlerWorker { for (IndexPatternOccurrence occurrence : all) { myOldItems.add(todoItemsCreator.createTodo(occurrence)); } + applyFilterAndRemoveDuplicates(myOldItems, myTodoFilter); } if (myOldTodoTexts == null) { final StepIntersection intersection = new StepIntersection( @@ -272,7 +298,8 @@ public class TodoCheckinHandlerWorker { @Override public TextRange convert(TodoItem o) { - return o.getTextRange(); + final TextRange textRange = o.getTextRange(); + return new TextRange(textRange.getStartOffset(), textRange.getEndOffset() - 1); } } @@ -285,7 +312,15 @@ public class TodoCheckinHandlerWorker { @Override public TextRange convert(LineFragment o) { - return o.getRange(FragmentSide.SIDE2); + final TextRange textRange = o.getRange(FragmentSide.SIDE2); + return new TextRange(textRange.getStartOffset(), textRange.getEndOffset() - 1); } } + + public List inOneList() { + final List list = new ArrayList(); + list.addAll(getAddedOrEditedTodos()); + list.addAll(getInChangedTodos()); + return list; + } } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowEP.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowEP.java index 5db6a20c1b44..1f593483f295 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowEP.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowEP.java @@ -51,6 +51,9 @@ public class ToolWindowEP extends AbstractExtensionPointBean { @Attribute("secondary") public boolean secondary; + @Attribute("canCloseContents") + public boolean canCloseContents; + private ToolWindowFactory myFactory; public ToolWindowFactory getToolWindowFactory() { diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java index 38481d8a9e9d..6b6bc2187738 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java @@ -16,8 +16,8 @@ package com.intellij.openapi.wm; import com.intellij.openapi.Disposable; -import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,7 +54,12 @@ public abstract class ToolWindowManager { /** * @deprecated {@link com.intellij.openapi.wm.ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} */ - public abstract ToolWindow registerToolWindow(@NotNull String id,@NotNull JComponent component,@NotNull ToolWindowAnchor anchor, Disposable parentDisposable, boolean canWorkInDumbMode); + public abstract ToolWindow registerToolWindow(@NotNull String id, + @NotNull JComponent component, + @NotNull ToolWindowAnchor anchor, + Disposable parentDisposable, + boolean canWorkInDumbMode, + boolean canCloseContents); public abstract ToolWindow registerToolWindow(@NotNull String id, boolean canCloseContent, @NotNull ToolWindowAnchor anchor); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index 6d976bc72805..7779474e25c3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -251,7 +251,12 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return HEADLESS_WINDOW; } - public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, Disposable parentDisposable, boolean canWorkInDumbMode) { + public ToolWindow registerToolWindow(@NotNull String id, + @NotNull JComponent component, + @NotNull ToolWindowAnchor anchor, + Disposable parentDisposable, + boolean canWorkInDumbMode, + boolean canCloseContents) { return HEADLESS_WINDOW; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index e02c51fc3a5c..a8350a7cd5dd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -19,12 +19,7 @@ import com.intellij.Patches; import com.intellij.ide.ui.LafManager; import com.intellij.ide.ui.LafManagerListener; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -48,26 +43,12 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.wm.FocusCommand; -import com.intellij.openapi.wm.FocusWatcher; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.openapi.wm.IdeFrame; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowAnchor; -import com.intellij.openapi.wm.ToolWindowContentUiType; -import com.intellij.openapi.wm.ToolWindowEP; -import com.intellij.openapi.wm.ToolWindowFactory; -import com.intellij.openapi.wm.ToolWindowType; +import com.intellij.openapi.wm.*; import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.openapi.wm.ex.ToolWindowManagerListener; import com.intellij.openapi.wm.ex.WindowManagerEx; -import com.intellij.openapi.wm.impl.commands.ApplyWindowInfoCmd; -import com.intellij.openapi.wm.impl.commands.FinalizableCommand; -import com.intellij.openapi.wm.impl.commands.InvokeLaterCmd; -import com.intellij.openapi.wm.impl.commands.RequestFocusInEditorComponentCmd; -import com.intellij.openapi.wm.impl.commands.RequestFocusInToolWindowCmd; -import com.intellij.openapi.wm.impl.commands.UpdateRootPaneCmd; +import com.intellij.openapi.wm.impl.commands.*; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.switcher.QuickAccessSettings; import com.intellij.ui.switcher.SwitchManager; @@ -83,36 +64,16 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.Icon; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JRootPane; -import javax.swing.KeyStroke; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; +import javax.swing.*; import javax.swing.event.EventListenerList; import javax.swing.event.HyperlinkListener; -import java.awt.AWTEvent; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dialog; -import java.awt.Dimension; -import java.awt.KeyEventDispatcher; -import java.awt.KeyboardFocusManager; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Window; +import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Set; /** * @author Anton Katilin @@ -487,7 +448,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements label.setForeground(new Color(treeFg.getRed(), treeFg.getGreen(), treeFg.getBlue(), 180)); final ToolWindowFactory factory = bean.getToolWindowFactory(); final ToolWindowImpl toolWindow = - (ToolWindowImpl)registerToolWindow(bean.id, label, toolWindowAnchor, myProject, DumbService.isDumbAware(factory)); + (ToolWindowImpl)registerToolWindow(bean.id, label, toolWindowAnchor, myProject, DumbService.isDumbAware(factory), bean.canCloseContents); toolWindow.setContentFactory(factory); if (bean.icon != null) { Icon icon = IconLoader.findIcon(bean.icon, factory.getClass()); @@ -1026,15 +987,15 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, Disposable parentDisposable) { - return registerToolWindow(id, component, anchor, parentDisposable, false); + return registerToolWindow(id, component, anchor, parentDisposable, false, false); } public ToolWindow registerToolWindow(@NotNull final String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, Disposable parentDisposable, - boolean canWorkInDumbMode) { - return registerDisposable(id, parentDisposable, registerToolWindow(id, component, anchor, canWorkInDumbMode)); + boolean canWorkInDumbMode, boolean canCloseContents) { + return registerDisposable(id, parentDisposable, registerToolWindow(id, component, anchor, false, canCloseContents, canWorkInDumbMode)); } private ToolWindow registerToolWindow(@NotNull final String id, diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index ce557e350fd5..bba8d04f5532 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -228,9 +228,10 @@ before.commit.files.contain.code.smells.edit.them.confirm.text=Some files contai {0,choice, 0#No errors|1#One error|2#{0} errors} and {1,choice, 0#no warnings|1#one warning|2#{1} warnings} found.\n\ Would you like to review them? code.smells.review.button=&Review -todo.in.new.review.button=&Review new or changed TODOs +todo.in.new.review.button=&Review before.checkin.standard.options.check.smells=Perform code analy&sis for affected files -before.checkin.new.todo.check=Check for added TODO items +before.checkin.new.todo.check=Check TODO ({0}) +before.checkin.new.todo.check.title=Check TODO # Changes view changes.nodetitle.unversioned.files=Unversioned Files diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 3cf38093581e..b13535f0b77c 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -564,7 +564,7 @@ + factoryClass="com.intellij.ide.todo.TodoToolWindowFactory" canCloseContents="true"/> diff --git a/platform/lang-impl/src/com/intellij/ide/todo/TodoPanelSettings.java b/platform/vcs-api/src/com/intellij/ide/todo/TodoPanelSettings.java similarity index 80% rename from platform/lang-impl/src/com/intellij/ide/todo/TodoPanelSettings.java rename to platform/vcs-api/src/com/intellij/ide/todo/TodoPanelSettings.java index 6adff8164bc2..5bd450341710 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/TodoPanelSettings.java +++ b/platform/vcs-api/src/com/intellij/ide/todo/TodoPanelSettings.java @@ -16,6 +16,7 @@ package com.intellij.ide.todo; +import com.intellij.openapi.util.JDOMExternalizable; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -24,12 +25,12 @@ import java.util.Iterator; /** * @author Vladimir Kondratyev */ -class TodoPanelSettings{ - private boolean myArePackagesShown; - private boolean myAreModulesShown; - private boolean myAreFlattenPackages; - private boolean myIsAutoScrollToSource; - private String myTodoFilterName; +public class TodoPanelSettings implements JDOMExternalizable { + public boolean myArePackagesShown; + public boolean myAreModulesShown; + public boolean myAreFlattenPackages; + public boolean myIsAutoScrollToSource; + public String myTodoFilterName; @NonNls private static final String ATTRIBUTE_VALUE = "value"; @NonNls private static final String ELEMENT_ARE_PACKAGES_SHOWN = "are-packages-shown"; @@ -39,6 +40,17 @@ class TodoPanelSettings{ @NonNls private static final String ELEMENT_TODO_FILTER = "todo-filter"; @NonNls private static final String ATTRIBUTE_NAME = "name"; + public TodoPanelSettings() { + } + + public TodoPanelSettings(TodoPanelSettings s) { + myArePackagesShown = s.myArePackagesShown; + myAreModulesShown = s.myAreModulesShown; + myAreFlattenPackages = s.myAreFlattenPackages; + myIsAutoScrollToSource = s.myIsAutoScrollToSource; + myTodoFilterName = s.myTodoFilterName; + } + public void readExternal(Element e){ for(Iterator i=e.getChildren().iterator();i.hasNext();){ Element child=(Element)i.next(); @@ -84,7 +96,7 @@ class TodoPanelSettings{ } } - boolean areModulesShown() { + public boolean areModulesShown() { return myAreModulesShown; } @@ -92,7 +104,7 @@ class TodoPanelSettings{ myAreModulesShown = state; } - boolean arePackagesShown(){ + public boolean arePackagesShown(){ return myArePackagesShown; } @@ -100,27 +112,27 @@ class TodoPanelSettings{ myArePackagesShown=state; } - boolean areFlattenPackages(){ + public boolean areFlattenPackages(){ return myAreFlattenPackages; } - void setAreFlattenPackages(boolean state){ + public void setAreFlattenPackages(boolean state){ myAreFlattenPackages=state; } - boolean isAutoScrollToSource(){ + public boolean isAutoScrollToSource(){ return myIsAutoScrollToSource; } - void setAutoScrollToSource(boolean state){ + public void setAutoScrollToSource(boolean state){ myIsAutoScrollToSource=state; } - String getTodoFilterName(){ + public String getTodoFilterName(){ return myTodoFilterName; } - void setTodoFilterName(String todoFilterName){ + public void setTodoFilterName(String todoFilterName){ myTodoFilterName=todoFilterName; } } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java index c598b5702c76..feb81aec45b1 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs; +import com.intellij.ide.todo.TodoPanelSettings; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ProjectComponent; @@ -58,6 +59,7 @@ public final class VcsConfiguration implements PersistentStateComponent public boolean OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT = true; public boolean CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT = true; public boolean CHECK_NEW_TODO = true; + public TodoPanelSettings myTodoPanelSettings = new TodoPanelSettings(); public boolean PERFORM_UPDATE_IN_BACKGROUND = true; public boolean PERFORM_COMMIT_IN_BACKGROUND = true; public boolean PERFORM_EDIT_IN_BACKGROUND = true; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java index 3015e11c392b..3076308798d1 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java @@ -215,7 +215,7 @@ public class MavenProjectsNavigator extends SimpleProjectComponent implements Pe JPanel panel = new MavenProjectsNavigatorPanel(myProject, myTree); final ToolWindowManagerEx manager = ToolWindowManagerEx.getInstanceEx(myProject); - myToolWindow = manager.registerToolWindow(TOOL_WINDOW_ID, panel, ToolWindowAnchor.RIGHT, myProject, true); + myToolWindow = manager.registerToolWindow(TOOL_WINDOW_ID, panel, ToolWindowAnchor.RIGHT, myProject, true, false); myToolWindow.setIcon(MavenIcons.MAVEN_ICON); final ToolWindowManagerAdapter listener = new ToolWindowManagerAdapter() { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java index e5176107d6bf..67cfce21914e 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java @@ -102,7 +102,7 @@ public class UIDesignerToolWindowManager implements ProjectComponent { myToolWindowPanel.setSecondComponent(myPropertyInspector); myToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(UIDesignerBundle.message("toolwindow.ui.designer"), myToolWindowPanel, - ToolWindowAnchor.LEFT, myProject, true); + ToolWindowAnchor.LEFT, myProject, true, false); myToolWindow.setIcon(IconLoader.getIcon("/com/intellij/uiDesigner/icons/toolWindowUIDesigner.png")); myToolWindow.setAvailable(false, null); } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 9a8aa3592a9e..6efda3ee5575 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -744,6 +744,7 @@ +