From 99e0303b4ad45cf1c407c8424ffe282ffbbe42c2 Mon Sep 17 00:00:00 2001 From: Nikita Gubarkov Date: Tue, 20 Oct 2020 20:17:12 +0300 Subject: [PATCH] IDEA-242733 Updated NLS for intellij.emojipicker & reformatted code GitOrigin-RevId: 11b8c76106b0dbd522ac7e033a57af3589cae830 --- .../messages/EmojiCategoriesBundle.properties | 13 ++ .../messages/EmojipickerBundle.properties | 14 +- .../jetbrains/plugins/emojipicker/Emoji.java | 10 +- .../plugins/emojipicker/EmojiCategory.java | 10 +- .../plugins/emojipicker/EmojiSearchIndex.java | 60 ++++--- .../plugins/emojipicker/EmojiSkinTone.java | 8 +- .../action/OpenEmojiPickerAction.java | 38 +++-- .../messages/EmojiCategoriesBundle.java | 35 ++++ .../messages/EmojipickerBundle.java | 29 ++++ .../emojipicker/service/EmojiService.java | 158 ++++++++---------- .../emojipicker/ui/EmojiCategoryPanel.java | 13 +- .../emojipicker/ui/EmojiInfoPanel.java | 20 +-- .../emojipicker/ui/EmojiListPanel.java | 120 +++++++------ .../plugins/emojipicker/ui/EmojiPicker.java | 73 ++++---- .../emojipicker/ui/EmojiPickerStyle.java | 2 - .../emojipicker/ui/EmojiSearchField.java | 12 +- .../emojipicker/ui/EmojiSkinTonesPanel.java | 34 ++-- 17 files changed, 361 insertions(+), 288 deletions(-) create mode 100644 plugins/emojipicker/resources/messages/EmojiCategoriesBundle.properties create mode 100644 plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojiCategoriesBundle.java create mode 100644 plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojipickerBundle.java diff --git a/plugins/emojipicker/resources/messages/EmojiCategoriesBundle.properties b/plugins/emojipicker/resources/messages/EmojiCategoriesBundle.properties new file mode 100644 index 000000000000..7d10f9be0552 --- /dev/null +++ b/plugins/emojipicker/resources/messages/EmojiCategoriesBundle.properties @@ -0,0 +1,13 @@ +# Copyright 2000-2020 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. +# These properties are accessed dynamically, so suppress "unused" warnings +# suppress inspection "UnusedProperty" for whole file + +category.EmojiPicker.RecentlyUsed=Recently Used +category.EmojiPicker.SmileysAndPeople=Smileys \\& People +category.EmojiPicker.AnimalsAndNature=Animals \\& Nature +category.EmojiPicker.FoodAndDrink=Food \\& Drink +category.EmojiPicker.TravelAndPlaces=Travel \\& Places +category.EmojiPicker.Activities=Activities +category.EmojiPicker.Objects=Objects +category.EmojiPicker.Symbols=Symbols +category.EmojiPicker.Flags=Flags \ No newline at end of file diff --git a/plugins/emojipicker/resources/messages/EmojipickerBundle.properties b/plugins/emojipicker/resources/messages/EmojipickerBundle.properties index bc9daee04038..b929ffae5f63 100644 --- a/plugins/emojipicker/resources/messages/EmojipickerBundle.properties +++ b/plugins/emojipicker/resources/messages/EmojipickerBundle.properties @@ -1,16 +1,8 @@ # Copyright 2000-2020 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. -action.EmojiPicker.Open.text=Emo_ji & Symbols + +action.EmojiPicker.Open.text=Emo_ji \\& Symbols message.EmojiPicker.Initializing=Initializing emoji picker message.EmojiPicker.BuildingIndex=Building search index message.EmojiPicker.SavingIndexData=Saving data - -category.EmojiPicker.RecentlyUsed=Recently Used -category.EmojiPicker.SmileysAndPeople=Smileys & People -category.EmojiPicker.AnimalsAndNature=Animals & Nature -category.EmojiPicker.FoodAndDrink=Food & Drink -category.EmojiPicker.TravelAndPlaces=Travel & Places -category.EmojiPicker.Activities=Activities -category.EmojiPicker.Objects=Objects -category.EmojiPicker.Symbols=Symbols -category.EmojiPicker.Flags=Flags \ No newline at end of file +message.EmojiPicker.NoEmojiFound=No emoji found diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/Emoji.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/Emoji.java index 7b58b8394b8f..9680c3dbb32d 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/Emoji.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/Emoji.java @@ -1,15 +1,17 @@ // Copyright 2000-2020 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.emojipicker; +import com.intellij.openapi.util.NlsSafe; +import org.jetbrains.annotations.NonNls; + import java.io.Serializable; public class Emoji implements Serializable { - private final int myId; - private final String myValue; + @NonNls private final String myValue; private final boolean myToned; - public Emoji(int id, String value, boolean toned) { + public Emoji(int id, @NonNls String value, boolean toned) { myId = id; myValue = value; myToned = toned; @@ -19,8 +21,8 @@ public class Emoji implements Serializable { return myId; } + @NlsSafe public String getTonedValue(EmojiSkinTone tone) { return myToned ? myValue + tone.getStringValue() : myValue; } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiCategory.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiCategory.java index 2d230bb9c314..8bf42ccb4f8e 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiCategory.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiCategory.java @@ -2,6 +2,7 @@ package org.jetbrains.plugins.emojipicker; import com.intellij.openapi.util.IconLoader; +import org.jetbrains.annotations.NonNls; import javax.swing.*; import java.io.Serializable; @@ -9,9 +10,7 @@ import java.util.List; public class EmojiCategory implements Serializable { - - - private final String myId; + @NonNls private final String myId; private final List myEmoji; private transient Icon myIcon; @@ -20,6 +19,7 @@ public class EmojiCategory implements Serializable { myEmoji = emojiList; } + @NonNls public String getId() { return myId; } @@ -30,11 +30,9 @@ public class EmojiCategory implements Serializable { public Icon getIcon() { Icon icon = myIcon; - if(icon == null) { + if (icon == null) { myIcon = icon = IconLoader.getIcon("/icons/categories/" + myId + ".svg", EmojiCategory.class); } return icon; } - - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSearchIndex.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSearchIndex.java index d1c08c12c25d..dc42670451f0 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSearchIndex.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSearchIndex.java @@ -1,38 +1,38 @@ // Copyright 2000-2020 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.emojipicker; +import org.jetbrains.annotations.NonNls; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class EmojiSearchIndex implements Serializable { - - - private final String myChars; + @NonNls private final String myChars; private final int[] myData; private final int myRootNodeOffset, myTotalEmojiIndices; - private EmojiSearchIndex(String chars, int[] data, int rootNodeOffset, int totalEmojiIndices) { + private EmojiSearchIndex(@NonNls String chars, int[] data, int rootNodeOffset, int totalEmojiIndices) { myChars = chars; myData = data; myRootNodeOffset = rootNodeOffset; myTotalEmojiIndices = totalEmojiIndices; } - private int findNodeForPrefix(String key, int prefixOffset, int nodeOffset) { - if(prefixOffset == key.length()) return nodeOffset; + private int findNodeForPrefix(@NonNls String key, int prefixOffset, int nodeOffset) { + if (prefixOffset == key.length()) return nodeOffset; int children = myData[nodeOffset + 2]; for (int c = 0; c < children; c++) { int child = myData[nodeOffset + 3 + c]; int childCharsFrom = myData[child], childCharsTo = myData[child + 1]; - int i, limit = Math.min(key.length() - prefixOffset, childCharsTo - childCharsFrom); + int i, limit = Math.min(key.length() - prefixOffset, childCharsTo - childCharsFrom); for (i = 0; i < limit; i++) { - if(key.charAt(prefixOffset + i) != myChars.charAt(childCharsFrom + i)) break; + if (key.charAt(prefixOffset + i) != myChars.charAt(childCharsFrom + i)) break; } - if(i == childCharsTo - childCharsFrom) return findNodeForPrefix(key, prefixOffset + i, child); - if(i == key.length() - prefixOffset) return child; - if(i > 0) return -1; + if (i == childCharsTo - childCharsFrom) return findNodeForPrefix(key, prefixOffset + i, child); + if (i == key.length() - prefixOffset) return child; + if (i > 0) return -1; } return -1; } @@ -50,13 +50,13 @@ public class EmojiSearchIndex implements Serializable { } } - public boolean lookupIds(boolean[] idMap, String prefix) { - if(idMap.length < myTotalEmojiIndices) { + public boolean lookupIds(boolean[] idMap, @NonNls String prefix) { + if (idMap.length < myTotalEmojiIndices) { throw new IllegalArgumentException("Output array is too small: " + idMap.length + ", but there are " + myTotalEmojiIndices + "emoji indices"); } int node = findNodeForPrefix(prefix, 0, myRootNodeOffset); - if(node == -1) return false; + if (node == -1) return false; Arrays.fill(idMap, false); collectIdsFromSubtree(idMap, node); return true; @@ -67,34 +67,32 @@ public class EmojiSearchIndex implements Serializable { } - - - public static class PrefixTree { - private String myPrefix; + @NonNls private String myPrefix; private final List myChildren = new ArrayList<>(); private final List myValues = new ArrayList<>(); - private PrefixTree(String prefix) { myPrefix = prefix; } + private PrefixTree(@NonNls String prefix) { myPrefix = prefix; } + public PrefixTree() { this(""); } - public void add(String key, int value) { - if(key.isEmpty()) { + public void add(@NonNls String key, int value) { + if (key.isEmpty()) { myValues.add(value); return; } - for(int c = 0; c < myChildren.size(); c++) { + for (int c = 0; c < myChildren.size(); c++) { PrefixTree child = myChildren.get(c); - int i, limit = Math.min(key.length(), child.myPrefix.length()); + int i, limit = Math.min(key.length(), child.myPrefix.length()); for (i = 0; i < limit; i++) { - if(key.charAt(i) != child.myPrefix.charAt(i)) break; + if (key.charAt(i) != child.myPrefix.charAt(i)) break; } - if(i == child.myPrefix.length()) { + if (i == child.myPrefix.length()) { child.add(key.substring(limit), value); return; } - else if(i > 0) { + else if (i > 0) { PrefixTree firstPart = new PrefixTree(key.substring(0, i)); child.myPrefix = child.myPrefix.substring(i); @@ -128,8 +126,8 @@ public class EmojiSearchIndex implements Serializable { System.arraycopy(childrenLinks, 0, data.myData, data.myDataPointer, childrenLinks.length); data.myDataPointer += childrenLinks.length; data.write(myValues.size()); - for(int i : myValues) { - if(i > data.myMaxEmojiId) data.myMaxEmojiId = i; + for (int i : myValues) { + if (i > data.myMaxEmojiId) data.myMaxEmojiId = i; data.write(i); } return index; @@ -139,15 +137,15 @@ public class EmojiSearchIndex implements Serializable { StringBuffer myChars; int[] myData; int myDataPointer, myMaxEmojiId = -1; + private void ensureDataCapacity(int remaining) { - if(myDataPointer + remaining > myData.length) myData = Arrays.copyOf(myData, myData.length * 2); + if (myDataPointer + remaining > myData.length) myData = Arrays.copyOf(myData, myData.length * 2); } + private BuildData write(int i) { myData[myDataPointer++] = i; return this; } } - } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSkinTone.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSkinTone.java index 8b246eac036e..fa0f07d89578 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSkinTone.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/EmojiSkinTone.java @@ -1,6 +1,8 @@ // Copyright 2000-2020 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.emojipicker; +import org.jetbrains.annotations.NonNls; + public enum EmojiSkinTone { NO_TONE(""), LIGHT("🏻"), @@ -9,12 +11,12 @@ public enum EmojiSkinTone { MEDIUM_DARK("🏾"), DARK("🏿"); - private final String myValue; + @NonNls private final String myValue; - EmojiSkinTone(String value) {this.myValue = value;} + EmojiSkinTone(@NonNls String value) {this.myValue = value;} + @NonNls public String getStringValue() { return myValue; } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/action/OpenEmojiPickerAction.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/action/OpenEmojiPickerAction.java index 3364c6a1ddb4..5592b8f579e0 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/action/OpenEmojiPickerAction.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/action/OpenEmojiPickerAction.java @@ -27,12 +27,16 @@ public class OpenEmojiPickerAction extends DumbAwareAction { private static Context getContext(AnActionEvent e, boolean findOnly) { Editor editor = e.getData(CommonDataKeys.EDITOR); - if(editor != null) { - if(editor.isViewer()) return null; - if(findOnly) return Context.FOUND; + if (editor != null) { + if (editor.isViewer()) return null; + if (findOnly) return Context.FOUND; Consumer input; - if(editor instanceof EditorImpl) input = ((EditorImpl) editor)::type; - else if(editor.getContentComponent() instanceof TypingTarget) input = ((TypingTarget) editor.getContentComponent())::type; + if (editor instanceof EditorImpl) { + input = ((EditorImpl)editor)::type; + } + else if (editor.getContentComponent() instanceof TypingTarget) { + input = ((TypingTarget)editor.getContentComponent())::type; + } else { input = s -> WriteCommandAction.writeCommandAction(editor.getProject()).run(() -> { com.intellij.openapi.editor.Document doc = editor.getDocument(); @@ -46,28 +50,29 @@ public class OpenEmojiPickerAction extends DumbAwareAction { } Component component = e.getData(PlatformDataKeys.CONTEXT_COMPONENT); - if(component instanceof EmojiSearchField) { + if (component instanceof EmojiSearchField) { // Easy way to block recursive pickers return null; } - if(component instanceof TypingTarget) { - if(findOnly) return Context.FOUND; + if (component instanceof TypingTarget) { + if (findOnly) return Context.FOUND; return new Context( - ((TypingTarget) component)::type, + ((TypingTarget)component)::type, p -> p.showUnderneathOf(component) ); } - if(component instanceof JTextComponent) { - if(findOnly) return Context.FOUND; - JTextComponent field = (JTextComponent) component; + if (component instanceof JTextComponent) { + if (findOnly) return Context.FOUND; + JTextComponent field = (JTextComponent)component; Document doc = field.getDocument(); return new Context( s -> { try { doc.insertString(field.getCaretPosition(), s, null); - } catch (BadLocationException exception) { + } + catch (BadLocationException exception) { throw new RuntimeException(exception); } }, @@ -86,24 +91,21 @@ public class OpenEmojiPickerAction extends DumbAwareAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { Context context = getContext(e, false); - if(context != null) { + if (context != null) { JBPopup popup = EmojiPicker.createPopup(e.getProject(), context.myInputCallback); context.myPopupShowCallback.accept(popup); } } - - - private static class Context { private static final Context FOUND = new Context(null, null); private final Consumer myInputCallback; private final Consumer myPopupShowCallback; + private Context(Consumer inputCallback, Consumer popupShowCallback) { myInputCallback = inputCallback; myPopupShowCallback = popupShowCallback; } } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojiCategoriesBundle.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojiCategoriesBundle.java new file mode 100644 index 000000000000..d22220a97159 --- /dev/null +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojiCategoriesBundle.java @@ -0,0 +1,35 @@ +package org.jetbrains.plugins.emojipicker.messages; + +import com.intellij.DynamicBundle; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.PropertyKey; +import org.jetbrains.plugins.emojipicker.EmojiCategory; + +import java.util.function.Supplier; + +public class EmojiCategoriesBundle extends DynamicBundle { + @NonNls private static final String BUNDLE = "messages.EmojiCategoriesBundle"; + private static final EmojiCategoriesBundle INSTANCE = new EmojiCategoriesBundle(); + + private EmojiCategoriesBundle() { + super(BUNDLE); + } + + @NotNull + public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) { + return INSTANCE.getMessage(key, params); + } + + @NotNull + public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, + Object @NotNull ... params) { + return INSTANCE.getLazyMessage(key, params); + } + + public static @Nls String findNameForCategory(EmojiCategory category) { + if (category == null) return null; + return message("category.EmojiPicker." + category.getId()); + } +} diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojipickerBundle.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojipickerBundle.java new file mode 100644 index 000000000000..5864908bd4d6 --- /dev/null +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/messages/EmojipickerBundle.java @@ -0,0 +1,29 @@ +package org.jetbrains.plugins.emojipicker.messages; + +import com.intellij.DynamicBundle; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.PropertyKey; + +import java.util.function.Supplier; + +public class EmojipickerBundle extends DynamicBundle { + @NonNls private static final String BUNDLE = "messages.EmojipickerBundle"; + private static final EmojipickerBundle INSTANCE = new EmojipickerBundle(); + + private EmojipickerBundle() { + super(BUNDLE); + } + + @NotNull + public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) { + return INSTANCE.getMessage(key, params); + } + + @NotNull + public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, + Object @NotNull ... params) { + return INSTANCE.getLazyMessage(key, params); + } +} diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/service/EmojiService.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/service/EmojiService.java index aeb02072ba40..0077fdd467e4 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/service/EmojiService.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/service/EmojiService.java @@ -7,8 +7,9 @@ import com.intellij.openapi.progress.PerformInBackgroundOption; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; -import com.intellij.openapi.util.NlsSafe; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.emojipicker.Emoji; @@ -32,18 +33,18 @@ import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; +import static org.jetbrains.plugins.emojipicker.messages.EmojipickerBundle.message; + @Service @State(name = "EmojiPickerState", storages = @Storage("emoji.picker.xml")) public final class EmojiService implements PersistentStateComponent { - - private final List myEmoji; private final List myCategories; private final EmojiCategory myRecentlyUsedCategory; private volatile SearchIndex myEmojiSearchIndex; - private final String[] myEmojiNames; + @Nls private final String[] myEmojiNames; private volatile EmojiSkinTone mySkinTone; private volatile boolean dirty; @@ -61,62 +62,65 @@ public final class EmojiService implements PersistentStateComponent(); List emoji; SearchIndex searchIndex; - String[] emojiNames; + @Nls String[] emojiNames; try { - try(ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedEmojiPath))) { - emoji = (List) in.readObject(); + try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedEmojiPath))) { + emoji = (List)in.readObject(); myCategories.add(myRecentlyUsedCategory); - myCategories.addAll((List) in.readObject()); + myCategories.addAll((List)in.readObject()); } - try(ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedIndexPath))) { - searchIndex = new SearchIndex((EmojiSearchIndex) in.readObject()); + try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedIndexPath))) { + searchIndex = new SearchIndex((EmojiSearchIndex)in.readObject()); } - try(ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedNamesPath))) { - emojiNames = (String[]) in.readObject(); + try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedNamesPath))) { + emojiNames = (String[])in.readObject(); } - } catch (IOException | ClassNotFoundException ignore) { + } + catch (IOException | ClassNotFoundException ignore) { Files.createDirectories(configDir); EmojiData emojiData = EmojiData.read(); emoji = emojiData.myEmoji; myCategories.clear(); myCategories.add(myRecentlyUsedCategory); myCategories.addAll(emojiData.myCategories); - String[] names = emojiNames = new String[emoji.size()]; + @Nls String[] names = emojiNames = new String[emoji.size()]; CldrData cldr = new CldrData(emojiData); final Locale baseLocale = Locale.ENGLISH; cldr.read(baseLocale, emojiNames); searchIndex = new SearchIndex(cldr.myIndexTree.buildIndex()); ProgressManager.getInstance().run( - new Task.Backgroundable(null, getString("message.EmojiPicker.Initializing"), false, PerformInBackgroundOption.ALWAYS_BACKGROUND) { + new Task.Backgroundable(null, message("message.EmojiPicker.Initializing"), false, PerformInBackgroundOption.ALWAYS_BACKGROUND) { @Override public void run(@NotNull ProgressIndicator indicator) { try { - try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedEmojiPath, StandardOpenOption.CREATE))) { + try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedEmojiPath, StandardOpenOption.CREATE))) { out.writeObject(emojiData.myEmoji); out.writeObject(emojiData.myCategories); } - try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedNamesPath, StandardOpenOption.CREATE))) { + try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedNamesPath, StandardOpenOption.CREATE))) { out.writeObject(names); } - indicator.setText(getString("message.EmojiPicker.BuildingIndex")); + indicator.setText(message("message.EmojiPicker.BuildingIndex")); indicator.setIndeterminate(false); Locale[] locales = Locale.getAvailableLocales(); - double multiplier = 1.0 / (double) locales.length; + double multiplier = 1.0 / (double)locales.length; for (int i = 0; i < locales.length; i++) { - indicator.setFraction((double) i * multiplier); - if(!locales[i].equals(baseLocale)) cldr.read(locales[i], null); + indicator.setFraction((double)i * multiplier); + if (!locales[i].equals(baseLocale)) cldr.read(locales[i], null); } indicator.setIndeterminate(true); SearchIndex searchIndex = new SearchIndex(cldr.myIndexTree.buildIndex()); - indicator.setText(getString("message.EmojiPicker.SavingIndexData")); - try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedIndexPath, StandardOpenOption.CREATE))) { + indicator.setText(message("message.EmojiPicker.SavingIndexData")); + try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedIndexPath, StandardOpenOption.CREATE))) { out.writeObject(searchIndex.myIndex); } myEmojiSearchIndex = searchIndex; - } catch (IOException e) { + } + catch (IOException e) { throw new UncheckedIOException(e); - } catch (SAXException e) { + } + catch (SAXException e) { throw new RuntimeException(e); } } @@ -132,30 +136,18 @@ public final class EmojiService implements PersistentStateComponent findEmojiByPrefix(String prefix) { + public List findEmojiByPrefix(@NonNls String prefix) { return myEmojiSearchIndex.lookupEmoji(prefix); } public void saveRecentlyUsedEmoji(Emoji emoji) { myRecentlyUsedCategory.getEmoji().remove(emoji); - while(myRecentlyUsedCategory.getEmoji().size() >= 32) { + while (myRecentlyUsedCategory.getEmoji().size() >= 32) { myRecentlyUsedCategory.getEmoji().remove(myRecentlyUsedCategory.getEmoji().size() - 1); } myRecentlyUsedCategory.getEmoji().add(0, emoji); @@ -173,15 +165,15 @@ public final class EmojiService implements PersistentStateComponent emoji) { mySkinTone = tone; myRecentlyUsedEmoji = emoji; @@ -219,13 +209,9 @@ public final class EmojiService implements PersistentStateComponent lookupEmoji(String prefix) { - if(myIndex.lookupIds(myIdMap, prefix)) { + synchronized List lookupEmoji(@NonNls String prefix) { + if (myIndex.lookupIds(myIdMap, prefix)) { List result = new ArrayList<>(100); for (int i = 0; i < myIdMap.length; i++) { - if(myIdMap[i]) result.add(myEmoji.get(i)); + if (myIdMap[i]) result.add(myEmoji.get(i)); } return result; } - else return List.of(); + else { + return List.of(); + } } - } - - - private static class EmojiData { private final List myEmoji = new ArrayList<>(); private final List myCategories = new ArrayList<>(); - private final Map myIndicesMap = new HashMap<>(); + private final Map<@NonNls String, Integer> myIndicesMap = new HashMap<>(); private static EmojiData read() throws IOException { - Set tonedEmojiSet = readToned(); + Set<@NonNls String> tonedEmojiSet = readToned(); EmojiData emojiData = new EmojiData(); - try(BufferedReader reader = new BufferedReader(new InputStreamReader( + try (BufferedReader reader = new BufferedReader(new InputStreamReader( EmojiService.class.getResourceAsStream("/data/emoji.txt"), StandardCharsets.UTF_8))) { EmojiCategory category = null; - String s; - while((s = reader.readLine()) != null) { - if(s.isBlank()) category = null; + @NonNls String s; + while ((s = reader.readLine()) != null) { + if (s.isBlank()) { + category = null; + } else { - if(category == null) { + if (category == null) { emojiData.myCategories.add(category = new EmojiCategory(s, new ArrayList<>())); } else { @@ -285,19 +271,15 @@ public final class EmojiService implements PersistentStateComponent readToned() throws IOException { - try(BufferedReader reader = new BufferedReader(new InputStreamReader( + private static Set<@NonNls String> readToned() throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader( EmojiService.class.getResourceAsStream("/data/toned.txt"), StandardCharsets.UTF_8))) { return reader.lines().collect(Collectors.toSet()); } } - } - - - private static class CldrData { private final EmojiData myEmojiData; @@ -316,38 +298,38 @@ public final class EmojiService implements PersistentStateComponent emojiPicker.selectCategory(category, true)) { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); - if(emojiPicker.getCurrentFocusTarget() == category) { + if (emojiPicker.getCurrentFocusTarget() == category) { int x = getWidth() / 2, y = getHeight() / 2; g.setColor(myStyle.myFocusBorderColor); g.drawRoundRect(x - 15, y - 15, 30, 30, 4, 4); } - if(myActiveCategory == category) { + if (myActiveCategory == category) { g.setColor(myStyle.mySelectedCategoryColor); g.fillRect(0, getHeight() - 2, getWidth(), 2); } @@ -62,5 +62,4 @@ class EmojiCategoryPanel extends JPanel { myActiveCategory = category; repaint(); } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiInfoPanel.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiInfoPanel.java index 074ef32ba149..4135395d4afd 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiInfoPanel.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiInfoPanel.java @@ -2,7 +2,9 @@ package org.jetbrains.plugins.emojipicker.ui; import com.intellij.ide.ui.AntialiasingType; +import com.intellij.openapi.util.NlsSafe; import com.intellij.ui.scale.JBUIScale; +import org.jetbrains.annotations.Nls; import org.jetbrains.plugins.emojipicker.Emoji; import org.jetbrains.plugins.emojipicker.EmojiSkinTone; import org.jetbrains.plugins.emojipicker.service.EmojiService; @@ -12,10 +14,9 @@ import java.awt.*; import java.awt.font.TextLayout; public class EmojiInfoPanel extends JPanel { - private final EmojiPickerStyle myStyle; - private String myCurrentEmoji; - private String myCurrentEmojiName; + @NlsSafe private String myCurrentEmoji; + @Nls private String myCurrentEmojiName; EmojiInfoPanel(EmojiPickerStyle style) { myStyle = style; @@ -26,16 +27,16 @@ public class EmojiInfoPanel extends JPanel { @Override public void paintComponent(Graphics g) { - ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false)); + ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false)); g.setColor(myCurrentEmoji != null ? myStyle.myToolbarColor : myStyle.myBackgroundColor); g.fillRoundRect(0, 0, getWidth(), getHeight(), 6, 6); g.fillRect(0, 0, getWidth(), getHeight() - 6); - if(myCurrentEmoji != null) { + if (myCurrentEmoji != null) { g.setColor(myStyle.myBorderColor); g.drawLine(0, 0, getWidth(), 0); - new TextLayout(myCurrentEmoji, myStyle.myEmojiFont, ((Graphics2D) g).getFontRenderContext()) - .draw((Graphics2D) g, 16, getHeight() - 17); - if(myCurrentEmojiName != null) { + new TextLayout(myCurrentEmoji, myStyle.myEmojiFont, ((Graphics2D)g).getFontRenderContext()) + .draw((Graphics2D)g, 16, getHeight() - 17); + if (myCurrentEmojiName != null) { g.setFont(myStyle.myFont); g.setColor(myStyle.myTextColor); g.drawString(myCurrentEmojiName, 49, getHeight() - 20); @@ -44,7 +45,7 @@ public class EmojiInfoPanel extends JPanel { } void showEmojiInfo(Emoji emoji, EmojiSkinTone skinTone) { - if(emoji == null) { + if (emoji == null) { myCurrentEmoji = myCurrentEmojiName = null; } else { @@ -53,5 +54,4 @@ public class EmojiInfoPanel extends JPanel { } repaint(); } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiListPanel.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiListPanel.java index 55e28eaeb672..102ad1a76139 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiListPanel.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiListPanel.java @@ -8,9 +8,13 @@ import com.intellij.util.ImageLoader; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.StartupUiUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; import org.jetbrains.plugins.emojipicker.Emoji; import org.jetbrains.plugins.emojipicker.EmojiCategory; import org.jetbrains.plugins.emojipicker.EmojiSkinTone; +import org.jetbrains.plugins.emojipicker.messages.EmojiCategoriesBundle; +import org.jetbrains.plugins.emojipicker.messages.EmojipickerBundle; import org.jetbrains.plugins.emojipicker.service.EmojiService; import javax.swing.*; @@ -24,8 +28,6 @@ import java.util.List; import java.util.Objects; class EmojiListPanel extends JBScrollPane { - - private static final Image NO_EMOJI_FOUND_IMAGE = ImageLoader.scaleImage(Objects.requireNonNull( ImageLoader.loadFromStream(EmojiListPanel.class.getResourceAsStream("/icons/NoEmojiFound.png"))), 40); private final Dimension myCellSize = new Dimension(JBUIScale.scale(40), JBUIScale.scale(40)); @@ -58,30 +60,34 @@ class EmojiListPanel extends JBScrollPane { } }); getViewport().addChangeListener(e -> { - if(myCurrentPanel == myCategoriesPanel) { + if (myCurrentPanel == myCategoriesPanel) { Component topComponent = myCategoriesPanel.getComponentAt(getViewport().getViewPosition()); - if(topComponent instanceof Category) emojiPicker.selectCategory(((Category) topComponent).myCategory, false); - else emojiPicker.selectCategory(myCategoriesPanel.myCategories.get(0).myCategory, false); + if (topComponent instanceof Category) { + emojiPicker.selectCategory(((Category)topComponent).myCategory, false); + } + else { + emojiPicker.selectCategory(myCategoriesPanel.myCategories.get(0).myCategory, false); + } } }); setBorder(JBUI.Borders.customLine(myStyle.myBorderColor, 1, 0, 0, 0)); } void selectCategory(EmojiCategory category) { - if(myCurrentPanel != myCategoriesPanel) { + if (myCurrentPanel != myCategoriesPanel) { setViewportView(myCurrentPanel = myCategoriesPanel); } - if(category == null || category == myCategoriesPanel.myCategories.get(0).myCategory) { + if (category == null || category == myCategoriesPanel.myCategories.get(0).myCategory) { setCurrentItem(myCategoriesPanel.myCategories.get(0).myCategory.getEmoji().isEmpty() ? myCategoriesPanel.myCategories.get(1) : myCategoriesPanel.myCategories.get(0), 0); myCategoriesPanel.scrollRectToVisible(new Rectangle(0, 0, 1, getHeight())); } else { Category cat = null; - for(Category c : myCategoriesPanel.myCategories) { - if(c.myCategory == category) cat = c; + for (Category c : myCategoriesPanel.myCategories) { + if (c.myCategory == category) cat = c; } - if(cat == null) return; + if (cat == null) return; setCurrentItem(cat, 0); cat.scrollRectToVisible(new Rectangle(0, 0, 1, getHeight())); } @@ -90,52 +96,56 @@ class EmojiListPanel extends JBScrollPane { void updateSkinTone(EmojiSkinTone skinTone) { myCurrentSkinTone = skinTone; myCurrentPanel.repaint(); - if(myCurrentItemCategory != null && myCurrentItemIndex >= 0) { + if (myCurrentItemCategory != null && myCurrentItemIndex >= 0) { myEmojiPicker.updateEmojiInfo(myCurrentItemCategory.myCategory.getEmoji().get(myCurrentItemIndex), myCurrentSkinTone); } } - void updateSearchFilter(String text) { - if(text.isEmpty()) { + void updateSearchFilter(@NonNls String text) { + if (text.isEmpty()) { myEmojiPicker.selectCategory(myCategoriesPanel.myCategories.get(0).myCategory, true); } else { myEmojiPicker.selectCategory(null, false); mySearchCategoryPanel.myCategory = new EmojiCategory(null, EmojiService.getInstance().findEmojiByPrefix(text.strip())); mySearchCategoryPanel.updateLayout(getWidth()); - if(mySearchCategoryPanel.myCategory.getEmoji().isEmpty()) setCurrentItem(null, -1); - else setCurrentItem(mySearchCategoryPanel, 0); + if (mySearchCategoryPanel.myCategory.getEmoji().isEmpty()) { + setCurrentItem(null, -1); + } + else { + setCurrentItem(mySearchCategoryPanel, 0); + } setViewportView(myCurrentPanel = mySearchCategoryPanel); } } void selectCurrentEmoji() { - if(!hasCurrentItem()) return; + if (!hasCurrentItem()) return; Emoji emoji = myCurrentItemCategory.myCategory.getEmoji().get(myCurrentItemIndex); EmojiService.getInstance().saveRecentlyUsedEmoji(emoji); myEmojiPicker.selectEmoji(emoji.getTonedValue(myCurrentSkinTone)); } void navigate(int dx, int dy) { - if(myCurrentItemIndex < 0) return; + if (myCurrentItemIndex < 0) return; int x = (myCurrentItemIndex % myItemsPerRow + dx + myItemsPerRow) % myItemsPerRow; int y = myCurrentItemIndex / myItemsPerRow + dy; int newIndex = myItemsPerRow * y + x; - if(newIndex >= 0 && newIndex < myCurrentItemCategory.myCategory.getEmoji().size()) { + if (newIndex >= 0 && newIndex < myCurrentItemCategory.myCategory.getEmoji().size()) { setCurrentItem(myCurrentItemCategory, newIndex); } else { int cat = myCategoriesPanel.findCategoryIndex(myCurrentItemCategory); - if(cat == -1) return; + if (cat == -1) return; boolean up = newIndex < 0; cat += up ? -1 : 1; - if(cat < 0 || cat >= myCategoriesPanel.myCategories.size()) return; + if (cat < 0 || cat >= myCategoriesPanel.myCategories.size()) return; Category c = myCategoriesPanel.myCategories.get(cat); int rows = (c.myCategory.getEmoji().size() + myItemsPerRow - 1) / myItemsPerRow; y = up ? rows - 1 : 0; - if(y < 0 || myItemsPerRow * y + x >= c.myCategory.getEmoji().size()) { + if (y < 0 || myItemsPerRow * y + x >= c.myCategory.getEmoji().size()) { y--; - if(y < 0) return; + if (y < 0) return; } setCurrentItem(c, myItemsPerRow * y + x); } @@ -162,9 +172,6 @@ class EmojiListPanel extends JBScrollPane { } - - - private abstract class UpdatableLayoutPanel extends JPanel { private UpdatableLayoutPanel() { @@ -172,7 +179,6 @@ class EmojiListPanel extends JBScrollPane { } abstract void updateLayout(int width); - } @@ -184,21 +190,20 @@ class EmojiListPanel extends JBScrollPane { myCategories = categories; setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); add(Box.createRigidArea(new Dimension(0, 15))); - for(Category c : categories) add(c); + for (Category c : categories) add(c); } @Override void updateLayout(int width) { - for(Category c : myCategories) c.updateLayout(width); + for (Category c : myCategories) c.updateLayout(width); } private int findCategoryIndex(Category c) { for (int i = 0; i < myCategories.size(); i++) { - if(myCategories.get(i) == c) return i; + if (myCategories.get(i) == c) return i; } return -1; } - } @@ -207,37 +212,42 @@ class EmojiListPanel extends JBScrollPane { private static final int NO_LABEL_PADDING = 12; private static final int LABEL_HEIGHT = 32; private EmojiCategory myCategory; - private final String myName; + @Nls private final String myName; private final Insets myPadding; private Category(EmojiCategory category) { myCategory = category; - myName = EmojiService.getInstance().findNameForCategory(category); + myName = EmojiCategoriesBundle.findNameForCategory(category); myPadding = JBUI.insets(myName == null ? NO_LABEL_PADDING : LABEL_HEIGHT, myHorizontalPadding, 8, myHorizontalPadding); MouseAdapter mouseAdapter = new MouseAdapter() { private int getItemIndexUnderCursor(Point point) { - if(point.x < myPadding.left || point.y < myPadding.top) return -1; + if (point.x < myPadding.left || point.y < myPadding.top) return -1; int x = xVisibleToGrid(point.x), y = yVisibleToGrid(point.y); - if(x >= myItemsPerRow || point.x > xGridToVisible(x) + myCellSize.width || point.y > yGridToVisible(y) + myCellSize.height) { + if (x >= myItemsPerRow || point.x > xGridToVisible(x) + myCellSize.width || point.y > yGridToVisible(y) + myCellSize.height) { return -1; } int index = myItemsPerRow * y + x; return index >= 0 && index < myCategory.getEmoji().size() ? index : -1; } + private boolean setCurrentItemUnderCursor(Point point) { int item = getItemIndexUnderCursor(point); - if(item != -1) { + if (item != -1) { setCurrentItem(Category.this, item); return true; } - else return false; + else { + return false; + } } + @Override public void mouseClicked(MouseEvent e) { - if(setCurrentItemUnderCursor(e.getPoint())) { + if (setCurrentItemUnderCursor(e.getPoint())) { selectCurrentEmoji(); } } + @Override public void mouseMoved(MouseEvent e) { setCurrentItemUnderCursor(e.getPoint()); @@ -250,12 +260,15 @@ class EmojiListPanel extends JBScrollPane { private int xVisibleToGrid(int x) { return (x - myPadding.left) / (myCellSize.width + myCellGaps.width); } + private int yVisibleToGrid(int y) { return (y - myPadding.top) / (myCellSize.height + myCellGaps.height); } + private int xGridToVisible(int x) { return x * (myCellSize.width + myCellGaps.width) + myPadding.left; } + private int yGridToVisible(int y) { return y * (myCellSize.height + myCellGaps.height) + myPadding.top; } @@ -277,21 +290,23 @@ class EmojiListPanel extends JBScrollPane { @Override public void paint(Graphics g) { super.paint(g); - ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false)); - if(myName == null && myCategory.getEmoji().isEmpty()) paintNoEmojiFound(g); + ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false)); + if (myName == null && myCategory.getEmoji().isEmpty()) { + paintNoEmojiFound(g); + } else { - if(myItemsPerRow <= 0) return; + if (myItemsPerRow <= 0) return; paintSelection(g); paintItems(g); - if(myName != null) paintCategoryLabel(g); + if (myName != null) paintCategoryLabel(g); } } private void paintNoEmojiFound(Graphics g) { - if(g instanceof Graphics2D) { + if (g instanceof Graphics2D) { int x = (getWidth() - NO_EMOJI_FOUND_IMAGE.getWidth(this)) / 2; int y = (getHeight() - NO_EMOJI_FOUND_IMAGE.getHeight(this)) / 2; - Graphics2D g2 = (Graphics2D) g; + Graphics2D g2 = (Graphics2D)g; final Composite saveComposite = g2.getComposite(); g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5F)); StartupUiUtil.drawImage(g, NO_EMOJI_FOUND_IMAGE, x, y, null); @@ -299,14 +314,14 @@ class EmojiListPanel extends JBScrollPane { } g.setColor(myStyle.myNoEmojiFoundTextColor); g.setFont(myStyle.myLightFont); - String message = "No emoji found"; + @Nls String message = EmojipickerBundle.message("message.EmojiPicker.NoEmojiFound"); int x = (getWidth() - g.getFontMetrics().stringWidth(message)) / 2; int y = (getHeight() + NO_EMOJI_FOUND_IMAGE.getHeight(this)) / 2 + 25; g.drawString(message, x, y); } private void paintSelection(Graphics g) { - if(myCurrentItemCategory == this && myCurrentItemIndex != -1) { + if (myCurrentItemCategory == this && myCurrentItemIndex != -1) { int x = xGridToVisible(myCurrentItemIndex % myItemsPerRow); int y = yGridToVisible(myCurrentItemIndex / myItemsPerRow); g.setColor(myStyle.myHoverBackgroundColor); @@ -317,18 +332,18 @@ class EmojiListPanel extends JBScrollPane { private void paintItems(Graphics g) { Rectangle bounds = g.getClipBounds(); int from = yVisibleToGrid(bounds.y) * myItemsPerRow, to = yVisibleToGrid(bounds.y + bounds.height) * myItemsPerRow + myItemsPerRow; - if(from < 0) from = 0; + if (from < 0) from = 0; int itemCount = myCategory.getEmoji().size(); - if(to > itemCount) to = itemCount; - if(from > to) from = to; + if (to > itemCount) to = itemCount; + if (from > to) from = to; FontMetrics metrics = g.getFontMetrics(myStyle.myEmojiFont); int verticalOffset = metrics.getHeight() / 2 - metrics.getDescent(); for (int i = from; i < to; i++) { int x = xGridToVisible(i % myItemsPerRow), y = yGridToVisible(i / myItemsPerRow); - String item = myCategory.getEmoji().get(i).getTonedValue(myCurrentSkinTone); + @Nls String item = myCategory.getEmoji().get(i).getTonedValue(myCurrentSkinTone); int width = metrics.stringWidth(item); - new TextLayout(item, myStyle.myEmojiFont, ((Graphics2D) g).getFontRenderContext()) - .draw((Graphics2D) g,x + (myCellSize.width - width) / 2F, y + myCellSize.height / 2F + verticalOffset); + new TextLayout(item, myStyle.myEmojiFont, ((Graphics2D)g).getFontRenderContext()) + .draw((Graphics2D)g, x + (myCellSize.width - width) / 2F, y + myCellSize.height / 2F + verticalOffset); } } @@ -340,8 +355,5 @@ class EmojiListPanel extends JBScrollPane { g.setColor(myStyle.myTextColor); g.drawString(myName, 16, offset + 20); } - } - - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPicker.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPicker.java index d0378994fda4..90cfbf84531a 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPicker.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPicker.java @@ -5,6 +5,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.ui.WindowMoveListener; +import org.jetbrains.annotations.NonNls; import org.jetbrains.plugins.emojipicker.Emoji; import org.jetbrains.plugins.emojipicker.EmojiCategory; import org.jetbrains.plugins.emojipicker.EmojiSkinTone; @@ -22,8 +23,6 @@ import java.util.function.Consumer; public class EmojiPicker extends JLayeredPane { - - private final List myCategories; private final EmojiSearchField mySearchField; private final EmojiCategoryPanel myCategoryPanel; @@ -32,7 +31,8 @@ public class EmojiPicker extends JLayeredPane { private final JPanel myEmojiSkinTonesModal; private final EmojiSkinTonesPanel myEmojiSkinTonesPanel; private final KeyboardManager myKeyboardManager; - private Consumer myInputCallback = emoji -> {}; + private Consumer myInputCallback = emoji -> { + }; private EmojiPicker() { @@ -43,7 +43,7 @@ public class EmojiPicker extends JLayeredPane { gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; gbc.gridx = 0; - GridBagConstraints fillerGbc = (GridBagConstraints) gbc.clone(); + GridBagConstraints fillerGbc = (GridBagConstraints)gbc.clone(); fillerGbc.weighty = 1; EmojiPickerStyle style = new EmojiPickerStyle(); @@ -78,6 +78,7 @@ public class EmojiPicker extends JLayeredPane { selectCategory(myCategories.get(0), true); selectSkinToneFromPanel(); } + private static void applyWindowMoveListener(Component c) { WindowMoveListener listener = new WindowMoveListener(c); c.addMouseListener(listener); @@ -86,14 +87,14 @@ public class EmojiPicker extends JLayeredPane { void selectCategory(EmojiCategory category, boolean scrollToCategory) { myCategoryPanel.selectCategory(category); - if(scrollToCategory) { - if(!mySearchField.getText().isEmpty()) mySearchField.setText(""); + if (scrollToCategory) { + if (!mySearchField.getText().isEmpty()) mySearchField.setText(""); myEmojiListPanel.selectCategory(category); myKeyboardManager.resetFocus(); } } - void search(String text) { + void search(@NonNls String text) { myEmojiListPanel.updateSearchFilter(text); myKeyboardManager.resetFocus(); myKeyboardManager.emojiNavigationMode = false; @@ -103,7 +104,7 @@ public class EmojiPicker extends JLayeredPane { myEmojiInfoPanel.showEmojiInfo(emoji, skinTone); } - void selectEmoji(String emoji) { + void selectEmoji(@NonNls String emoji) { myInputCallback.accept(emoji); } @@ -149,19 +150,18 @@ public class EmojiPicker extends JLayeredPane { .setShowBorder(false) .createPopup(); picker.myInputCallback = emoji -> { - if(emoji != null) { + if (emoji != null) { inputCallback.accept(emoji); popup.closeOk(null); } - else popup.cancel(); + else { + popup.cancel(); + } }; return popup; } - - - private class KeyboardManager { private final List focusTargets = new ArrayList<>(); @@ -175,7 +175,7 @@ public class EmojiPicker extends JLayeredPane { } private void resetFocus() { - if(currentFocusTarget != 0) { + if (currentFocusTarget != 0) { currentFocusTarget = 0; emojiNavigationMode = false; myCategoryPanel.repaint(); @@ -185,8 +185,8 @@ public class EmojiPicker extends JLayeredPane { private boolean handleKey(int k, int modifiers) { Object focus = focusTargets.get(currentFocusTarget); - if(focus == myEmojiSkinTonesPanel) { - if(myEmojiSkinTonesPanel.isVisible()) { + if (focus == myEmojiSkinTonesPanel) { + if (myEmojiSkinTonesPanel.isVisible()) { switch (k) { case KeyEvent.VK_UP: case KeyEvent.VK_DOWN: @@ -201,7 +201,7 @@ public class EmojiPicker extends JLayeredPane { return true; } } - else if(k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) { + else if (k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) { openSkinToneSelectionPanel(); myEmojiSkinTonesPanel.focusItem(1); return true; @@ -222,29 +222,31 @@ public class EmojiPicker extends JLayeredPane { case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT: resetFocus(); - if(!emojiNavigationMode) { + if (!emojiNavigationMode) { emojiNavigationMode = k == KeyEvent.VK_UP || k == KeyEvent.VK_DOWN || (k == KeyEvent.VK_LEFT && mySearchField.getCaretPosition() == 0) || (k == KeyEvent.VK_RIGHT && mySearchField.getCaretPosition() == mySearchField.getText().length()); } - if(!myEmojiListPanel.hasCurrentItem()) emojiNavigationMode = false; - if(emojiNavigationMode) { + if (!myEmojiListPanel.hasCurrentItem()) emojiNavigationMode = false; + if (emojiNavigationMode) { myEmojiListPanel.navigate( keyToOffset(k, KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT), keyToOffset(k, KeyEvent.VK_DOWN, KeyEvent.VK_UP) ); return true; } - else return false; + else { + return false; + } } - if(focus instanceof EmojiCategory) { - if(k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) { - selectCategory((EmojiCategory) focus, true); + if (focus instanceof EmojiCategory) { + if (k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) { + selectCategory((EmojiCategory)focus, true); return true; } } - else if(focus == mySearchField && k == KeyEvent.VK_ENTER) { + else if (focus == mySearchField && k == KeyEvent.VK_ENTER) { myEmojiListPanel.selectCurrentEmoji(); return true; } @@ -252,50 +254,53 @@ public class EmojiPicker extends JLayeredPane { } private int keyToOffset(int key, int positive, int negative) { - if(key == positive) return 1; - if(key == negative) return -1; + if (key == positive) return 1; + if (key == negative) return -1; return 0; } - } - - - private static class JPanelFillLayout implements LayoutManager2 { @Override public void addLayoutComponent(Component comp, Object constraints) {} + @Override public Dimension maximumLayoutSize(Container target) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } + @Override public float getLayoutAlignmentX(Container target) { return 0.5f; } + @Override public float getLayoutAlignmentY(Container target) { return 0.5f; } + @Override public void invalidateLayout(Container target) {} + @Override public void addLayoutComponent(String name, Component comp) {} + @Override public void removeLayoutComponent(Component comp) {} + @Override public Dimension preferredLayoutSize(Container parent) { synchronized (parent.getTreeLock()) { return parent.getSize(); } } + @Override public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } + @Override public void layoutContainer(Container parent) { synchronized (parent.getTreeLock()) { Dimension size = parent.getSize(); for (int i = 0; i < parent.getComponentCount(); i++) { - if(parent.getComponent(i).getClass() == JPanel.class) parent.getComponent(i).setBounds(0, 0, size.width, size.height); + if (parent.getComponent(i).getClass() == JPanel.class) parent.getComponent(i).setBounds(0, 0, size.width, size.height); } } } } - - } \ No newline at end of file diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPickerStyle.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPickerStyle.java index 115d4659629e..f35ec96bef1b 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPickerStyle.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiPickerStyle.java @@ -11,7 +11,6 @@ import java.util.stream.Stream; class EmojiPickerStyle { - final Font myFont = JBUI.Fonts.label().deriveFont(Font.BOLD, JBUIScale.scale(13F)); final Font myLightFont = myFont.deriveFont(Font.PLAIN); final Font myEmojiFont = Stream.of(GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) @@ -28,5 +27,4 @@ class EmojiPickerStyle { final Color myFocusBorderColor = new JBColor(0x97C3F3, 0x97C3F3); final Color myTextColor = JBUI.CurrentTheme.Label.foreground(); final Color myNoEmojiFoundTextColor = new JBColor(0x808080, 0xBBBBBB); - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSearchField.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSearchField.java index 362069d1bc69..80f839866a66 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSearchField.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSearchField.java @@ -23,10 +23,12 @@ public class EmojiSearchField extends ExtendableTextField { public Icon getIcon(boolean hovered) { return AllIcons.Actions.Search; } + @Override public boolean isIconBeforeText() { return true; } + @Override public int getIconGap() { return JBUIScale.scale(6); @@ -45,14 +47,17 @@ public class EmojiSearchField extends ExtendableTextField { public Icon getIcon(boolean hovered) { return emojiPicker.getCurrentSkinToneIcon(hovered); } + @Override public boolean isIconBeforeText() { return false; } + @Override public int getIconGap() { return JBUIScale.scale(6); } + @Override public Runnable getActionOnClick() { return emojiPicker::openSkinToneSelectionPanel; @@ -76,14 +81,16 @@ public class EmojiSearchField extends ExtendableTextField { void handle(KeyEvent e, boolean typed) { int c = typed ? e.getKeyChar() : e.getKeyCode(); boolean mayIntercept = c == KeyEvent.VK_SPACE || c == KeyEvent.VK_ENTER; - if(mayIntercept == typed && emojiPicker.handleKey(c, e.getModifiersEx())) { + if (mayIntercept == typed && emojiPicker.handleKey(c, e.getModifiersEx())) { e.consume(); } } + @Override public void keyTyped(KeyEvent e) { handle(e, true); } + @Override public void keyPressed(KeyEvent e) { handle(e, false); @@ -98,12 +105,11 @@ public class EmojiSearchField extends ExtendableTextField { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); - if(myEmojiPicker.getCurrentFocusTarget() instanceof EmojiSkinTonesPanel) { + if (myEmojiPicker.getCurrentFocusTarget() instanceof EmojiSkinTonesPanel) { g.setColor(myStyle.myFocusBorderColor); Insets i = getInsets(); final int SIZE = 30; g.drawRoundRect(getWidth() - i.right - SIZE - 8, getHeight() / 2 - SIZE / 2, SIZE, SIZE, 6, 6); } } - } diff --git a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSkinTonesPanel.java b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSkinTonesPanel.java index 2da74e1daee4..0199451577d5 100644 --- a/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSkinTonesPanel.java +++ b/plugins/emojipicker/src/org/jetbrains/plugins/emojipicker/ui/EmojiSkinTonesPanel.java @@ -3,6 +3,7 @@ package org.jetbrains.plugins.emojipicker.ui; import com.intellij.ide.ui.AntialiasingType; import com.intellij.openapi.ui.popup.IconButton; +import com.intellij.openapi.util.NlsSafe; import com.intellij.ui.InplaceButton; import org.jetbrains.plugins.emojipicker.EmojiSkinTone; import org.jetbrains.plugins.emojipicker.service.EmojiService; @@ -14,10 +15,8 @@ import java.util.EnumMap; import java.util.Map; public class EmojiSkinTonesPanel extends JPanel { - - private static final int ITEM_SIZE = 34; - private static final String ITEM_EMOJI = "🖐"; + @NlsSafe private static final String ITEM_EMOJI = "🖐"; private final EmojiPickerStyle myStyle; private final Map myItemMap = new EnumMap<>(EmojiSkinTone.class); @@ -28,7 +27,7 @@ public class EmojiSkinTonesPanel extends JPanel { myStyle = style; setVisible(false); setLayout(new GridBagLayout()); - for(EmojiSkinTone tone : EmojiSkinTone.values()) { + for (EmojiSkinTone tone : EmojiSkinTone.values()) { Item item = new Item(emojiPicker, tone); myItemMap.put(tone, item); } @@ -45,7 +44,7 @@ public class EmojiSkinTonesPanel extends JPanel { @Override public void paint(Graphics g) { super.paint(g); - if(myFocusedItem != -1) { + if (myFocusedItem != -1) { g.setColor(myStyle.myFocusBorderColor); g.drawRoundRect(3, myFocusedItem * ITEM_SIZE + 3, ITEM_SIZE - 4, ITEM_SIZE - 4, 6, 6); } @@ -66,8 +65,8 @@ public class EmojiSkinTonesPanel extends JPanel { void setCurrentItemFromFocus() { Component c = getComponent(myFocusedItem); - for(Item item : myItemMap.values()) { - if(item.myButton == c) { + for (Item item : myItemMap.values()) { + if (item.myButton == c) { myCurrentSkinTone = item.myTone; return; } @@ -84,8 +83,8 @@ public class EmojiSkinTonesPanel extends JPanel { gbc.gridx = 0; removeAll(); add(myItemMap.get(myCurrentSkinTone).myButton, gbc); - for(Map.Entry item : myItemMap.entrySet()) { - if(item.getKey() != myCurrentSkinTone) add(item.getValue().myButton, gbc); + for (Map.Entry item : myItemMap.entrySet()) { + if (item.getKey() != myCurrentSkinTone) add(item.getValue().myButton, gbc); } doLayout(); setVisible(true); @@ -114,33 +113,34 @@ public class EmojiSkinTonesPanel extends JPanel { private class Icon implements javax.swing.Icon { private final boolean myHover; + private Icon(boolean hover) { myHover = hover; } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { - ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false)); - if(myHover) { + ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false)); + if (myHover) { g.setColor(myStyle.myHoverBackgroundColor); g.fillRoundRect(x, y, getIconWidth(), getIconHeight(), 6, 6); } - String emoji = ITEM_EMOJI + myTone.getStringValue(); + @NlsSafe String emoji = ITEM_EMOJI + myTone.getStringValue(); FontMetrics metrics = g.getFontMetrics(myStyle.myEmojiFont); int verticalOffset = metrics.getHeight() / 2 - metrics.getDescent(); int width = metrics.stringWidth(emoji); - new TextLayout(emoji, myStyle.myEmojiFont, ((Graphics2D) g).getFontRenderContext()) - .draw((Graphics2D) g, x + (getIconWidth() - width) / 2F, y + getIconHeight() / 2F + verticalOffset); + new TextLayout(emoji, myStyle.myEmojiFont, ((Graphics2D)g).getFontRenderContext()) + .draw((Graphics2D)g, x + (getIconWidth() - width) / 2F, y + getIconHeight() / 2F + verticalOffset); } + @Override public int getIconWidth() { return ITEM_SIZE; } + @Override public int getIconHeight() { return ITEM_SIZE; } } - } - - }