├── resources ├── screenshots │ ├── example.png │ └── settings.png └── META-INF │ └── plugin.xml ├── src └── co │ └── notime │ └── intellijPlugin │ └── backgroundImagePlus │ ├── NotificationCenter.java │ ├── action │ ├── ClearBackground.java │ └── RandomBackground.java │ ├── RandomBackgroundTask.java │ ├── BackgroundService.java │ ├── ImagesHandler.java │ └── ui │ ├── Settings.form │ └── Settings.java ├── README.md ├── LICENSE └── .gitignore /resources/screenshots/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachlankrautz/backgroundImagePlus/HEAD/resources/screenshots/example.png -------------------------------------------------------------------------------- /resources/screenshots/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachlankrautz/backgroundImagePlus/HEAD/resources/screenshots/settings.png -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/NotificationCenter.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus; 2 | 3 | import com.intellij.notification.Notification; 4 | import com.intellij.notification.NotificationType; 5 | import com.intellij.notification.Notifications; 6 | 7 | /** 8 | * Author: Allan de Queiroz 9 | * Date: 07/05/17 10 | */ 11 | class NotificationCenter { 12 | 13 | static void notice(String message) { 14 | Notification n = new Notification( 15 | "extras", 16 | "Notice", 17 | message, 18 | NotificationType.INFORMATION); 19 | Notifications.Bus.notify(n); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Background Image Plus 2 | Set background random background images in Intellij editor. 3 | 4 | ![Alt text](https://github.com/lachlankrautz/backgroundImagePlus/blob/master/resources/screenshots/example.png?raw=true "Title") 5 | 6 | ### Settings 7 | 8 | Settings -> Appearance & Behaviour -> Background Image Plus 9 | - Backgrounds: folder (recursive) to pull random background images from 10 | - Change every: Set interval to change background every x minutes 11 | 12 | ![Alt text](https://github.com/lachlankrautz/backgroundImagePlus/blob/master/resources/screenshots/settings.png?raw=true "Title") 13 | 14 | ### Menu Items 15 | 16 | View: 17 | - Set Background Image 18 | - Random Background Image 19 | - Clear Background Image (cancels "change every" interval) 20 | 21 | ### Usage 22 | 23 | - Set backgrounds folder 24 | - Optionally set "change every" interval 25 | - Optionally bind "Random Background Image" action to a hotkey 26 | - Cycle background images while procrastinating 27 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/action/ClearBackground.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus.action; 2 | 3 | import co.notime.intellijPlugin.backgroundImagePlus.BackgroundService; 4 | import co.notime.intellijPlugin.backgroundImagePlus.ui.Settings; 5 | import com.intellij.ide.util.PropertiesComponent; 6 | import com.intellij.openapi.actionSystem.AnAction; 7 | import com.intellij.openapi.actionSystem.AnActionEvent; 8 | import com.intellij.openapi.wm.impl.IdeBackgroundUtil; 9 | 10 | /** 11 | * Author: Lachlan Krautz 12 | * Date: 22/07/16 13 | */ 14 | public class ClearBackground extends AnAction { 15 | 16 | public void actionPerformed(AnActionEvent e) { 17 | PropertiesComponent prop = PropertiesComponent.getInstance(); 18 | prop.setValue(IdeBackgroundUtil.EDITOR_PROP, null); 19 | prop.setValue(IdeBackgroundUtil.FRAME_PROP, null); 20 | prop.setValue(Settings.AUTO_CHANGE, false); 21 | BackgroundService.stop(); 22 | IdeBackgroundUtil.repaintAllWindows(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Lachlan Krautz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/action/RandomBackground.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus.action; 2 | 3 | import co.notime.intellijPlugin.backgroundImagePlus.BackgroundService; 4 | import co.notime.intellijPlugin.backgroundImagePlus.ui.Settings; 5 | import com.intellij.ide.util.PropertiesComponent; 6 | import com.intellij.openapi.actionSystem.AnAction; 7 | import com.intellij.openapi.actionSystem.AnActionEvent; 8 | import co.notime.intellijPlugin.backgroundImagePlus.RandomBackgroundTask; 9 | 10 | /** 11 | * Author: Lachlan Krautz 12 | * Date: 21/07/16 13 | */ 14 | public class RandomBackground extends AnAction { 15 | 16 | public RandomBackground() { 17 | super("Random Background Image"); 18 | PropertiesComponent prop = PropertiesComponent.getInstance(); 19 | if (prop.getBoolean(Settings.AUTO_CHANGE, false)) { 20 | BackgroundService.start(); 21 | } 22 | } 23 | 24 | @Override 25 | public void actionPerformed(AnActionEvent evt) { 26 | RandomBackgroundTask task = new RandomBackgroundTask(); 27 | task.run(); 28 | PropertiesComponent prop = PropertiesComponent.getInstance(); 29 | if (prop.getBoolean(Settings.AUTO_CHANGE, false)) { 30 | BackgroundService.restart(); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/workspace.xml 8 | .idea/tasks.xml 9 | .idea/dictionaries 10 | .idea/vcs.xml 11 | .idea/jsLibraryMappings.xml 12 | 13 | # Sensitive or high-churn files: 14 | .idea/dataSources.ids 15 | .idea/dataSources.xml 16 | .idea/dataSources.local.xml 17 | .idea/sqlDataSources.xml 18 | .idea/dynamic.xml 19 | .idea/uiDesigner.xml 20 | 21 | # Gradle: 22 | .idea/gradle.xml 23 | .idea/libraries 24 | 25 | # Mongo Explorer plugin: 26 | .idea/mongoSettings.xml 27 | 28 | ## File-based project format: 29 | *.iws 30 | 31 | ## Plugin-specific files: 32 | 33 | # IntelliJ 34 | /out/ 35 | 36 | # mpeltonen/sbt-idea plugin 37 | .idea_modules/ 38 | 39 | # JIRA plugin 40 | atlassian-ide-plugin.xml 41 | 42 | # Crashlytics plugin (for Android Studio and IntelliJ) 43 | com_crashlytics_export_strings.xml 44 | crashlytics.properties 45 | crashlytics-build.properties 46 | fabric.properties 47 | ### Java template 48 | *.class 49 | 50 | # Mobile Tools for Java (J2ME) 51 | .mtj.tmp/ 52 | 53 | # Package Files # 54 | *.jar 55 | *.war 56 | *.ear 57 | 58 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 59 | hs_err_pid* 60 | 61 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/RandomBackgroundTask.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus; 2 | 3 | import co.notime.intellijPlugin.backgroundImagePlus.ui.Settings; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.openapi.wm.impl.IdeBackgroundUtil; 6 | import java.io.File; 7 | 8 | /** 9 | * Author: Allan de Queiroz 10 | * Date: 07/05/17 11 | */ 12 | public class RandomBackgroundTask implements Runnable { 13 | 14 | private ImagesHandler imagesHandler; 15 | 16 | public RandomBackgroundTask() { 17 | imagesHandler = new ImagesHandler(); 18 | } 19 | 20 | @Override 21 | public void run() { 22 | PropertiesComponent prop = PropertiesComponent.getInstance(); 23 | String folder = prop.getValue(Settings.FOLDER); 24 | if (folder == null || folder.isEmpty()) { 25 | NotificationCenter.notice("Image folder not set"); 26 | return; 27 | } 28 | File file = new File(folder); 29 | if (!file.exists()) { 30 | NotificationCenter.notice("Image folder not set"); 31 | return; 32 | } 33 | String image = imagesHandler.getRandomImage(folder); 34 | if (image == null) { 35 | NotificationCenter.notice("No image found"); 36 | return; 37 | } 38 | if (image.contains(",")) { 39 | NotificationCenter.notice("Intellij wont load images with ',' character\n" + image); 40 | } 41 | prop.setValue(IdeBackgroundUtil.FRAME_PROP, null); 42 | prop.setValue(IdeBackgroundUtil.EDITOR_PROP, image); 43 | // NotificationCenter.notice("Image: " + image.replace(folder + File.separator, "")); 44 | IdeBackgroundUtil.repaintAllWindows(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/BackgroundService.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus; 2 | 3 | import co.notime.intellijPlugin.backgroundImagePlus.ui.Settings; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.openapi.wm.impl.IdeBackgroundUtil; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.RejectedExecutionException; 8 | import java.util.concurrent.ScheduledExecutorService; 9 | import java.util.concurrent.TimeUnit; 10 | 11 | /** 12 | * Author: Lachlan Krautz 13 | * Date: 22/07/16 14 | */ 15 | public class BackgroundService { 16 | 17 | private static ScheduledExecutorService service = null; 18 | private static int runningInterval = 0; 19 | 20 | public static void start () { 21 | PropertiesComponent prop = PropertiesComponent.getInstance(); 22 | int interval = prop.getInt(Settings.INTERVAL, 0); 23 | if (runningInterval == interval || interval == 0) { 24 | return; 25 | } 26 | if (service != null) { 27 | stop(); 28 | } 29 | RandomBackgroundTask task = new RandomBackgroundTask(); 30 | service = Executors.newSingleThreadScheduledExecutor(); 31 | try { 32 | int delay = prop.isValueSet(IdeBackgroundUtil.EDITOR_PROP) 33 | ? interval 34 | : 0; 35 | service.scheduleAtFixedRate(task, delay, interval, TimeUnit.MINUTES); 36 | runningInterval = interval; 37 | } catch (RejectedExecutionException e) { 38 | stop(); 39 | } 40 | } 41 | 42 | public static void stop () { 43 | if (service != null && !service.isTerminated()) { 44 | service.shutdownNow(); 45 | } 46 | service = null; 47 | runningInterval = 0; 48 | } 49 | 50 | public static void restart () { 51 | stop(); 52 | start(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/ImagesHandler.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus; 2 | 3 | import javax.activation.MimetypesFileTypeMap; 4 | import java.io.File; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Random; 8 | 9 | /** 10 | * Author: Allan de Queiroz 11 | * Date: 07/05/17 12 | */ 13 | class ImagesHandler { 14 | 15 | private MimetypesFileTypeMap typeMap; 16 | 17 | ImagesHandler() { 18 | typeMap = new MimetypesFileTypeMap(); 19 | } 20 | 21 | /** 22 | * @param folder folder to search for images 23 | * @return random image or null 24 | */ 25 | String getRandomImage(String folder) { 26 | if (folder.isEmpty()) { 27 | return null; 28 | } 29 | List images = new ArrayList<>(); 30 | collectImages(images, folder); 31 | int count = images.size(); 32 | if (count == 0) { 33 | return null; 34 | } 35 | Random randomGenerator = new Random(); 36 | int index = randomGenerator.nextInt(images.size()); 37 | return images.get(index); 38 | } 39 | 40 | private void collectImages(List images, String folder) { 41 | File root = new File(folder); 42 | if (!root.exists()) { 43 | return; 44 | } 45 | File[] list = root.listFiles(); 46 | if (list == null) { 47 | return; 48 | } 49 | 50 | for (File f : list) { 51 | if (f.isDirectory()) { 52 | collectImages(images, f.getAbsolutePath()); 53 | } else { 54 | if (!isImage(f)) { 55 | continue; 56 | } 57 | images.add(f.getAbsolutePath()); 58 | } 59 | } 60 | } 61 | 62 | private boolean isImage(File file) { 63 | String[] parts = typeMap.getContentType(file).split("/"); 64 | return parts.length != 0 && parts[0].equals("image"); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | co.notime.intellijPlugin.backgroundImagePlus 3 | Background Image Plus 4 | 1.2.1 5 | Lachlan Krautz 6 | 7 | 9 | ]]> 10 | 11 | 13 | Added menu items 14 | ]]> 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | com.intellij.modules.lang 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 40 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/ui/Settings.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 | -------------------------------------------------------------------------------- /src/co/notime/intellijPlugin/backgroundImagePlus/ui/Settings.java: -------------------------------------------------------------------------------- 1 | package co.notime.intellijPlugin.backgroundImagePlus.ui; 2 | 3 | import co.notime.intellijPlugin.backgroundImagePlus.BackgroundService; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.openapi.fileChooser.FileChooserDescriptor; 6 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; 7 | import com.intellij.openapi.options.Configurable; 8 | import com.intellij.openapi.options.ConfigurationException; 9 | import com.intellij.openapi.ui.TextBrowseFolderListener; 10 | import com.intellij.openapi.ui.TextFieldWithBrowseButton; 11 | import org.jetbrains.annotations.Nls; 12 | import org.jetbrains.annotations.Nullable; 13 | import javax.swing.*; 14 | import java.awt.event.ActionEvent; 15 | import java.io.File; 16 | 17 | /** 18 | * Author: Lachlan Krautz 19 | * Date: 22/07/16 20 | */ 21 | public class Settings implements Configurable { 22 | 23 | public static final String FOLDER = "BackgroundImagesFolder"; 24 | public static final String AUTO_CHANGE = "BackgroundImagesAutoChange"; 25 | public static final String INTERVAL = "BackgroundImagesInterval"; 26 | 27 | private TextFieldWithBrowseButton imageFolder; 28 | private JPanel rootPanel; 29 | private JSpinner intervalSpinner; 30 | private JCheckBox autoChangeCheckBox; 31 | 32 | @SuppressWarnings("unused") 33 | private JLabel measurement; 34 | 35 | @Nls 36 | @Override 37 | public String getDisplayName() { 38 | return "Background Image"; 39 | } 40 | 41 | @Nullable 42 | @Override 43 | public String getHelpTopic() { 44 | return null; 45 | } 46 | 47 | @Nullable 48 | @Override 49 | public JComponent createComponent() { 50 | FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); 51 | imageFolder.addBrowseFolderListener(new TextBrowseFolderListener(descriptor) { 52 | @Override 53 | public void actionPerformed(ActionEvent e) { 54 | JFileChooser fc = new JFileChooser(); 55 | String current = imageFolder.getText(); 56 | if (!current.isEmpty()) { 57 | fc.setCurrentDirectory(new File(current)); 58 | } 59 | fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 60 | fc.showOpenDialog(rootPanel); 61 | 62 | File file = fc.getSelectedFile(); 63 | String path = file == null 64 | ? "" 65 | : file.getAbsolutePath(); 66 | imageFolder.setText(path); 67 | } 68 | }); 69 | autoChangeCheckBox.addActionListener(e -> intervalSpinner.setEnabled(autoChangeCheckBox.isSelected())); 70 | return rootPanel; 71 | } 72 | 73 | @Override 74 | public boolean isModified() { 75 | PropertiesComponent prop = PropertiesComponent.getInstance(); 76 | String storedFolder = prop.getValue(FOLDER); 77 | String uiFolder = imageFolder.getText(); 78 | if (storedFolder == null) { 79 | storedFolder = ""; 80 | } 81 | return !storedFolder.equals(uiFolder) 82 | || intervalModified(prop) 83 | || prop.getBoolean(AUTO_CHANGE) != autoChangeCheckBox.isSelected(); 84 | } 85 | 86 | private boolean intervalModified (PropertiesComponent prop) { 87 | int storedInterval = prop.getInt(INTERVAL, 0); 88 | int uiInterval = ((SpinnerNumberModel) intervalSpinner.getModel()).getNumber().intValue(); 89 | return storedInterval != uiInterval; 90 | } 91 | 92 | @Override 93 | public void apply() throws ConfigurationException { 94 | PropertiesComponent prop = PropertiesComponent.getInstance(); 95 | 96 | boolean autoChange = autoChangeCheckBox.isSelected(); 97 | int interval = ((SpinnerNumberModel) intervalSpinner.getModel()).getNumber().intValue(); 98 | 99 | prop.setValue(FOLDER, imageFolder.getText()); 100 | prop.setValue(INTERVAL, interval, 0); 101 | prop.setValue(AUTO_CHANGE, autoChange); 102 | intervalSpinner.setEnabled(autoChange); 103 | 104 | if (autoChange && interval > 0) { 105 | BackgroundService.start(); 106 | } else { 107 | BackgroundService.stop(); 108 | } 109 | } 110 | 111 | @Override 112 | public void reset() { 113 | PropertiesComponent prop = PropertiesComponent.getInstance(); 114 | imageFolder.setText(prop.getValue(FOLDER)); 115 | intervalSpinner.setValue(prop.getInt(INTERVAL, 0)); 116 | autoChangeCheckBox.setSelected(prop.getBoolean(AUTO_CHANGE, false)); 117 | intervalSpinner.setEnabled(autoChangeCheckBox.isSelected()); 118 | } 119 | 120 | @Override 121 | public void disposeUIResources() {} 122 | 123 | private void createUIComponents() { 124 | PropertiesComponent prop = PropertiesComponent.getInstance(); 125 | intervalSpinner = new JSpinner(new SpinnerNumberModel(prop.getInt(INTERVAL, 0), 0, 1000, 5)); 126 | } 127 | 128 | } 129 | --------------------------------------------------------------------------------