From 08cc736214a70203fa20e373f8c15f89d80d0664 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 5 Feb 2019 11:59:17 +0100 Subject: [PATCH 1/7] Cleanup (minor optimization; formatting) --- .../vfs/newvfs/events/VFileCreateEvent.java | 37 +++++-------- .../LocalFileSystemRefreshWorker.java | 9 ++-- .../vfs/newvfs/persistent/RefreshWorker.java | 53 +++++++------------ .../persistent/VfsEventGenerationHelper.java | 38 ++++++------- 4 files changed, 54 insertions(+), 83 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java index febb55431c8a..591ef016640e 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java @@ -5,7 +5,6 @@ import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileSystem; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -13,12 +12,12 @@ import org.jetbrains.annotations.Nullable; * @author max */ public class VFileCreateEvent extends VFileEvent { - @NotNull private final VirtualFile myParent; + private final @NotNull VirtualFile myParent; + private final @NotNull String myChildName; private final boolean myDirectory; - private final boolean myEmptyDirectory; - @NotNull private final String myChildName; private final FileAttributes myAttributes; private final String mySymlinkTarget; + private final boolean myEmptyDirectory; private VirtualFile myCreatedFile; public VFileCreateEvent(Object requestor, @@ -30,8 +29,8 @@ public class VFileCreateEvent extends VFileEvent { boolean isFromRefresh, boolean isEmptyDirectory) { super(requestor, isFromRefresh); - myChildName = childName; myParent = parent; + myChildName = childName; myDirectory = isDirectory; myAttributes = attributes; mySymlinkTarget = symlinkTarget; @@ -47,13 +46,6 @@ public class VFileCreateEvent extends VFileEvent { return myDirectory; } - /** - * @return true if the newly created file is a directory which has no children. - */ - public boolean isEmptyDirectory() { - return isDirectory() && myEmptyDirectory; - } - @NotNull public VirtualFile getParent() { return myParent; @@ -69,11 +61,9 @@ public class VFileCreateEvent extends VFileEvent { return mySymlinkTarget; } - @NonNls - @Override - public String toString() { - return "VfsEvent[create " + (myDirectory ? (isEmptyDirectory() ? "(empty) " :"") + "dir " - : "file ") + myChildName + " in " + myParent.getUrl() + "]"; + /** @return true if the newly created file is a directory which has no children. */ + public boolean isEmptyDirectory() { + return isDirectory() && myEmptyDirectory; } @NotNull @@ -105,12 +95,7 @@ public class VFileCreateEvent extends VFileEvent { @Override public boolean isValid() { - if (myParent.isValid()) { - boolean childExists = myParent.findChild(myChildName) != null; - return !childExists; - } - - return false; + return myParent.isValid() && myParent.findChild(myChildName) == null; } @Override @@ -133,4 +118,10 @@ public class VFileCreateEvent extends VFileEvent { result = 31 * result + myChildName.hashCode(); return result; } + + @Override + public String toString() { + String kind = myDirectory ? (isEmptyDirectory() ? "(empty) " : "") + "dir " : "file "; + return "VfsEvent[create " + kind + myChildName + " in " + myParent.getUrl() + "]"; + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java index 323e722089e4..2f08a58f9ec6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java @@ -3,7 +3,6 @@ package com.intellij.openapi.vfs.newvfs.persistent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileAttributes; @@ -35,9 +34,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -class LocalFileSystemRefreshWorker { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker"); +import static com.intellij.openapi.vfs.newvfs.persistent.VfsEventGenerationHelper.LOG; +class LocalFileSystemRefreshWorker { private final boolean myIsRecursive; private final Queue myRefreshQueue = new Queue<>(100); private final VfsEventGenerationHelper myHelper = new VfsEventGenerationHelper(); @@ -89,9 +88,7 @@ class LocalFileSystemRefreshWorker { while (!myRefreshQueue.isEmpty()) { NewVirtualFile file = myRefreshQueue.pullFirst(); - boolean fileDirty = file.isDirty(); - if (LOG.isTraceEnabled()) LOG.trace("file=" + file + " dirty=" + fileDirty); - if (!fileDirty) continue; + if (!myHelper.checkDirty(file)) continue; checkCancelled(file); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index b48fbef968d5..a0bb00305395 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -3,12 +3,10 @@ package com.intellij.openapi.vfs.newvfs.persistent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -36,14 +34,13 @@ import java.util.List; import java.util.Set; import static com.intellij.openapi.util.Pair.pair; +import static com.intellij.openapi.vfs.newvfs.persistent.VfsEventGenerationHelper.LOG; import static com.intellij.util.containers.ContainerUtil.newTroveSet; /** * @author max */ public class RefreshWorker { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker"); - private final boolean myIsRecursive; private final Queue> myRefreshQueue = new Queue<>(100); private final VfsEventGenerationHelper myHelper = new VfsEventGenerationHelper(); @@ -74,6 +71,7 @@ public class RefreshWorker { myLocalFileSystemRefreshWorker.scan(); return; } + NewVirtualFile root = myRefreshQueue.peekFirst().first; NewVirtualFileSystem fs = root.getFileSystem(); if (root.isDirectory()) { @@ -93,9 +91,7 @@ public class RefreshWorker { while (!myRefreshQueue.isEmpty()) { Pair pair = myRefreshQueue.pullFirst(); NewVirtualFile file = pair.first; - boolean fileDirty = file.isDirty(); - if (LOG.isTraceEnabled()) LOG.trace("file=" + file + " dirty=" + fileDirty); - if (!fileDirty) continue; + if (!myHelper.checkDirty(file)) continue; checkCancelled(file); @@ -216,18 +212,11 @@ public class RefreshWorker { return true; }); - if (hasEvents) { - break; - } + + if (hasEvents) break; } } - @NotNull - private static Path appendPath(@NotNull String parent, @NotNull String name) { - return StringUtil.endsWith(parent, "/") ? Paths.get(parent + name) : Paths.get(parent + "/" + name); - } - - private void partialDirRefresh(@NotNull NewVirtualFileSystem fs, @NotNull TObjectHashingStrategy strategy, @NotNull VirtualDirectoryImpl dir) { @@ -289,9 +278,8 @@ public class RefreshWorker { return true; }); - if (hasEvents) { - break; - } + + if (hasEvents) break; } } @@ -314,21 +302,10 @@ public class RefreshWorker { FileAttributes attributes = fs.getAttributes(file); if (attributes == null) return null; String symlinkTarget = attributes.isSymLink() ? fs.resolveSymLink(file) : null; - return new NewChildRecord(name, appendPath(dir.getPath(), name), attributes, symlinkTarget); + return new NewChildRecord(name, Paths.get(dir.getPath() + '/' + name), attributes, symlinkTarget); } - private void checkAndScheduleFileNameChange(@Nullable OpenTHashSet actualNames, @NotNull VirtualFile child) { - if (actualNames != null) { - String currentName = child.getName(); - String actualName = actualNames.get(currentName); - if (actualName != null && !currentName.equals(actualName)) { - myHelper.scheduleAttributeChange(child, VirtualFile.PROP_NAME, currentName, actualName); - } - } - } - - private static class RefreshCancelledException extends RuntimeException { - } + private static class RefreshCancelledException extends RuntimeException { } private void checkCancelled(@NotNull NewVirtualFile stopAt) { if (myCancelled || ourCancellingCondition != null && ourCancellingCondition.fun(stopAt)) { @@ -373,13 +350,23 @@ public class RefreshWorker { if (currentIsDirectory != upToDateIsDirectory || currentIsSymlink != upToDateIsSymlink || currentIsSpecial != upToDateIsSpecial) { myHelper.scheduleDeletion(child); String symlinkTarget = upToDateIsSymlink ? fs.resolveSymLink(child) : null; - myHelper.scheduleCreation(parent, child.getName(), appendPath(parent.getPath(), child.getName()), childAttributes, symlinkTarget); + myHelper.scheduleCreation(parent, child.getName(), Paths.get(parent.getPath() + '/' + child.getName()), childAttributes, symlinkTarget); return true; } return false; } + private void checkAndScheduleFileNameChange(@Nullable OpenTHashSet actualNames, @NotNull VirtualFile child) { + if (actualNames != null) { + String currentName = child.getName(); + String actualName = actualNames.get(currentName); + if (actualName != null && !currentName.equals(actualName)) { + myHelper.scheduleAttributeChange(child, VirtualFile.PROP_NAME, currentName, actualName); + } + } + } + private static Function ourCancellingCondition; @TestOnly diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java index a09a11a6b9b4..08b7e64490e4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java @@ -7,6 +7,7 @@ import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.local.LocalFileSystemBase; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.events.*; import org.jetbrains.annotations.NotNull; @@ -15,8 +16,8 @@ import java.util.ArrayList; import java.util.List; class VfsEventGenerationHelper { - protected static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker"); - private static final Logger LOG_ATTRIBUTES = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker_Attributes"); + static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker"); + private final List myEvents = new ArrayList<>(); @NotNull @@ -24,26 +25,20 @@ class VfsEventGenerationHelper { return myEvents; } - void scheduleAttributeChange(@NotNull VirtualFile file, @VirtualFile.PropName @NotNull String property, Object current, Object upToDate) { - if (LOG.isTraceEnabled()) LOG.trace("update '" + property + "' file=" + file); - myEvents.add(new VFilePropertyChangeEvent(null, file, property, current, upToDate, true)); + boolean checkDirty(@NotNull NewVirtualFile file) { + boolean fileDirty = file.isDirty(); + if (LOG.isTraceEnabled()) LOG.trace("file=" + file + " dirty=" + fileDirty); + return fileDirty; } void checkContentChanged(@NotNull VirtualFile file, long oldTimestamp, long newTimestamp, long oldLength, long newLength) { if (oldTimestamp != newTimestamp || oldLength != newLength) { - scheduleUpdateContent(file, oldTimestamp, newTimestamp, oldLength, newLength); - } - } - - void scheduleUpdateContent(@NotNull VirtualFile file, long oldTimestamp, long newTimestamp, long oldLength, long newLength) { - if (LOG.isTraceEnabled()) { - LOG.trace( + if (LOG.isTraceEnabled()) LOG.trace( "update file=" + file + - (oldTimestamp != newTimestamp ? ", oldtimestamp=" + oldTimestamp + ", newtimestamp=" + newTimestamp : "") + - (oldLength != newLength ? ", oldlength=" + oldLength + ", length=" + newLength : "") - ); + (oldTimestamp != newTimestamp ? " TS=" + oldTimestamp + "->" + newTimestamp : "") + + (oldLength != newLength ? " len=" + oldLength + "->" + newLength : "")); + myEvents.add(new VFileContentChangeEvent(null, file, file.getModificationStamp(), -1, oldTimestamp, newTimestamp, oldLength, newLength, true)); } - myEvents.add(new VFileContentChangeEvent(null, file, file.getModificationStamp(), -1, oldTimestamp, newTimestamp, oldLength, newLength, true)); } void scheduleCreation(@NotNull VirtualFile parent, @@ -51,9 +46,8 @@ class VfsEventGenerationHelper { @NotNull Path path, @NotNull FileAttributes attributes, String symlinkTarget) { - boolean isEmptyDir = attributes.isDirectory() && !LocalFileSystemBase.hasChildren(path); - if (LOG.isTraceEnabled()) LOG.trace("create parent=" + parent + " name=" + childName + " attr=" + attributes); + boolean isEmptyDir = attributes.isDirectory() && !LocalFileSystemBase.hasChildren(path); myEvents.add(new VFileCreateEvent(null, parent, childName, attributes.isDirectory(), attributes, symlinkTarget, true, isEmptyDir)); } @@ -76,14 +70,16 @@ class VfsEventGenerationHelper { } void checkWritableAttributeChange(@NotNull VirtualFile file, boolean oldWritable, boolean newWritable) { - if (LOG_ATTRIBUTES.isTraceEnabled()) { - LOG_ATTRIBUTES.trace("file=" + file + " writable vfs=" + file.isWritable() + " persistence=" + oldWritable + " real=" + newWritable); - } if (oldWritable != newWritable) { scheduleAttributeChange(file, VirtualFile.PROP_WRITABLE, oldWritable, newWritable); } } + void scheduleAttributeChange(@NotNull VirtualFile file, @VirtualFile.PropName @NotNull String property, Object current, Object upToDate) { + if (LOG.isTraceEnabled()) LOG.trace("update file=" + file + ' ' + property + '=' + current + "->" + upToDate); + myEvents.add(new VFilePropertyChangeEvent(null, file, property, current, upToDate, true)); + } + void addAllEventsFrom(@NotNull VfsEventGenerationHelper otherHelper) { myEvents.addAll(otherHelper.myEvents); } From 23cf11cc48cbe6839cbbefafbc6b8081621b0393 Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Fri, 1 Feb 2019 18:14:33 +0300 Subject: [PATCH 2/7] [github] Rework PR metadata popup Always show filter field, some minor UI tweaks --- .../GithubPullRequestsMetadataServiceImpl.kt | 218 +++++++++++------- 1 file changed, 140 insertions(+), 78 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt index 4f952d4f6215..7b64f6373083 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt @@ -8,18 +8,20 @@ import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.Task import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.ui.popup.JBPopupListener import com.intellij.openapi.ui.popup.LightweightWindowEvent -import com.intellij.openapi.ui.popup.PopupChooserBuilder import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.Pair import com.intellij.openapi.util.text.StringUtil -import com.intellij.ui.CollectionListModel -import com.intellij.ui.ColorUtil -import com.intellij.ui.SimpleTextAttributes +import com.intellij.ui.* import com.intellij.ui.components.JBList +import com.intellij.ui.speedSearch.NameFilteringListModel +import com.intellij.ui.speedSearch.SpeedSearch import com.intellij.util.ui.ColorIcon +import com.intellij.util.ui.EmptyIcon import com.intellij.util.ui.JBUI -import com.intellij.util.ui.StatusText +import com.intellij.util.ui.JBUI.Panels.simplePanel import com.intellij.util.ui.UIUtil import com.intellij.util.ui.components.BorderLayoutPanel import org.jetbrains.plugins.github.api.GithubApiRequestExecutor @@ -36,10 +38,16 @@ import org.jetbrains.plugins.github.pullrequest.data.GithubPullRequestsBusyState import org.jetbrains.plugins.github.pullrequest.data.GithubPullRequestsDataLoader import org.jetbrains.plugins.github.util.* import java.awt.Component +import java.awt.Cursor +import java.awt.event.ActionListener +import java.awt.event.KeyEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent import java.util.concurrent.CompletableFuture import java.util.function.Consumer import java.util.function.Function import javax.swing.* +import javax.swing.event.DocumentEvent class GithubPullRequestsMetadataServiceImpl internal constructor(private val project: Project, private val progressManager: ProgressManager, @@ -101,8 +109,7 @@ class GithubPullRequestsMetadataServiceImpl internal constructor(private val pro override fun adjustLabels(pullRequest: Long, parentComponent: JComponent) { showChooser(pullRequest, "Labels", parentComponent, - { SelectionListCellRenderer.Labels() }, { it.name }, - { _, _ -> repoIssuesLabels }, { it.labels.orEmpty() }) + { SelectionListCellRenderer.Labels() }, { _, _ -> repoIssuesLabels }, { it.labels.orEmpty() }) .handleOnEdt(getAdjustmentHandler(pullRequest, "label") { delta, indicator -> requestExecutor.execute(indicator, GithubApiRequests.Repos.Issues.Labels @@ -120,89 +127,152 @@ class GithubPullRequestsMetadataServiceImpl internal constructor(private val pro return showChooser(pullRequest, popupTitle, parentComponent, { list -> val avatarIconsProvider = avatarIconsProviderFactory.create(JBUI.uiIntValue("GitHub.Avatars.Size", 20), list) SelectionListCellRenderer.Users(avatarIconsProvider) - }, { it.login }, availableListProvider, currentListExtractor) + }, availableListProvider, currentListExtractor) } private fun showChooser(pullRequest: Long, popupTitle: String, parentComponent: JComponent, - cellRendererFactory: (JList>) -> ListCellRenderer>, - speedSearchNamer: (T) -> String, + cellRendererFactory: (JList>) -> SelectionListCellRenderer, availableListProvider: (ProgressIndicator, GithubPullRequestDetailed) -> List, currentListExtractor: (GithubPullRequestDetailed) -> List) : CompletableFuture> { val listModel = CollectionListModel>() - val list = JBList>(listModel) + val list = JBList>(listModel).apply { + visibleRowCount = 7 + isFocusable = false + selectionMode = ListSelectionModel.SINGLE_SELECTION + } + val listCellRenderer = cellRendererFactory(list) + list.cellRenderer = listCellRenderer - val builder = PopupChooserBuilder>(list) - .setTitle(popupTitle) - .setResizable(true) - .setMovable(true) - .setNamerForFiltering { speedSearchNamer(it.value) } - .setAutoSelectIfEmpty(false) - .setCloseOnEnter(false) - .setRenderer(cellRendererFactory(list)) - .setItemsChosenCallback { - for (item in it) { - item.selected = !item.selected + val speedSearch = SpeedSearch() + val filteringListModel = NameFilteringListModel>(list, + { listCellRenderer.getText(it.value) }, + speedSearch::shouldBeShowing, + speedSearch) + + speedSearch.addChangeListener { + val prevSelection = list.selectedValue // save to restore the selection on filter drop + filteringListModel.refilter() + if (filteringListModel.size > 0) { + val fullMatchIndex = if (speedSearch.isHoldingFilter) filteringListModel.closestMatchIndex + else filteringListModel.getElementIndex(prevSelection) + if (fullMatchIndex != -1) { + list.selectedIndex = fullMatchIndex + } + + if (filteringListModel.size <= list.selectedIndex || !filteringListModel.contains(list.selectedValue)) { + list.selectedIndex = 0 } - list.repaint() } - val popup = builder.createPopup() + } - val updater = builder.backgroundUpdater - updater.paintBusy(true) - list.emptyText.text = "Loading..." + val scrollPane = ScrollPaneFactory.createScrollPane(list, true).apply { + viewport.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) + isFocusable = false + } - var originalSelection: Set = setOf() - - val progressIndicator = EmptyProgressIndicator() - Disposer.register(popup, Disposable { progressIndicator.cancel() }) - - val loadingFuture = GithubAsyncUtil - .futureOfMutable { dataLoader.getDataProvider(pullRequest).detailsRequest } - .thenComposeAsync(Function { details: GithubPullRequestDetailedWithHtml -> - originalSelection = currentListExtractor(details).toHashSet() - progressManager.submitBackgroundTask(project, "Load List Of Possibilities", true, progressIndicator) { - availableListProvider(it, details) + val searchField = SearchTextField(false).apply { + border = IdeBorderFactory.createBorder(SideBorder.BOTTOM) + UIUtil.setBackgroundRecursively(this, UIUtil.getListBackground()) + textEditor.border = JBUI.Borders.empty() + //focus dark magic, otherwise focus shifts to searchfield panel + isFocusable = false + addDocumentListener(object : DocumentAdapter() { + override fun textChanged(e: DocumentEvent) { + speedSearch.updatePattern(text) } }) - .thenAcceptAsync(Consumer { possibilities -> - listModel.replaceAll(possibilities - .map { SelectableWrapper(it, originalSelection.contains(it)) } - .sortedBy { !it.selected }) + } - updater.paintBusy(false) - list.emptyText.text = StatusText.DEFAULT_EMPTY_TEXT + val panel = simplePanel(scrollPane).addToTop(searchField) + ScrollingUtil.installActions(list, panel) + ListUtil.installAutoSelectOnMouseMove(list) - popup.pack(true, true) - }, EDT_EXECUTOR) - .exceptionally { - updater.paintBusy(false) - list.emptyText.clear() - list.emptyText.appendText("Can't load the list", SimpleTextAttributes.ERROR_ATTRIBUTES) - list.emptyText.appendSecondaryText(it.message.orEmpty(), SimpleTextAttributes.ERROR_ATTRIBUTES, null) - throw it + fun toggleSelection() { + for (item in list.selectedValuesList) { + item.selected = !item.selected } + list.repaint() + } - Disposer.register(popup, Disposable { - loadingFuture.cancel(true) + list.addMouseListener(object : MouseAdapter() { + override fun mouseReleased(e: MouseEvent) { + if (UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED) && !UIUtil.isSelectionButtonDown(e) && !e.isConsumed) toggleSelection() + } }) val result = CompletableFuture>() - popup.addListener(object : JBPopupListener { - override fun onClosed(event: LightweightWindowEvent) { - if (!loadingFuture.isDone || loadingFuture.isCancelled || loadingFuture.isCompletedExceptionally) { - result.cancel(true) - return + JBPopupFactory.getInstance().createComponentPopupBuilder(panel, searchField) + .setRequestFocus(true) + .setCancelOnClickOutside(true) + .setTitle(popupTitle) + .setResizable(true) + .setMovable(true) + .setKeyboardActions(listOf(Pair.create(ActionListener { toggleSelection() }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)))) + .addListener(object : JBPopupListener { + private lateinit var loadingFuture: CompletableFuture + private lateinit var originalSelection: Set + + override fun beforeShown(event: LightweightWindowEvent) { + val popup = event.asPopup() + + list.setPaintBusy(true) + list.emptyText.text = "Loading..." + + + val progressIndicator = EmptyProgressIndicator() + + loadingFuture = GithubAsyncUtil + .futureOfMutable { dataLoader.getDataProvider(pullRequest).detailsRequest } + .thenComposeAsync(Function { details: GithubPullRequestDetailedWithHtml -> + originalSelection = currentListExtractor(details).toHashSet() + progressManager.submitBackgroundTask(project, "Load List Of Possibilities", true, progressIndicator) { + availableListProvider(it, details) + } + }) + .thenAcceptAsync(Consumer { possibilities -> + listModel.replaceAll(possibilities + .map { SelectableWrapper(it, originalSelection.contains(it)) } + .sortedBy { !it.selected }) + + list.setPaintBusy(false) + list.emptyText.text = UIBundle.message("message.noMatchesFound") + + popup.pack(true, true) + + if (list.selectedIndex == -1) { + list.selectedIndex = 0 + } + }, EDT_EXECUTOR) + .exceptionally { + list.setPaintBusy(false) + list.emptyText.clear() + list.emptyText.appendText("Can't load the list", SimpleTextAttributes.ERROR_ATTRIBUTES) + list.emptyText.appendSecondaryText(it.message.orEmpty(), SimpleTextAttributes.ERROR_ATTRIBUTES, null) + throw it + } + + Disposer.register(popup, Disposable { + progressIndicator.cancel() + loadingFuture.cancel(true) + }) } - val selected = listModel.items.filter { it.selected }.map { it.value } - result.complete(CollectionDelta(originalSelection, selected)) - } - }) - popup.showUnderneathOf(parentComponent) + override fun onClosed(event: LightweightWindowEvent) { + if (!loadingFuture.isDone || loadingFuture.isCancelled || loadingFuture.isCompletedExceptionally) { + result.cancel(true) + return + } + + val selected = listModel.items.filter { it.selected }.map { it.value } + result.complete(CollectionDelta(originalSelection, selected)) + } + }) + .createPopup() + .showUnderneathOf(parentComponent) return result } @@ -240,19 +310,19 @@ class GithubPullRequestsMetadataServiceImpl internal constructor(private val pro private data class SelectableWrapper(val value: T, var selected: Boolean = false) - private sealed class SelectionListCellRenderer - : ListCellRenderer>, BorderLayoutPanel() { + private sealed class SelectionListCellRenderer : ListCellRenderer>, BorderLayoutPanel() { private val mainLabel = JLabel() private val checkIconLabel = JLabel() init { checkIconLabel.iconTextGap = JBUI.scale(UIUtil.DEFAULT_VGAP) + checkIconLabel.border = JBUI.Borders.empty(0, 4) addToLeft(checkIconLabel) addToCenter(mainLabel) - border = JBUI.Borders.empty(2) + border = JBUI.Borders.empty(4, 0) } override fun getListCellRendererComponent(list: JList>, @@ -260,9 +330,8 @@ class GithubPullRequestsMetadataServiceImpl internal constructor(private val pro index: Int, isSelected: Boolean, cellHasFocus: Boolean): Component { - font = list.font - foreground = UIUtil.getListForeground(isSelected, list.hasFocus()) - background = UIUtil.getListBackground(isSelected, list.hasFocus()) + foreground = UIUtil.getListForeground(isSelected, true) + background = UIUtil.getListBackground(isSelected, true) mainLabel.foreground = foreground mainLabel.font = font @@ -270,14 +339,7 @@ class GithubPullRequestsMetadataServiceImpl internal constructor(private val pro mainLabel.text = getText(value.value) mainLabel.icon = getIcon(value.value) - if (value.selected) { - checkIconLabel.icon = AllIcons.Actions.Checked - checkIconLabel.border = JBUI.Borders.empty(0, 4) - } - else { - checkIconLabel.icon = null - checkIconLabel.border = JBUI.Borders.empty(0, 10) - } + checkIconLabel.icon = if (value.selected) AllIcons.Actions.Checked else EmptyIcon.create(AllIcons.Actions.Checked) return this } From a7e623970a3525f150036c8bfcbe638bb361adee Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Tue, 5 Feb 2019 14:02:22 +0300 Subject: [PATCH 3/7] [github] Better checkmark icon in PR metadata popup --- .../service/GithubPullRequestsMetadataServiceImpl.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt index 7b64f6373083..ad868e235792 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GithubPullRequestsMetadataServiceImpl.kt @@ -1,7 +1,6 @@ // Copyright 2000-2019 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 org.jetbrains.plugins.github.pullrequest.data.service -import com.intellij.icons.AllIcons import com.intellij.openapi.Disposable import com.intellij.openapi.progress.EmptyProgressIndicator import com.intellij.openapi.progress.ProgressIndicator @@ -18,11 +17,8 @@ import com.intellij.ui.* import com.intellij.ui.components.JBList import com.intellij.ui.speedSearch.NameFilteringListModel import com.intellij.ui.speedSearch.SpeedSearch -import com.intellij.util.ui.ColorIcon -import com.intellij.util.ui.EmptyIcon -import com.intellij.util.ui.JBUI +import com.intellij.util.ui.* import com.intellij.util.ui.JBUI.Panels.simplePanel -import com.intellij.util.ui.UIUtil import com.intellij.util.ui.components.BorderLayoutPanel import org.jetbrains.plugins.github.api.GithubApiRequestExecutor import org.jetbrains.plugins.github.api.GithubApiRequests @@ -339,7 +335,8 @@ class GithubPullRequestsMetadataServiceImpl internal constructor(private val pro mainLabel.text = getText(value.value) mainLabel.icon = getIcon(value.value) - checkIconLabel.icon = if (value.selected) AllIcons.Actions.Checked else EmptyIcon.create(AllIcons.Actions.Checked) + val icon = LafIconLookup.getIcon("checkmark", isSelected, false) + checkIconLabel.icon = if (value.selected) icon else EmptyIcon.create(icon) return this } From d5748653e785f51f4a7a822d13ae3bd9381d51ec Mon Sep 17 00:00:00 2001 From: Nikita Skvortsov Date: Tue, 5 Feb 2019 14:20:54 +0300 Subject: [PATCH 4/7] run integration tests with Gradle 5.2 --- .../gradle/tooling/builder/AbstractModelBuilderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java b/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java index 3b833d03b83a..b352f15b93a6 100644 --- a/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java +++ b/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java @@ -72,7 +72,7 @@ public abstract class AbstractModelBuilderTest { {"2.6"}, /*{"2.7"}, {"2.8"}, {"2.9"}, {"2.10"}, {"2.11"}, {"2.12"}, {"2.13"}, */{"2.14.1"}, {"3.0"}, /*{"3.1"}, {"3.2"}, {"3.3"}, {"3.4"},*/ {"3.5"}, {"4.0"}, /*{"4.1"}, {"4.2"}, {"4.3"}, {"4.4"}, {"4.5.1"}, {"4.6"}, {"4.7"}, {"4.8"}, {"4.9"},*/ {"4.10.3"}, - {"5.0"} + {"5.0"}, {"5.2"} }; public static final String BASE_GRADLE_VERSION = String.valueOf(SUPPORTED_GRADLE_VERSIONS[SUPPORTED_GRADLE_VERSIONS.length - 1][0]); From 8da1ec73f106364f9f88a6fc2a16b340b5ca8f16 Mon Sep 17 00:00:00 2001 From: Vladislav Shishov Date: Tue, 5 Feb 2019 14:18:25 +0300 Subject: [PATCH 5/7] [gui-test] delete LogActionsDuringTest rule --- .../focus/GoToClassTwiceFocusTest.kt | 1 - .../testGuiFramework/impl/GuiTestCase.kt | 4 -- .../impl/LogActionsDuringTest.kt | 41 ------------------- 3 files changed, 46 deletions(-) delete mode 100644 platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/LogActionsDuringTest.kt diff --git a/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/focus/GoToClassTwiceFocusTest.kt b/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/focus/GoToClassTwiceFocusTest.kt index 8ba0540bd52c..429dc6f6f492 100644 --- a/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/focus/GoToClassTwiceFocusTest.kt +++ b/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/focus/GoToClassTwiceFocusTest.kt @@ -6,7 +6,6 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.keymap.KeymapUtil import com.intellij.testGuiFramework.fixtures.IdeFrameFixture import com.intellij.testGuiFramework.impl.GuiTestCase -import com.intellij.testGuiFramework.impl.LogActionsDuringTest import com.intellij.testGuiFramework.impl.ScreenshotsDuringTest import com.intellij.testGuiFramework.tests.community.CommunityProjectCreator import com.intellij.testGuiFramework.util.Key.ESCAPE diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCase.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCase.kt index 47da8e9288d5..f611dedc21d1 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCase.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCase.kt @@ -88,10 +88,6 @@ open class GuiTestCase { @JvmField val testMethod = TestName() - @Rule - @JvmField - val logActionsDuringTest = LogActionsDuringTest() - val projectFolder: String by lazy { val dir = File(projectsFolder, testMethod.methodName) if (!dir.mkdirs()) { diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/LogActionsDuringTest.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/LogActionsDuringTest.kt deleted file mode 100644 index b33072ecc8b0..000000000000 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/LogActionsDuringTest.kt +++ /dev/null @@ -1,41 +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.testGuiFramework.impl - -import com.intellij.application.subscribe -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.ex.AnActionListener -import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.util.Disposer -import org.junit.rules.TestWatcher -import org.junit.runner.Description - -private val LOG = logger() - -/** - * Rule that logs all actions during the test. - */ -class LogActionsDuringTest : TestWatcher() { - private var disposable: Disposable? = null - - private val actionListener = object : AnActionListener { - override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) { - LOG.info("Action: $action (actionId: ${ActionManager.getInstance().getId(action)}); DataContext: $dataContext; Event: $event") - } - } - - override fun starting(description: Description) { - disposable = Disposer.newDisposable() - AnActionListener.TOPIC.subscribe(disposable!!, actionListener) - } - - override fun finished(description: Description) { - disposable?.let { - this.disposable = null - Disposer.dispose(it) - } - } -} From 21bb50227360f2e5ceeda2d4110596f7a12f0f08 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 5 Feb 2019 09:36:01 +0100 Subject: [PATCH 6/7] use extensionList --- .../com/intellij/uast/UastMetaLanguage.java | 14 +++++++---- ...nMethodIsAlwaysInvertedInspectionTest.java | 5 +--- .../org/jetbrains/uast/UastLanguagePlugin.kt | 25 ++++--------------- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/java/java-analysis-api/src/com/intellij/uast/UastMetaLanguage.java b/java/java-analysis-api/src/com/intellij/uast/UastMetaLanguage.java index 66aea1626805..62c827b47584 100644 --- a/java/java-analysis-api/src/com/intellij/uast/UastMetaLanguage.java +++ b/java/java-analysis-api/src/com/intellij/uast/UastMetaLanguage.java @@ -1,24 +1,28 @@ -// 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. +// Copyright 2000-2019 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.uast; import com.intellij.lang.Language; import com.intellij.lang.MetaLanguage; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.uast.UastLanguagePlugin; import java.util.Collection; -import java.util.HashSet; +import java.util.Collections; import java.util.Set; /** * @author yole */ public class UastMetaLanguage extends MetaLanguage { - private final Set myLanguages = new HashSet<>(); + private final Set myLanguages; protected UastMetaLanguage() { super("UAST"); - for (UastLanguagePlugin plugin: UastLanguagePlugin.Companion.getInstances()) { + + Collection languagePlugins = UastLanguagePlugin.Companion.getInstances(); + myLanguages = new THashSet<>(languagePlugins.size()); + for (UastLanguagePlugin plugin: languagePlugins) { myLanguages.add(plugin.getLanguage()); } } @@ -31,6 +35,6 @@ public class UastMetaLanguage extends MetaLanguage { @NotNull @Override public Collection getMatchingLanguages() { - return myLanguages; + return Collections.unmodifiableSet(myLanguages); } } diff --git a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/BooleanMethodIsAlwaysInvertedInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/BooleanMethodIsAlwaysInvertedInspectionTest.java index 81e174f55d7b..f395a169f38f 100644 --- a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/BooleanMethodIsAlwaysInvertedInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/BooleanMethodIsAlwaysInvertedInspectionTest.java @@ -1,6 +1,4 @@ -// Copyright 2000-2017 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. +// Copyright 2000-2019 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.codeInspection; import com.intellij.codeInspection.booleanIsAlwaysInverted.BooleanMethodIsAlwaysInvertedInspection; @@ -9,7 +7,6 @@ import com.intellij.testFramework.IdeaTestUtil; import com.siyeh.ig.IGInspectionTestCase; public class BooleanMethodIsAlwaysInvertedInspectionTest extends IGInspectionTestCase { - public void testUnusedMethod() { doTest(); } diff --git a/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt b/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt index 529f393c65c9..61eb6fef1555 100644 --- a/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt +++ b/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 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-2019 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 org.jetbrains.uast import com.intellij.lang.Language @@ -21,13 +7,12 @@ import com.intellij.psi.* interface UastLanguagePlugin { companion object { - val extensionPointName: ExtensionPointName = - ExtensionPointName.create("org.jetbrains.uast.uastLanguagePlugin") - private val extensionArray: Array by lazy(LazyThreadSafetyMode.PUBLICATION) { extensionPointName.extensions } + val extensionPointName = ExtensionPointName("org.jetbrains.uast.uastLanguagePlugin") + private val extensions by lazy(LazyThreadSafetyMode.PUBLICATION) { extensionPointName.extensionList } - fun getInstances(): Collection = extensionArray.toList() + fun getInstances(): Collection = extensions - fun byLanguage(language: Language): UastLanguagePlugin? = extensionArray.firstOrNull { it.language === language } + fun byLanguage(language: Language): UastLanguagePlugin? = extensions.firstOrNull { it.language === language } } data class ResolvedMethod(val call: UCallExpression, val method: PsiMethod) From 7b384ead07fcaa92283898681d7c64b8f0b5b046 Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Tue, 5 Feb 2019 12:12:56 +0100 Subject: [PATCH 7/7] FUS: report project together with actions and intention --- .../impl/ShowIntentionActionsHandler.java | 2 +- .../intellij/ide/actions/ActionsCollector.java | 15 ++++----------- .../actions/persistence/ActionsCollectorImpl.java | 5 +++-- .../actions/persistence/IntentionsCollector.java | 6 ++++++ .../statistic/eventLog/EventLogConfiguration.kt | 2 +- .../actionSystem/impl/ActionManagerImpl.java | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java index 6dbc085e4bfc..8b33c118b1c0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/ShowIntentionActionsHandler.java @@ -197,7 +197,7 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler { } private static void invokeIntention(@NotNull IntentionAction action, @Nullable Editor editor, @NotNull PsiFile file) { - IntentionsCollector.getInstance().record(action, file.getLanguage()); + IntentionsCollector.getInstance().record(file.getProject(), action, file.getLanguage()); PsiElement elementToMakeWritable = action.getElementToMakeWritable(file); if (elementToMakeWritable != null && !FileModificationService.getInstance().preparePsiElementsForWrite(elementToMakeWritable)) { return; diff --git a/platform/platform-api/src/com/intellij/ide/actions/ActionsCollector.java b/platform/platform-api/src/com/intellij/ide/actions/ActionsCollector.java index 3bf664d3ae8f..90b2939cd3f9 100644 --- a/platform/platform-api/src/com/intellij/ide/actions/ActionsCollector.java +++ b/platform/platform-api/src/com/intellij/ide/actions/ActionsCollector.java @@ -4,6 +4,7 @@ package com.intellij.ide.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; import com.intellij.util.xmlb.annotations.MapAnnotation; import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.NotNull; @@ -18,18 +19,10 @@ import java.util.Map; */ public abstract class ActionsCollector { /** - * Only actions from platform and JB plugins are recorded. - * If no context class is provided then nothing will be recorded. - * @deprecated use {@link #record(String, Class)} instead + * @deprecated use {@link #record(Project, AnAction, AnActionEvent)} instead */ @Deprecated - public void record(String actionId) {} - - /** - * @deprecated use {@link #record(AnAction, AnActionEvent)} instead - */ - @Deprecated - public void record(@Nullable String actionId, @NotNull Class context, @Nullable AnActionEvent event) {} + public void record(@Nullable AnAction action, @Nullable AnActionEvent event) {} /** * Records explicitly whitelisted actions @@ -47,7 +40,7 @@ public abstract class ActionsCollector { * Records action id for global actions or action class name for actions generated on runtime. * Only actions from platform and JB plugins are recorded. */ - public abstract void record(@Nullable AnAction action, @Nullable AnActionEvent event); + public abstract void record(@Nullable Project project, @Nullable AnAction action, @Nullable AnActionEvent event); public abstract State getState(); diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/ActionsCollectorImpl.java b/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/ActionsCollectorImpl.java index 73a56b90254f..64bbc1abc4f8 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/ActionsCollectorImpl.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/ActionsCollectorImpl.java @@ -16,6 +16,7 @@ import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.RoamingType; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -53,11 +54,11 @@ public class ActionsCollectorImpl extends ActionsCollector implements Persistent } @Override - public void record(@Nullable AnAction action, @Nullable AnActionEvent event) { + public void record(@Nullable Project project, @Nullable AnAction action, @Nullable AnActionEvent event) { if (action == null) return; final PluginInfo info = PluginInfoDetectorKt.getPluginInfo(action.getClass()); - final FeatureUsageData data = new FeatureUsageData().addOS().addPluginInfo(info); + final FeatureUsageData data = new FeatureUsageData().addOS().addProject(project).addPluginInfo(info); if (event != null) { data.addInputEvent(event). diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/IntentionsCollector.java b/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/IntentionsCollector.java index 7b8b4c4a8547..859a29dcfaa5 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/IntentionsCollector.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/collectors/fus/actions/persistence/IntentionsCollector.java @@ -12,6 +12,7 @@ import com.intellij.internal.statistic.utils.PluginInfo; import com.intellij.internal.statistic.utils.PluginInfoDetectorKt; import com.intellij.lang.Language; import com.intellij.openapi.components.*; +import com.intellij.openapi.project.Project; import com.intellij.util.xmlb.annotations.MapAnnotation; import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.NotNull; @@ -41,10 +42,15 @@ public class IntentionsCollector implements PersistentStateComponent clazz = getOriginalHandlerClass(action); final PluginInfo info = PluginInfoDetectorKt.getPluginInfo(clazz); final FeatureUsageData data = new FeatureUsageData().addOS(). + addProject(project). addPluginInfo(info). addLanguage(language); diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt b/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt index c2466f9752e5..a3bc11cbf68f 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt +++ b/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt @@ -17,7 +17,7 @@ import java.util.prefs.Preferences object EventLogConfiguration { private val LOG = Logger.getInstance(EventLogConfiguration::class.java) private const val SALT_PREFERENCE_KEY = "feature_usage_event_log_salt" - const val version: Int = 7 + const val version: Int = 8 val sessionId: String = UUID.randomUUID().toString().shortedUUID() diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java index 1b56428a6e1d..6090d2419731 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java @@ -1191,7 +1191,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab } //noinspection AssignmentToStaticFieldFromInstanceMethod IdeaLogger.ourLastActionId = myLastPreformedActionId; - ActionsCollector.getInstance().record(action, event); + ActionsCollector.getInstance().record(CommonDataKeys.PROJECT.getData(dataContext), action, event); for (AnActionListener listener : myActionListeners) { listener.beforeActionPerformed(action, dataContext, event); }