[vcs-log] properly support working with filter pairs in filter models

Some filter models work with several filters simultaneously, for example FileFilterModel sets both structure and root filters, and TextFilterModel works with text and hash filters. For FileFilterModel a special composite filter class, VcsLogFileFilter, was used. It implemented VcsLogFilter interface, but was not actually a filter, which was confusing. On the other hand, TextFilterModel did not have a special filter class and just secretly created a hash filter. In order to unify working with such models, FilterPair class is introduced, and a descendant of FilterModel for working with filter pairs is extracted. Both FileFilterModel and TextFilterModel are adjusted to work with FilterPair.
This commit is contained in:
Julia Beliaeva
2019-02-05 22:24:12 +03:00
parent 0ed10240d5
commit bd5bb3c84a
11 changed files with 277 additions and 343 deletions
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log;
import com.intellij.util.containers.ContainerUtil;
@@ -36,7 +22,7 @@ public interface VcsLogFilterCollection {
FilterKey<VcsLogDateFilter> DATE_FILTER = FilterKey.create("date");
FilterKey<VcsLogTextFilter> TEXT_FILTER = FilterKey.create("text");
FilterKey<VcsLogStructureFilter> STRUCTURE_FILTER = FilterKey.create("structure");
FilterKey<VcsLogRootFilter> ROOT_FILTER = FilterKey.create("root");
FilterKey<VcsLogRootFilter> ROOT_FILTER = FilterKey.create("roots");
@Nullable
<T extends VcsLogFilter> T get(@NotNull FilterKey<T> key);
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.ui.filter;
import com.intellij.icons.AllIcons;
@@ -41,7 +27,8 @@ import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.List;
public class BranchFilterPopupComponent extends MultipleValueFilterPopupComponent<VcsLogBranchFilter> {
public class BranchFilterPopupComponent
extends MultipleValueFilterPopupComponent<VcsLogBranchFilter, VcsLogClassicFilterUi.BranchFilterModel> {
public static final String BRANCH_FILTER_NAME = "Branch";
private final VcsLogClassicFilterUi.BranchFilterModel myBranchFilterModel;
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.ui.filter;
import com.intellij.openapi.actionSystem.ActionGroup;
@@ -31,7 +17,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Calendar;
import java.util.Date;
class DateFilterPopupComponent extends FilterPopupComponent<VcsLogDateFilter> {
class DateFilterPopupComponent extends FilterPopupComponent<VcsLogDateFilter, FilterModel<VcsLogDateFilter>> {
DateFilterPopupComponent(FilterModel<VcsLogDateFilter> filterModel) {
super("Date", filterModel);
@@ -7,72 +7,46 @@ import com.intellij.vcs.log.VcsLogDataPack;
import com.intellij.vcs.log.VcsLogFilter;
import com.intellij.vcs.log.VcsLogFilterCollection;
import com.intellij.vcs.log.impl.MainVcsLogUiProperties;
import com.intellij.vcs.log.visible.filters.FilterPair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
abstract class FilterModel<Filter extends VcsLogFilter> {
@NotNull private final VcsLogFilterCollection.FilterKey<? extends Filter> myFilterKey;
abstract class FilterModel<Filter> {
@NotNull protected final MainVcsLogUiProperties myUiProperties;
@NotNull private final Computable<? extends VcsLogDataPack> myDataPackProvider;
@NotNull private final Collection<Runnable> mySetFilterListeners = ContainerUtil.newArrayList();
@Nullable private Filter myFilter;
@Nullable protected Filter myFilter;
FilterModel(@NotNull VcsLogFilterCollection.FilterKey<? extends Filter> filterKey,
@NotNull Computable<? extends VcsLogDataPack> provider,
@NotNull MainVcsLogUiProperties uiProperties,
@Nullable VcsLogFilterCollection filters) {
myFilterKey = filterKey;
FilterModel(@NotNull Computable<? extends VcsLogDataPack> provider,
@NotNull MainVcsLogUiProperties uiProperties) {
myUiProperties = uiProperties;
myDataPackProvider = provider;
if (filters != null) {
saveFilter(getFilterFromCollection(filters));
}
}
@Nullable
protected Filter getFilterFromCollection(@NotNull VcsLogFilterCollection filters) {
return filters.get(myFilterKey);
}
void setFilter(@Nullable Filter filter) {
myFilter = filter;
saveFilter(filter);
saveFilterToProperties(filter);
for (Runnable listener : mySetFilterListeners) {
listener.run();
}
}
protected void saveFilter(@Nullable Filter filter) {
myUiProperties.saveFilterValues(myFilterKey.getName(), filter == null ? null : getFilterValues(filter));
}
@Nullable
Filter getFilter() {
if (myFilter == null) {
myFilter = getLastFilter();
myFilter = getFilterFromProperties();
}
return myFilter;
}
@Nullable
protected abstract Filter createFilter(@NotNull List<String> values);
@NotNull
protected abstract List<String> getFilterValues(@NotNull Filter filter);
protected abstract void saveFilterToProperties(@Nullable Filter filter);
@Nullable
protected Filter getLastFilter() {
List<String> values = myUiProperties.getFilterValues(myFilterKey.getName());
if (values != null) {
return createFilter(values);
}
return null;
}
protected abstract Filter getFilterFromProperties();
@NotNull
VcsLogDataPack getDataPack() {
@@ -82,4 +56,126 @@ abstract class FilterModel<Filter extends VcsLogFilter> {
void addSetFilterListener(@NotNull Runnable runnable) {
mySetFilterListeners.add(runnable);
}
public static abstract class SingleFilterModel<Filter extends VcsLogFilter> extends FilterModel<Filter> {
@NotNull private final VcsLogFilterCollection.FilterKey<? extends Filter> myFilterKey;
SingleFilterModel(@NotNull VcsLogFilterCollection.FilterKey<? extends Filter> filterKey,
@NotNull Computable<? extends VcsLogDataPack> provider,
@NotNull MainVcsLogUiProperties uiProperties,
@Nullable VcsLogFilterCollection filters) {
super(provider, uiProperties);
myFilterKey = filterKey;
if (filters != null) {
saveFilterToProperties(filters.get(myFilterKey));
}
}
@Nullable
protected abstract Filter createFilter(@NotNull List<String> values);
@NotNull
protected abstract List<String> getFilterValues(@NotNull Filter filter);
@Override
protected void saveFilterToProperties(@Nullable Filter filter) {
myUiProperties.saveFilterValues(myFilterKey.getName(), filter == null ? null : getFilterValues(filter));
}
@Override
@Nullable
protected Filter getFilterFromProperties() {
List<String> values = myUiProperties.getFilterValues(myFilterKey.getName());
if (values != null) {
return createFilter(values);
}
return null;
}
}
public static abstract class PairFilterModel<Filter1 extends VcsLogFilter, Filter2 extends VcsLogFilter>
extends FilterModel<FilterPair<Filter1, Filter2>> {
@NotNull private final VcsLogFilterCollection.FilterKey<? extends Filter1> myFilterKey1;
@NotNull private final VcsLogFilterCollection.FilterKey<? extends Filter2> myFilterKey2;
PairFilterModel(@NotNull VcsLogFilterCollection.FilterKey<? extends Filter1> filterKey1,
@NotNull VcsLogFilterCollection.FilterKey<? extends Filter2> filterKey2,
@NotNull Computable<? extends VcsLogDataPack> provider,
@NotNull MainVcsLogUiProperties uiProperties,
@Nullable VcsLogFilterCollection filters) {
super(provider, uiProperties);
myFilterKey1 = filterKey1;
myFilterKey2 = filterKey2;
if (filters != null) {
Filter1 filter1 = filters.get(myFilterKey1);
Filter2 filter2 = filters.get(myFilterKey2);
FilterPair<Filter1, Filter2> filter = (filter1 == null && filter2 == null) ? null : new FilterPair<>(filter1, filter2);
saveFilterToProperties(filter);
}
}
@Override
protected void saveFilterToProperties(@Nullable FilterPair<Filter1, Filter2> filter) {
if (filter == null || filter.getFilter1() == null) {
myUiProperties.saveFilterValues(myFilterKey1.getName(), null);
}
else {
myUiProperties.saveFilterValues(myFilterKey1.getName(), getFilter1Values(filter.getFilter1()));
}
if (filter == null || filter.getFilter2() == null) {
myUiProperties.saveFilterValues(myFilterKey2.getName(), null);
}
else {
myUiProperties.saveFilterValues(myFilterKey2.getName(), getFilter2Values(filter.getFilter2()));
}
}
@Nullable
@Override
protected FilterPair<Filter1, Filter2> getFilterFromProperties() {
List<String> values1 = myUiProperties.getFilterValues(myFilterKey1.getName());
Filter1 filter1 = null;
if (values1 != null) {
filter1 = createFilter1(values1);
}
List<String> values2 = myUiProperties.getFilterValues(myFilterKey2.getName());
Filter2 filter2 = null;
if (values2 != null) {
filter2 = createFilter2(values2);
}
if (filter1 == null && filter2 == null) return null;
return new FilterPair<>(filter1, filter2);
}
@Nullable
public Filter1 getFilter1() {
FilterPair<Filter1, Filter2> filterPair = getFilter();
if (filterPair == null) return null;
return filterPair.getFilter1();
}
@Nullable
public Filter2 getFilter2() {
FilterPair<Filter1, Filter2> filterPair = getFilter();
if (filterPair == null) return null;
return filterPair.getFilter2();
}
@NotNull
protected abstract List<String> getFilter1Values(@NotNull Filter1 filter1);
@NotNull
protected abstract List<String> getFilter2Values(@NotNull Filter2 filter2);
@Nullable
protected abstract Filter1 createFilter1(@NotNull List<String> values);
@Nullable
protected abstract Filter2 createFilter2(@NotNull List<String> values);
}
}
@@ -1,39 +1,24 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.ui.filter;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.vcs.log.VcsLogFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Base class for components which allow to set up filter for the VCS Log, by displaying a popup with available choices.
*/
abstract class FilterPopupComponent<Filter extends VcsLogFilter> extends VcsLogPopupComponent {
abstract class FilterPopupComponent<Filter, Model extends FilterModel<Filter>> extends VcsLogPopupComponent {
/**
* Special value that indicates that no filtering is on.
*/
protected static final String ALL = "All";
@NotNull protected final FilterModel<Filter> myFilterModel;
@NotNull protected final Model myFilterModel;
FilterPopupComponent(@NotNull String filterName, @NotNull FilterModel<Filter> filterModel) {
FilterPopupComponent(@NotNull String filterName, @NotNull Model filterModel) {
super(filterName);
myFilterModel = filterModel;
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.ui.filter;
import com.intellij.openapi.actionSystem.ActionGroup;
@@ -34,7 +20,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
abstract class MultipleValueFilterPopupComponent<Filter extends VcsLogFilter> extends FilterPopupComponent<Filter> {
abstract class MultipleValueFilterPopupComponent<Filter extends VcsLogFilter, Model extends FilterModel.SingleFilterModel<Filter>>
extends FilterPopupComponent<Filter, Model> {
private static final int MAX_FILTER_VALUE_LENGTH = 30;
@@ -42,7 +29,7 @@ abstract class MultipleValueFilterPopupComponent<Filter extends VcsLogFilter> ex
MultipleValueFilterPopupComponent(@NotNull String filterName,
@NotNull MainVcsLogUiProperties uiProperties,
@NotNull FilterModel<Filter> filterModel) {
@NotNull Model filterModel) {
super(filterName, filterModel);
myUiProperties = uiProperties;
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.ui.filter;
import com.intellij.openapi.actionSystem.*;
@@ -35,11 +21,11 @@ import com.intellij.vcs.log.VcsLogDataPack;
import com.intellij.vcs.log.VcsLogRootFilter;
import com.intellij.vcs.log.VcsLogStructureFilter;
import com.intellij.vcs.log.impl.MainVcsLogUiProperties;
import com.intellij.vcs.log.visible.filters.VcsLogFileFilter;
import com.intellij.vcs.log.visible.filters.VcsLogFilterObject;
import com.intellij.vcs.log.ui.VcsLogColorManager;
import com.intellij.vcs.log.ui.table.VcsLogGraphTable;
import com.intellij.vcs.log.util.VcsLogUtil;
import com.intellij.vcs.log.visible.filters.FilterPair;
import com.intellij.vcs.log.visible.filters.VcsLogFilterObject;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,7 +37,9 @@ import java.awt.event.KeyEvent;
import java.util.List;
import java.util.*;
class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilter> {
class StructureFilterPopupComponent extends FilterPopupComponent<FilterPair<VcsLogStructureFilter, VcsLogRootFilter>,
FilterModel.PairFilterModel<VcsLogStructureFilter, VcsLogRootFilter>> {
private static final int FILTER_LABEL_LENGTH = 30;
private static final int CHECKBOX_ICON_SIZE = 15;
private static final FileByNameComparator FILE_BY_NAME_COMPARATOR = new FileByNameComparator();
@@ -61,21 +49,29 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
@NotNull private final VcsLogColorManager myColorManager;
StructureFilterPopupComponent(@NotNull MainVcsLogUiProperties uiProperties,
@NotNull FilterModel<VcsLogFileFilter> filterModel,
@NotNull FilterModel.PairFilterModel<VcsLogStructureFilter, VcsLogRootFilter> filterModel,
@NotNull VcsLogColorManager colorManager) {
super("Paths", filterModel);
myUiProperties = uiProperties;
myColorManager = colorManager;
}
private static VcsLogRootFilter getRootFilter(@Nullable FilterPair<VcsLogStructureFilter, VcsLogRootFilter> filter) {
if (filter == null) return null;
return filter.getFilter2();
}
private static VcsLogStructureFilter getStructureFilter(@Nullable FilterPair<VcsLogStructureFilter, VcsLogRootFilter> filter) {
if (filter == null) return null;
return filter.getFilter1();
}
@NotNull
@Override
protected String getText(@NotNull VcsLogFileFilter filter) {
Collection<VirtualFile> roots = filter.getRootFilter() == null ? getAllRoots() : filter.getRootFilter().getRoots();
Collection<FilePath> files =
filter.getStructureFilter() == null ? Collections.emptySet() : filter.getStructureFilter().getFiles();
Collection<VirtualFile> visibleRoots =
VcsLogUtil.getAllVisibleRoots(getAllRoots(), filter.getRootFilter(), filter.getStructureFilter());
protected String getText(@NotNull FilterPair<VcsLogStructureFilter, VcsLogRootFilter> filter) {
Collection<VirtualFile> roots = getRootFilter(filter) == null ? getAllRoots() : getRootFilter(filter).getRoots();
Collection<FilePath> files = getStructureFilter(filter) == null ? Collections.emptySet() : getStructureFilter(filter).getFiles();
Collection<VirtualFile> visibleRoots = VcsLogUtil.getAllVisibleRoots(getAllRoots(), getRootFilter(filter), getStructureFilter(filter));
if (files.isEmpty()) {
return getTextFromRoots(roots, visibleRoots.size() == getAllRoots().size());
@@ -121,9 +117,9 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
@Nullable
@Override
protected String getToolTip(@NotNull VcsLogFileFilter filter) {
return getToolTip(filter.getRootFilter() == null ? getAllRoots() : filter.getRootFilter().getRoots(),
filter.getStructureFilter() == null ? Collections.emptySet() : filter.getStructureFilter().getFiles());
protected String getToolTip(@NotNull FilterPair<VcsLogStructureFilter, VcsLogRootFilter> filter) {
return getToolTip(getRootFilter(filter) == null ? getAllRoots() : getRootFilter(filter).getRoots(),
getStructureFilter(filter) == null ? Collections.emptySet() : getStructureFilter(filter).getFiles());
}
@NotNull
@@ -201,9 +197,9 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
}
private boolean isVisible(@NotNull VirtualFile root) {
VcsLogFileFilter filter = myFilterModel.getFilter();
if (filter != null && filter.getRootFilter() != null) {
return filter.getRootFilter().getRoots().contains(root);
FilterPair<VcsLogStructureFilter, VcsLogRootFilter> filter = myFilterModel.getFilter();
if (getRootFilter(filter) != null) {
return getRootFilter(filter).getRoots().contains(root);
}
return true;
}
@@ -211,8 +207,8 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
private void setVisible(@NotNull VirtualFile root, boolean visible) {
Set<VirtualFile> roots = getAllRoots();
VcsLogFileFilter previousFilter = myFilterModel.getFilter();
VcsLogRootFilter rootFilter = previousFilter != null ? previousFilter.getRootFilter() : null;
FilterPair<VcsLogStructureFilter, VcsLogRootFilter> previousFilter = myFilterModel.getFilter();
VcsLogRootFilter rootFilter = getRootFilter(previousFilter);
Collection<VirtualFile> visibleRoots;
if (rootFilter == null) {
@@ -223,11 +219,11 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
? ContainerUtil.union(new HashSet<>(rootFilter.getRoots()), Collections.singleton(root))
: ContainerUtil.subtract(rootFilter.getRoots(), Collections.singleton(root));
}
myFilterModel.setFilter(new VcsLogFileFilter(null, VcsLogFilterObject.fromRoots(visibleRoots)));
myFilterModel.setFilter(new FilterPair<>(null, VcsLogFilterObject.fromRoots(visibleRoots)));
}
private void setVisibleOnly(@NotNull VirtualFile root) {
myFilterModel.setFilter(new VcsLogFileFilter(null, VcsLogFilterObject.fromRoot(root)));
myFilterModel.setFilter(new FilterPair<>(null, VcsLogFilterObject.fromRoot(root)));
}
@NotNull
@@ -302,7 +298,7 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
}
private boolean isEnabled() {
return myFilterModel.getFilter() == null || myFilterModel.getFilter().getStructureFilter() == null;
return getStructureFilter(myFilterModel.getFilter()) == null;
}
}
@@ -348,22 +344,22 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getRequiredData(CommonDataKeys.PROJECT);
VcsLogDataPack dataPack = myFilterModel.getDataPack();
VcsLogFileFilter filter = myFilterModel.getFilter();
FilterPair<VcsLogStructureFilter, VcsLogRootFilter> filter = myFilterModel.getFilter();
Collection<VirtualFile> files;
if (filter == null || filter.getStructureFilter() == null) {
if (getStructureFilter(filter) == null) {
files = Collections.emptySet();
}
else {
// for now, ignoring non-existing paths
files = ContainerUtil.mapNotNull(filter.getStructureFilter().getFiles(), FilePath::getVirtualFile);
files = ContainerUtil.mapNotNull(getStructureFilter(filter).getFiles(), FilePath::getVirtualFile);
}
VcsStructureChooser chooser = new VcsStructureChooser(project, "Select Files or Folders to Filter by", files,
new ArrayList<>(dataPack.getLogProviders().keySet()));
if (chooser.showAndGet()) {
VcsLogStructureFilter structureFilter = VcsLogFilterObject.fromVirtualFiles(chooser.getSelectedFiles());
myFilterModel.setFilter(new VcsLogFileFilter(structureFilter, null));
myFilterModel.setFilter(new FilterPair<>(structureFilter, null));
myUiProperties.addRecentlyFilteredGroup(myName, VcsLogClassicFilterUi.FileFilterModel.getFilterValues(structureFilter));
}
}
@@ -388,12 +384,12 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogFileFilte
@Override
public boolean isSelected(@NotNull AnActionEvent e) {
return myFilterModel.getFilter() != null && myFilterModel.getFilter().getStructureFilter() == myFilter;
return getStructureFilter(myFilterModel.getFilter()) == myFilter;
}
@Override
public void setSelected(@NotNull AnActionEvent e, boolean state) {
myFilterModel.setFilter(new VcsLogFileFilter(myFilter, null));
myFilterModel.setFilter(new FilterPair<>(myFilter, null));
}
@Override
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.ui.filter;
import com.intellij.ide.DataManager;
@@ -25,8 +11,8 @@ import com.intellij.util.ui.JBDimension;
import com.intellij.vcs.log.VcsLogUserFilter;
import com.intellij.vcs.log.data.VcsLogData;
import com.intellij.vcs.log.impl.MainVcsLogUiProperties;
import com.intellij.vcs.log.visible.filters.VcsLogUserFilterImpl;
import com.intellij.vcs.log.util.VcsUserUtil;
import com.intellij.vcs.log.visible.filters.VcsLogUserFilterImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,13 +24,14 @@ import java.util.TreeSet;
/**
* Show a popup to select a user or enter the user name.
*/
public class UserFilterPopupComponent extends MultipleValueFilterPopupComponent<VcsLogUserFilter> {
public class UserFilterPopupComponent
extends MultipleValueFilterPopupComponent<VcsLogUserFilter, FilterModel.SingleFilterModel<VcsLogUserFilter>> {
public static final String USER_FILER_NAME = "User";
@NotNull private final VcsLogData myLogData;
UserFilterPopupComponent(@NotNull MainVcsLogUiProperties uiProperties,
@NotNull VcsLogData logData,
@NotNull FilterModel<VcsLogUserFilter> filterModel) {
@NotNull FilterModel.SingleFilterModel<VcsLogUserFilter> filterModel) {
super(USER_FILER_NAME, uiProperties, filterModel);
myLogData = logData;
}
@@ -25,7 +25,7 @@ import com.intellij.vcs.log.impl.MainVcsLogUiProperties;
import com.intellij.vcs.log.ui.VcsLogActionPlaces;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
import com.intellij.vcs.log.util.VcsLogUtil;
import com.intellij.vcs.log.visible.filters.VcsLogFileFilter;
import com.intellij.vcs.log.visible.filters.FilterPair;
import com.intellij.vcs.log.visible.filters.VcsLogFilterObject;
import com.intellij.vcs.log.visible.filters.VcsLogUserFilterImpl;
import com.intellij.vcsUtil.VcsUtil;
@@ -52,7 +52,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
@NotNull private VcsLogDataPack myDataPack;
@NotNull private final BranchFilterModel myBranchFilterModel;
@NotNull private final FilterModel<VcsLogUserFilter> myUserFilterModel;
@NotNull private final FilterModel.SingleFilterModel<VcsLogUserFilter> myUserFilterModel;
@NotNull private final FilterModel<VcsLogDateFilter> myDateFilterModel;
@NotNull private final FileFilterModel myStructureFilterModel;
@NotNull private final TextFilterModel myTextFilterModel;
@@ -83,8 +83,8 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
for (FilterModel<?> model : models) {
model.addSetFilterListener(() -> {
myUi.applyFiltersAndUpdateUi(getFilters());
myBranchFilterModel
.onStructureFilterChanged(new HashSet<>(myLogData.getRoots()), myStructureFilterModel.getFilter());
myBranchFilterModel.onStructureFilterChanged(new HashSet<>(myLogData.getRoots()), myStructureFilterModel.getRootFilter(),
myStructureFilterModel.getStructureFilter());
});
}
}
@@ -116,8 +116,8 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
@Override
public VcsLogFilterCollection getFilters() {
ApplicationManager.getApplication().assertIsDispatchThread();
return VcsLogFilterObject.collection(myBranchFilterModel.getFilter(), myUserFilterModel.getFilter(), myTextFilterModel.getHashFilters(),
myDateFilterModel.getFilter(), myTextFilterModel.getTextFilter(),
return VcsLogFilterObject.collection(myBranchFilterModel.getFilter(), myUserFilterModel.getFilter(), myTextFilterModel.getFilter2(),
myDateFilterModel.getFilter(), myTextFilterModel.getFilter1(),
myStructureFilterModel.getStructureFilter(),
myStructureFilterModel.getRootFilter());
}
@@ -139,7 +139,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
myBranchFilterModel.setFilter((VcsLogBranchFilter)filter);
}
else if (filter instanceof VcsLogStructureFilter) {
myStructureFilterModel.setFilter(new VcsLogFileFilter((VcsLogStructureFilter)filter, null));
myStructureFilterModel.setStructureFilter((VcsLogStructureFilter)filter);
}
JComponent toolbar = myUi.getToolbar();
@@ -166,7 +166,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
}
}
public static class BranchFilterModel extends FilterModel<VcsLogBranchFilter> {
public static class BranchFilterModel extends FilterModel.SingleFilterModel<VcsLogBranchFilter> {
@Nullable
private Collection<VirtualFile> myVisibleRoots;
@@ -175,12 +175,14 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
super(VcsLogFilterCollection.BRANCH_FILTER, provider, properties, filters);
}
public void onStructureFilterChanged(@NotNull Set<VirtualFile> roots, @Nullable VcsLogFileFilter filter) {
if (filter == null) {
public void onStructureFilterChanged(@NotNull Set<VirtualFile> roots,
@Nullable VcsLogRootFilter rootFilter,
@Nullable VcsLogStructureFilter structureFilter) {
if (rootFilter == null && structureFilter == null) {
myVisibleRoots = null;
}
else {
myVisibleRoots = VcsLogUtil.getAllVisibleRoots(roots, filter.getRootFilter(), filter.getStructureFilter());
myVisibleRoots = VcsLogUtil.getAllVisibleRoots(roots, rootFilter, structureFilter);
}
}
@@ -203,12 +205,12 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
}
}
private static class TextFilterModel extends FilterModel<VcsLogTextFilter> {
private static class TextFilterModel extends FilterModel.PairFilterModel<VcsLogTextFilter, VcsLogHashFilter> {
@Nullable private String myText;
TextFilterModel(@NotNull NotNullComputable<? extends VcsLogDataPack> dataPackProvider, @NotNull MainVcsLogUiProperties properties,
@Nullable VcsLogFilterCollection filters) {
super(VcsLogFilterCollection.TEXT_FILTER, dataPackProvider, properties, filters);
super(VcsLogFilterCollection.TEXT_FILTER, VcsLogFilterCollection.HASH_FILTER, dataPackProvider, properties, filters);
}
@NotNull
@@ -216,8 +218,8 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
if (myText != null) {
return myText;
}
else if (getFilter() != null) {
return getFilter().getText();
else if (getFilter1() != null) {
return getFilter1().getText();
}
else {
return "";
@@ -230,54 +232,59 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
boolean hasUnsavedChanges() {
if (myText == null) return false;
return getFilter() == null || !myText.equals(getFilter().getText());
return getFilter1() == null || !myText.equals(getFilter1().getText());
}
@Override
void setFilter(@Nullable VcsLogTextFilter filter) {
void setFilter(@Nullable FilterPair<VcsLogTextFilter, VcsLogHashFilter> filter) {
super.setFilter(filter);
myText = null;
}
@NotNull
@Override
protected VcsLogTextFilter createFilter(@NotNull List<String> values) {
return VcsLogFilterObject.fromPattern(ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(values)),
myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_REGEX),
myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_MATCH_CASE));
protected List<String> getFilter1Values(@NotNull VcsLogTextFilter filter) {
return Collections.singletonList(filter.getText());
}
@NotNull
@Override
protected List<String> getFilterValues(@NotNull VcsLogTextFilter filter) {
return Collections.singletonList(filter.getText());
protected List<String> getFilter2Values(@NotNull VcsLogHashFilter filter) {
return ContainerUtil.newArrayList(filter.getHashes());
}
@Nullable
VcsLogTextFilter getTextFilter() {
VcsLogTextFilter filter = getFilter();
if (filter == null) return null;
String text = filter.getText().trim();
if (StringUtil.isEmptyOrSpaces(text)) return null;
@Override
protected VcsLogTextFilter createFilter1(@NotNull List<String> values) {
return createTextFilter(ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(values)));
}
return VcsLogFilterObject.fromPattern(text, myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_REGEX),
@Nullable
@Override
protected VcsLogHashFilter createFilter2(@NotNull List<String> values) {
return VcsLogFilterObject.fromHashes(values);
}
@NotNull
private VcsLogTextFilter createTextFilter(@NotNull String text) {
return VcsLogFilterObject.fromPattern(text,
myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_REGEX),
myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_MATCH_CASE));
}
@Nullable
VcsLogHashFilter getHashFilters() {
VcsLogTextFilter filter = getFilter();
if (filter == null) return null;
String text = filter.getText().trim();
if (StringUtil.isEmptyOrSpaces(text)) return null;
return VcsLogFilterObject.fromHash(text);
public void setFilterText(@NotNull String text) {
if (StringUtil.isEmptyOrSpaces(text)) {
setFilter(null);
}
else {
VcsLogTextFilter textFilter = createTextFilter(text);
VcsLogHashFilter hashFilter = VcsLogFilterObject.fromHash(text);
setFilter(new FilterPair<>(textFilter, hashFilter));
}
}
}
static class FileFilterModel extends FilterModel<VcsLogFileFilter> {
@NotNull private static final String ROOTS = "roots";
@NotNull private static final String STRUCTURE = "structure";
static class FileFilterModel extends FilterModel.PairFilterModel<VcsLogStructureFilter, VcsLogRootFilter> {
@NotNull private static final String DIR = "dir:";
@NotNull private static final String FILE = "file:";
@NotNull private final Set<VirtualFile> myRoots;
@@ -286,31 +293,20 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
@NotNull Set<VirtualFile> roots,
@NotNull MainVcsLogUiProperties uiProperties,
@Nullable VcsLogFilterCollection filters) {
super(VcsLogFileFilter.FILE_FILTER, dataPackGetter, uiProperties, filters);
super(VcsLogFilterCollection.STRUCTURE_FILTER, VcsLogFilterCollection.ROOT_FILTER, dataPackGetter, uiProperties, filters);
myRoots = roots;
}
@Nullable
@Override
protected VcsLogFileFilter getFilterFromCollection(@NotNull VcsLogFilterCollection filters) {
VcsLogRootFilter rootFilter = filters.get(VcsLogFilterCollection.ROOT_FILTER);
VcsLogStructureFilter structureFilter = filters.get(VcsLogFilterCollection.STRUCTURE_FILTER);
if (rootFilter == null && structureFilter == null) return null;
return new VcsLogFileFilter(structureFilter, rootFilter);
@NotNull
protected List<String> getFilter1Values(@NotNull VcsLogStructureFilter filter) {
return getFilterValues(filter);
}
@Override
protected void saveFilter(@Nullable VcsLogFileFilter filter) {
if (filter == null) {
myUiProperties.saveFilterValues(ROOTS, null);
myUiProperties.saveFilterValues(STRUCTURE, null);
}
else if (filter.getStructureFilter() != null) {
myUiProperties.saveFilterValues(STRUCTURE, getFilterValues(filter.getStructureFilter()));
}
else if (filter.getRootFilter() != null) {
myUiProperties.saveFilterValues(ROOTS, getFilterValues(filter.getRootFilter()));
}
@NotNull
protected List<String> getFilter2Values(@NotNull VcsLogRootFilter filter) {
return ContainerUtil.map(filter.getRoots(), VirtualFile::getPath);
}
@NotNull
@@ -318,40 +314,15 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
return ContainerUtil.map(filter.getFiles(), path -> (path.isDirectory() ? DIR : FILE) + path.getPath());
}
@NotNull
private static List<String> getFilterValues(@NotNull VcsLogRootFilter filter) {
return ContainerUtil.map(filter.getRoots(), VirtualFile::getPath);
}
@NotNull
static VcsLogStructureFilter createStructureFilter(@NotNull List<String> values) {
return VcsLogFilterObject.fromPaths(ContainerUtil.map(values, path -> {
if (path.startsWith(DIR)) {
return VcsUtil.getFilePath(path.substring(DIR.length()), true);
}
else if (path.startsWith(FILE)) {
return VcsUtil.getFilePath(path.substring(FILE.length()), false);
}
return VcsUtil.getFilePath(path);
}));
}
@Nullable
@Override
protected VcsLogFileFilter getLastFilter() {
List<String> values = myUiProperties.getFilterValues(STRUCTURE);
if (values != null) {
return new VcsLogFileFilter(createStructureFilter(values), null);
}
values = myUiProperties.getFilterValues(ROOTS);
if (values != null) {
return new VcsLogFileFilter(null, createRootsFilter(values));
}
return null;
@NotNull
protected VcsLogStructureFilter createFilter1(@NotNull List<String> values) {
return createStructureFilter(values);
}
@Override
@Nullable
private VcsLogRootFilter createRootsFilter(@NotNull List<String> values) {
protected VcsLogRootFilter createFilter2(@NotNull List<String> values) {
List<VirtualFile> selectedRoots = ContainerUtil.newArrayList();
for (String path : values) {
VirtualFile root = LocalFileSystem.getInstance().findFileByPath(path);
@@ -371,34 +342,35 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
return VcsLogFilterObject.fromRoots(selectedRoots);
}
@NotNull
@Override
protected VcsLogFileFilter createFilter(@NotNull List<String> values) {
throw new UnsupportedOperationException("Can not create file filter from list of strings");
}
@NotNull
@Override
protected List<String> getFilterValues(@NotNull VcsLogFileFilter filter) {
throw new UnsupportedOperationException("Can not save file filter to a list of strings");
@Nullable
protected VcsLogRootFilter getRootFilter() {
return getFilter2();
}
@Nullable
VcsLogRootFilter getRootFilter() {
VcsLogFileFilter filter = getFilter();
if (filter == null) return null;
return filter.getRootFilter();
protected VcsLogStructureFilter getStructureFilter() {
return getFilter1();
}
@Nullable
VcsLogStructureFilter getStructureFilter() {
VcsLogFileFilter filter = getFilter();
if (filter == null) return null;
return filter.getStructureFilter();
protected void setStructureFilter(@NotNull VcsLogStructureFilter filter) {
setFilter(new FilterPair<>(filter, null));
}
@NotNull
static VcsLogStructureFilter createStructureFilter(@NotNull List<String> values) {
return VcsLogFilterObject.fromPaths(ContainerUtil.map(values, path -> {
if (path.startsWith(DIR)) {
return VcsUtil.getFilePath(path.substring(DIR.length()), true);
}
else if (path.startsWith(FILE)) {
return VcsUtil.getFilePath(path.substring(FILE.length()), false);
}
return VcsUtil.getFilePath(path);
}));
}
}
private static class DateFilterModel extends FilterModel<VcsLogDateFilter> {
private static class DateFilterModel extends FilterModel.SingleFilterModel<VcsLogDateFilter> {
DateFilterModel(@NotNull NotNullComputable<? extends VcsLogDataPack> dataPackGetter, @NotNull MainVcsLogUiProperties uiProperties,
@Nullable VcsLogFilterCollection filters) {
super(VcsLogFilterCollection.DATE_FILTER, dataPackGetter, uiProperties, filters);
@@ -433,7 +405,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
}
}
private class UserFilterModel extends FilterModel<VcsLogUserFilter> {
private class UserFilterModel extends FilterModel.SingleFilterModel<VcsLogUserFilter> {
UserFilterModel(@NotNull NotNullComputable<? extends VcsLogDataPack> dataPackGetter, @NotNull MainVcsLogUiProperties uiProperties,
@Nullable VcsLogFilterCollection filters) {
super(VcsLogFilterCollection.USER_FILTER, dataPackGetter, uiProperties, filters);
@@ -478,9 +450,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi {
}
protected void applyFilter() {
boolean isRegexpAllowed = myTextFilterModel.myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_REGEX);
boolean isMatchCase = myTextFilterModel.myUiProperties.get(MainVcsLogUiProperties.TEXT_FILTER_MATCH_CASE);
myTextFilterModel.setFilter(VcsLogFilterObject.fromPattern(getText(), isRegexpAllowed, isMatchCase));
myTextFilterModel.setFilterText(getText());
addCurrentTextToHistory();
}
@@ -0,0 +1,6 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.visible.filters
import com.intellij.vcs.log.VcsLogFilter
data class FilterPair<F1 : VcsLogFilter, F2 : VcsLogFilter>(val filter1: F1?, val filter2: F2?)
@@ -1,52 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.visible.filters;
import com.intellij.vcs.log.VcsLogFilter;
import com.intellij.vcs.log.VcsLogFilterCollection;
import com.intellij.vcs.log.VcsLogRootFilter;
import com.intellij.vcs.log.VcsLogStructureFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class VcsLogFileFilter implements VcsLogFilter {
public static final VcsLogFilterCollection.FilterKey<VcsLogFileFilter> FILE_FILTER = VcsLogFilterCollection.FilterKey.create("file");
@Nullable private final VcsLogStructureFilter myStructureFilter;
@Nullable private final VcsLogRootFilter myRootFilter;
public VcsLogFileFilter(@Nullable VcsLogStructureFilter structureFilter, @Nullable VcsLogRootFilter rootFilter) {
myStructureFilter = structureFilter;
myRootFilter = rootFilter;
}
@Nullable
public VcsLogStructureFilter getStructureFilter() {
return myStructureFilter;
}
@Nullable
public VcsLogRootFilter getRootFilter() {
return myRootFilter;
}
@NotNull
@Override
public VcsLogFilterCollection.FilterKey<?> getKey() {
return FILE_FILTER;
}
@NotNull
@Override
public String getPresentation() {
StringBuilder result = new StringBuilder();
if (myRootFilter != null) {
result.append(myRootFilter.getPresentation());
}
if (myStructureFilter != null) {
if (result.length() > 0) {
result.append(" ");
}
result.append(myStructureFilter.getPresentation());
}
return result.toString();
}
}