OmegaT の背景に画像を表示します。
copy trunk/ to tags/0.2.20140507/
@@ -0,0 +1,15 @@ | ||
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<project xmlns="http://www.netbeans.org/ns/project/1"> | |
3 | + <type>org.netbeans.modules.java.j2seproject</type> | |
4 | + <configuration> | |
5 | + <data xmlns="http://www.netbeans.org/ns/j2se-project/3"> | |
6 | + <name>Moenizer</name> | |
7 | + <source-roots> | |
8 | + <root id="src.dir"/> | |
9 | + </source-roots> | |
10 | + <test-roots> | |
11 | + <root id="test.src.dir"/> | |
12 | + </test-roots> | |
13 | + </data> | |
14 | + </configuration> | |
15 | +</project> |
@@ -0,0 +1,70 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer; | |
18 | + | |
19 | +import com.vlsolutions.swing.docking.DockViewTitleBar; | |
20 | +import com.vlsolutions.swing.docking.ui.DockViewTitleBarUI; | |
21 | +import java.awt.Color; | |
22 | +import java.awt.Graphics; | |
23 | +import java.awt.Graphics2D; | |
24 | +import javax.swing.JComponent; | |
25 | +import javax.swing.UIManager; | |
26 | + | |
27 | +/** | |
28 | + * | |
29 | + * @author Yu-Tang | |
30 | + */ | |
31 | +public class MoeDockViewTitleBarUI extends DockViewTitleBarUI { | |
32 | + | |
33 | + /* hack to use custom painting except on mac os (ugly opacity effects) */ | |
34 | + private static boolean useCustomPaint = System.getProperty("os.name"). | |
35 | + toLowerCase().indexOf("mac os") < 0; | |
36 | + | |
37 | + /* Alpha value for transparency (0-255) */ | |
38 | + private static int activeAlpha = 150; // transparent 0 <- ... -> 255 opaque | |
39 | + private static int inactiveAlpha = 100; // transparent 0 <- ... -> 255 opaque | |
40 | + | |
41 | + private Color activePanelColor = MoeDockViewTitleBarUI.makeTranslucentColor( | |
42 | + UIManager.getColor("Panel.background"), activeAlpha); | |
43 | + private Color inactivePanelColor = MoeDockViewTitleBarUI.makeTranslucentColor( | |
44 | + UIManager.getColor("Panel.background"), inactiveAlpha); | |
45 | + //private Color highlight = makeTranslucent(UIManager.getColor("controlLtHighlight")); | |
46 | + | |
47 | + | |
48 | + public MoeDockViewTitleBarUI(DockViewTitleBar tb) { | |
49 | + super(tb); | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + public void paint(Graphics g, JComponent c) { | |
54 | + if (MoeDockViewTitleBarUI.useCustomPaint) { | |
55 | + DockViewTitleBar tb = (DockViewTitleBar)c; | |
56 | + | |
57 | + Graphics2D g2 = (Graphics2D) g.create(); | |
58 | + g2.setColor(tb.isActive() ? activePanelColor : inactivePanelColor); | |
59 | + g2.fillRect(0, 0, tb.getWidth(), tb.getHeight()); // emptyborder doesnt repaint | |
60 | + g2.dispose(); | |
61 | + } else { | |
62 | + super.paint(g, c); | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + private static Color makeTranslucentColor(Color color, int alpha) { | |
67 | + return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); | |
68 | + } | |
69 | + | |
70 | +} |
@@ -0,0 +1,326 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer; | |
18 | + | |
19 | +import java.io.File; | |
20 | +import java.io.FileFilter; | |
21 | +import java.net.URL; | |
22 | +import java.util.HashSet; | |
23 | +import java.util.Set; | |
24 | +import java.util.regex.Matcher; | |
25 | +import java.util.regex.Pattern; | |
26 | +import org.omegat.util.FileUtil; | |
27 | +import org.omegat.util.Log; | |
28 | + | |
29 | +/** | |
30 | + * | |
31 | + * @author Yu-Tang | |
32 | + */ | |
33 | +public class MoeConfig { | |
34 | + private static final String CONFIG_FILE_NAME = "moenizer.conf"; | |
35 | + private static final String SCRIPT_FILE_NAME = "moenizer.groovy"; | |
36 | + | |
37 | + private static final float DEFAULT_OPACITY = 0.5f; | |
38 | + private static final int MAX_OPACITY_IN_PERCENTAGE = 100; // Opaque | |
39 | + private static final int MIN_OPACITY_IN_PERCENTAGE = 0; // Transparent | |
40 | + | |
41 | + private static final long DEFAULT_INTERVAL = 60L * 1000L; // 1 minute in milliseconds | |
42 | + private static final long MAX_INTERVAL = 86400L * 1000L; // 24 hours | |
43 | + private static final long MIN_INTERVAL = 3L * 1000L; // 3 seconds | |
44 | + | |
45 | + private static final Pattern RE_LINEBREAK = Pattern.compile("[\\n\\r]+"); | |
46 | + private static final Pattern RE_OPACITY = Pattern.compile("(\\d+)\\s*%$"); | |
47 | + private static final Pattern RE_INTERVAL = Pattern.compile("(\\d+)\\s*([msh])", Pattern.CASE_INSENSITIVE); | |
48 | + private static final Pattern RE_SCRIPT = Pattern.compile("(?:/|\\\\\\\\[^\\\\]|[a-zA-Z]:\\\\).+\\.groovy"); | |
49 | + private static final Pattern RE_SOURCE = Pattern.compile("(?:http://|https://|/|\\\\\\\\[^\\\\]|[a-zA-Z]:\\\\).+"); | |
50 | + private static final Pattern RE_HAS_IMAGE_EXTENSION = Pattern.compile(".+\\.(?:bmp|png|jpg|jpeg|gif)"); | |
51 | + private static final Pattern RE_HAS_INTERNET_SHORTCUT_EXTENSION = Pattern.compile(".+\\.(?:url|website|webloc)"); | |
52 | + private static final Pattern RE_HTTP_OR_HTTPS_PROTOCOL = Pattern.compile("(?:http://|https://).+"); | |
53 | + private static final Pattern RE_SOURCE_IN_PLUGIN_DIR = Pattern.compile(".+\\.(?:bmp|png|jpg|jpeg|gif|url|website|webloc)"); | |
54 | + | |
55 | + private static ConfigData data; | |
56 | + private static HashSet<Object> sources; | |
57 | + | |
58 | + static { | |
59 | + // load config from file | |
60 | + ConfigData cd = loadConfig(); | |
61 | + | |
62 | + // flatten source dir to files (images only) | |
63 | + HashSet<Object> flattenSources = getFlattenSources(cd.source); | |
64 | + | |
65 | + // scan plugin dir if both sources and script are empty | |
66 | + if (flattenSources.isEmpty() && cd.script.isEmpty()) { | |
67 | + cd.script = getScriptInPluginDir(); | |
68 | + flattenSources = getSourcesInPluginDir(); | |
69 | + } | |
70 | + | |
71 | + // set default interval if current interval is 0 and has multiple sources | |
72 | + if (cd.interval == 0 && flattenSources.size() > 1) { | |
73 | + cd.interval = DEFAULT_INTERVAL; | |
74 | + } | |
75 | + | |
76 | + data = cd; | |
77 | + sources = flattenSources; | |
78 | + } | |
79 | + | |
80 | + public static long getInterval() { | |
81 | + return data.interval; | |
82 | + } | |
83 | + | |
84 | + public static float getOpacity() { | |
85 | + return data.opacity; | |
86 | + } | |
87 | + | |
88 | + public static File getScript() { | |
89 | + return data.script.isEmpty() ? null : new File(data.script); | |
90 | + } | |
91 | + | |
92 | + public static Object[] getSources() { | |
93 | + return sources.toArray(); | |
94 | + } | |
95 | + | |
96 | + | |
97 | + private static ConfigData loadConfig() { | |
98 | + ConfigData data = getDefaultConfig(); | |
99 | + try { | |
100 | + File file = new File(MoeUtil.getPluginJarDir(), CONFIG_FILE_NAME); | |
101 | + if ( file.isFile() ) { | |
102 | + String text = FileUtil.readTextFile(file); | |
103 | + String[] lines = RE_LINEBREAK.split(text); | |
104 | + for (String line: lines) { | |
105 | + if ( ! line.isEmpty() ) { | |
106 | + if (setOpacity(data, line) == true) { | |
107 | + // probably opacity value is changed from default | |
108 | + } else if (setInterval(data, line) == true) { | |
109 | + // probably interval value is changed from default | |
110 | + } else if (setScript(data, line) == true) { | |
111 | + // script URI | |
112 | + } else if (addSource(data, line) == true) { | |
113 | + // source URI (image) | |
114 | + } else { | |
115 | + // ignore | |
116 | + } | |
117 | + } | |
118 | + } | |
119 | + } else { | |
120 | + } | |
121 | + } catch (Exception ex) { | |
122 | + Log.log(ex); | |
123 | + } | |
124 | + return data; | |
125 | + } | |
126 | + | |
127 | + private static ConfigData getDefaultConfig() { | |
128 | + ConfigData cd = new ConfigData(); | |
129 | + cd.opacity = DEFAULT_OPACITY; | |
130 | + cd.interval = 0L; | |
131 | + cd.script = ""; | |
132 | + cd.source = new HashSet<String>(); // should be unique | |
133 | + return cd; | |
134 | + } | |
135 | + | |
136 | + /** | |
137 | + * set new opacity value to ConfigData | |
138 | + * @param data | |
139 | + * @param line | |
140 | + * @return true if line contains opacity value | |
141 | + */ | |
142 | + private static boolean setOpacity(ConfigData data, String line) { | |
143 | + Matcher matcher = RE_OPACITY.matcher(line); | |
144 | + if ( matcher.matches() ) { | |
145 | + String num = matcher.group(1); | |
146 | + int i = Integer.parseInt(num); // in percent | |
147 | + if (i > MAX_OPACITY_IN_PERCENTAGE) { | |
148 | + data.opacity = MAX_OPACITY_IN_PERCENTAGE; | |
149 | + } else if (i < MIN_OPACITY_IN_PERCENTAGE) { | |
150 | + data.opacity = MIN_OPACITY_IN_PERCENTAGE; | |
151 | + } else { | |
152 | + float f = ((float) i / MAX_OPACITY_IN_PERCENTAGE); | |
153 | + data.opacity = f; | |
154 | + } | |
155 | + return true; | |
156 | + } | |
157 | + return false; | |
158 | + } | |
159 | + | |
160 | + /** | |
161 | + * set new interval value to ConfigData | |
162 | + * @param data | |
163 | + * @param line | |
164 | + * @return true if line contains interval value | |
165 | + */ | |
166 | + private static boolean setInterval(ConfigData data, String line) { | |
167 | + Matcher matcher = RE_INTERVAL.matcher(line); | |
168 | + if ( matcher.matches() ) { | |
169 | + String num = matcher.group(1); | |
170 | + String unit = matcher.group(2).toLowerCase(); // s | m | h | |
171 | + | |
172 | + long i = Long.parseLong(num); | |
173 | + if (unit.equals("s")) { | |
174 | + i = i * 1000; | |
175 | + } else if (unit.equals("m")) { | |
176 | + i = i * 60 * 1000; | |
177 | + } else if (unit.equals("h")) { | |
178 | + i = i * 60 * 60 * 1000; | |
179 | + } | |
180 | + | |
181 | + // validate range | |
182 | + if (i > MAX_INTERVAL) { | |
183 | + data.interval = MAX_INTERVAL; | |
184 | + } else if (i < MIN_INTERVAL) { | |
185 | + data.interval = MIN_INTERVAL; | |
186 | + } else { | |
187 | + data.interval = i; | |
188 | + } | |
189 | + return true; | |
190 | + } | |
191 | + return false; | |
192 | + } | |
193 | + | |
194 | + /** | |
195 | + * set new script URI to ConfigData | |
196 | + * @param data | |
197 | + * @param line | |
198 | + * @return true if line contains script URI | |
199 | + */ | |
200 | + private static boolean setScript(ConfigData data, String line) { | |
201 | + Matcher matcher = RE_SCRIPT.matcher(line); | |
202 | + if ( matcher.matches() ) { | |
203 | + data.script = line; | |
204 | + return true; | |
205 | + } | |
206 | + return false; | |
207 | + } | |
208 | + | |
209 | + /** | |
210 | + * add new source URI to ConfigData | |
211 | + * @param data | |
212 | + * @param line | |
213 | + * @return true if line contains source URI | |
214 | + */ | |
215 | + private static boolean addSource(ConfigData data, String line) { | |
216 | + Matcher matcher = RE_SOURCE.matcher(line); | |
217 | + if ( matcher.matches() ) { | |
218 | + data.source.add(line); | |
219 | + return true; | |
220 | + } | |
221 | + return false; | |
222 | + } | |
223 | + | |
224 | + /** | |
225 | + * | |
226 | + * @param source | |
227 | + * @return URL object or File object (file only) | |
228 | + */ | |
229 | + private static HashSet<Object> getFlattenSources(Set<String> source) { | |
230 | + HashSet<Object> newSource = new HashSet<Object>(); // should be unique | |
231 | + for (String s: source) { | |
232 | + try { | |
233 | + if (RE_HTTP_OR_HTTPS_PROTOCOL.matcher(s.toLowerCase()).matches()) { | |
234 | + newSource.add(new URL(s)); | |
235 | + } else { | |
236 | + File file = new File(s); | |
237 | + // Single file and image file ? | |
238 | + if (file.isFile() && RE_HAS_IMAGE_EXTENSION.matcher(s.toLowerCase()).matches()) { | |
239 | + newSource.add(file); | |
240 | + } else if (file.isDirectory()) { | |
241 | + File[] listFiles = file.listFiles(new FileFilter() { | |
242 | + @Override | |
243 | + public boolean accept(File f) { | |
244 | + if (f.isFile()) { | |
245 | + String fileName = f.getName().toLowerCase(); | |
246 | + if (RE_HAS_IMAGE_EXTENSION.matcher(fileName).matches() || | |
247 | + RE_HAS_INTERNET_SHORTCUT_EXTENSION.matcher(fileName).matches()) { | |
248 | + return true; | |
249 | + } | |
250 | + } | |
251 | + return false; | |
252 | + } | |
253 | + }); | |
254 | + for (File f: listFiles) { | |
255 | + String fileName = f.getName().toLowerCase(); | |
256 | + // image file | |
257 | + if (RE_HAS_IMAGE_EXTENSION.matcher(fileName).matches()) { | |
258 | + newSource.add(file); | |
259 | + // internet shortcut | |
260 | + } else if (RE_HAS_INTERNET_SHORTCUT_EXTENSION.matcher(fileName).matches()) { | |
261 | + URL url = MoeUtil.getURL(file); | |
262 | + if (url != null) { | |
263 | + newSource.add(url); | |
264 | + } | |
265 | + } | |
266 | + } | |
267 | + } | |
268 | + } | |
269 | + } catch (Exception ex) { | |
270 | + Log.log(ex); | |
271 | + } | |
272 | + } | |
273 | + return newSource; | |
274 | + } | |
275 | + | |
276 | + private static String getScriptInPluginDir() { | |
277 | + try { | |
278 | + File file = new File(MoeUtil.getPluginJarDir(), SCRIPT_FILE_NAME); | |
279 | + if (file.isFile()) { | |
280 | + return file.getCanonicalPath(); | |
281 | + } | |
282 | + } catch (Exception ex) { /* ignore */ } | |
283 | + return ""; | |
284 | + } | |
285 | + | |
286 | + private static HashSet<Object> getSourcesInPluginDir() { | |
287 | + HashSet<Object> newSource = new HashSet<Object>(); // should be unique | |
288 | + try { | |
289 | + File dir = MoeUtil.getPluginJarDir(); | |
290 | + File[] listFiles = dir.listFiles(new FileFilter() { | |
291 | + @Override | |
292 | + public boolean accept(File f) { | |
293 | + if (f.isFile()) { | |
294 | + String fileName = f.getName().toLowerCase(); | |
295 | + if (RE_SOURCE_IN_PLUGIN_DIR.matcher(fileName).matches()) { | |
296 | + return true; | |
297 | + } | |
298 | + } | |
299 | + return false; | |
300 | + } | |
301 | + }); | |
302 | + for (File f: listFiles) { | |
303 | + String fileName = f.getName().toLowerCase(); | |
304 | + // image file | |
305 | + if (RE_HAS_IMAGE_EXTENSION.matcher(fileName).matches()) { | |
306 | + newSource.add(f); | |
307 | + // internet shortcut | |
308 | + } else if (RE_HAS_INTERNET_SHORTCUT_EXTENSION.matcher(fileName).matches()) { | |
309 | + URL url = MoeUtil.getURL(f); | |
310 | + if (url != null) { | |
311 | + newSource.add(url); | |
312 | + } | |
313 | + } | |
314 | + } | |
315 | + } catch (Exception ex) { /* ignore */ } | |
316 | + return newSource; | |
317 | + } | |
318 | + | |
319 | + private static class ConfigData { | |
320 | + protected float opacity; // 0.0f <--> 1.0f | |
321 | + protected long interval; // by milliseconds | |
322 | + protected String script; | |
323 | + protected Set<String> source; | |
324 | + } | |
325 | +} | |
326 | + |
@@ -0,0 +1,150 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer; | |
18 | + | |
19 | +import java.awt.image.BufferedImage; | |
20 | +import java.util.concurrent.TimeUnit; | |
21 | +import javax.swing.SwingUtilities; | |
22 | +import javax.swing.SwingWorker; | |
23 | + | |
24 | +import org.omegat.core.CoreEvents; | |
25 | +import org.omegat.core.events.IApplicationEventListener; | |
26 | +import org.omegat.core.events.IProjectEventListener; | |
27 | +import jp.sourceforge.users.yutang.omegat.plugin.moenizer.imageloader.IImageLoader; | |
28 | +import jp.sourceforge.users.yutang.omegat.plugin.moenizer.imageloader.ImageLoader; | |
29 | +import org.omegat.core.Core; | |
30 | +import org.omegat.util.Log; | |
31 | + | |
32 | +/** | |
33 | + * allow to set background image | |
34 | + * | |
35 | + * @author Yu-Tang | |
36 | + */ | |
37 | +public class Moenizer implements IApplicationEventListener, IProjectEventListener { | |
38 | + | |
39 | + private static boolean instantiated = false; | |
40 | + | |
41 | + private IImageLoader imageLoader; | |
42 | + private MoeUI ui; | |
43 | + | |
44 | + public static void loadPlugins() { | |
45 | + try { | |
46 | + // Not initialize in console mode | |
47 | + if (!instantiated) { | |
48 | + CoreEvents.registerApplicationEventListener(new Moenizer()); | |
49 | + instantiated = true; | |
50 | + } else { | |
51 | + throw new RuntimeException("Moenizer plugin could be instantiated only once."); | |
52 | + } | |
53 | + } catch (Throwable ex) { | |
54 | + String msg = ex.getMessage(); | |
55 | + Log.logErrorRB(msg); | |
56 | + Core.pluginLoadingError(msg); | |
57 | + } | |
58 | + } | |
59 | + | |
60 | + public static void unloadPlugins() { | |
61 | + // do nothing | |
62 | + } | |
63 | + | |
64 | + @Override | |
65 | + public void onApplicationStartup() { | |
66 | + try { | |
67 | + CoreEvents.registerProjectChangeListener(this); | |
68 | + | |
69 | + ui = null; | |
70 | + imageLoader = ImageLoader.getInstance(); | |
71 | + // この時点ではまだウィンドウがインスタンス化されていないので、 | |
72 | + // ウィンドウに対する処理は少し待つ。 | |
73 | + | |
74 | + (new SlideShow()).execute(); | |
75 | + | |
76 | + ui = MoeUI.getMoeUI(); | |
77 | + | |
78 | + // この時点でコンポーネントの透過設定をしても反映されない(タイミング?)。 | |
79 | + // Workaround として、invokeLater でキューに突っ込んで、後で処理する。 | |
80 | + SwingUtilities.invokeLater(new Runnable() { | |
81 | + @Override | |
82 | + public void run() { | |
83 | + CoreEvents.unregisterApplicationEventListener(Moenizer.this); | |
84 | + ui.transparent(); | |
85 | + } | |
86 | + }); | |
87 | + //CoreEvents.unregisterApplicationEventListener(this); // ここで発行すると、スレッドエラーになるので注意 | |
88 | + } catch(Exception e) { | |
89 | + Log.log("Error raised at " + this.getClass().getCanonicalName() + ".onApplicationStartup()\n" + e); | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + @Override | |
94 | + public void onApplicationShutdown() { | |
95 | + // not used. | |
96 | + } | |
97 | + | |
98 | + @Override | |
99 | + public void onProjectChanged(PROJECT_CHANGE_TYPE eventType) { | |
100 | + switch (eventType) { | |
101 | + case CREATE: | |
102 | + case LOAD: | |
103 | + // ここですぐ透過処理をしてもうまく適用されないので、後まわしにする。 | |
104 | + SwingUtilities.invokeLater(new Runnable() { | |
105 | + @Override | |
106 | + public void run() { | |
107 | + CoreEvents.unregisterProjectChangeListener(Moenizer.this); | |
108 | + ui.transparentEditor(); | |
109 | + } | |
110 | + }); | |
111 | + | |
112 | + // 一回 Editor の透過処理をしたら、透過状態が維持されるので、二回目 | |
113 | + // 以降は、透過処理は不要。 | |
114 | + //CoreEvents.unregisterProjectChangeListener(this); // ここで発行すると、スレッドエラーになるので注意 | |
115 | + break; | |
116 | + case CLOSE: | |
117 | + break; | |
118 | + } | |
119 | + } | |
120 | + | |
121 | + private class SlideShow extends SwingWorker<Object, Void> { | |
122 | + private long interval = -1; | |
123 | + | |
124 | + @Override | |
125 | + protected Object doInBackground() throws Exception { | |
126 | + while (imageLoader.availableNext()) { | |
127 | + imageLoader.readyForNextImage(); | |
128 | + interval = interval < 0 ? 0 : imageLoader.getNextInterval(); | |
129 | + if (interval > 0) { | |
130 | + try { | |
131 | + TimeUnit.MILLISECONDS.sleep(interval); | |
132 | + } catch (InterruptedException e) { /* ignore */ } | |
133 | + } | |
134 | + BufferedImage image = imageLoader.getNextImage(); | |
135 | + | |
136 | + if (image != null) { | |
137 | + // 初期化直後に、まだ MoeUI がインスタンス化されていない | |
138 | + // 空白時間に遭遇する可能性があるため、その場合は 0.1 秒 | |
139 | + // 単位で MoeUI のインスタンス化を待機する。 | |
140 | + while (ui == null) { | |
141 | + TimeUnit.MILLISECONDS.sleep(100); | |
142 | + } | |
143 | + ui.setBackground(image); | |
144 | + } | |
145 | + } | |
146 | + return null; | |
147 | + } | |
148 | + } | |
149 | + | |
150 | +} |
@@ -0,0 +1,60 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer.imageloader; | |
18 | + | |
19 | +import java.awt.image.BufferedImage; | |
20 | + | |
21 | +/** | |
22 | + * Interface for Image Loader | |
23 | + * | |
24 | + * calling order is: | |
25 | + * 1. availableNext() ... exit from loop if returned false | |
26 | + * 2. readyForNextImage() | |
27 | + * 3. getNextInterval() ... skiped first time | |
28 | + * 4. getNextImage() | |
29 | + * ... loop back to step 1 | |
30 | + * | |
31 | + * @author Yu-Tang | |
32 | + */ | |
33 | +public interface IImageLoader { | |
34 | + | |
35 | + /** | |
36 | + * get if next image available. | |
37 | + * @return bool. | |
38 | + */ | |
39 | + boolean availableNext(); | |
40 | + | |
41 | + /** | |
42 | + * get next interval. | |
43 | + * This method is not called at first time loop. | |
44 | + * @return long by milliseconds | |
45 | + */ | |
46 | + long getNextInterval(); | |
47 | + | |
48 | + /** | |
49 | + * Do anything should be done for the next image. | |
50 | + * Calling before getNextImage(). | |
51 | + */ | |
52 | + void readyForNextImage(); | |
53 | + | |
54 | + /** | |
55 | + * get next image. | |
56 | + * @return BufferedImage object. Can be null if image is not available. | |
57 | + */ | |
58 | + BufferedImage getNextImage(); | |
59 | + | |
60 | +} |
@@ -0,0 +1,56 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer.imageloader; | |
18 | + | |
19 | +import java.lang.reflect.Method; | |
20 | +import java.net.URL; | |
21 | +import static jp.sourceforge.users.yutang.omegat.plugin.moenizer.MoeConfig.*; | |
22 | +import org.omegat.util.Log; | |
23 | + | |
24 | +/** | |
25 | + * | |
26 | + * @author Yu-Tang | |
27 | + */ | |
28 | +public class ImageLoader { | |
29 | + | |
30 | + public static IImageLoader getInstance() { | |
31 | + Object[] sources = getSources(); | |
32 | + | |
33 | + if (sources.length == 0) { | |
34 | + return null; // no source, no need loader | |
35 | + } | |
36 | + | |
37 | + // default | |
38 | + return new DefaultImageLoader(); | |
39 | + } | |
40 | + | |
41 | + private static Object getAcceptableSource(Class<?> c, Object[] sources) { | |
42 | + for (Object source: sources) { | |
43 | + try { | |
44 | + Method method = c.getDeclaredMethod("isAcceptable", new Class[]{ Object.class }); | |
45 | + boolean isAcceptable = (Boolean) method.invoke(null, source); | |
46 | + if (isAcceptable) { | |
47 | + return source; | |
48 | + } | |
49 | + } catch (Exception ex) { | |
50 | + Log.log(ex); | |
51 | + } | |
52 | + } | |
53 | + return null; | |
54 | + } | |
55 | + | |
56 | +} |
@@ -0,0 +1,162 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer.imageloader; | |
18 | + | |
19 | +import java.awt.image.BufferedImage; | |
20 | +import java.io.File; | |
21 | +import java.net.URL; | |
22 | +import java.util.regex.Pattern; | |
23 | +import javax.imageio.ImageIO; | |
24 | +import static jp.sourceforge.users.yutang.omegat.plugin.moenizer.MoeConfig.*; | |
25 | +import org.omegat.util.Log; | |
26 | + | |
27 | +/** | |
28 | + * Default image loader. | |
29 | + * | |
30 | + * calling order is: | |
31 | + * 1. availableNext() ... exit if returned false | |
32 | + * 2. readyForNextImage() | |
33 | + * 3. getNextInterval() ... skipped first time | |
34 | + * 4. getNextImage() | |
35 | + * ... loop back to step 1 | |
36 | + * | |
37 | + * @author Yu-Tang | |
38 | + */ | |
39 | +public class DefaultImageLoader implements IImageLoader { | |
40 | + | |
41 | + private static final Pattern RE_HAS_IMAGE_EXTENSION = Pattern.compile(".+\\.(?:bmp|png|jpg|jpeg|gif)"); | |
42 | + private long interval; | |
43 | + private Object[] sources; | |
44 | + private Object currentSource; | |
45 | + private int sourceIndex; | |
46 | + | |
47 | + protected BufferedImage image; | |
48 | + | |
49 | + public DefaultImageLoader() { | |
50 | + interval = getInterval(); | |
51 | + sources = getSources(); | |
52 | + currentSource = null; | |
53 | + image = null; | |
54 | + sourceIndex = -1; | |
55 | + } | |
56 | + | |
57 | + /** | |
58 | + * get if source is acceptable. | |
59 | + * @return bool. | |
60 | + */ | |
61 | + public static boolean isAcceptable(Object source) { | |
62 | + if (source instanceof URL) { | |
63 | + return true; | |
64 | + } else if (source instanceof File) { | |
65 | + String name = ((File) source).getName().toLowerCase(); | |
66 | + if (RE_HAS_IMAGE_EXTENSION.matcher(name).matches()) { | |
67 | + return true; | |
68 | + } | |
69 | + } | |
70 | + return false; | |
71 | + } | |
72 | + | |
73 | + @Override | |
74 | + public boolean availableNext() { | |
75 | + boolean ret = false; | |
76 | + if (sources.length == 0) { | |
77 | + // it's over! | |
78 | + } else if (sources.length == 1) { | |
79 | + if (currentSource == null || interval > 0) { // first time or refresh | |
80 | + currentSource = sources[0]; | |
81 | + ret = true; | |
82 | + } | |
83 | + } else { | |
84 | + currentSource = getCircularNextSource(); | |
85 | + ret = true; | |
86 | + } | |
87 | + return ret; | |
88 | + } | |
89 | + | |
90 | + /** | |
91 | + * get next image. | |
92 | + * @return BufferedImage object. Can be null if image is not available. | |
93 | + */ | |
94 | + @Override | |
95 | + public BufferedImage getNextImage() { | |
96 | + return image; | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * Do anything should be done for the next image. | |
101 | + * Calling before getNextImage(). | |
102 | + */ | |
103 | + @Override | |
104 | + public void readyForNextImage() { | |
105 | + //TODO use cache | |
106 | + image = null; | |
107 | + try { | |
108 | + if (currentSource != null) { | |
109 | + if (currentSource instanceof File) { | |
110 | + image = ImageIO.read((File) currentSource); | |
111 | + } else if (currentSource instanceof URL) { | |
112 | + image = ImageIO.read((URL) currentSource); | |
113 | + } else { | |
114 | + removeCurrentSource(); | |
115 | + } | |
116 | + } | |
117 | + } catch (Exception ex) { | |
118 | + Log.log(ex); | |
119 | + removeCurrentSource(); | |
120 | + } | |
121 | + } | |
122 | + | |
123 | + /** | |
124 | + * get next interval. | |
125 | + * This method is not called at first time loop. | |
126 | + * @return long by milliseconds | |
127 | + */ | |
128 | + @Override | |
129 | + public long getNextInterval() { | |
130 | + return interval; | |
131 | + } | |
132 | + | |
133 | + private Object getCircularNextSource() { | |
134 | + sourceIndex++; | |
135 | + if (sourceIndex >= sources.length) { | |
136 | + sourceIndex = 0; | |
137 | + } | |
138 | + return sources[sourceIndex]; | |
139 | + } | |
140 | + | |
141 | + private void removeCurrentSource() { | |
142 | + if (sourceIndex >= 0 && sourceIndex < sources.length) { | |
143 | + sourceIndex = 0; // something is wrong. rewind index. | |
144 | + } else { | |
145 | + Object[] newSources = new Object[sources.length - 1]; | |
146 | + for (int i = 0; i < sources.length; i++) { | |
147 | + if ( i == sourceIndex ) { | |
148 | + // skip | |
149 | + } else if ( i < sourceIndex ) { | |
150 | + newSources[i] = sources[i]; | |
151 | + } else { | |
152 | + newSources[i - 1] = sources[i]; | |
153 | + } | |
154 | + } | |
155 | + sources = newSources; | |
156 | + if (sourceIndex >= sources.length) { | |
157 | + sourceIndex = 0; | |
158 | + } | |
159 | + } | |
160 | + } | |
161 | + | |
162 | +} |
@@ -0,0 +1,88 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer; | |
18 | + | |
19 | +import java.awt.AlphaComposite; | |
20 | +import java.awt.Graphics; | |
21 | +import java.awt.Graphics2D; | |
22 | +import java.awt.Rectangle; | |
23 | +import java.awt.TexturePaint; | |
24 | +import java.awt.image.BufferedImage; | |
25 | +import javax.swing.JLayeredPane; | |
26 | + | |
27 | +/** | |
28 | + * | |
29 | + * @author Yu-Tang | |
30 | + */ | |
31 | +public class MoeLayeredPane extends JLayeredPane { | |
32 | + | |
33 | + private BufferedImage image; | |
34 | + private TexturePaint paint; | |
35 | + private float alpha; | |
36 | + | |
37 | + public MoeLayeredPane() { | |
38 | + super(); | |
39 | + this.image = null; | |
40 | + this.paint = null; | |
41 | + this.alpha = MoeConfig.getOpacity(); | |
42 | + } | |
43 | + | |
44 | + public MoeLayeredPane(BufferedImage image) { | |
45 | + super(); | |
46 | + setPicture(image); | |
47 | + this.alpha = MoeConfig.getOpacity(); | |
48 | + } | |
49 | + | |
50 | + public void setBackground(BufferedImage image) { | |
51 | + setPicture(image); | |
52 | + this.repaint(); | |
53 | + } | |
54 | + | |
55 | + @Override | |
56 | + protected void paintComponent(Graphics g) { | |
57 | + if (image != null) { | |
58 | + Graphics2D g2 = (Graphics2D)g.create(); | |
59 | + g2.setComposite(makeComposite(alpha)); | |
60 | + | |
61 | + if (getWidth() > image.getWidth() || getHeight() > image.getHeight()) { | |
62 | + g2.setPaint(paint); | |
63 | + g2.fillRect(0, 0, getWidth(), getHeight()); | |
64 | + } else { | |
65 | + g2.drawImage(image, 0, 0, this); | |
66 | + } | |
67 | + | |
68 | + g2.dispose(); | |
69 | + } | |
70 | + super.paintComponent(g); | |
71 | + } | |
72 | + | |
73 | + private AlphaComposite makeComposite(float alpha) { | |
74 | + int type = AlphaComposite.SRC_OVER; | |
75 | + return(AlphaComposite.getInstance(type, alpha)); | |
76 | + } | |
77 | + | |
78 | + private void setPicture(BufferedImage image) { | |
79 | + this.image = image; | |
80 | + | |
81 | + if (image == null) { | |
82 | + this.paint = null; | |
83 | + } else { | |
84 | + Rectangle rect = new Rectangle(image.getWidth(), image.getHeight()); | |
85 | + this.paint = new TexturePaint(image, rect); | |
86 | + } | |
87 | + } | |
88 | +} |
@@ -0,0 +1,294 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer; | |
18 | + | |
19 | +import com.sun.java.swing.plaf.windows.WindowsMenuBarUI; | |
20 | +import com.vlsolutions.swing.docking.DockView; | |
21 | +import com.vlsolutions.swing.docking.DockViewTitleBar; | |
22 | +import com.vlsolutions.swing.docking.Dockable; | |
23 | +import com.vlsolutions.swing.docking.DockableState; | |
24 | +import com.vlsolutions.swing.docking.DockingDesktop; | |
25 | +import com.vlsolutions.swing.docking.SplitContainer; | |
26 | +import java.awt.Color; | |
27 | +import java.awt.Component; | |
28 | +import java.awt.Container; | |
29 | +import java.awt.Graphics; | |
30 | +import java.awt.SystemColor; | |
31 | +import java.awt.image.BufferedImage; | |
32 | +import javax.swing.JComponent; | |
33 | +import javax.swing.JEditorPane; | |
34 | +import javax.swing.JFrame; | |
35 | +import javax.swing.JMenuBar; | |
36 | +import javax.swing.JPanel; | |
37 | +import javax.swing.JScrollPane; | |
38 | +import javax.swing.JTextPane; | |
39 | +import org.omegat.core.Core; | |
40 | +import org.omegat.util.gui.UIThreadsUtil; | |
41 | + | |
42 | +/** | |
43 | + * | |
44 | + * @author Yu-Tang | |
45 | + */ | |
46 | +public class MoeUI { | |
47 | + | |
48 | + private static MoeUI moeUI; | |
49 | + | |
50 | + private JFrame frame; | |
51 | + private MoeLayeredPane layeredPane; | |
52 | + private Container contentPane; | |
53 | + private JMenuBar menuBar; | |
54 | + private DockingDesktop desktop; | |
55 | + | |
56 | + static { | |
57 | + moeUI = null; | |
58 | + } | |
59 | + | |
60 | + // Singleton. Not allow to Instanciate from outside. Use getMoeUI() to get instance. | |
61 | + private MoeUI(BufferedImage image) { | |
62 | + UIThreadsUtil.mustBeSwingThread(); | |
63 | + | |
64 | + initUI(image); | |
65 | + } | |
66 | + | |
67 | + private MoeUI() { | |
68 | + UIThreadsUtil.mustBeSwingThread(); | |
69 | + | |
70 | + initUI(null); | |
71 | + } | |
72 | + | |
73 | + public static MoeUI getMoeUI(BufferedImage image) { | |
74 | + if (moeUI == null) { | |
75 | + moeUI = new MoeUI(image); | |
76 | + } | |
77 | + return moeUI; | |
78 | + } | |
79 | + | |
80 | + public static MoeUI getMoeUI() { | |
81 | + if (moeUI == null) { | |
82 | + moeUI = new MoeUI(); | |
83 | + } | |
84 | + return moeUI; | |
85 | + } | |
86 | + | |
87 | + public void transparent() { | |
88 | + UIThreadsUtil.mustBeSwingThread(); | |
89 | + | |
90 | + transparent(menuBar); | |
91 | + transparentRecursive(contentPane); | |
92 | + transparentInstantStart(desktop); | |
93 | + | |
94 | + frame.repaint(); | |
95 | + } | |
96 | + | |
97 | + public void transparentEditor() { | |
98 | + // Editor に表示されるドキュメントは、以下のケースでまったく異なる。 | |
99 | + // | |
100 | + // 1. インスタントスタートガイドが表示されている場合(初期状態) | |
101 | + // -> view = JTextPane, HTMLDocument | |
102 | + // 2. プロジェクトをロードまたは新規作成して、分節編集画面が表示されている場合 | |
103 | + // -> view = JEditorPane, DefaultStyledDocument | |
104 | + // | |
105 | + // そのため、2 のタイミングで透過処理をやり直す必要がある。 | |
106 | + // このメソッドは、2 の透過処理専用。 | |
107 | + | |
108 | + UIThreadsUtil.mustBeSwingThread(); | |
109 | + | |
110 | + JEditorPane editor = getJEditorPaneFromEditor(desktop); | |
111 | + if (editor == null) { | |
112 | + return; | |
113 | + } | |
114 | + | |
115 | + /* ここで JEditorPane に半透明の背景色を設定すると、テキストの選択(反転) | |
116 | + * などの色の変化が正常に更新されず色残りしてしまう。 | |
117 | + * そのため、JEditorPane への処理では単純に背景を透明にして、元画像自体で | |
118 | + * 色味を調整しておく方針とする。 | |
119 | + * | |
120 | + int alpha = 100; // transparent <- 0...255 -> opaque | |
121 | + Color color = SystemColor.menu; | |
122 | + editor.setBackground(new Color( color.getRGB() & 0xffffff | 100 << 24, true)); | |
123 | + * */ | |
124 | + editor.setOpaque(false); | |
125 | + frame.repaint(); | |
126 | + } | |
127 | + | |
128 | + public void setBackground(final BufferedImage image) { | |
129 | + UIThreadsUtil.executeInSwingThread(new Runnable() { | |
130 | + @Override | |
131 | + public void run() { | |
132 | + layeredPane.setBackground(image); | |
133 | + } | |
134 | + }); | |
135 | + } | |
136 | + | |
137 | + private void initUI(BufferedImage image) { | |
138 | + frame = Core.getMainWindow().getApplicationFrame(); | |
139 | + if (image == null) { | |
140 | + layeredPane = new MoeLayeredPane(); | |
141 | + } else { | |
142 | + layeredPane = new MoeLayeredPane(image); | |
143 | + } | |
144 | + contentPane = frame.getContentPane(); | |
145 | + menuBar = frame.getJMenuBar(); | |
146 | + desktop = getDockingDesktop(contentPane); | |
147 | + | |
148 | + // replace LayeredPane with MoeLayeredPane | |
149 | + frame.setLayeredPane(layeredPane); | |
150 | + frame.setContentPane(contentPane); | |
151 | + frame.setJMenuBar(menuBar); | |
152 | + | |
153 | + frame.validate(); | |
154 | + } | |
155 | + | |
156 | + private void transparent(JMenuBar menuBar) { | |
157 | +// menuBar.setUI ( new BasicMenuBarUI () { | |
158 | +// 上記だと初期表示時に、アクティブメニューがアクティブで描画されない。 | |
159 | +// マウス通過などのタイミングで再描画された際にアクティブカラーになるが、 | |
160 | +// 見栄えが悪いので、Windows 用の UI を指定する。 | |
161 | +// アクティブメニューがアクティブで描画されない問題はこれで解決するが、 | |
162 | +// 変わりに Mac や *nix など別 L&F 環境下では違和感があるかもしれない。 | |
163 | + menuBar.setUI ( new WindowsMenuBarUI () { | |
164 | + @Override | |
165 | + public void paint ( Graphics g, JComponent c ) { | |
166 | + int alpha = 100; // transparent <- 0...255 -> opaque | |
167 | + Color oldColor = g.getColor(); | |
168 | + Color color = SystemColor.menu; | |
169 | + g.setColor ( new Color( color.getRGB() & 0xffffff | alpha << 24, true)); | |
170 | + g.fillRect ( 0, 0, c.getWidth (), c.getHeight () ); | |
171 | + g.setColor ( oldColor ); // restore | |
172 | + } | |
173 | + } ); | |
174 | + menuBar.setOpaque(false); | |
175 | + } | |
176 | + | |
177 | + private void transparentRecursive(Component component) { | |
178 | + if (component instanceof JComponent) { | |
179 | + JComponent c = (JComponent) component; | |
180 | + if (c.isOpaque()) { | |
181 | + c.setOpaque(false); | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + if (component instanceof Container) { | |
186 | + Container container = (Container) component; | |
187 | + for (Component c: container.getComponents()) { | |
188 | + transparentRecursive(c); | |
189 | + } | |
190 | + } | |
191 | + | |
192 | + if (component instanceof DockingDesktop) { | |
193 | + transparentRecursive((DockingDesktop) component); | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + private void transparentRecursive(DockingDesktop desktop) { | |
198 | + //DockingPanel dockingPanel = dockingDesktop.getDockingPanel(); // Scoping NG | |
199 | + // DockingPanel にアクセスできないので、下位要素から上にさかのぼって処理する。 | |
200 | + // 階層的には、こんな感じになっている。 | |
201 | + // ----------------------- | |
202 | + // DockingDesktop | |
203 | + // + DockingPanel <-- splitContainer.getParent() | |
204 | + // + splitContainer(HORIZONTAL) <-- splitContainer.getParent() | |
205 | + // + splitContainer(VERTICAL) <-- DockView.getParent() | |
206 | + // + DockView <-- Dockable.getParent() | |
207 | + // + Dockable <-- DockableState.getDockable() | |
208 | + for (DockableState d: desktop.getDockables()) { | |
209 | + double width = d.getPosition().getWidth(); | |
210 | + // width (height や x, y でも可) が 0.0 以外の場合はアイコン化されているので、透過処理不要 | |
211 | + // 他に適切な判定方法がありそうだけれども、分からなかったので、とりあえずこれで。 | |
212 | + if (width == 0.0) { | |
213 | + transparentRecursive(d); | |
214 | + } | |
215 | + } | |
216 | + } | |
217 | + | |
218 | + private void transparentRecursive(DockableState dockableState) { | |
219 | + Dockable dockable = dockableState.getDockable(); | |
220 | + | |
221 | + // DockView | |
222 | + Container container = dockable.getComponent().getParent(); | |
223 | + DockView view = (DockView) container; | |
224 | + if (view.isOpaque()) { | |
225 | + view.setOpaque(false); | |
226 | + } | |
227 | + DockViewTitleBar titleBar = view.getTitleBar(); | |
228 | + if (titleBar.isOpaque()) { | |
229 | + titleBar.setOpaque(false); | |
230 | + } | |
231 | + titleBar.setUI(new MoeDockViewTitleBarUI(titleBar)); | |
232 | + | |
233 | + // SplitContainer(VERTICAL) | |
234 | + container = container.getParent(); | |
235 | + if (container == null) { | |
236 | + return; | |
237 | + } else if (container.isOpaque()) { | |
238 | + ((SplitContainer) container).setOpaque(false); | |
239 | + } | |
240 | + | |
241 | + // SplitContainer(HORIZONTAL) | |
242 | + container = container.getParent(); | |
243 | + if (container == null) { | |
244 | + return; | |
245 | + } else if (container.isOpaque()) { | |
246 | + ((SplitContainer) container).setOpaque(false); | |
247 | + } | |
248 | + } | |
249 | + | |
250 | + private void transparentInstantStart(DockingDesktop desktop) { | |
251 | + // お手軽スタートは、以下のような HTML で背景色が指定されている。 | |
252 | + // <body ... bgcolor="white" ...> | |
253 | + // そのため、コンポーネント自体を透過にしても、HTML Body 背景色の | |
254 | + // 白指定が効いて透過にならない。そこで、背景色指定を削除する。 | |
255 | + JEditorPane ep = getJEditorPaneFromEditor(desktop); | |
256 | + if (ep != null) { | |
257 | + ep.setText(ep.getText().replace(" bgcolor=\"white\"", "")); | |
258 | + ep.setCaretPosition(0); | |
259 | + } | |
260 | + } | |
261 | + | |
262 | + private DockingDesktop getDockingDesktop(Container container) { | |
263 | + for (Component c: container.getComponents()) { | |
264 | + if (c instanceof DockingDesktop) { | |
265 | + return (DockingDesktop) c; | |
266 | + } | |
267 | + } | |
268 | + return null; | |
269 | + } | |
270 | + | |
271 | + private JEditorPane getJEditorPaneFromEditor(DockingDesktop desktop) { | |
272 | + for (DockableState d: desktop.getDockables()) { | |
273 | + Dockable dockable = d.getDockable(); | |
274 | + if (dockable.getDockKey().getKey().equalsIgnoreCase("EDITOR")) { | |
275 | + JScrollPane sp; | |
276 | + | |
277 | + // OmegaT 3.1.0 or later | |
278 | + if (dockable.getComponent() instanceof JPanel) { | |
279 | + // dockable.getComponent() => org.omegat.gui.main.DockablePanel | |
280 | + // extends JPanel implements Dockable | |
281 | + JPanel jp = (JPanel) dockable.getComponent(); | |
282 | + sp = (JScrollPane) jp.getComponent(0); | |
283 | + | |
284 | + // less than OmegaT 3.1.0 | |
285 | + } else { | |
286 | + sp = (JScrollPane) dockable.getComponent(); | |
287 | + } | |
288 | + | |
289 | + return (JEditorPane) sp.getViewport().getView(); | |
290 | + } | |
291 | + } | |
292 | + return null; | |
293 | + } | |
294 | +} |
@@ -0,0 +1,111 @@ | ||
1 | +/************************************************************************** | |
2 | + Moenizer - Allow to set background image for OmegaT. | |
3 | + | |
4 | + Copyright (C) 2013-2014 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/Moenizer/ | |
7 | + | |
8 | + This file is part of plugin for OmegaT. | |
9 | + http://www.omegat.org/ | |
10 | + | |
11 | + License: GNU GPL version 3 or (at your option) any later version. | |
12 | + | |
13 | + You should have received a copy of the GNU General Public License | |
14 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + **************************************************************************/ | |
16 | + | |
17 | +package jp.sourceforge.users.yutang.omegat.plugin.moenizer; | |
18 | + | |
19 | +import java.io.BufferedReader; | |
20 | +import java.io.File; | |
21 | +import java.io.FileInputStream; | |
22 | +import java.io.IOException; | |
23 | +import java.io.InputStreamReader; | |
24 | +import java.io.StringWriter; | |
25 | +import java.net.URISyntaxException; | |
26 | +import java.net.URL; | |
27 | +import java.security.CodeSource; | |
28 | +import java.util.regex.Matcher; | |
29 | +import java.util.regex.Pattern; | |
30 | +import org.omegat.util.LFileCopy; | |
31 | +import org.omegat.util.Log; | |
32 | +import org.omegat.util.OConsts; | |
33 | + | |
34 | +/** | |
35 | + * | |
36 | + * @author Yu-Tang | |
37 | + */ | |
38 | +public class MoeUtil { | |
39 | + | |
40 | + private static final Pattern RE_URL_IN_SHORTCUT = Pattern.compile("\\[InternetShortcut\\]\\s+URL=(.+)\\b"); | |
41 | + private static final Pattern RE_URL_IN_WEBLOC = Pattern.compile("<key>URL</key>\\s+<string>(.+)</string>"); | |
42 | + private static File pluginJarFile; | |
43 | + | |
44 | + static { | |
45 | + pluginJarFile = null; | |
46 | + } | |
47 | + | |
48 | + public static File getPluginJarFile() throws URISyntaxException { | |
49 | + if (pluginJarFile == null) { | |
50 | + CodeSource codeSource = MoeUtil.class.getProtectionDomain().getCodeSource(); | |
51 | + pluginJarFile = new File(codeSource.getLocation().toURI().getPath()); | |
52 | + } | |
53 | + return pluginJarFile; | |
54 | + } | |
55 | + | |
56 | + public static File getPluginJarDir() throws URISyntaxException { | |
57 | + File jarFile = getPluginJarFile(); | |
58 | + return new File(jarFile.getParentFile().getPath()); | |
59 | + } | |
60 | + | |
61 | + public static URL getURL(File file) { | |
62 | + String fileName = file.getName().toLowerCase(); | |
63 | + try { | |
64 | + if (fileName.endsWith(".url") || fileName.endsWith(".website")) { | |
65 | + // .url is Internet ShortCut file for IE8 or earlier, Firefox | |
66 | + // .website is Pinned Site ShortCut file for IE9 or later | |
67 | + | |
68 | + // Windows 日本語環境で作成すると Shift-JIS 文字列が含まれること | |
69 | + // があるため、文字コードはその OS の既定文字コードを想定した方 | |
70 | + // が望ましいと思われる。 | |
71 | + String text = readTextFile(file, System.getProperty("sun.jnu.encoding")); | |
72 | + Matcher matcher = RE_URL_IN_SHORTCUT.matcher(text); | |
73 | + if (matcher.find()) { | |
74 | + return new URL(matcher.group(1)); | |
75 | + } else { | |
76 | + Log.log("Could not find valid URL in internet shortcut file '" + file.getCanonicalPath() + "'"); | |
77 | + } | |
78 | + | |
79 | + } else if (fileName.endsWith(".webloc")) { | |
80 | + // .webloc is Mac OS X Website Location file for safari | |
81 | + String text = readTextFile(file, OConsts.UTF8); | |
82 | + Matcher matcher = RE_URL_IN_WEBLOC.matcher(text); | |
83 | + if (matcher.find()) { | |
84 | + return new URL(matcher.group(1)); | |
85 | + } else { | |
86 | + Log.log("Could not find valid URL in website location file '" + file.getCanonicalPath() + "'"); | |
87 | + } | |
88 | + | |
89 | + } else { // unknown | |
90 | + // ignore | |
91 | + } | |
92 | + } catch (IOException ex) { | |
93 | + Log.log(ex); | |
94 | + } | |
95 | + return null; | |
96 | + } | |
97 | + | |
98 | + /** | |
99 | + * Read file as platform dependent encoding text. | |
100 | + */ | |
101 | + public static String readTextFile(File file, String encoding) throws IOException { | |
102 | + BufferedReader rd = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding)); | |
103 | + try { | |
104 | + StringWriter out = new StringWriter(); | |
105 | + LFileCopy.copy(rd, out); | |
106 | + return out.toString(); | |
107 | + } finally { | |
108 | + rd.close(); | |
109 | + } | |
110 | + } | |
111 | +} |
@@ -0,0 +1,10 @@ | ||
1 | +Manifest-Version: 1.0 | |
2 | +Main-Class: org.omegat.Main | |
3 | +License: GNU Public License version 3 or later | |
4 | +Specification-Version: 1.0 | |
5 | +Implementation-Version: 0.2 | |
6 | +Permissions: all-permissions | |
7 | +Class-Path: lib/lib-mnemonics.jar | |
8 | +OmegaT-Plugins: | |
9 | + jp.sourceforge.users.yutang.omegat.plugin.moenizer.Moenizer | |
10 | +OmegaT-Plugin: true |
@@ -0,0 +1,74 @@ | ||
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<!-- You may freely edit this file. See commented blocks below for --> | |
3 | +<!-- some examples of how to customize the build. --> | |
4 | +<!-- (If you delete it and reopen the project it will be recreated.) --> | |
5 | +<!-- By default, only the Clean and Build commands use this build script. --> | |
6 | +<!-- Commands such as Run, Debug, and Test only use this build script if --> | |
7 | +<!-- the Compile on Save feature is turned off for the project. --> | |
8 | +<!-- You can turn off the Compile on Save (or Deploy on Save) setting --> | |
9 | +<!-- in the project's Project Properties dialog box.--> | |
10 | +<project name="Moenizer" default="default" basedir="."> | |
11 | + <description>Builds, tests, and runs the project Moenizer.</description> | |
12 | + <import file="nbproject/build-impl.xml"/> | |
13 | + <!-- | |
14 | + | |
15 | + There exist several targets which are by default empty and which can be | |
16 | + used for execution of your tasks. These targets are usually executed | |
17 | + before and after some main targets. They are: | |
18 | + | |
19 | + -pre-init: called before initialization of project properties | |
20 | + -post-init: called after initialization of project properties | |
21 | + -pre-compile: called before javac compilation | |
22 | + -post-compile: called after javac compilation | |
23 | + -pre-compile-single: called before javac compilation of single file | |
24 | + -post-compile-single: called after javac compilation of single file | |
25 | + -pre-compile-test: called before javac compilation of JUnit tests | |
26 | + -post-compile-test: called after javac compilation of JUnit tests | |
27 | + -pre-compile-test-single: called before javac compilation of single JUnit test | |
28 | + -post-compile-test-single: called after javac compilation of single JUunit test | |
29 | + -pre-jar: called before JAR building | |
30 | + -post-jar: called after JAR building | |
31 | + -post-clean: called after cleaning build products | |
32 | + | |
33 | + (Targets beginning with '-' are not intended to be called on their own.) | |
34 | + | |
35 | + Example of inserting an obfuscator after compilation could look like this: | |
36 | + | |
37 | + <target name="-post-compile"> | |
38 | + <obfuscate> | |
39 | + <fileset dir="${build.classes.dir}"/> | |
40 | + </obfuscate> | |
41 | + </target> | |
42 | + | |
43 | + For list of available properties check the imported | |
44 | + nbproject/build-impl.xml file. | |
45 | + | |
46 | + | |
47 | + Another way to customize the build is by overriding existing main targets. | |
48 | + The targets of interest are: | |
49 | + | |
50 | + -init-macrodef-javac: defines macro for javac compilation | |
51 | + -init-macrodef-junit: defines macro for junit execution | |
52 | + -init-macrodef-debug: defines macro for class debugging | |
53 | + -init-macrodef-java: defines macro for class execution | |
54 | + -do-jar-with-manifest: JAR building (if you are using a manifest) | |
55 | + -do-jar-without-manifest: JAR building (if you are not using a manifest) | |
56 | + run: execution of project | |
57 | + -javadoc-build: Javadoc generation | |
58 | + test-report: JUnit report generation | |
59 | + | |
60 | + An example of overriding the target for project execution could look like this: | |
61 | + | |
62 | + <target name="run" depends="Moenizer-impl.jar"> | |
63 | + <exec dir="bin" executable="launcher.exe"> | |
64 | + <arg file="${dist.jar}"/> | |
65 | + </exec> | |
66 | + </target> | |
67 | + | |
68 | + Notice that the overridden target depends on the jar target and not only on | |
69 | + the compile target as the regular run target does. Again, for a list of available | |
70 | + properties which you can use, check the target you are overriding in the | |
71 | + nbproject/build-impl.xml file. | |
72 | + | |
73 | + --> | |
74 | +</project> |