OmegaT のメニューバーにフォルダーツリー参照用のメニューを追加します。
Change package jp/sourceforge/... to jp/osdn/... and some refactoring
@@ -0,0 +1,15 @@ | ||
1 | +/************************************************************************** | |
2 | + This code is only a stub. | |
3 | + **************************************************************************/ | |
4 | + | |
5 | +package org.omegat.util; | |
6 | + | |
7 | +public class StringUtil { | |
8 | + /** | |
9 | + * Check if string is empty, i.e. null or length==0 | |
10 | + */ | |
11 | + public static boolean isEmpty(final String str) { | |
12 | + throw new UnsupportedOperationException("This code is only a stub."); | |
13 | + } | |
14 | + | |
15 | +} |
@@ -0,0 +1,12 @@ | ||
1 | +/************************************************************************** | |
2 | + This code is only a stub. | |
3 | + **************************************************************************/ | |
4 | + | |
5 | +package org.omegat.util; | |
6 | + | |
7 | +public class OStrings { | |
8 | + /** Returns a localized String for a key */ | |
9 | + public static String getString(String key) { | |
10 | + throw new UnsupportedOperationException("This code is only a stub."); | |
11 | + } | |
12 | +} |
@@ -6,5 +6,5 @@ | ||
6 | 6 | Permissions: all-permissions |
7 | 7 | Class-Path: lib/lib-mnemonics.jar |
8 | 8 | OmegaT-Plugins: |
9 | - jp.sourceforge.users.yutang.omegat.plugin.foldermenu.FolderMenu | |
9 | + jp.osdn.users.yutang.omegat.plugin.foldermenu.FolderMenu | |
10 | 10 | OmegaT-Plugin: true |
@@ -1,117 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu; | |
18 | - | |
19 | -import java.io.File; | |
20 | -import java.io.IOException; | |
21 | -import javax.swing.JMenu; | |
22 | -import javax.swing.JMenuBar; | |
23 | -import javax.swing.JSeparator; | |
24 | -import org.omegat.core.Core; | |
25 | -import org.omegat.util.FileUtil; | |
26 | -import org.omegat.util.Log; | |
27 | -import org.omegat.util.StaticUtils; | |
28 | -import org.openide.awt.Mnemonics; | |
29 | - | |
30 | -/** | |
31 | - * | |
32 | - * @author Yu Tang | |
33 | - */ | |
34 | -public class MenuManager { | |
35 | - | |
36 | - private JMenu root; | |
37 | - private ShellLinkMenu currentProject; | |
38 | - private ShellLinkMenuItem currentSourceFile; | |
39 | - private ShellLinkMenuItem currentTargetFile; | |
40 | - | |
41 | - public MenuManager() { | |
42 | - root = createLocalizedMenu(L10n.get(L10n.Key.FOLDERS_MENU_LABEL)); // Folders menu | |
43 | - root.addMenuKeyListener(MenuHelper.getMenuKeyListener()); // for opening folder with enter key | |
44 | - root.addMenuListener(MenuHelper.getRootMenuListener()); | |
45 | - | |
46 | - // ProjectRoot | |
47 | - try { | |
48 | - currentProject = new ShellLinkMenu(L10n.get(L10n.Key.PROJECT_ROOT_MENU_LABEL)); | |
49 | - root.add(currentProject.getMenu()); | |
50 | - } catch (IOException ex) { | |
51 | - Log.log(ex); | |
52 | - return; | |
53 | - } | |
54 | - | |
55 | - // User Config | |
56 | - try { | |
57 | - File confDir = new File(StaticUtils.getConfigDir()); | |
58 | - root.add(new ShellLinkMenu(confDir, L10n.get(L10n.Key.USER_CONFIG_MENU_LABEL)).getMenu()); | |
59 | - } catch (IOException ex) { | |
60 | - Log.log(ex); | |
61 | - } | |
62 | - | |
63 | - // ---- separator ---- | |
64 | - root.add(new JSeparator()); | |
65 | - | |
66 | - // Current Source File | |
67 | - currentSourceFile = new ShellLinkMenuItem(L10n.get(L10n.Key.SOURCE_DOC_MENU_LABEL)); | |
68 | - root.add(currentSourceFile.getMenuItem()); | |
69 | - | |
70 | - // Current Target File | |
71 | - currentTargetFile = new ShellLinkMenuItem(L10n.get(L10n.Key.TARGET_DOC_MENU_LABEL)); | |
72 | - root.add(currentTargetFile.getMenuItem()); | |
73 | - | |
74 | - // insert Files menu before the last menu (Help menu.) | |
75 | - JMenuBar mainMenuBar = (JMenuBar) Core.getMainWindow().getMainMenu().getOptionsMenu().getParent(); | |
76 | - mainMenuBar.add(root, mainMenuBar.getMenuCount() - 1); | |
77 | - } | |
78 | - | |
79 | - public void createProjectItems() { | |
80 | - File rootDir = new File(Core.getProject().getProjectProperties().getProjectRoot()); | |
81 | - try { | |
82 | - currentProject.link(rootDir); | |
83 | - } catch (IOException ex) { | |
84 | - Log.log(ex); | |
85 | - } | |
86 | - } | |
87 | - | |
88 | - public void removeAllProjectItems() { | |
89 | - currentProject.unlink(); | |
90 | - } | |
91 | - | |
92 | - public void linkCurrentSourceFile(File file) throws IOException { | |
93 | - String sourceRoot = Core.getProject().getProjectProperties().getSourceRoot(); | |
94 | - String midName = FileUtil.computeRelativePath(new File(sourceRoot), file); | |
95 | - currentSourceFile.link(file, midName); | |
96 | - } | |
97 | - | |
98 | - public void unlinkCurrentSourceFile() { | |
99 | - currentSourceFile.unlink(); | |
100 | - } | |
101 | - | |
102 | - public void linkCurrentTargetFile(File file) throws IOException { | |
103 | - String targetRoot = Core.getProject().getProjectProperties().getTargetRoot(); | |
104 | - String midName = FileUtil.computeRelativePath(new File(targetRoot), file); | |
105 | - currentTargetFile.link(file, midName); | |
106 | - } | |
107 | - | |
108 | - public void unlinkCurrentTargetFile() { | |
109 | - currentTargetFile.unlink(); | |
110 | - } | |
111 | - | |
112 | - private JMenu createLocalizedMenu(String labelString) { | |
113 | - JMenu m = new JMenu(); | |
114 | - Mnemonics.setLocalizedText(m, labelString); | |
115 | - return m; | |
116 | - } | |
117 | -} | |
\ No newline at end of file |
@@ -1,99 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu; | |
18 | - | |
19 | -import org.omegat.core.CoreEvents; | |
20 | -import org.omegat.core.events.IApplicationEventListener; | |
21 | -import org.omegat.core.events.IProjectEventListener; | |
22 | -import jp.sourceforge.users.yutang.omegat.plugin.foldermenu.filepreview.FilePreview; | |
23 | -import org.omegat.core.Core; | |
24 | -import org.omegat.util.Log; | |
25 | - | |
26 | -/** | |
27 | - * easy access to project folders from menu | |
28 | - * | |
29 | - * @author Yu Tang | |
30 | - */ | |
31 | -public class FolderMenu implements IApplicationEventListener, IProjectEventListener { | |
32 | - | |
33 | - private static boolean instantiated = false; | |
34 | - | |
35 | - private MenuManager menuManager; | |
36 | - | |
37 | - public static void loadPlugins() { | |
38 | - try { | |
39 | - // Not initialize in console mode | |
40 | - if (instantiated) { | |
41 | - throw new RuntimeException("FolderMenu plugin could be instantiated only once."); | |
42 | - } else if (isRunningJavaWebStart()) { | |
43 | - // Just log it, no error. | |
44 | - Log.log("FolderMenu plugin is not available with Java Web Start."); | |
45 | - } else { | |
46 | - CoreEvents.registerApplicationEventListener(new FolderMenu()); | |
47 | - } | |
48 | - } catch (Throwable ex) { | |
49 | - String msg = ex.getMessage(); | |
50 | - Log.logErrorRB("LD_ERROR", msg); | |
51 | - Core.pluginLoadingError(msg); | |
52 | - } | |
53 | - } | |
54 | - | |
55 | - private FolderMenu() { | |
56 | - FolderMenu.instantiated = true; | |
57 | - } | |
58 | - | |
59 | - public static void unloadPlugins() { | |
60 | - // do nothing | |
61 | - } | |
62 | - | |
63 | - @Override | |
64 | - public void onApplicationStartup() { | |
65 | - menuManager = new MenuManager(); | |
66 | - MenuHelper.setMenuManager(menuManager); | |
67 | - FilePreview.init(); | |
68 | - CoreEvents.registerProjectChangeListener(this); | |
69 | - } | |
70 | - | |
71 | - @Override | |
72 | - public void onApplicationShutdown() { /* do nothing */ } | |
73 | - | |
74 | - @Override | |
75 | - public void onProjectChanged(PROJECT_CHANGE_TYPE eventType) { | |
76 | - switch (eventType) { | |
77 | - case CREATE: | |
78 | - case LOAD: | |
79 | - menuManager.createProjectItems(); | |
80 | - break; | |
81 | - case CLOSE: | |
82 | - menuManager.removeAllProjectItems(); | |
83 | - menuManager.unlinkCurrentSourceFile(); | |
84 | - break; | |
85 | - } | |
86 | - } | |
87 | - | |
88 | - private static boolean isRunningJavaWebStart() { | |
89 | - boolean hasJNLP = false; | |
90 | - try { | |
91 | - Class.forName("javax.jnlp.ServiceManager"); | |
92 | - hasJNLP = true; | |
93 | - } catch (ClassNotFoundException ex) { | |
94 | - // ignore | |
95 | - } | |
96 | - return hasJNLP; | |
97 | - } | |
98 | - | |
99 | -} | |
\ No newline at end of file |
@@ -1,41 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
3 | - | |
4 | - Copyright (C) 2013 Yu Tang | |
5 | - Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | - Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
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.foldermenu.filepreview; | |
18 | - | |
19 | -import java.io.File; | |
20 | - | |
21 | -/** | |
22 | - * | |
23 | - * @author Yu Tang | |
24 | - */ | |
25 | -public interface IPreview { | |
26 | - | |
27 | - /** activate preview window */ | |
28 | - public void activate(); | |
29 | - | |
30 | - /** get temporary files for preview */ | |
31 | - public String[] getTempFiles(); | |
32 | - | |
33 | - /** open preview window */ | |
34 | - public void open(); | |
35 | - | |
36 | - /** close preview window */ | |
37 | - public void close(); | |
38 | - | |
39 | - /** reload document */ | |
40 | - public void reload(); | |
41 | - } |
@@ -1,398 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu.filepreview; | |
18 | - | |
19 | -import java.io.File; | |
20 | -import java.io.IOException; | |
21 | -import java.io.InputStream; | |
22 | -import java.util.ArrayList; | |
23 | -import java.util.Arrays; | |
24 | -import java.util.List; | |
25 | -import jp.sourceforge.users.yutang.omegat.plugin.foldermenu.L10n; | |
26 | -import org.omegat.util.LFileCopy; | |
27 | -import org.omegat.util.Log; | |
28 | -import static org.omegat.util.Platform.OsType.WIN32; | |
29 | -import static org.omegat.util.Platform.OsType.WIN64; | |
30 | -import static org.omegat.util.Platform.getOsType; | |
31 | -import org.omegat.util.StaticUtils; | |
32 | - | |
33 | -/** | |
34 | - * Word 文書をプレビュー用に開きます。 | |
35 | - * | |
36 | - * | |
37 | - * @author Yu Tang | |
38 | - */ | |
39 | -public class WordPreview implements IPreview { | |
40 | - | |
41 | - private static final String WSF_NAME = "WordPreview.wsf"; | |
42 | - private static boolean _isMSWordAvailable; | |
43 | - private static File _wsf; | |
44 | - | |
45 | - private final File originalFile; | |
46 | - private long originalFileLastModified; // will update at each every time compiling target docs | |
47 | - private final String windowTitle; | |
48 | - private final File temporaryFile; // Primary temp file | |
49 | - private final File temporaryFile2; // Secondary temp file | |
50 | - | |
51 | - public WordPreview(final File originalFile) throws IOException { | |
52 | - this.originalFile = originalFile; | |
53 | - this.originalFileLastModified = originalFile.lastModified(); | |
54 | - this.temporaryFile = getTempFile(originalFile); | |
55 | - this.windowTitle = StaticUtils.format( | |
56 | - L10n.get(L10n.Key.WORD_WINDOW_CAPTION), | |
57 | - originalFile.getName()); | |
58 | - this.temporaryFile2 = getTempFile2(this.temporaryFile); | |
59 | - } | |
60 | - | |
61 | - static { | |
62 | - // _isMSWordAvailable | |
63 | - switch (getOsType()) { | |
64 | - case WIN64: | |
65 | - case WIN32: | |
66 | - new Thread() { | |
67 | - @Override | |
68 | - public void run() { | |
69 | - _isMSWordAvailable = getMSWordAvailable(); | |
70 | - if (_isMSWordAvailable) { | |
71 | - Log.log("FolderMenu: WordPreview function is available."); | |
72 | - } else { | |
73 | - Log.log("FolderMenu: WordPreview function is not available."); | |
74 | - } | |
75 | - } | |
76 | - }.start(); | |
77 | - break; | |
78 | - default: // Mac, Linux and others | |
79 | - _isMSWordAvailable = false; | |
80 | - break; | |
81 | - } | |
82 | - | |
83 | - // _wsf | |
84 | - File tempDir = new File(System.getProperty("java.io.tmpdir")); | |
85 | - _wsf = new File(tempDir, WSF_NAME); | |
86 | - } | |
87 | - | |
88 | - public static boolean isAvailable(File file) { | |
89 | - return isAvailable() && | |
90 | - file.isFile() && | |
91 | - file.getName().toLowerCase().endsWith(".docx"); | |
92 | - } | |
93 | - | |
94 | - public static boolean isAvailable() { | |
95 | - return _isMSWordAvailable; | |
96 | - } | |
97 | - | |
98 | - public static void init() { | |
99 | - // force executing static initializer | |
100 | - } | |
101 | - | |
102 | - private static boolean getMSWordAvailable() { | |
103 | - final int RET_OK = 0; | |
104 | - try { | |
105 | - Command command = new Command(); | |
106 | - String s; | |
107 | - if (RET_OK == command.execDOS("assoc", ".docx")) { | |
108 | - s = command.getStdout(); | |
109 | - // s's data example) | |
110 | - // ----------------------------------------------------- | |
111 | - //.docx=Word.Document.12 | |
112 | - //<-(\r\n) | |
113 | - // ----------------------------------------------------- | |
114 | - // 末尾に空行が入るので注意。 | |
115 | - // 他のパターンとして、AOO/LO 環境で以下のようなケースもあり。 | |
116 | - //.docx=OpenOffice.Docx | |
117 | - //.docx=LibreOffice.WriterDocument.1 | |
118 | - if (s.toLowerCase().startsWith(".docx=word.document.")) { | |
119 | - String classString = s.substring(".docx=".length()).replaceAll("\\r\\n", ""); | |
120 | - if (RET_OK == command.exec("reg", "query", "HKCR\\" + classString + "\\shell\\open\\command", "/ve")) { | |
121 | - s = command.getStdout(); | |
122 | - // s's data example) | |
123 | - // ----------------------------------------------------- | |
124 | - //<-(\r\n) | |
125 | - //HKEY_CLASSES_ROOT\Word.document.12\shell\open\command | |
126 | - //(既定) REG_SZ "C:\PROGRA~2\MICROS~4\OFFICE11\WINWORD.EXE" /n /dde | |
127 | - //<-(\r\n) | |
128 | - // ----------------------------------------------------- | |
129 | - // 前後に空行が入るので注意。 | |
130 | - return s.toUpperCase().indexOf("\\WINWORD.EXE") > -1; | |
131 | - } | |
132 | - } | |
133 | - } | |
134 | - } catch (Exception ex) { | |
135 | - Log.log(ex); | |
136 | - } | |
137 | - return false; | |
138 | - } | |
139 | - | |
140 | - private static File getWSF() throws IOException { | |
141 | - if (! _wsf.exists()) { | |
142 | - InputStream in = WordPreview.class.getResourceAsStream(WSF_NAME); | |
143 | - try { | |
144 | - LFileCopy.copy(in, _wsf); | |
145 | - } finally { | |
146 | - in.close(); | |
147 | - } | |
148 | - _wsf.deleteOnExit(); | |
149 | - } | |
150 | - return _wsf; | |
151 | - } | |
152 | - | |
153 | - @Override | |
154 | - public String[] getTempFiles() { | |
155 | - // ここでは、残留する可能性のある一時ファイルをすべて申告します。 | |
156 | - String[] paths = new String[3]; | |
157 | - try { | |
158 | - paths[0] = this.temporaryFile.getCanonicalPath(); | |
159 | - paths[1] = this.temporaryFile2.getCanonicalPath(); | |
160 | - | |
161 | - // MS Word が作成する(プレビュー用ファイルの)一時ファイルも、強制 | |
162 | - // 終了時などには残留する可能性があるため、ここで申告しておきます。 | |
163 | - final String PREFIX = "~$"; | |
164 | - String parent = this.temporaryFile.getParent(); | |
165 | - String name = this.temporaryFile.getName(); | |
166 | - paths[2] = (new File(parent, PREFIX + name.substring(2))).getCanonicalPath(); | |
167 | - } catch (IOException ex) { | |
168 | - Log.log(ex); | |
169 | - } | |
170 | - return paths; | |
171 | - } | |
172 | - | |
173 | - @Override | |
174 | - public void activate() { | |
175 | - try { | |
176 | - final Command command = new Command(); | |
177 | - final String job = "activate"; | |
178 | - final int ret = command.execWSF(job, this.windowTitle); | |
179 | - } catch (IOException ex) { | |
180 | - Log.log(ex); | |
181 | - } catch (InterruptedException ex) { | |
182 | - Log.log(ex); | |
183 | - } | |
184 | - } | |
185 | - | |
186 | - @Override | |
187 | - public void open() { | |
188 | - | |
189 | - // 以下の処理は少し時間がかかるため、別スレッドに処理を委譲します。 | |
190 | - new Thread() { | |
191 | - @Override | |
192 | - public void run() { | |
193 | - try { | |
194 | - // 起動前にファイルをコピーする。 | |
195 | - // OmegaT は訳文ファイルの作成時に、既存の訳文ファイルを上書きする。 | |
196 | - // そのため、オリジナルのファイルをそのまま開くとファイルがロックされ、 | |
197 | - // 次回のコンパイル時に上書きできずに失敗する。それを避けるために、 | |
198 | - // プレビュー専用の一時ファイルをコピーして、そちらを開く。 | |
199 | - // コピー先は、temp フォルダーではなく、オリジナルと同じフォルダー内に | |
200 | - // コピーする。文書に相対パスで画像リンクなどが張られている場合のリンク | |
201 | - // 切れを防ぐため。 | |
202 | - // そのままコピーすると FolderMenu プラグインのメニュー上で一時ファイル | |
203 | - // が見えてしまうため、hidden 属性を付けておく。 | |
204 | - LFileCopy.copy(originalFile, temporaryFile); | |
205 | - | |
206 | - // make temp file hidden on Windows | |
207 | - addHiddenFileAttribute(temporaryFile); | |
208 | - | |
209 | - // Desktop.getDesktop().open(temp); | |
210 | - // 上記のようにして一時ファイルを開くと、場合によっては Word | |
211 | - // の MRU に一時ファイルを開いた履歴が大量に残ってしまう。 | |
212 | - // これを回避するため、WSH を経由して COM オートメーションで | |
213 | - // 処理する。 | |
214 | - | |
215 | - // open the document | |
216 | - Command command = new Command(); | |
217 | - String document = temporaryFile.getCanonicalPath(); | |
218 | - String document2 = temporaryFile2.getCanonicalPath(); | |
219 | - String job = "open"; | |
220 | - int ret = command.execWSF(job, document, document2, windowTitle); | |
221 | - | |
222 | - if (! command.stderr.isEmpty()) { | |
223 | - Log.log("Word error(" + ret + "): " + command.stderr); | |
224 | - } | |
225 | - onWordApplicationQuit(ret); | |
226 | - } catch (IOException ex) { | |
227 | - Log.log(ex); | |
228 | - } catch (InterruptedException ex) { | |
229 | - Log.log(ex); | |
230 | - } | |
231 | - } | |
232 | - }.start(); | |
233 | - } | |
234 | - | |
235 | - private File getTempFile(final File originalFile) throws IOException { | |
236 | - String prefix = "_WordPreview"; | |
237 | - String name = originalFile.getName(); | |
238 | - String suffix = name.substring(name.lastIndexOf(".")); | |
239 | - File parentFolder = originalFile.getParentFile(); | |
240 | - File tempFile = File.createTempFile(prefix, suffix, parentFolder); | |
241 | - tempFile.deleteOnExit(); | |
242 | - return tempFile; | |
243 | - } | |
244 | - | |
245 | - // foo.ext => foo(2).ext | |
246 | - private File getTempFile2(final File primaryTempFile) throws IOException { | |
247 | - String name = primaryTempFile.getName(); | |
248 | - int lastDotPos = name.lastIndexOf("."); | |
249 | - String baseName = name.substring(0, lastDotPos); | |
250 | - String extension = name.substring(lastDotPos); | |
251 | - String fileName = baseName + "(2)" + extension; | |
252 | - File parentFolder = primaryTempFile.getParentFile(); | |
253 | - File tempFile2 = new File(parentFolder, fileName); | |
254 | - tempFile2.deleteOnExit(); | |
255 | - return tempFile2; | |
256 | - } | |
257 | - | |
258 | - private void addHiddenFileAttribute(File file) { | |
259 | - try { | |
260 | - new ProcessBuilder("attrib","+H", file.getCanonicalPath()).start(); | |
261 | - } catch (IOException ex) { | |
262 | - Log.log(ex); | |
263 | - } | |
264 | - } | |
265 | - | |
266 | - private void onWordApplicationQuit(final int returnCode) { | |
267 | - try { | |
268 | - // remove this from Previews collection | |
269 | - FilePreview.delete(originalFile); | |
270 | - | |
271 | - // try to delete temporary file | |
272 | - temporaryFile.delete(); | |
273 | - | |
274 | - // try to delete WSF file | |
275 | - if (FilePreview.size(WordPreview.class) == 0) { | |
276 | - _wsf.delete(); | |
277 | - } | |
278 | - | |
279 | - } catch (IOException ex) { | |
280 | - Log.log(ex); | |
281 | - } | |
282 | - } | |
283 | - | |
284 | - @Override | |
285 | - public void close() { | |
286 | - try { | |
287 | - // close the document | |
288 | - final Command command = new Command(); | |
289 | - final String job = "close"; | |
290 | - final String document = temporaryFile.getCanonicalPath(); | |
291 | - command.execWSF(job, document); | |
292 | - } catch (IOException ex) { | |
293 | - Log.log(ex); | |
294 | - } catch (InterruptedException ex) { | |
295 | - Log.log(ex); | |
296 | - } | |
297 | - } | |
298 | - | |
299 | - @Override | |
300 | - public void reload() { | |
301 | - if (! isOriginalFileUpdated()) { | |
302 | - return; | |
303 | - } | |
304 | - | |
305 | - try { | |
306 | - File temp = getTempFile(originalFile); | |
307 | - | |
308 | - // copy the file to avoid locking the file unnecessarily | |
309 | - LFileCopy.copy(originalFile, temp); | |
310 | - | |
311 | - // rename to secondary temp file (and pass it to WSF) | |
312 | - temp.renameTo(temporaryFile2); | |
313 | - | |
314 | - // make temp file hidden on Windows | |
315 | - addHiddenFileAttribute(temporaryFile2); | |
316 | - | |
317 | - // update lastModified value | |
318 | - this.originalFileLastModified = originalFile.lastModified(); | |
319 | - } catch (IOException ex) { | |
320 | - Log.log(ex); | |
321 | - } | |
322 | - } | |
323 | - | |
324 | - private boolean isOriginalFileUpdated() { | |
325 | - return this.originalFileLastModified != this.originalFile.lastModified(); | |
326 | - } | |
327 | - | |
328 | - // バッファあふれ非対応のため、少量のテキスト(だいたい 500文字ていど)が | |
329 | - // 予想される場合のみ利用してください。 | |
330 | - // また同期実行です。プロセスの終了を待機してから制御を返します。 | |
331 | - protected static class Command { | |
332 | - | |
333 | - private int exitCode = 0; | |
334 | - private String stdout = ""; | |
335 | - private String stderr = ""; | |
336 | - | |
337 | - public int getExitCode() { | |
338 | - return exitCode; | |
339 | - } | |
340 | - | |
341 | - public String getStdout() { | |
342 | - return stdout; | |
343 | - } | |
344 | - | |
345 | - public String getStderr() { | |
346 | - return stderr; | |
347 | - } | |
348 | - | |
349 | - public int exec(String... command) | |
350 | - throws IOException, InterruptedException { | |
351 | - return startProcessAndWait(Arrays.asList(command)); | |
352 | - } | |
353 | - | |
354 | - public int execDOS(String... command) | |
355 | - throws IOException, InterruptedException { | |
356 | - List<String> commands = new ArrayList<String>(command.length + 2); | |
357 | - commands.add("cmd.exe"); | |
358 | - commands.add("/c"); | |
359 | - commands.addAll(Arrays.asList(command)); | |
360 | - | |
361 | - return startProcessAndWait(commands); | |
362 | - } | |
363 | - | |
364 | - public int execWSF(String job, String... command) | |
365 | - throws IOException, InterruptedException { | |
366 | - String script = getWSF().getCanonicalPath(); | |
367 | - List<String> commands = new ArrayList<String>(command.length + 4); | |
368 | - commands.add("cscript.exe"); | |
369 | - commands.add("//nologo"); | |
370 | - commands.add("//Job:" + job); | |
371 | - commands.add(script); | |
372 | - commands.addAll(Arrays.asList(command)); | |
373 | - | |
374 | - return startProcessAndWait(commands); | |
375 | - } | |
376 | - | |
377 | - private int startProcessAndWait(List<String> command) | |
378 | - throws IOException, InterruptedException { | |
379 | - ProcessBuilder pb = new ProcessBuilder(command); | |
380 | - Process process = pb.start(); | |
381 | - exitCode = process.waitFor(); // 0: succeed | |
382 | - stdout = getString(process.getInputStream()); | |
383 | - stderr = getString(process.getErrorStream()); | |
384 | - return exitCode; | |
385 | - } | |
386 | - | |
387 | - private String getString(InputStream is) throws IOException { | |
388 | - byte[] b = new byte[1024]; | |
389 | - int size = is.read(b); | |
390 | - if (size > 0) { | |
391 | - return new String(b, 0, size); | |
392 | - } else { | |
393 | - return ""; | |
394 | - } | |
395 | - } | |
396 | - | |
397 | - } | |
398 | -} |
@@ -1,102 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
3 | - | |
4 | - Copyright (C) 2013 Yu Tang | |
5 | - Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | - Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
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.foldermenu.filepreview; | |
18 | - | |
19 | -import java.io.File; | |
20 | -import java.io.IOException; | |
21 | -import org.omegat.util.FileUtil; | |
22 | -import org.omegat.util.Log; | |
23 | -import org.omegat.util.StaticUtils; | |
24 | - | |
25 | -/** | |
26 | - * Cleanup temp files | |
27 | - * | |
28 | - * @author Yu Tang | |
29 | - */ | |
30 | -public class TempFileCleaner { | |
31 | - | |
32 | - private static final String LOG_FILE_NAME = "FilePreviewTempFiles.log"; | |
33 | - private static final File logFile; | |
34 | - | |
35 | - private TempFileCleaner() { /* not allow instanciation. static only. */ } | |
36 | - | |
37 | - static { | |
38 | - logFile = new File(StaticUtils.getConfigDir(), LOG_FILE_NAME); | |
39 | - } | |
40 | - | |
41 | - public static void cleanup() { | |
42 | - // load temp file list from log file | |
43 | - String[] list = readTempFileList().split("\\n"); | |
44 | - String content = ""; | |
45 | - | |
46 | - // try to delete them | |
47 | - for (String path: list) { | |
48 | - if (! path.isEmpty()) { | |
49 | - File f = new File(path); | |
50 | - if (f.isFile()) { | |
51 | - if (! f.delete()) { | |
52 | - f.deleteOnExit(); | |
53 | - content += path + "\n"; | |
54 | - } | |
55 | - } | |
56 | - } | |
57 | - } | |
58 | - | |
59 | - // save back to log file or delete log if empty | |
60 | - writeTempFileList(content); | |
61 | - } | |
62 | - | |
63 | - public static void addToList(String[] filePaths) { | |
64 | - // load temp file list from log file | |
65 | - String list = readTempFileList(); | |
66 | - | |
67 | - // add the file to the list | |
68 | - for (String path: filePaths) | |
69 | - list += path + "\n"; | |
70 | - | |
71 | - // save back to log file or delete log if empty | |
72 | - writeTempFileList(list); | |
73 | - } | |
74 | - | |
75 | - // 末尾改行付きのリストを返します。 | |
76 | - private static String readTempFileList() { | |
77 | - String ret = ""; | |
78 | - if (logFile.isFile()) { | |
79 | - try { | |
80 | - ret = FileUtil.readTextFile(logFile); | |
81 | - if (!ret.isEmpty() && !ret.endsWith("\n")) | |
82 | - ret += "\n"; | |
83 | - } catch (IOException ex) { | |
84 | - Log.log(ex); | |
85 | - } | |
86 | - } | |
87 | - return ret; | |
88 | - } | |
89 | - | |
90 | - private static void writeTempFileList(final String content) { | |
91 | - if (content.isEmpty()) { | |
92 | - if (logFile.isFile()) | |
93 | - logFile.delete(); | |
94 | - } else { | |
95 | - try { | |
96 | - FileUtil.writeTextFile(logFile, content); | |
97 | - } catch (IOException ex) { | |
98 | - Log.log(ex); | |
99 | - } | |
100 | - } | |
101 | - } | |
102 | -} |
@@ -1,221 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
3 | - | |
4 | - Copyright (C) 2013 Yu Tang | |
5 | - Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | - Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
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.foldermenu.filepreview; | |
18 | - | |
19 | -import java.io.File; | |
20 | -import java.io.IOException; | |
21 | -import java.util.HashMap; | |
22 | -import javax.swing.SwingUtilities; | |
23 | -import org.omegat.core.Core; | |
24 | -import org.omegat.core.CoreEvents; | |
25 | -import org.omegat.core.events.IApplicationEventListener; | |
26 | -import org.omegat.core.events.IProjectEventListener; | |
27 | -import org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE; | |
28 | -import static org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE.CLOSE; | |
29 | -import static org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE.COMPILE; | |
30 | - | |
31 | -/** | |
32 | - * must call init() before using this class. | |
33 | - * | |
34 | - * @author Yu Tang | |
35 | - */ | |
36 | - | |
37 | -public class FilePreview { | |
38 | - | |
39 | - // key = target file's canonical path | |
40 | - private static final HashMap<String, IPreview> previews = new HashMap<String, IPreview>(); | |
41 | - | |
42 | - private static IProjectEventListener projectEventListener = null; | |
43 | - private static IApplicationEventListener applicationEventListener = null; | |
44 | - | |
45 | - static { | |
46 | - // cleanup left temp files if they exists | |
47 | - TempFileCleaner.cleanup(); | |
48 | - | |
49 | - // call each Preview#init() | |
50 | - WordPreview.init(); | |
51 | - | |
52 | - //@@TODO WSF reload 時にselectionがテキストボックスの場合、restore に失敗するバグ | |
53 | - } | |
54 | - | |
55 | - public static boolean delete(final File originalFile) throws IOException { | |
56 | - String key = originalFile.getCanonicalPath(); | |
57 | - IPreview deleted = previews.remove(key); | |
58 | - if (previews.isEmpty()) | |
59 | - unhookProjectChangeEvent(); | |
60 | - return (deleted != null); | |
61 | - } | |
62 | - | |
63 | - public static void init() { | |
64 | - // force executing static initializer | |
65 | - } | |
66 | - | |
67 | - public static boolean open(File file) throws IOException { | |
68 | - // not available for directory | |
69 | - if (! file.isFile()) | |
70 | - return false; | |
71 | - | |
72 | - // does file exists inside of the target folder? | |
73 | - if (! isUnderTargetFolder(file)) | |
74 | - return false; | |
75 | - | |
76 | - // file type or environment is not supported | |
77 | - if (! available(file)) | |
78 | - return false; | |
79 | - | |
80 | - // Preview instance is already there? | |
81 | - String key = file.getCanonicalPath(); | |
82 | - if (previews.containsKey(key)) { | |
83 | - previews.get(key).activate(); | |
84 | - return true; | |
85 | - } | |
86 | - | |
87 | - // open it | |
88 | - IPreview p = new WordPreview(file); | |
89 | - p.open(); | |
90 | - hookProjectChangeEvent(); | |
91 | - hookApplicationChangeEvent(); | |
92 | - previews.put(key, p); | |
93 | - | |
94 | - // add temp files to cleaner list | |
95 | - TempFileCleaner.addToList(p.getTempFiles()); | |
96 | - | |
97 | - return true; | |
98 | - } | |
99 | - | |
100 | - public static int size(Class<?> classObj) { | |
101 | - if (classObj == null) { | |
102 | - return previews.size(); | |
103 | - } else { | |
104 | - int i = 0; | |
105 | - for (Object o: previews.values()) { | |
106 | - if (classObj.isInstance(o)) | |
107 | - i++; | |
108 | - } | |
109 | - return i; | |
110 | - } | |
111 | - } | |
112 | - | |
113 | - private static boolean available(File file) { | |
114 | - return WordPreview.isAvailable(file); | |
115 | - } | |
116 | - | |
117 | - /** hook project change event */ | |
118 | - private static void hookProjectChangeEvent() { | |
119 | - if (projectEventListener != null) | |
120 | - return; | |
121 | - | |
122 | - projectEventListener= new IProjectEventListener() { | |
123 | - | |
124 | - @Override | |
125 | - public void onProjectChanged(PROJECT_CHANGE_TYPE eventType) { | |
126 | - switch (eventType) { | |
127 | - case CLOSE: | |
128 | - onProjectClose(); | |
129 | - break; | |
130 | - case COMPILE: | |
131 | - onProjectCompile(); | |
132 | - break; | |
133 | - } | |
134 | - } | |
135 | - | |
136 | - }; | |
137 | - | |
138 | - CoreEvents.registerProjectChangeListener(projectEventListener); | |
139 | - } | |
140 | - | |
141 | - /** unhook project change event */ | |
142 | - private static void unhookProjectChangeEvent() { | |
143 | - if (projectEventListener == null) | |
144 | - return; | |
145 | - | |
146 | - CoreEvents.unregisterProjectChangeListener(projectEventListener); | |
147 | - projectEventListener= null; | |
148 | - } | |
149 | - | |
150 | - /** hook application change event */ | |
151 | - private static void hookApplicationChangeEvent() { | |
152 | - if (applicationEventListener != null) | |
153 | - return; | |
154 | - | |
155 | - applicationEventListener= new IApplicationEventListener() { | |
156 | - | |
157 | - @Override | |
158 | - public void onApplicationStartup() { | |
159 | - /* do nothing */ | |
160 | - } | |
161 | - | |
162 | - @Override | |
163 | - public void onApplicationShutdown() { | |
164 | - closeAllPreviews(); | |
165 | - } | |
166 | - | |
167 | - }; | |
168 | - | |
169 | - CoreEvents.registerApplicationEventListener(applicationEventListener); | |
170 | - } | |
171 | - | |
172 | - /** unhook project change event */ | |
173 | - private static void unhookApplicationChangeEvent() { | |
174 | - if (applicationEventListener == null) | |
175 | - return; | |
176 | - | |
177 | - CoreEvents.unregisterApplicationEventListener(applicationEventListener); | |
178 | - applicationEventListener= null; | |
179 | - } | |
180 | - | |
181 | - private static void onProjectClose() { | |
182 | - closeAllPreviews(); | |
183 | - | |
184 | - // イベントリスナーの登録解除をここで発行するとスレッドエラーになるので | |
185 | - // 後で実行する。 | |
186 | - SwingUtilities.invokeLater(new Runnable() { | |
187 | - @Override | |
188 | - public void run() { | |
189 | - unhookProjectChangeEvent(); | |
190 | - unhookApplicationChangeEvent(); | |
191 | - } | |
192 | - }); | |
193 | - } | |
194 | - | |
195 | - private static void onProjectCompile() { | |
196 | - reloadAllPreviews(); | |
197 | - } | |
198 | - | |
199 | - private static boolean isUnderTargetFolder(final File file) throws IOException { | |
200 | - // does file exists inside of the target folder? | |
201 | - String targetRoot = Core.getProject().getProjectProperties().getTargetRoot(); | |
202 | - return file.getCanonicalPath().startsWith(targetRoot); | |
203 | - } | |
204 | - | |
205 | - private static void closeAllPreviews() { | |
206 | - if (! previews.isEmpty()) { | |
207 | - for (IPreview preview: previews.values()) { | |
208 | - preview.close(); | |
209 | - } | |
210 | - } | |
211 | - } | |
212 | - | |
213 | - private static void reloadAllPreviews() { | |
214 | - if (! previews.isEmpty()) { | |
215 | - for (IPreview preview: previews.values()) { | |
216 | - preview.reload(); | |
217 | - } | |
218 | - } | |
219 | - } | |
220 | - | |
221 | -} |
@@ -1,309 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu; | |
18 | - | |
19 | -import java.awt.Component; | |
20 | -import java.awt.Desktop; | |
21 | -import java.awt.event.ActionEvent; | |
22 | -import java.awt.event.ActionListener; | |
23 | -import java.awt.event.KeyEvent; | |
24 | -import java.awt.event.MouseEvent; | |
25 | -import java.awt.event.MouseListener; | |
26 | -import java.io.File; | |
27 | -import java.io.FileFilter; | |
28 | -import java.io.IOException; | |
29 | -import java.util.Comparator; | |
30 | -import javax.swing.Icon; | |
31 | -import javax.swing.JMenu; | |
32 | -import javax.swing.JMenuItem; | |
33 | -import javax.swing.MenuElement; | |
34 | -import javax.swing.MenuSelectionManager; | |
35 | -import javax.swing.event.MenuEvent; | |
36 | -import javax.swing.event.MenuKeyEvent; | |
37 | -import javax.swing.event.MenuKeyListener; | |
38 | -import javax.swing.event.MenuListener; | |
39 | -import javax.swing.filechooser.FileSystemView; | |
40 | -import jp.sourceforge.users.yutang.omegat.plugin.foldermenu.filepreview.FilePreview; | |
41 | -import org.omegat.core.Core; | |
42 | -import org.omegat.core.data.IProject; | |
43 | -import org.omegat.util.Log; | |
44 | -import static org.omegat.util.Platform.getOsType; | |
45 | -import org.omegat.util.StaticUtils; | |
46 | - | |
47 | -/** | |
48 | - * | |
49 | - * @author Yu Tang | |
50 | - */ | |
51 | -public class MenuHelper { | |
52 | - | |
53 | - static { | |
54 | - fs = FileSystemView.getFileSystemView(); | |
55 | - ff = new FileFilter() { | |
56 | - | |
57 | - @Override | |
58 | - public boolean accept(File file) { | |
59 | - // except dot started named files (i.e. ".svn") and hidden files | |
60 | - return !file.getName().startsWith(".") && !file.isHidden(); | |
61 | - } | |
62 | - | |
63 | - }; | |
64 | - | |
65 | - al = new ActionListener() { | |
66 | - | |
67 | - @Override | |
68 | - public void actionPerformed(ActionEvent e) { open( (JMenuItem) e.getSource()); } | |
69 | - | |
70 | - }; | |
71 | - | |
72 | - mkl = new MenuKeyListener() { | |
73 | - | |
74 | - @Override | |
75 | - public void menuKeyTyped(MenuKeyEvent e) { /* do nothing */ } | |
76 | - | |
77 | - @Override | |
78 | - public void menuKeyPressed(MenuKeyEvent e) { | |
79 | - if (e.getKeyCode() == KeyEvent.VK_ENTER) { | |
80 | - MenuSelectionManager manager = e.getMenuSelectionManager(); | |
81 | - MenuElement[] selectedPath = manager.getSelectedPath(); | |
82 | - MenuElement selection = selectedPath[selectedPath.length-1]; | |
83 | - if (selection instanceof JMenu) { | |
84 | - JMenu menu = (JMenu) selection; | |
85 | - if (menu.isEnabled()) { | |
86 | - manager.clearSelectedPath(); | |
87 | - open(menu); | |
88 | - } | |
89 | - } | |
90 | - } | |
91 | - } | |
92 | - | |
93 | - @Override | |
94 | - public void menuKeyReleased(MenuKeyEvent e) { /* do nothing */ } | |
95 | - | |
96 | - }; | |
97 | - | |
98 | - mol = new MouseListener() { | |
99 | - | |
100 | - @Override | |
101 | - public void mouseClicked(MouseEvent e) { open((JMenuItem) e.getSource()); } | |
102 | - | |
103 | - @Override | |
104 | - public void mousePressed(MouseEvent e) { /* do nothing */ } | |
105 | - | |
106 | - @Override | |
107 | - public void mouseReleased(MouseEvent e) { /* do nothing */ } | |
108 | - | |
109 | - @Override | |
110 | - public void mouseEntered(MouseEvent e) { /* do nothing */ } | |
111 | - | |
112 | - @Override | |
113 | - public void mouseExited(MouseEvent e) { /* do nothing */ } | |
114 | - | |
115 | - }; | |
116 | - | |
117 | - mel = new MenuListener() { | |
118 | - | |
119 | - @Override | |
120 | - public void menuSelected(MenuEvent e) { | |
121 | - // Lazy create submenus | |
122 | - ((ShellLinkMenu) e.getSource()).createChildren(); | |
123 | - } | |
124 | - | |
125 | - @Override | |
126 | - public void menuDeselected(MenuEvent e) { /* do nothing */ } | |
127 | - | |
128 | - @Override | |
129 | - public void menuCanceled(MenuEvent e) { /* do nothing */ } | |
130 | - | |
131 | - }; | |
132 | - | |
133 | - /* for Folders root menu only */ | |
134 | - melRoot = new MenuListener() { | |
135 | - | |
136 | - @Override | |
137 | - public void menuSelected(MenuEvent e) { | |
138 | - | |
139 | - // update menuitems for CurrentSourceFile and CurrentTargetFile | |
140 | - IProject project = Core.getProject(); | |
141 | - File sourceFile = null; | |
142 | - File translatedFile = null; | |
143 | - | |
144 | - if (project.isProjectLoaded()) { | |
145 | - // relative path to the root of Source directory | |
146 | - String currentFile = Core.getEditor().getCurrentFile(); | |
147 | - if (currentFile != null) { | |
148 | - String sourceRoot = project.getProjectProperties().getSourceRoot(); | |
149 | - sourceFile = new File(sourceRoot + currentFile); | |
150 | - translatedFile = FilterHelper.getTargetFile(currentFile); | |
151 | - } | |
152 | - } | |
153 | - | |
154 | - if (sourceFile == null || !sourceFile.isFile()) { | |
155 | - if (prevSourceFile != null) { | |
156 | - menuManager.unlinkCurrentSourceFile(); | |
157 | - prevSourceFile = null; | |
158 | - } | |
159 | - if (prevTranslatedFile != null) { | |
160 | - menuManager.unlinkCurrentTargetFile(); | |
161 | - prevTranslatedFile = null; | |
162 | - } | |
163 | - return; | |
164 | - } | |
165 | - | |
166 | - try { | |
167 | - if (!sourceFile.equals(prevSourceFile)) { | |
168 | - menuManager.linkCurrentSourceFile(sourceFile); | |
169 | - prevSourceFile = sourceFile; | |
170 | - } | |
171 | - } catch (IOException ex) { | |
172 | - Log.log(ex.getMessage()); | |
173 | - menuManager.unlinkCurrentSourceFile(); | |
174 | - prevSourceFile = null; | |
175 | - } | |
176 | - | |
177 | - if (translatedFile == null || !translatedFile.isFile()) { | |
178 | - if (prevTranslatedFile != null) { | |
179 | - menuManager.unlinkCurrentTargetFile(); | |
180 | - prevTranslatedFile = null; | |
181 | - } | |
182 | - } else { | |
183 | - try { | |
184 | - if (!translatedFile.equals(prevTranslatedFile)) { | |
185 | - menuManager.linkCurrentTargetFile(translatedFile); | |
186 | - prevTranslatedFile = translatedFile; | |
187 | - } | |
188 | - } catch (IOException ex) { | |
189 | - Log.log(ex.getMessage()); | |
190 | - menuManager.unlinkCurrentTargetFile(); | |
191 | - prevTranslatedFile = null; | |
192 | - } | |
193 | - } | |
194 | - } | |
195 | - | |
196 | - @Override | |
197 | - public void menuDeselected(MenuEvent e) { | |
198 | - // remove children's all menuitems | |
199 | - JMenu menu = (JMenu) e.getSource(); | |
200 | - for (Component c: menu.getMenuComponents()) { | |
201 | - if (c instanceof JMenu) { | |
202 | - JMenu m = (JMenu) c; | |
203 | - if (m.isEnabled()) { | |
204 | - m.removeAll(); | |
205 | - } | |
206 | - } | |
207 | - } | |
208 | - } | |
209 | - | |
210 | - @Override | |
211 | - public void menuCanceled(MenuEvent e) { /* do nothing */ } | |
212 | - | |
213 | - }; | |
214 | - | |
215 | - comp = new Comparator<File>() { | |
216 | - | |
217 | - @Override | |
218 | - public int compare(File f1, File f2) { | |
219 | - if (f1.isFile() == f2.isFile()) { | |
220 | - return f1.getName().compareToIgnoreCase(f2.getName()); | |
221 | - } else { | |
222 | - return f1.isFile() ? 1 : -1; | |
223 | - } | |
224 | - } | |
225 | - | |
226 | - }; | |
227 | - } | |
228 | - | |
229 | - private MenuHelper() {} // no instanciation, static only. | |
230 | - | |
231 | - public static Icon getIcon(File file) { | |
232 | - return fs.getSystemIcon(file); | |
233 | - } | |
234 | - | |
235 | - public static File[] getFilteredListFiles(File folder) { | |
236 | - return folder.listFiles(ff); | |
237 | - } | |
238 | - | |
239 | - public static ActionListener getActionListener() { | |
240 | - return al; | |
241 | - } | |
242 | - | |
243 | - public static MenuKeyListener getMenuKeyListener() { | |
244 | - return mkl; | |
245 | - } | |
246 | - | |
247 | - public static MouseListener getMouseListener() { | |
248 | - return mol; | |
249 | - } | |
250 | - | |
251 | - public static MenuListener getMenuListener() { | |
252 | - return mel; | |
253 | - } | |
254 | - | |
255 | - public static MenuListener getRootMenuListener() { | |
256 | - return melRoot; | |
257 | - } | |
258 | - | |
259 | - public static Comparator<File> getComparator() { | |
260 | - return comp; | |
261 | - } | |
262 | - | |
263 | - private static void open(JMenuItem item) { | |
264 | - if (! item.isEnabled()) { | |
265 | - return; | |
266 | - } | |
267 | - | |
268 | - String path = item.getActionCommand(); | |
269 | - try { | |
270 | - switch (getOsType()) { | |
271 | - case WIN64: | |
272 | - case WIN32: | |
273 | - File file = new File(path); | |
274 | - if (! FilePreview.open(file)) { | |
275 | - Desktop.getDesktop().open(file); | |
276 | - } | |
277 | - break; | |
278 | - case MAC64: | |
279 | - case MAC32: | |
280 | - new ProcessBuilder("open", path).start(); | |
281 | - break; | |
282 | - default: // Linux and others | |
283 | - new ProcessBuilder("xdg-open", path).start(); | |
284 | - break; | |
285 | - } | |
286 | - } catch (IOException ex) { | |
287 | - Log.log(ex); | |
288 | - Core.getMainWindow().showMessageDialog(StaticUtils.format( | |
289 | - L10n.get(L10n.Key.ERROR_FILE_HAS_NO_ASSOC), path)); | |
290 | - } | |
291 | - } | |
292 | - | |
293 | - public static void setMenuManager(MenuManager manager) { | |
294 | - menuManager = manager; | |
295 | - } | |
296 | - | |
297 | - private static final FileSystemView fs; | |
298 | - private static final FileFilter ff; | |
299 | - private static final ActionListener al; | |
300 | - private static final MenuKeyListener mkl; | |
301 | - private static final MouseListener mol; | |
302 | - private static final MenuListener mel; | |
303 | - private static final MenuListener melRoot; | |
304 | - private static final Comparator<File> comp; | |
305 | - private static MenuManager menuManager; | |
306 | - private static File prevSourceFile; | |
307 | - private static File prevTranslatedFile; | |
308 | - | |
309 | -} |
@@ -1,345 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
3 | - | |
4 | - Copyright (C) 2000-2006 Keith Godfrey and Maxym Mykhalchuk | |
5 | - 2005-2006 Henry Pijffers | |
6 | - 2006 Martin Wunderlich | |
7 | - 2006-2007 Didier Briel | |
8 | - 2008 Martin Fleurke, Didier Briel | |
9 | - 2009 Didier Briel, Arno Peters, Alex Buloichik | |
10 | - 2010 Alex Buloichik | |
11 | - 2011 Alex Buloichik, Didier Briel | |
12 | - 2012 Guido Leenders, Thomas Cordonnier | |
13 | - 2013 Alex Buloichik | |
14 | - 2014 Yu Tang | |
15 | - | |
16 | - Home page: http://sourceforge.jp/users/yu-tang/ | |
17 | - Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
18 | - | |
19 | - This file is part of plugin for OmegaT. | |
20 | - http://www.omegat.org/ | |
21 | - | |
22 | - License: GNU GPL version 3 or (at your option) any later version. | |
23 | - | |
24 | - You should have received a copy of the GNU General Public License | |
25 | - along with this program. If not, see <http://www.gnu.org/licenses/>. | |
26 | - **************************************************************************/ | |
27 | - | |
28 | -package jp.sourceforge.users.yutang.omegat.plugin.foldermenu; | |
29 | - | |
30 | -import gen.core.filters.Files; | |
31 | -import gen.core.filters.Filter; | |
32 | -import gen.core.filters.Filters; | |
33 | -import java.io.File; | |
34 | -import java.io.IOException; | |
35 | -import java.util.Map; | |
36 | -import java.util.regex.Pattern; | |
37 | -import org.omegat.core.Core; | |
38 | -import org.omegat.core.data.ProjectProperties; | |
39 | -import org.omegat.filters2.AbstractFilter; | |
40 | -import org.omegat.filters2.FilterContext; | |
41 | -import org.omegat.filters2.IFilter; | |
42 | -import org.omegat.filters2.TranslationException; | |
43 | -import org.omegat.filters2.master.FilterMaster; | |
44 | -import org.omegat.util.Language; | |
45 | - | |
46 | -// | |
47 | - | |
48 | -/** | |
49 | - * Based on org.omegat.filters2.master.FilterMaster#translateFile. | |
50 | - * | |
51 | - * A master class that registers and handles all the filters. Singleton - there can be only one instance of | |
52 | - * this class. | |
53 | - * | |
54 | - * @author Maxym Mykhalchuk | |
55 | - * @author Henry Pijffers | |
56 | - * @author Martin Wunderlich | |
57 | - * @author Didier Briel | |
58 | - * @author Martin Fleurke | |
59 | - * @author Arno Peters | |
60 | - * @author Alex Buloichik (alex73mail@gmail.com) | |
61 | - * @author Guido Leenders | |
62 | - * @author Thomas Cordonnier | |
63 | - * + | |
64 | - * @author Yu-Tang | |
65 | - */ | |
66 | -public class FilterHelper { | |
67 | - | |
68 | - /** | |
69 | - * Get translated file object corresponding to source file. | |
70 | - * It does not check whether a file exists. | |
71 | - * | |
72 | - * @param filename | |
73 | - * Relative source file path to the Source root directory. | |
74 | - * @return File object, can be null. | |
75 | - */ | |
76 | - public static File getTargetFile(String filename) { | |
77 | - try { | |
78 | - ProjectProperties props = Core.getProject().getProjectProperties(); | |
79 | - String sourcedir = props.getSourceRoot(); | |
80 | - String targetdir = props.getTargetRoot(); | |
81 | - FilterMaster fm = Core.getFilterMaster(); | |
82 | - FilterContext fc = new FilterContext(props); | |
83 | - | |
84 | - LookupInformation lookup = lookupFilter(sourcedir + File.separator + filename, fc, fm.getConfig()); | |
85 | - if (lookup == null) { | |
86 | - // The file is not supported by any of the filters. | |
87 | - return null; | |
88 | - } | |
89 | - | |
90 | - File inFile = new File(sourcedir + File.separator + filename); | |
91 | - | |
92 | - String name = inFile.getName(); | |
93 | - String path = filename.substring(0, filename.length() - name.length()); | |
94 | - | |
95 | - File outFile = new File(targetdir | |
96 | - + File.separator | |
97 | - + path | |
98 | - + File.separator | |
99 | - + constructTargetFilename(lookup.outFilesInfo.getSourceFilenameMask(), name, | |
100 | - lookup.outFilesInfo.getTargetFilenamePattern(), fc.getTargetLang(), | |
101 | - lookup.outFilesInfo.getSourceEncoding(), lookup.outFilesInfo.getTargetEncoding(), | |
102 | - lookup.filterObject.getFileFormatName())); | |
103 | - return outFile; | |
104 | - } catch (Exception ex) { | |
105 | - return null; | |
106 | - } | |
107 | - } | |
108 | - | |
109 | - static class LookupInformation { | |
110 | - public final Files outFilesInfo; | |
111 | - public final IFilter filterObject; | |
112 | - public final Map<String, String> config; | |
113 | - | |
114 | - public LookupInformation(IFilter filterObject, Files outFilesInfo, Map<String, String> config) { | |
115 | - this.filterObject = filterObject; | |
116 | - this.outFilesInfo = outFilesInfo; | |
117 | - this.config = config; | |
118 | - } | |
119 | - } | |
120 | - | |
121 | - /** | |
122 | - * Gets the filter according to the source filename provided. In case of failing to find a filter to | |
123 | - * handle the file returns <code>null</code>. | |
124 | - * | |
125 | - * In case of finding an appropriate filter it | |
126 | - * <ul> | |
127 | - * <li>Creates the filter (use <code>OneFilter.getFilter()</code> to get it) | |
128 | - * <li>Creates a reader (use <code>OneFilter.getReader()</code> to get it) | |
129 | - * <li>Checks whether the filter supports the file. | |
130 | - * </ul> | |
131 | - * It <b>does not</b> check whether the filter supports the inFile, i.e. it doesn't call | |
132 | - * <code>isFileSupported</code> | |
133 | - * | |
134 | - * | |
135 | - * @param filename | |
136 | - * The source filename. | |
137 | - * @return The filter to handle the inFile. | |
138 | - */ | |
139 | - private static LookupInformation lookupFilter(String filename, FilterContext fc, Filters filters) throws TranslationException, | |
140 | - IOException { | |
141 | - File inFile = new File(filename); | |
142 | - String name = inFile.getName(); | |
143 | - String path = inFile.getParent(); | |
144 | - if (path == null) | |
145 | - path = ""; | |
146 | - | |
147 | - for (Filter f : filters.getFilters()) { | |
148 | - if (!f.isEnabled()) { | |
149 | - continue; | |
150 | - } | |
151 | - for (Files ff : f.getFiles()) { | |
152 | - if (matchesMask(name, ff.getSourceFilenameMask())) { | |
153 | - IFilter filterObject; | |
154 | - filterObject = FilterMaster.getFilterInstance(f.getClassName()); | |
155 | - | |
156 | - if (filterObject != null) { | |
157 | - fc.setInEncoding(ff.getSourceEncoding()); | |
158 | - fc.setOutEncoding(ff.getTargetEncoding()); | |
159 | - // only for exist filters | |
160 | - Map<String, String> config = FilterMaster.forFilter(f.getOption()); | |
161 | - if (!filterObject.isFileSupported(inFile, config, fc)) { | |
162 | - break; | |
163 | - } | |
164 | - | |
165 | - return new LookupInformation(filterObject, ff, config); | |
166 | - } | |
167 | - } | |
168 | - } | |
169 | - } | |
170 | - return null; | |
171 | - } | |
172 | - | |
173 | - /** | |
174 | - * Construct a target filename according to pattern from a file's name. Filename should be "name.ext", | |
175 | - * without path. | |
176 | - * <p> | |
177 | - * Output filename pattern is pretty complex. <br> | |
178 | - * It may consist of normal characters and some substituted variables. They have the format | |
179 | - * <code>${variableName}</code> and are case insensitive. <br> | |
180 | - * There're such variables: | |
181 | - * <ul> | |
182 | - * <li><code>${filename}</code> - full filename of the input file, both name and extension (default) | |
183 | - * <li><code>${nameOnly}</code> - only the name of the input file without extension part | |
184 | - * <li><code>${extension}</code> - the extension of the input file | |
185 | - * <li><code>${nameOnly-1}</code> - only the name of the input file with first extension | |
186 | - * <li><code>${extension-1}</code> - the extensions, without the first one | |
187 | - * <li><code>${targetLocale}</code> - target locale code (of a form "xx_YY") | |
188 | - * <li><code>${targetLanguage}</code> - the target language and country code together (of a form "XX-YY") | |
189 | - * <li><code>${targetLanguageCode}</code> - the target language only ("XX") | |
190 | - * <li><code>${targetCountryCode}</code> - the target country only ("YY") | |
191 | - * <li><code>${1}, ${2}, ...</code> - variables captured by jokers (* or ?) | |
192 | - * </ul> | |
193 | - * <p> | |
194 | - * Most file filters will use default "<code>${filename}</code>, that leads to the name of translated file | |
195 | - * being the same as the name of source file. But for example the Java(TM) Resource Bundles file filter | |
196 | - * will have the pattern equal to "<code>${nameonly}_${targetlanguage}.${extension}</code> ". | |
197 | - * <p> | |
198 | - * E.g. if you have | |
199 | - * <ul> | |
200 | - * <li>a source filename mask "*.ext1.ext2" | |
201 | - * <li>file name "thisisfile.ext1.ext2" | |
202 | - * </ul> | |
203 | - * Then | |
204 | - * <ul> | |
205 | - * <li><code>${nameOnly}</code> will be equal to "thisisfile" | |
206 | - * <li>and <code>${extension}</code> - "ext1.ext2" | |
207 | - * <li><code>${nameOnly-1}</code> will be equal to "thisisfile.ext1" | |
208 | - * <li>and <code>${extension-1}</code> - "ext2" | |
209 | - * </ul> | |
210 | - * | |
211 | - * @param filename | |
212 | - * Filename to change | |
213 | - * @param pattern | |
214 | - * Pattern, according to which we change the filename | |
215 | - * @return The changed filename | |
216 | - */ | |
217 | - private static String constructTargetFilename(String sourceMask, String filename, String pattern, | |
218 | - Language targetLang, String sourceEncoding, String targetEncoding, String filterFormatName) { | |
219 | - int lastStarPos = sourceMask.lastIndexOf('*'); | |
220 | - int dot = 0; | |
221 | - if (lastStarPos >= 0) { | |
222 | - // bugfix #1204740 | |
223 | - // so where's the dot next to the star | |
224 | - int lastDotPos = sourceMask.indexOf('.', lastStarPos); | |
225 | - // counting chars after the dot | |
226 | - int extlength = sourceMask.length() - lastDotPos; | |
227 | - // going forward this many chars | |
228 | - // and finding the dot we looked for | |
229 | - dot = filename.length() - extlength; | |
230 | - } else { | |
231 | - dot = filename.lastIndexOf('.'); | |
232 | - } | |
233 | - | |
234 | - String nameOnly = filename; | |
235 | - String extension = ""; | |
236 | - if (dot >= 0) { | |
237 | - nameOnly = filename.substring(0, dot); | |
238 | - extension = filename.substring(dot + 1); | |
239 | - } | |
240 | - | |
241 | - String res = pattern; | |
242 | - res = res.replace(AbstractFilter.TFP_FILENAME, filename); | |
243 | - res = res.replace(AbstractFilter.TFP_NAMEONLY, nameOnly); | |
244 | - res = res.replace(AbstractFilter.TFP_EXTENSION, extension); | |
245 | - | |
246 | - res = res.replace(AbstractFilter.TFP_TARGET_LOCALE, targetLang.getLocaleCode()); | |
247 | - res = res.replace(AbstractFilter.TFP_TARGET_LANGUAGE, targetLang.getLanguage()); | |
248 | - res = res.replace(AbstractFilter.TFP_TARGET_LANG_CODE, targetLang.getLanguageCode()); | |
249 | - res = res.replace(AbstractFilter.TFP_TARGET_COUNTRY_CODE, targetLang.getCountryCode()); | |
250 | - // Replace also old variable spelling | |
251 | - res = res.replace(AbstractFilter.TFP_TARGET_COUTRY_CODE, targetLang.getCountryCode()); | |
252 | - res = res.replace(AbstractFilter.TFP_TARGET_LOCALE_LCID, targetLang.getLocaleLCID()); | |
253 | - // | |
254 | - // System generation time | |
255 | - // | |
256 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LA, FilterMaster.now("a")); | |
257 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LD, FilterMaster.now("d")); | |
258 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LDD, FilterMaster.now("dd")); | |
259 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LH, FilterMaster.now("h")); | |
260 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LHH, FilterMaster.now("hh")); | |
261 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LM, FilterMaster.now("m")); | |
262 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LMM, FilterMaster.now("mm")); | |
263 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LS, FilterMaster.now("s")); | |
264 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LSS, FilterMaster.now("ss")); | |
265 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_LYYYY, FilterMaster.now("yyyy")); | |
266 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UD, FilterMaster.now("D")); | |
267 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UEEE, FilterMaster.now("EEE")); | |
268 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UEEEE, FilterMaster.now("EEEE")); | |
269 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UH, FilterMaster.now("H")); | |
270 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UHH, FilterMaster.now("HH")); | |
271 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UM, FilterMaster.now("M")); | |
272 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UMM, FilterMaster.now("MM")); | |
273 | - res = res.replace(AbstractFilter.TFP_TIMESTAMP_UMMM, FilterMaster.now("MMM")); | |
274 | - // | |
275 | - // Workstation properties | |
276 | - // | |
277 | - res = res.replace(AbstractFilter.TFP_SYSTEM_OS_NAME, System.getProperty("os.name")); | |
278 | - res = res.replace(AbstractFilter.TFP_SYSTEM_OS_VERSION, System.getProperty("os.arch")); | |
279 | - res = res.replace(AbstractFilter.TFP_SYSTEM_OS_ARCH, System.getProperty("os.version")); | |
280 | - res = res.replace(AbstractFilter.TFP_SYSTEM_USER_NAME, System.getProperty("user.name")); | |
281 | - String hostName = null; | |
282 | - try { | |
283 | - hostName = java.net.InetAddress.getLocalHost().getHostName(); | |
284 | - } catch (java.net.UnknownHostException uhe) { | |
285 | - hostName = ""; | |
286 | - } | |
287 | - res = res.replace(AbstractFilter.TFP_SYSTEM_HOST_NAME, hostName); | |
288 | - // | |
289 | - // File properties. | |
290 | - // | |
291 | - String sourceEncodingText = "auto"; | |
292 | - if (sourceEncoding != null) { | |
293 | - sourceEncodingText = sourceEncoding; | |
294 | - } | |
295 | - res = res.replace(AbstractFilter.TFP_FILE_SOURCE_ENCODING, sourceEncodingText); | |
296 | - // | |
297 | - String targetEncodingText = "auto"; | |
298 | - if (targetEncoding != null) { | |
299 | - targetEncodingText = targetEncoding; | |
300 | - } | |
301 | - res = res.replace(AbstractFilter.TFP_FILE_TARGET_ENCODING, targetEncodingText); | |
302 | - // | |
303 | - res = res.replace(AbstractFilter.TFP_FILE_FILTER_NAME, filterFormatName); | |
304 | - // | |
305 | - | |
306 | - String sourceMaskPattern = sourceMask.replaceAll("\\?","(.)").replaceAll("\\*","(.*?)"); | |
307 | - java.util.regex.Matcher sourceMatcher = Pattern.compile(sourceMaskPattern).matcher(filename); | |
308 | - if (sourceMatcher.find()) { | |
309 | - for (int i = 1; i <= sourceMatcher.groupCount(); i++) { | |
310 | - res = res.replaceAll("\\$\\{" + i + "\\}", sourceMatcher.group(i)); | |
311 | - } | |
312 | - } | |
313 | - | |
314 | - String[] splitName = filename.split("\\."); | |
315 | - StringBuffer nameOnlyBuf = new StringBuffer (splitName[0]); | |
316 | - StringBuffer extensionBuf = new StringBuffer (splitName[splitName.length - 1]); | |
317 | - for (int i = 0; i < splitName.length; i++) { | |
318 | - res = res.replaceAll ("\\$\\{nameOnly-" + i + "\\}", nameOnlyBuf.toString()); | |
319 | - res = res.replaceAll ("\\$\\{extension-" + i + "\\}", extensionBuf.toString()); | |
320 | - if (i + 1 < splitName.length) { | |
321 | - nameOnlyBuf.append (".").append(splitName[i + 1]); | |
322 | - extensionBuf.insert(0, splitName[splitName.length - i - 2] + '.'); | |
323 | - } | |
324 | - } | |
325 | - | |
326 | - return res; | |
327 | - } | |
328 | - | |
329 | - /** | |
330 | - * Whether the mask matches the filename. Filename should be "name.ext", without path. | |
331 | - * | |
332 | - * @param filename | |
333 | - * The filename to check | |
334 | - * @param mask | |
335 | - * The mask, against which the filename is tested | |
336 | - * @return Whether the mask matches the filename. | |
337 | - */ | |
338 | - private static boolean matchesMask(String filename, String mask) { | |
339 | - mask = mask.replaceAll("\\.", "\\\\."); | |
340 | - mask = mask.replaceAll("\\*", ".*"); | |
341 | - mask = mask.replaceAll("\\?", "."); | |
342 | - return filename.matches("(?iu)" + mask); | |
343 | - } | |
344 | - | |
345 | -} |
@@ -1,66 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu; | |
18 | - | |
19 | -import java.io.File; | |
20 | -import java.io.IOException; | |
21 | -import javax.swing.JMenuItem; | |
22 | - | |
23 | -/** | |
24 | - * | |
25 | - * @author Yu Tang | |
26 | - */ | |
27 | -public class ShellLinkMenuItem extends JMenuItem { | |
28 | - | |
29 | - public ShellLinkMenuItem() { | |
30 | - super(); | |
31 | - } | |
32 | - | |
33 | - public ShellLinkMenuItem(File file) throws IOException { | |
34 | - super(file.getName(), MenuHelper.getIcon(file)); | |
35 | - setActionCommand(file.getCanonicalPath()); | |
36 | - addActionListener(MenuHelper.getActionListener()); | |
37 | - } | |
38 | - | |
39 | - public ShellLinkMenuItem(String label) { | |
40 | - super(label); | |
41 | - setEnabled(false); | |
42 | - } | |
43 | - | |
44 | - public JMenuItem getMenuItem() { | |
45 | - return (JMenuItem) this; | |
46 | - } | |
47 | - | |
48 | - public void link(File file, String toolTipText) throws IOException { | |
49 | - setToolTipText(toolTipText); | |
50 | - setActionCommand(file.getCanonicalPath()); | |
51 | - setIcon(MenuHelper.getIcon(file)); | |
52 | - setEnabled(true); | |
53 | - | |
54 | - if (getActionListeners().length == 0) { | |
55 | - addActionListener(MenuHelper.getActionListener()); | |
56 | - } | |
57 | - } | |
58 | - | |
59 | - public void unlink() { | |
60 | - setToolTipText(null); | |
61 | - setEnabled(false); | |
62 | - setActionCommand(""); | |
63 | - setIcon(null); | |
64 | - } | |
65 | - | |
66 | -} |
@@ -1,54 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu; | |
18 | - | |
19 | -import java.util.ResourceBundle; | |
20 | - | |
21 | -/** | |
22 | - * Manage localization. | |
23 | - * | |
24 | - * @author Yu Tang | |
25 | - */ | |
26 | -public class L10n { | |
27 | - | |
28 | - public enum Key { | |
29 | - // for menu | |
30 | - FOLDERS_MENU_LABEL, | |
31 | - PROJECT_ROOT_MENU_LABEL, | |
32 | - ROOT_MENU_LABEL, | |
33 | - USER_CONFIG_MENU_LABEL, | |
34 | - SOURCE_DOC_MENU_LABEL, | |
35 | - TARGET_DOC_MENU_LABEL, | |
36 | - | |
37 | - // for Word | |
38 | - WORD_WINDOW_CAPTION, | |
39 | - | |
40 | - // for error | |
41 | - ERROR_FILE_HAS_NO_ASSOC | |
42 | - } | |
43 | - | |
44 | - private static final ResourceBundle bundle; | |
45 | - | |
46 | - static { | |
47 | - bundle = ResourceBundle.getBundle(L10n.class.getPackage().getName() + ".Bundle"); | |
48 | - } | |
49 | - | |
50 | - public static String get(Key key) { | |
51 | - return bundle.getString(key.name()); | |
52 | - } | |
53 | - | |
54 | -} |
@@ -1,104 +0,0 @@ | ||
1 | -/************************************************************************** | |
2 | - FolderMenu - easy access to project folders from menu. | |
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/ | |
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.foldermenu; | |
18 | - | |
19 | -import java.io.File; | |
20 | -import java.io.IOException; | |
21 | -import java.util.Arrays; | |
22 | -import javax.swing.JMenu; | |
23 | -import static jp.sourceforge.users.yutang.omegat.plugin.foldermenu.MenuHelper.getComparator; | |
24 | -import static jp.sourceforge.users.yutang.omegat.plugin.foldermenu.MenuHelper.getFilteredListFiles; | |
25 | -import static jp.sourceforge.users.yutang.omegat.plugin.foldermenu.MenuHelper.getMenuListener; | |
26 | -import static jp.sourceforge.users.yutang.omegat.plugin.foldermenu.MenuHelper.getMouseListener; | |
27 | -import org.omegat.util.Log; | |
28 | -import org.openide.awt.Mnemonics; | |
29 | - | |
30 | -/** | |
31 | - * | |
32 | - * @author Yu Tang | |
33 | - */ | |
34 | -public class ShellLinkMenu extends JMenu { | |
35 | - | |
36 | - @SuppressWarnings("LeakingThisInConstructor") | |
37 | - public ShellLinkMenu(File folder, String label) throws IOException { | |
38 | - this(folder); | |
39 | - Mnemonics.setLocalizedText(this, label); | |
40 | - } | |
41 | - | |
42 | - public ShellLinkMenu(File folder) throws IOException { | |
43 | - super(folder.getName()); | |
44 | - | |
45 | - addMenuListener(getMenuListener()); | |
46 | - addMouseListener(getMouseListener()); | |
47 | - | |
48 | - setIcon(MenuHelper.getIcon(folder)); | |
49 | - setActionCommand(folder.getCanonicalPath()); | |
50 | - } | |
51 | - | |
52 | - @SuppressWarnings("LeakingThisInConstructor") | |
53 | - public ShellLinkMenu(String label) throws IOException { | |
54 | - super(); | |
55 | - Mnemonics.setLocalizedText(this, label); | |
56 | - | |
57 | - addMenuListener(getMenuListener()); | |
58 | - addMouseListener(getMouseListener()); | |
59 | - | |
60 | - setEnabled(false); | |
61 | - } | |
62 | - | |
63 | - public void createChildren() { | |
64 | - if (isEnabled() && getItemCount() == 0) { | |
65 | - File folder = new File(getActionCommand()); | |
66 | - File[] filteredListFiles = getFilteredListFiles(folder); | |
67 | - Arrays.sort(filteredListFiles, getComparator()); | |
68 | - | |
69 | - for (File file : filteredListFiles) { | |
70 | - try { | |
71 | - if (file.isDirectory() && hasChildren(file)) { | |
72 | - add(new ShellLinkMenu(file)); | |
73 | - } else { | |
74 | - add(new ShellLinkMenuItem(file)); | |
75 | - } | |
76 | - } catch (IOException ex) { | |
77 | - Log.log(ex); | |
78 | - } | |
79 | - } | |
80 | - } | |
81 | - } | |
82 | - | |
83 | - public JMenu getMenu() { | |
84 | - return (JMenu) this; | |
85 | - } | |
86 | - | |
87 | - public void link(File folder) throws IOException { | |
88 | - setActionCommand(folder.getCanonicalPath()); | |
89 | - setIcon(MenuHelper.getIcon(folder)); | |
90 | - setEnabled(true); | |
91 | - } | |
92 | - | |
93 | - public void unlink() { | |
94 | - setEnabled(false); | |
95 | - removeAll(); | |
96 | - setActionCommand(""); | |
97 | - setIcon(null); | |
98 | - } | |
99 | - | |
100 | - private boolean hasChildren(File folder) { | |
101 | - return getFilteredListFiles(folder).length > 0; | |
102 | - } | |
103 | - | |
104 | -} |
@@ -0,0 +1,345 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2000-2006 Keith Godfrey and Maxym Mykhalchuk | |
5 | + 2005-2006 Henry Pijffers | |
6 | + 2006 Martin Wunderlich | |
7 | + 2006-2007 Didier Briel | |
8 | + 2008 Martin Fleurke, Didier Briel | |
9 | + 2009 Didier Briel, Arno Peters, Alex Buloichik | |
10 | + 2010 Alex Buloichik | |
11 | + 2011 Alex Buloichik, Didier Briel | |
12 | + 2012 Guido Leenders, Thomas Cordonnier | |
13 | + 2013 Alex Buloichik | |
14 | + 2014 Yu Tang | |
15 | + | |
16 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
17 | + Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
18 | + | |
19 | + This file is part of plugin for OmegaT. | |
20 | + http://www.omegat.org/ | |
21 | + | |
22 | + License: GNU GPL version 3 or (at your option) any later version. | |
23 | + | |
24 | + You should have received a copy of the GNU General Public License | |
25 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
26 | + **************************************************************************/ | |
27 | + | |
28 | +package jp.osdn.users.yutang.omegat.plugin.foldermenu; | |
29 | + | |
30 | +import gen.core.filters.Files; | |
31 | +import gen.core.filters.Filter; | |
32 | +import gen.core.filters.Filters; | |
33 | +import java.io.File; | |
34 | +import java.io.IOException; | |
35 | +import java.util.Map; | |
36 | +import java.util.regex.Pattern; | |
37 | +import org.omegat.core.Core; | |
38 | +import org.omegat.core.data.ProjectProperties; | |
39 | +import org.omegat.filters2.AbstractFilter; | |
40 | +import org.omegat.filters2.FilterContext; | |
41 | +import org.omegat.filters2.IFilter; | |
42 | +import org.omegat.filters2.TranslationException; | |
43 | +import org.omegat.filters2.master.FilterMaster; | |
44 | +import org.omegat.util.Language; | |
45 | + | |
46 | +// | |
47 | + | |
48 | +/** | |
49 | + * Based on org.omegat.filters2.master.FilterMaster#translateFile. | |
50 | + * | |
51 | + * A master class that registers and handles all the filters. Singleton - there can be only one instance of | |
52 | + * this class. | |
53 | + * | |
54 | + * @author Maxym Mykhalchuk | |
55 | + * @author Henry Pijffers | |
56 | + * @author Martin Wunderlich | |
57 | + * @author Didier Briel | |
58 | + * @author Martin Fleurke | |
59 | + * @author Arno Peters | |
60 | + * @author Alex Buloichik (alex73mail@gmail.com) | |
61 | + * @author Guido Leenders | |
62 | + * @author Thomas Cordonnier | |
63 | + * + | |
64 | + * @author Yu-Tang | |
65 | + */ | |
66 | +public class FilterHelper { | |
67 | + | |
68 | + /** | |
69 | + * Get translated file object corresponding to source file. | |
70 | + * It does not check whether a file exists. | |
71 | + * | |
72 | + * @param filename | |
73 | + * Relative source file path to the Source root directory. | |
74 | + * @return File object, can be null. | |
75 | + */ | |
76 | + public static File getTargetFile(String filename) { | |
77 | + try { | |
78 | + ProjectProperties props = Core.getProject().getProjectProperties(); | |
79 | + String sourcedir = props.getSourceRoot(); | |
80 | + String targetdir = props.getTargetRoot(); | |
81 | + FilterMaster fm = Core.getFilterMaster(); | |
82 | + FilterContext fc = new FilterContext(props); | |
83 | + | |
84 | + LookupInformation lookup = lookupFilter(sourcedir + File.separator + filename, fc, fm.getConfig()); | |
85 | + if (lookup == null) { | |
86 | + // The file is not supported by any of the filters. | |
87 | + return null; | |
88 | + } | |
89 | + | |
90 | + File inFile = new File(sourcedir + File.separator + filename); | |
91 | + | |
92 | + String name = inFile.getName(); | |
93 | + String path = filename.substring(0, filename.length() - name.length()); | |
94 | + | |
95 | + File outFile = new File(targetdir | |
96 | + + File.separator | |
97 | + + path | |
98 | + + File.separator | |
99 | + + constructTargetFilename(lookup.outFilesInfo.getSourceFilenameMask(), name, | |
100 | + lookup.outFilesInfo.getTargetFilenamePattern(), fc.getTargetLang(), | |
101 | + lookup.outFilesInfo.getSourceEncoding(), lookup.outFilesInfo.getTargetEncoding(), | |
102 | + lookup.filterObject.getFileFormatName())); | |
103 | + return outFile; | |
104 | + } catch (Exception ex) { | |
105 | + return null; | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + static class LookupInformation { | |
110 | + public final Files outFilesInfo; | |
111 | + public final IFilter filterObject; | |
112 | + public final Map<String, String> config; | |
113 | + | |
114 | + public LookupInformation(IFilter filterObject, Files outFilesInfo, Map<String, String> config) { | |
115 | + this.filterObject = filterObject; | |
116 | + this.outFilesInfo = outFilesInfo; | |
117 | + this.config = config; | |
118 | + } | |
119 | + } | |
120 | + | |
121 | + /** | |
122 | + * Gets the filter according to the source filename provided. In case of failing to find a filter to | |
123 | + * handle the file returns <code>null</code>. | |
124 | + * | |
125 | + * In case of finding an appropriate filter it | |
126 | + * <ul> | |
127 | + * <li>Creates the filter (use <code>OneFilter.getFilter()</code> to get it) | |
128 | + * <li>Creates a reader (use <code>OneFilter.getReader()</code> to get it) | |
129 | + * <li>Checks whether the filter supports the file. | |
130 | + * </ul> | |
131 | + * It <b>does not</b> check whether the filter supports the inFile, i.e. it doesn't call | |
132 | + * <code>isFileSupported</code> | |
133 | + * | |
134 | + * | |
135 | + * @param filename | |
136 | + * The source filename. | |
137 | + * @return The filter to handle the inFile. | |
138 | + */ | |
139 | + private static LookupInformation lookupFilter(String filename, FilterContext fc, Filters filters) throws TranslationException, | |
140 | + IOException { | |
141 | + File inFile = new File(filename); | |
142 | + String name = inFile.getName(); | |
143 | + String path = inFile.getParent(); | |
144 | + if (path == null) | |
145 | + path = ""; | |
146 | + | |
147 | + for (Filter f : filters.getFilters()) { | |
148 | + if (!f.isEnabled()) { | |
149 | + continue; | |
150 | + } | |
151 | + for (Files ff : f.getFiles()) { | |
152 | + if (matchesMask(name, ff.getSourceFilenameMask())) { | |
153 | + IFilter filterObject; | |
154 | + filterObject = FilterMaster.getFilterInstance(f.getClassName()); | |
155 | + | |
156 | + if (filterObject != null) { | |
157 | + fc.setInEncoding(ff.getSourceEncoding()); | |
158 | + fc.setOutEncoding(ff.getTargetEncoding()); | |
159 | + // only for exist filters | |
160 | + Map<String, String> config = FilterMaster.forFilter(f.getOption()); | |
161 | + if (!filterObject.isFileSupported(inFile, config, fc)) { | |
162 | + break; | |
163 | + } | |
164 | + | |
165 | + return new LookupInformation(filterObject, ff, config); | |
166 | + } | |
167 | + } | |
168 | + } | |
169 | + } | |
170 | + return null; | |
171 | + } | |
172 | + | |
173 | + /** | |
174 | + * Construct a target filename according to pattern from a file's name. Filename should be "name.ext", | |
175 | + * without path. | |
176 | + * <p> | |
177 | + * Output filename pattern is pretty complex. <br> | |
178 | + * It may consist of normal characters and some substituted variables. They have the format | |
179 | + * <code>${variableName}</code> and are case insensitive. <br> | |
180 | + * There're such variables: | |
181 | + * <ul> | |
182 | + * <li><code>${filename}</code> - full filename of the input file, both name and extension (default) | |
183 | + * <li><code>${nameOnly}</code> - only the name of the input file without extension part | |
184 | + * <li><code>${extension}</code> - the extension of the input file | |
185 | + * <li><code>${nameOnly-1}</code> - only the name of the input file with first extension | |
186 | + * <li><code>${extension-1}</code> - the extensions, without the first one | |
187 | + * <li><code>${targetLocale}</code> - target locale code (of a form "xx_YY") | |
188 | + * <li><code>${targetLanguage}</code> - the target language and country code together (of a form "XX-YY") | |
189 | + * <li><code>${targetLanguageCode}</code> - the target language only ("XX") | |
190 | + * <li><code>${targetCountryCode}</code> - the target country only ("YY") | |
191 | + * <li><code>${1}, ${2}, ...</code> - variables captured by jokers (* or ?) | |
192 | + * </ul> | |
193 | + * <p> | |
194 | + * Most file filters will use default "<code>${filename}</code>, that leads to the name of translated file | |
195 | + * being the same as the name of source file. But for example the Java(TM) Resource Bundles file filter | |
196 | + * will have the pattern equal to "<code>${nameonly}_${targetlanguage}.${extension}</code> ". | |
197 | + * <p> | |
198 | + * E.g. if you have | |
199 | + * <ul> | |
200 | + * <li>a source filename mask "*.ext1.ext2" | |
201 | + * <li>file name "thisisfile.ext1.ext2" | |
202 | + * </ul> | |
203 | + * Then | |
204 | + * <ul> | |
205 | + * <li><code>${nameOnly}</code> will be equal to "thisisfile" | |
206 | + * <li>and <code>${extension}</code> - "ext1.ext2" | |
207 | + * <li><code>${nameOnly-1}</code> will be equal to "thisisfile.ext1" | |
208 | + * <li>and <code>${extension-1}</code> - "ext2" | |
209 | + * </ul> | |
210 | + * | |
211 | + * @param filename | |
212 | + * Filename to change | |
213 | + * @param pattern | |
214 | + * Pattern, according to which we change the filename | |
215 | + * @return The changed filename | |
216 | + */ | |
217 | + private static String constructTargetFilename(String sourceMask, String filename, String pattern, | |
218 | + Language targetLang, String sourceEncoding, String targetEncoding, String filterFormatName) { | |
219 | + int lastStarPos = sourceMask.lastIndexOf('*'); | |
220 | + int dot = 0; | |
221 | + if (lastStarPos >= 0) { | |
222 | + // bugfix #1204740 | |
223 | + // so where's the dot next to the star | |
224 | + int lastDotPos = sourceMask.indexOf('.', lastStarPos); | |
225 | + // counting chars after the dot | |
226 | + int extlength = sourceMask.length() - lastDotPos; | |
227 | + // going forward this many chars | |
228 | + // and finding the dot we looked for | |
229 | + dot = filename.length() - extlength; | |
230 | + } else { | |
231 | + dot = filename.lastIndexOf('.'); | |
232 | + } | |
233 | + | |
234 | + String nameOnly = filename; | |
235 | + String extension = ""; | |
236 | + if (dot >= 0) { | |
237 | + nameOnly = filename.substring(0, dot); | |
238 | + extension = filename.substring(dot + 1); | |
239 | + } | |
240 | + | |
241 | + String res = pattern; | |
242 | + res = res.replace(AbstractFilter.TFP_FILENAME, filename); | |
243 | + res = res.replace(AbstractFilter.TFP_NAMEONLY, nameOnly); | |
244 | + res = res.replace(AbstractFilter.TFP_EXTENSION, extension); | |
245 | + | |
246 | + res = res.replace(AbstractFilter.TFP_TARGET_LOCALE, targetLang.getLocaleCode()); | |
247 | + res = res.replace(AbstractFilter.TFP_TARGET_LANGUAGE, targetLang.getLanguage()); | |
248 | + res = res.replace(AbstractFilter.TFP_TARGET_LANG_CODE, targetLang.getLanguageCode()); | |
249 | + res = res.replace(AbstractFilter.TFP_TARGET_COUNTRY_CODE, targetLang.getCountryCode()); | |
250 | + // Replace also old variable spelling | |
251 | + res = res.replace(AbstractFilter.TFP_TARGET_COUTRY_CODE, targetLang.getCountryCode()); | |
252 | + res = res.replace(AbstractFilter.TFP_TARGET_LOCALE_LCID, targetLang.getLocaleLCID()); | |
253 | + // | |
254 | + // System generation time | |
255 | + // | |
256 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LA, FilterMaster.now("a")); | |
257 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LD, FilterMaster.now("d")); | |
258 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LDD, FilterMaster.now("dd")); | |
259 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LH, FilterMaster.now("h")); | |
260 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LHH, FilterMaster.now("hh")); | |
261 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LM, FilterMaster.now("m")); | |
262 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LMM, FilterMaster.now("mm")); | |
263 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LS, FilterMaster.now("s")); | |
264 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LSS, FilterMaster.now("ss")); | |
265 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_LYYYY, FilterMaster.now("yyyy")); | |
266 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UD, FilterMaster.now("D")); | |
267 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UEEE, FilterMaster.now("EEE")); | |
268 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UEEEE, FilterMaster.now("EEEE")); | |
269 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UH, FilterMaster.now("H")); | |
270 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UHH, FilterMaster.now("HH")); | |
271 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UM, FilterMaster.now("M")); | |
272 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UMM, FilterMaster.now("MM")); | |
273 | + res = res.replace(AbstractFilter.TFP_TIMESTAMP_UMMM, FilterMaster.now("MMM")); | |
274 | + // | |
275 | + // Workstation properties | |
276 | + // | |
277 | + res = res.replace(AbstractFilter.TFP_SYSTEM_OS_NAME, System.getProperty("os.name")); | |
278 | + res = res.replace(AbstractFilter.TFP_SYSTEM_OS_VERSION, System.getProperty("os.arch")); | |
279 | + res = res.replace(AbstractFilter.TFP_SYSTEM_OS_ARCH, System.getProperty("os.version")); | |
280 | + res = res.replace(AbstractFilter.TFP_SYSTEM_USER_NAME, System.getProperty("user.name")); | |
281 | + String hostName = null; | |
282 | + try { | |
283 | + hostName = java.net.InetAddress.getLocalHost().getHostName(); | |
284 | + } catch (java.net.UnknownHostException uhe) { | |
285 | + hostName = ""; | |
286 | + } | |
287 | + res = res.replace(AbstractFilter.TFP_SYSTEM_HOST_NAME, hostName); | |
288 | + // | |
289 | + // File properties. | |
290 | + // | |
291 | + String sourceEncodingText = "auto"; | |
292 | + if (sourceEncoding != null) { | |
293 | + sourceEncodingText = sourceEncoding; | |
294 | + } | |
295 | + res = res.replace(AbstractFilter.TFP_FILE_SOURCE_ENCODING, sourceEncodingText); | |
296 | + // | |
297 | + String targetEncodingText = "auto"; | |
298 | + if (targetEncoding != null) { | |
299 | + targetEncodingText = targetEncoding; | |
300 | + } | |
301 | + res = res.replace(AbstractFilter.TFP_FILE_TARGET_ENCODING, targetEncodingText); | |
302 | + // | |
303 | + res = res.replace(AbstractFilter.TFP_FILE_FILTER_NAME, filterFormatName); | |
304 | + // | |
305 | + | |
306 | + String sourceMaskPattern = sourceMask.replaceAll("\\?","(.)").replaceAll("\\*","(.*?)"); | |
307 | + java.util.regex.Matcher sourceMatcher = Pattern.compile(sourceMaskPattern).matcher(filename); | |
308 | + if (sourceMatcher.find()) { | |
309 | + for (int i = 1; i <= sourceMatcher.groupCount(); i++) { | |
310 | + res = res.replaceAll("\\$\\{" + i + "\\}", sourceMatcher.group(i)); | |
311 | + } | |
312 | + } | |
313 | + | |
314 | + String[] splitName = filename.split("\\."); | |
315 | + StringBuffer nameOnlyBuf = new StringBuffer (splitName[0]); | |
316 | + StringBuffer extensionBuf = new StringBuffer (splitName[splitName.length - 1]); | |
317 | + for (int i = 0; i < splitName.length; i++) { | |
318 | + res = res.replaceAll ("\\$\\{nameOnly-" + i + "\\}", nameOnlyBuf.toString()); | |
319 | + res = res.replaceAll ("\\$\\{extension-" + i + "\\}", extensionBuf.toString()); | |
320 | + if (i + 1 < splitName.length) { | |
321 | + nameOnlyBuf.append (".").append(splitName[i + 1]); | |
322 | + extensionBuf.insert(0, splitName[splitName.length - i - 2] + '.'); | |
323 | + } | |
324 | + } | |
325 | + | |
326 | + return res; | |
327 | + } | |
328 | + | |
329 | + /** | |
330 | + * Whether the mask matches the filename. Filename should be "name.ext", without path. | |
331 | + * | |
332 | + * @param filename | |
333 | + * The filename to check | |
334 | + * @param mask | |
335 | + * The mask, against which the filename is tested | |
336 | + * @return Whether the mask matches the filename. | |
337 | + */ | |
338 | + private static boolean matchesMask(String filename, String mask) { | |
339 | + mask = mask.replaceAll("\\.", "\\\\."); | |
340 | + mask = mask.replaceAll("\\*", ".*"); | |
341 | + mask = mask.replaceAll("\\?", "."); | |
342 | + return filename.matches("(?iu)" + mask); | |
343 | + } | |
344 | + | |
345 | +} |
@@ -0,0 +1,128 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2015 Yu Tang | |
5 | + Home page: http://osdn.jp/users/yu-tang/ | |
6 | + | |
7 | + This file is part of plugin for OmegaT. | |
8 | + http://www.omegat.org/ | |
9 | + | |
10 | + License: GNU GPL version 3 or (at your option) any later version. | |
11 | + | |
12 | + You should have received a copy of the GNU General Public License | |
13 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | + **************************************************************************/ | |
15 | + | |
16 | +package jp.osdn.users.yutang.omegat.plugin.foldermenu; | |
17 | + | |
18 | +import java.io.File; | |
19 | +import javax.swing.JMenu; | |
20 | +import javax.swing.JMenuItem; | |
21 | +import javax.swing.JSeparator; | |
22 | +import javax.swing.event.MenuEvent; | |
23 | +import javax.swing.event.MenuListener; | |
24 | +import jp.osdn.users.yutang.omegat.plugin.foldermenu.filepreview.FilePreview; | |
25 | +import org.omegat.core.Core; | |
26 | +import org.omegat.core.data.IProject; | |
27 | +import org.omegat.util.Log; | |
28 | +import org.omegat.util.StaticUtils; | |
29 | +import org.omegat.util.StringUtil; | |
30 | + | |
31 | +/** | |
32 | + * direct access to the relevant folders/files via menu | |
33 | + * | |
34 | + * @author Yu Tang | |
35 | + */ | |
36 | +public class FolderMenuListener implements MenuListener { | |
37 | + | |
38 | + public FolderMenuListener() { | |
39 | + FilePreview.init(); //@@TODO remove this | |
40 | + } | |
41 | + | |
42 | + @Override | |
43 | + public void menuSelected(MenuEvent e) { | |
44 | + JMenu menu = (JMenu) e.getSource(); | |
45 | + String action = menu.getActionCommand(); | |
46 | + Log.logInfoRB("LOG_MENU_CLICK", action); | |
47 | + | |
48 | + buildSubmenus(menu); | |
49 | + } | |
50 | + | |
51 | + @Override | |
52 | + public void menuDeselected(MenuEvent e) { | |
53 | + destruct((JMenu) e.getSource()); | |
54 | + } | |
55 | + | |
56 | + @Override | |
57 | + public void menuCanceled(MenuEvent e) { | |
58 | + destruct((JMenu) e.getSource()); | |
59 | + } | |
60 | + | |
61 | + private void destruct(JMenu menu) { | |
62 | + menu.removeAll(); | |
63 | + } | |
64 | + | |
65 | + private void buildSubmenus(JMenu parent) { | |
66 | + parent.add(createProjectRootMenu()); | |
67 | + parent.add(createUserConfigMenu()); | |
68 | + parent.add(createApplicationRootMenu()); | |
69 | + parent.add(new JSeparator()); | |
70 | + parent.add(createCurrentSourceDocumentMenuItem()); | |
71 | + parent.add(createCurrentTargetDocumentMenuItem()); | |
72 | + } | |
73 | + | |
74 | + private JMenuItem createProjectRootMenu() { | |
75 | + final String LABEL_TEXT = L10n.Entry.PROJECT_ROOT_MENU_LABEL.toString(); | |
76 | + IProject project = Core.getProject(); | |
77 | + String path = ""; | |
78 | + | |
79 | + if (project.isProjectLoaded()) { | |
80 | + path = project.getProjectProperties().getProjectRoot(); | |
81 | + } | |
82 | + return MenuFactory.createMenuItem(path, LABEL_TEXT); | |
83 | + } | |
84 | + | |
85 | + private JMenuItem createUserConfigMenu() { | |
86 | + final String LABEL_TEXT =L10n.Entry.USER_CONFIG_MENU_LABEL.toString(); | |
87 | + String path = StaticUtils.getConfigDir(); | |
88 | + return MenuFactory.createMenuItem(path, LABEL_TEXT); | |
89 | + } | |
90 | + | |
91 | + private JMenuItem createApplicationRootMenu() { | |
92 | + final String LABEL_TEXT = L10n.Entry.APPLICATION_ROOT_MENU_LABEL.toString(); | |
93 | + String path = StaticUtils.installDir(); | |
94 | + return MenuFactory.createMenuItem(path, LABEL_TEXT); | |
95 | + } | |
96 | + | |
97 | + private JMenuItem createCurrentSourceDocumentMenuItem() { | |
98 | + IProject project = Core.getProject(); | |
99 | + String currentFile = ""; | |
100 | + final String LABEL_TEXT = L10n.Entry.SOURCE_DOC_MENU_LABEL.toString(); | |
101 | + | |
102 | + if (project.isProjectLoaded()) { | |
103 | + // relative path to the root of Source directory | |
104 | + currentFile = Core.getEditor().getCurrentFile(); | |
105 | + if (!StringUtil.isEmpty(currentFile)) { | |
106 | + String sourceRoot = project.getProjectProperties().getSourceRoot(); | |
107 | + currentFile = sourceRoot + currentFile; | |
108 | + } | |
109 | + } | |
110 | + return MenuFactory.createMenuItem(currentFile, LABEL_TEXT); | |
111 | + } | |
112 | + | |
113 | + private JMenuItem createCurrentTargetDocumentMenuItem() { | |
114 | + IProject project = Core.getProject(); | |
115 | + final String LABEL_TEXT = L10n.Entry.TARGET_DOC_MENU_LABEL.toString(); | |
116 | + File translatedFile = new File(""); | |
117 | + | |
118 | + if (project.isProjectLoaded()) { | |
119 | + // relative path to the root of Source directory | |
120 | + String currentFile = Core.getEditor().getCurrentFile(); | |
121 | + if (currentFile != null) { | |
122 | + translatedFile = FilterHelper.getTargetFile(currentFile); | |
123 | + } | |
124 | + } | |
125 | + | |
126 | + return MenuFactory.createMenuItem(translatedFile, LABEL_TEXT); | |
127 | + } | |
128 | +} |
@@ -0,0 +1,230 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2015 Yu Tang | |
5 | + Home page: http://osdn.jp/users/yu-tang/ | |
6 | + | |
7 | + This file is part of plugin for OmegaT. | |
8 | + http://www.omegat.org/ | |
9 | + | |
10 | + License: GNU GPL version 3 or (at your option) any later version. | |
11 | + | |
12 | + You should have received a copy of the GNU General Public License | |
13 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | + **************************************************************************/ | |
15 | + | |
16 | +package jp.osdn.users.yutang.omegat.plugin.foldermenu; | |
17 | + | |
18 | +import java.awt.Desktop; | |
19 | +import java.awt.Insets; | |
20 | +import java.awt.Toolkit; | |
21 | +import java.awt.event.ActionEvent; | |
22 | +import java.awt.event.ActionListener; | |
23 | +import java.awt.event.KeyEvent; | |
24 | +import java.awt.event.MouseAdapter; | |
25 | +import java.awt.event.MouseEvent; | |
26 | +import java.awt.event.MouseListener; | |
27 | +import java.io.File; | |
28 | +import java.io.FileFilter; | |
29 | +import java.io.IOException; | |
30 | +import java.util.Arrays; | |
31 | +import java.util.Comparator; | |
32 | +import javax.swing.JMenu; | |
33 | +import javax.swing.JMenuItem; | |
34 | +import javax.swing.MenuElement; | |
35 | +import javax.swing.MenuSelectionManager; | |
36 | +import javax.swing.SwingConstants; | |
37 | +import javax.swing.event.MenuEvent; | |
38 | +import javax.swing.event.MenuKeyEvent; | |
39 | +import javax.swing.event.MenuKeyListener; | |
40 | +import javax.swing.event.MenuListener; | |
41 | +import jp.osdn.users.yutang.omegat.plugin.foldermenu.filepreview.FilePreview; | |
42 | +import org.omegat.core.Core; | |
43 | +import org.omegat.util.Log; | |
44 | +import org.omegat.util.OStrings; | |
45 | +import org.omegat.util.StaticUtils; | |
46 | +import org.openide.awt.Mnemonics; | |
47 | + | |
48 | +/** | |
49 | + * | |
50 | + * @author Yu Tang | |
51 | + */ | |
52 | +public class Listeners { | |
53 | + | |
54 | + private static final FileFilter fileFilter = new FileFilter() { | |
55 | + @Override | |
56 | + public boolean accept(File file) { | |
57 | + // except dot started named files (i.e. ".svn") and hidden files | |
58 | + return !file.getName().startsWith(".") && !file.isHidden(); | |
59 | + } | |
60 | + }; | |
61 | + | |
62 | + private static final Comparator<File> comparator = new Comparator<File>() { | |
63 | + @Override | |
64 | + public int compare(File f1, File f2) { | |
65 | + if (f1.isFile() == f2.isFile()) { | |
66 | + return f1.getName().compareToIgnoreCase(f2.getName()); | |
67 | + } else { | |
68 | + return f1.isFile() ? 1 : -1; | |
69 | + } | |
70 | + } | |
71 | + }; | |
72 | + | |
73 | + private static final ActionListener actionListener = new ActionListener() { | |
74 | + @Override | |
75 | + public void actionPerformed(ActionEvent e) { | |
76 | + open((JMenuItem) e.getSource()); | |
77 | + } | |
78 | + }; | |
79 | + | |
80 | + /** Use for folder only */ | |
81 | + private static final MenuKeyListener menuKeyListener = new MenuKeyListener() { | |
82 | + @Override | |
83 | + public void menuKeyTyped(MenuKeyEvent e) { /* do nothing */ } | |
84 | + | |
85 | + @Override | |
86 | + public void menuKeyPressed(MenuKeyEvent e) { | |
87 | + if (e.getKeyCode() == KeyEvent.VK_ENTER) { | |
88 | + MenuSelectionManager manager = e.getMenuSelectionManager(); | |
89 | + MenuElement[] selectedPath = manager.getSelectedPath(); | |
90 | + MenuElement selection = selectedPath[selectedPath.length-1]; | |
91 | + if (selection instanceof RunnableMenu) { | |
92 | + // ignore | |
93 | + } else if (selection instanceof JMenu) { | |
94 | + JMenu menu = (JMenu) selection; | |
95 | + if (menu.isEnabled()) { | |
96 | + manager.clearSelectedPath(); | |
97 | + open(menu); | |
98 | + } | |
99 | + } | |
100 | + } | |
101 | + } | |
102 | + | |
103 | + @Override | |
104 | + public void menuKeyReleased(MenuKeyEvent e) { /* do nothing */ } | |
105 | + }; | |
106 | + | |
107 | + /** Use for folder only */ | |
108 | + private static final MouseListener mouseListener = new MouseAdapter() { | |
109 | + @Override | |
110 | + public void mouseClicked(MouseEvent e) { | |
111 | + open((JMenuItem) e.getSource()); | |
112 | + } | |
113 | + }; | |
114 | + | |
115 | + /** Use for folder only */ | |
116 | + private static final MenuListener menuListener = new MenuListener() { | |
117 | + | |
118 | + @Override | |
119 | + public void menuSelected(MenuEvent e) { | |
120 | + JMenu m = (JMenu) e.getSource(); | |
121 | + | |
122 | + // create submenus | |
123 | + if (m instanceof Runnable) { | |
124 | + ((Runnable) m).run(); | |
125 | + } else { | |
126 | + createSubmenu(m); | |
127 | + } | |
128 | + | |
129 | + // Remove this listener | |
130 | + m.removeMenuListener(this); | |
131 | + } | |
132 | + | |
133 | + @Override | |
134 | + public void menuDeselected(MenuEvent e) { /* do nothing */ } | |
135 | + | |
136 | + @Override | |
137 | + public void menuCanceled(MenuEvent e) { /* do nothing */ } | |
138 | + }; | |
139 | + | |
140 | + /** Defeats instantiation. */ | |
141 | + private Listeners() {} | |
142 | + | |
143 | + public static ActionListener getActionListener() { | |
144 | + return actionListener; | |
145 | + } | |
146 | + | |
147 | + public static MenuKeyListener getMenuKeyListener() { | |
148 | + return menuKeyListener; | |
149 | + } | |
150 | + | |
151 | + public static MouseListener getMouseListener() { | |
152 | + return mouseListener; | |
153 | + } | |
154 | + | |
155 | + public static MenuListener getMenuListener() { | |
156 | + return menuListener; | |
157 | + } | |
158 | + | |
159 | + private static void open(JMenuItem item) { | |
160 | + if (!item.isEnabled()) { | |
161 | + return; | |
162 | + } | |
163 | + | |
164 | + String path = item.getActionCommand(); | |
165 | + try { | |
166 | + File file = new File(path); | |
167 | + if (!FilePreview.open(file)) { | |
168 | + Desktop.getDesktop().open(file); | |
169 | + } | |
170 | + } catch (IOException ex) { | |
171 | + Log.log(ex); | |
172 | + Core.getMainWindow().showMessageDialog(StaticUtils.format( | |
173 | + L10n.Entry.ERROR_FILE_HAS_NO_ASSOC.toString(), path)); | |
174 | + } | |
175 | + } | |
176 | + | |
177 | + private static void createSubmenu(JMenu menu) { | |
178 | + File folder = new File(menu.getActionCommand()); | |
179 | + File[] filteredListFiles = folder.listFiles(fileFilter); | |
180 | + Arrays.sort(filteredListFiles, comparator); | |
181 | + | |
182 | + createSubmenu(menu, filteredListFiles); | |
183 | + } | |
184 | + | |
185 | + private static void createSubmenu(JMenu menu, File[] files) { | |
186 | + int maxViewableMenuItemCount = getMaxViewableMenuItemCount(menu); | |
187 | + | |
188 | + // Add "more" menu at the tail if the part of popup menu will be out of screen | |
189 | + if (files.length > maxViewableMenuItemCount) { | |
190 | + int limit = maxViewableMenuItemCount - 1; | |
191 | + for (int i = 0; i < limit; i++) { | |
192 | + menu.add(MenuFactory.createMenuItem(files[i])); | |
193 | + } | |
194 | + | |
195 | + // create "More" menu | |
196 | + final File[] moreFiles = Arrays.copyOfRange(files, limit, files.length); | |
197 | + menu.add(createMoreMenu(moreFiles)); | |
198 | + } else { | |
199 | + for (File file : files) { | |
200 | + menu.add(MenuFactory.createMenuItem(file)); | |
201 | + } | |
202 | + } | |
203 | + } | |
204 | + | |
205 | + private static int getMaxViewableMenuItemCount(JMenu menu) { | |
206 | + int h = menu.getHeight(); | |
207 | + int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height; | |
208 | + Insets margin = menu.getPopupMenu().getMargin(); | |
209 | + Insets insets = menu.getPopupMenu().getInsets(); | |
210 | + int popupInsideHeight = screenHeight - margin.top - margin.bottom - insets.top - insets.bottom; | |
211 | + return popupInsideHeight / h; | |
212 | + } | |
213 | + | |
214 | + private static RunnableMenu createMoreMenu(final File[] files) { | |
215 | + RunnableMenu m = new RunnableMenu() { | |
216 | + @Override | |
217 | + public void run() { | |
218 | + createSubmenu(this, files); | |
219 | + } | |
220 | + }; | |
221 | + m.addMenuListener(Listeners.getMenuListener()); | |
222 | + Mnemonics.setLocalizedText(m, OStrings.getString("MW_MORE_SUBMENU")); | |
223 | + m.setHorizontalAlignment(SwingConstants.CENTER); | |
224 | + return m; | |
225 | + } | |
226 | + | |
227 | + private static abstract class RunnableMenu extends JMenu implements Runnable { | |
228 | + // | |
229 | + } | |
230 | +} |
@@ -0,0 +1,51 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2013-2015 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/ | |
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.osdn.users.yutang.omegat.plugin.foldermenu; | |
18 | + | |
19 | +import java.util.ResourceBundle; | |
20 | + | |
21 | +/** | |
22 | + * Manage localization. | |
23 | + * | |
24 | + * @author Yu Tang | |
25 | + */ | |
26 | +public class L10n { | |
27 | + | |
28 | + public enum Entry { | |
29 | + // for menu | |
30 | + FOLDERS_MENU_LABEL, | |
31 | + PROJECT_ROOT_MENU_LABEL, | |
32 | + USER_CONFIG_MENU_LABEL, | |
33 | + APPLICATION_ROOT_MENU_LABEL, | |
34 | + SOURCE_DOC_MENU_LABEL, | |
35 | + TARGET_DOC_MENU_LABEL, | |
36 | + | |
37 | + // for Word | |
38 | + WORD_WINDOW_CAPTION, | |
39 | + | |
40 | + // for error | |
41 | + ERROR_FILE_HAS_NO_ASSOC | |
42 | + ; | |
43 | + | |
44 | + @Override | |
45 | + public String toString() { | |
46 | + return bundle.getString(this.name()); | |
47 | + } | |
48 | + } | |
49 | + | |
50 | + private static final ResourceBundle bundle = ResourceBundle.getBundle(L10n.class.getPackage().getName() + ".Bundle"); | |
51 | +} |
@@ -0,0 +1,90 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2015 Yu Tang | |
5 | + Home page: http://osdn.jp/users/yu-tang/ | |
6 | + | |
7 | + This file is part of plugin for OmegaT. | |
8 | + http://www.omegat.org/ | |
9 | + | |
10 | + License: GNU GPL version 3 or (at your option) any later version. | |
11 | + | |
12 | + You should have received a copy of the GNU General Public License | |
13 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | + **************************************************************************/ | |
15 | + | |
16 | +package jp.osdn.users.yutang.omegat.plugin.foldermenu; | |
17 | + | |
18 | +import java.io.File; | |
19 | +import java.io.IOException; | |
20 | +import javax.swing.Icon; | |
21 | +import javax.swing.JMenu; | |
22 | +import javax.swing.JMenuItem; | |
23 | +import javax.swing.filechooser.FileSystemView; | |
24 | +import org.openide.awt.Mnemonics; | |
25 | + | |
26 | +/** | |
27 | + * Factory class for JMenu and JMenuItem | |
28 | + * | |
29 | + * @author Yu Tang | |
30 | + */ | |
31 | +public class MenuFactory { | |
32 | + | |
33 | + /** Defeats instantiation. */ | |
34 | + private MenuFactory() {} | |
35 | + | |
36 | + public static JMenuItem createMenuItem(final String path) { | |
37 | + File file = new File(path); | |
38 | + return createMenuItemImpl(file, file.getName(), false); | |
39 | + } | |
40 | + | |
41 | + public static JMenuItem createMenuItem(final String path, final String titleKey) { | |
42 | + return createMenuItemImpl(new File(path), titleKey, true); | |
43 | + } | |
44 | + | |
45 | + public static JMenuItem createMenuItem(final File file) { | |
46 | + return createMenuItemImpl(file, file.getName(), false); | |
47 | + } | |
48 | + | |
49 | + public static JMenuItem createMenuItem(final File file, final String titleKey) { | |
50 | + return createMenuItemImpl(file, titleKey, true); | |
51 | + } | |
52 | + | |
53 | + private static JMenuItem createMenuItemImpl(final File file, final String label, final boolean toBeLocalized) { | |
54 | + JMenuItem m; | |
55 | + Icon icon = FileSystemView.getFileSystemView().getSystemIcon(file); | |
56 | + if (file.isDirectory()) { | |
57 | + JMenu mnu = new JMenu(); | |
58 | + mnu.setIcon(icon); | |
59 | + mnu.addMenuListener(Listeners.getMenuListener()); // to create submenu | |
60 | + mnu.addMenuKeyListener(Listeners.getMenuKeyListener()); // to open a folder with enter key | |
61 | + mnu.addMouseListener(Listeners.getMouseListener()); // to open a folder with mouse clicking | |
62 | + m = mnu; | |
63 | + } else { | |
64 | + m = new JMenuItem(icon); | |
65 | + } | |
66 | + | |
67 | + // label string | |
68 | + if (toBeLocalized) { | |
69 | + Mnemonics.setLocalizedText(m, label); | |
70 | + } else { | |
71 | + m.setText(label); | |
72 | + } | |
73 | + | |
74 | + if (file.exists()) { | |
75 | + m.setActionCommand(file.getAbsolutePath()); | |
76 | + m.addActionListener(Listeners.getActionListener()); | |
77 | + String name = file.getName(); | |
78 | + if (!name.equals(label)) { | |
79 | + try { | |
80 | + m.setToolTipText(file.getCanonicalPath()); | |
81 | + } catch (IOException ex) { | |
82 | + m.setToolTipText(name); | |
83 | + } | |
84 | + } | |
85 | + } else { | |
86 | + m.setEnabled(false); | |
87 | + } | |
88 | + return m; | |
89 | + } | |
90 | +} |
@@ -0,0 +1,88 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2013-2015 Yu Tang | |
5 | + Home page: http://osdn.jp/users/yu-tang/ | |
6 | + | |
7 | + This file is part of plugin for OmegaT. | |
8 | + http://www.omegat.org/ | |
9 | + | |
10 | + License: GNU GPL version 3 or (at your option) any later version. | |
11 | + | |
12 | + You should have received a copy of the GNU General Public License | |
13 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | + **************************************************************************/ | |
15 | + | |
16 | +package jp.osdn.users.yutang.omegat.plugin.foldermenu; | |
17 | + | |
18 | +import javax.swing.JMenu; | |
19 | +import javax.swing.JMenuBar; | |
20 | +import javax.swing.SwingUtilities; | |
21 | +import org.omegat.core.CoreEvents; | |
22 | +import org.omegat.core.events.IApplicationEventListener; | |
23 | +import org.omegat.core.Core; | |
24 | +import org.omegat.util.Log; | |
25 | +import org.omegat.util.Platform; | |
26 | +import org.openide.awt.Mnemonics; | |
27 | + | |
28 | +/** | |
29 | + * easy access to project folders from menu | |
30 | + * | |
31 | + * @author Yu Tang | |
32 | + */ | |
33 | +public class FolderMenu implements IApplicationEventListener { | |
34 | + | |
35 | + private static boolean initialized = false; | |
36 | + | |
37 | + public static void loadPlugins() { | |
38 | + try { | |
39 | + // Not initialize in console mode | |
40 | + if (initialized) { | |
41 | + throw new RuntimeException("FolderMenu plugin could be instantiated only once."); | |
42 | + } else if (Platform.isWebStart()) { | |
43 | + // Just log it, no error. | |
44 | + Log.log("FolderMenu plugin is not available with Java Web Start."); | |
45 | + } else { | |
46 | + CoreEvents.registerApplicationEventListener(new FolderMenu()); | |
47 | + } | |
48 | + } catch (Throwable ex) { | |
49 | + String msg = ex.getMessage(); | |
50 | + Log.logErrorRB("LD_ERROR", msg); | |
51 | + Core.pluginLoadingError(msg); | |
52 | + } finally { | |
53 | + initialized = true; | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + public static void unloadPlugins() { | |
58 | + // do nothing | |
59 | + } | |
60 | + | |
61 | + @Override | |
62 | + public void onApplicationStartup() { | |
63 | + // insert Files menu before the last menu (Help menu.) | |
64 | + JMenu menu = createFolderMenu(); | |
65 | + JMenuBar mainMenuBar = (JMenuBar) Core.getMainWindow().getMainMenu().getOptionsMenu().getParent(); | |
66 | + mainMenuBar.add(menu, mainMenuBar.getMenuCount() - 1); | |
67 | + | |
68 | + // remove ApplicationEventListener | |
69 | + SwingUtilities.invokeLater(new Runnable() { | |
70 | + @Override | |
71 | + public void run() { | |
72 | + CoreEvents.unregisterApplicationEventListener(FolderMenu.this); | |
73 | + } | |
74 | + }); | |
75 | + } | |
76 | + | |
77 | + private static JMenu createFolderMenu() { | |
78 | + JMenu menu = new JMenu(); | |
79 | + menu.setActionCommand("foldersMenu"); | |
80 | + String labelString = L10n.Entry.FOLDERS_MENU_LABEL.toString(); | |
81 | + Mnemonics.setLocalizedText(menu, labelString); | |
82 | + menu.addMenuListener(new FolderMenuListener()); | |
83 | + return menu; | |
84 | + } | |
85 | + | |
86 | + @Override | |
87 | + public void onApplicationShutdown() { /* do nothing */ } | |
88 | +} | |
\ No newline at end of file |
@@ -0,0 +1,41 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2013 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
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.osdn.users.yutang.omegat.plugin.foldermenu.filepreview; | |
18 | + | |
19 | +import java.io.File; | |
20 | + | |
21 | +/** | |
22 | + * | |
23 | + * @author Yu Tang | |
24 | + */ | |
25 | +public interface IPreview { | |
26 | + | |
27 | + /** activate preview window */ | |
28 | + public void activate(); | |
29 | + | |
30 | + /** get temporary files for preview */ | |
31 | + public String[] getTempFiles(); | |
32 | + | |
33 | + /** open preview window */ | |
34 | + public void open(); | |
35 | + | |
36 | + /** close preview window */ | |
37 | + public void close(); | |
38 | + | |
39 | + /** reload document */ | |
40 | + public void reload(); | |
41 | + } |
@@ -0,0 +1,398 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
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/ | |
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.osdn.users.yutang.omegat.plugin.foldermenu.filepreview; | |
18 | + | |
19 | +import java.io.File; | |
20 | +import java.io.IOException; | |
21 | +import java.io.InputStream; | |
22 | +import java.util.ArrayList; | |
23 | +import java.util.Arrays; | |
24 | +import java.util.List; | |
25 | +import jp.osdn.users.yutang.omegat.plugin.foldermenu.L10n; | |
26 | +import org.omegat.util.LFileCopy; | |
27 | +import org.omegat.util.Log; | |
28 | +import static org.omegat.util.Platform.OsType.WIN32; | |
29 | +import static org.omegat.util.Platform.OsType.WIN64; | |
30 | +import static org.omegat.util.Platform.getOsType; | |
31 | +import org.omegat.util.StaticUtils; | |
32 | + | |
33 | +/** | |
34 | + * Word 文書をプレビュー用に開きます。 | |
35 | + * | |
36 | + * | |
37 | + * @author Yu Tang | |
38 | + */ | |
39 | +public class WordPreview implements IPreview { | |
40 | + | |
41 | + private static final String WSF_NAME = "WordPreview.wsf"; | |
42 | + private static boolean _isMSWordAvailable; | |
43 | + private static File _wsf; | |
44 | + | |
45 | + private final File originalFile; | |
46 | + private long originalFileLastModified; // will update at each every time compiling target docs | |
47 | + private final String windowTitle; | |
48 | + private final File temporaryFile; // Primary temp file | |
49 | + private final File temporaryFile2; // Secondary temp file | |
50 | + | |
51 | + public WordPreview(final File originalFile) throws IOException { | |
52 | + this.originalFile = originalFile; | |
53 | + this.originalFileLastModified = originalFile.lastModified(); | |
54 | + this.temporaryFile = getTempFile(originalFile); | |
55 | + this.windowTitle = StaticUtils.format( | |
56 | + L10n.Entry.WORD_WINDOW_CAPTION.toString(), | |
57 | + originalFile.getName()); | |
58 | + this.temporaryFile2 = getTempFile2(this.temporaryFile); | |
59 | + } | |
60 | + | |
61 | + static { | |
62 | + // _isMSWordAvailable | |
63 | + switch (getOsType()) { | |
64 | + case WIN64: | |
65 | + case WIN32: | |
66 | + new Thread() { | |
67 | + @Override | |
68 | + public void run() { | |
69 | + _isMSWordAvailable = getMSWordAvailable(); | |
70 | + if (_isMSWordAvailable) { | |
71 | + Log.log("FolderMenu: WordPreview function is available."); | |
72 | + } else { | |
73 | + Log.log("FolderMenu: WordPreview function is not available."); | |
74 | + } | |
75 | + } | |
76 | + }.start(); | |
77 | + break; | |
78 | + default: // Mac, Linux and others | |
79 | + _isMSWordAvailable = false; | |
80 | + break; | |
81 | + } | |
82 | + | |
83 | + // _wsf | |
84 | + File tempDir = new File(System.getProperty("java.io.tmpdir")); | |
85 | + _wsf = new File(tempDir, WSF_NAME); | |
86 | + } | |
87 | + | |
88 | + public static boolean isAvailable(File file) { | |
89 | + return isAvailable() && | |
90 | + file.isFile() && | |
91 | + file.getName().toLowerCase().endsWith(".docx"); | |
92 | + } | |
93 | + | |
94 | + public static boolean isAvailable() { | |
95 | + return _isMSWordAvailable; | |
96 | + } | |
97 | + | |
98 | + public static void init() { | |
99 | + // force executing static initializer | |
100 | + } | |
101 | + | |
102 | + private static boolean getMSWordAvailable() { | |
103 | + final int RET_OK = 0; | |
104 | + try { | |
105 | + Command command = new Command(); | |
106 | + String s; | |
107 | + if (RET_OK == command.execDOS("assoc", ".docx")) { | |
108 | + s = command.getStdout(); | |
109 | + // s's data example) | |
110 | + // ----------------------------------------------------- | |
111 | + //.docx=Word.Document.12 | |
112 | + //<-(\r\n) | |
113 | + // ----------------------------------------------------- | |
114 | + // 末尾に空行が入るので注意。 | |
115 | + // 他のパターンとして、AOO/LO 環境で以下のようなケースもあり。 | |
116 | + //.docx=OpenOffice.Docx | |
117 | + //.docx=LibreOffice.WriterDocument.1 | |
118 | + if (s.toLowerCase().startsWith(".docx=word.document.")) { | |
119 | + String classString = s.substring(".docx=".length()).replaceAll("\\r\\n", ""); | |
120 | + if (RET_OK == command.exec("reg", "query", "HKCR\\" + classString + "\\shell\\open\\command", "/ve")) { | |
121 | + s = command.getStdout(); | |
122 | + // s's data example) | |
123 | + // ----------------------------------------------------- | |
124 | + //<-(\r\n) | |
125 | + //HKEY_CLASSES_ROOT\Word.document.12\shell\open\command | |
126 | + //(既定) REG_SZ "C:\PROGRA~2\MICROS~4\OFFICE11\WINWORD.EXE" /n /dde | |
127 | + //<-(\r\n) | |
128 | + // ----------------------------------------------------- | |
129 | + // 前後に空行が入るので注意。 | |
130 | + return s.toUpperCase().indexOf("\\WINWORD.EXE") > -1; | |
131 | + } | |
132 | + } | |
133 | + } | |
134 | + } catch (Exception ex) { | |
135 | + Log.log(ex); | |
136 | + } | |
137 | + return false; | |
138 | + } | |
139 | + | |
140 | + private static File getWSF() throws IOException { | |
141 | + if (! _wsf.exists()) { | |
142 | + InputStream in = WordPreview.class.getResourceAsStream(WSF_NAME); | |
143 | + try { | |
144 | + LFileCopy.copy(in, _wsf); | |
145 | + } finally { | |
146 | + in.close(); | |
147 | + } | |
148 | + _wsf.deleteOnExit(); | |
149 | + } | |
150 | + return _wsf; | |
151 | + } | |
152 | + | |
153 | + @Override | |
154 | + public String[] getTempFiles() { | |
155 | + // ここでは、残留する可能性のある一時ファイルをすべて申告します。 | |
156 | + String[] paths = new String[3]; | |
157 | + try { | |
158 | + paths[0] = this.temporaryFile.getCanonicalPath(); | |
159 | + paths[1] = this.temporaryFile2.getCanonicalPath(); | |
160 | + | |
161 | + // MS Word が作成する(プレビュー用ファイルの)一時ファイルも、強制 | |
162 | + // 終了時などには残留する可能性があるため、ここで申告しておきます。 | |
163 | + final String PREFIX = "~$"; | |
164 | + String parent = this.temporaryFile.getParent(); | |
165 | + String name = this.temporaryFile.getName(); | |
166 | + paths[2] = (new File(parent, PREFIX + name.substring(2))).getCanonicalPath(); | |
167 | + } catch (IOException ex) { | |
168 | + Log.log(ex); | |
169 | + } | |
170 | + return paths; | |
171 | + } | |
172 | + | |
173 | + @Override | |
174 | + public void activate() { | |
175 | + try { | |
176 | + final Command command = new Command(); | |
177 | + final String job = "activate"; | |
178 | + final int ret = command.execWSF(job, this.windowTitle); | |
179 | + } catch (IOException ex) { | |
180 | + Log.log(ex); | |
181 | + } catch (InterruptedException ex) { | |
182 | + Log.log(ex); | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + @Override | |
187 | + public void open() { | |
188 | + | |
189 | + // 以下の処理は少し時間がかかるため、別スレッドに処理を委譲します。 | |
190 | + new Thread() { | |
191 | + @Override | |
192 | + public void run() { | |
193 | + try { | |
194 | + // 起動前にファイルをコピーする。 | |
195 | + // OmegaT は訳文ファイルの作成時に、既存の訳文ファイルを上書きする。 | |
196 | + // そのため、オリジナルのファイルをそのまま開くとファイルがロックされ、 | |
197 | + // 次回のコンパイル時に上書きできずに失敗する。それを避けるために、 | |
198 | + // プレビュー専用の一時ファイルをコピーして、そちらを開く。 | |
199 | + // コピー先は、temp フォルダーではなく、オリジナルと同じフォルダー内に | |
200 | + // コピーする。文書に相対パスで画像リンクなどが張られている場合のリンク | |
201 | + // 切れを防ぐため。 | |
202 | + // そのままコピーすると FolderMenu プラグインのメニュー上で一時ファイル | |
203 | + // が見えてしまうため、hidden 属性を付けておく。 | |
204 | + LFileCopy.copy(originalFile, temporaryFile); | |
205 | + | |
206 | + // make temp file hidden on Windows | |
207 | + addHiddenFileAttribute(temporaryFile); | |
208 | + | |
209 | + // Desktop.getDesktop().open(temp); | |
210 | + // 上記のようにして一時ファイルを開くと、場合によっては Word | |
211 | + // の MRU に一時ファイルを開いた履歴が大量に残ってしまう。 | |
212 | + // これを回避するため、WSH を経由して COM オートメーションで | |
213 | + // 処理する。 | |
214 | + | |
215 | + // open the document | |
216 | + Command command = new Command(); | |
217 | + String document = temporaryFile.getCanonicalPath(); | |
218 | + String document2 = temporaryFile2.getCanonicalPath(); | |
219 | + String job = "open"; | |
220 | + int ret = command.execWSF(job, document, document2, windowTitle); | |
221 | + | |
222 | + if (! command.stderr.isEmpty()) { | |
223 | + Log.log("Word error(" + ret + "): " + command.stderr); | |
224 | + } | |
225 | + onWordApplicationQuit(ret); | |
226 | + } catch (IOException ex) { | |
227 | + Log.log(ex); | |
228 | + } catch (InterruptedException ex) { | |
229 | + Log.log(ex); | |
230 | + } | |
231 | + } | |
232 | + }.start(); | |
233 | + } | |
234 | + | |
235 | + private File getTempFile(final File originalFile) throws IOException { | |
236 | + String prefix = "_WordPreview"; | |
237 | + String name = originalFile.getName(); | |
238 | + String suffix = name.substring(name.lastIndexOf(".")); | |
239 | + File parentFolder = originalFile.getParentFile(); | |
240 | + File tempFile = File.createTempFile(prefix, suffix, parentFolder); | |
241 | + tempFile.deleteOnExit(); | |
242 | + return tempFile; | |
243 | + } | |
244 | + | |
245 | + // foo.ext => foo(2).ext | |
246 | + private File getTempFile2(final File primaryTempFile) throws IOException { | |
247 | + String name = primaryTempFile.getName(); | |
248 | + int lastDotPos = name.lastIndexOf("."); | |
249 | + String baseName = name.substring(0, lastDotPos); | |
250 | + String extension = name.substring(lastDotPos); | |
251 | + String fileName = baseName + "(2)" + extension; | |
252 | + File parentFolder = primaryTempFile.getParentFile(); | |
253 | + File tempFile2 = new File(parentFolder, fileName); | |
254 | + tempFile2.deleteOnExit(); | |
255 | + return tempFile2; | |
256 | + } | |
257 | + | |
258 | + private void addHiddenFileAttribute(File file) { | |
259 | + try { | |
260 | + new ProcessBuilder("attrib","+H", file.getCanonicalPath()).start(); | |
261 | + } catch (IOException ex) { | |
262 | + Log.log(ex); | |
263 | + } | |
264 | + } | |
265 | + | |
266 | + private void onWordApplicationQuit(final int returnCode) { | |
267 | + try { | |
268 | + // remove this from Previews collection | |
269 | + FilePreview.delete(originalFile); | |
270 | + | |
271 | + // try to delete temporary file | |
272 | + temporaryFile.delete(); | |
273 | + | |
274 | + // try to delete WSF file | |
275 | + if (FilePreview.size(WordPreview.class) == 0) { | |
276 | + _wsf.delete(); | |
277 | + } | |
278 | + | |
279 | + } catch (IOException ex) { | |
280 | + Log.log(ex); | |
281 | + } | |
282 | + } | |
283 | + | |
284 | + @Override | |
285 | + public void close() { | |
286 | + try { | |
287 | + // close the document | |
288 | + final Command command = new Command(); | |
289 | + final String job = "close"; | |
290 | + final String document = temporaryFile.getCanonicalPath(); | |
291 | + command.execWSF(job, document); | |
292 | + } catch (IOException ex) { | |
293 | + Log.log(ex); | |
294 | + } catch (InterruptedException ex) { | |
295 | + Log.log(ex); | |
296 | + } | |
297 | + } | |
298 | + | |
299 | + @Override | |
300 | + public void reload() { | |
301 | + if (! isOriginalFileUpdated()) { | |
302 | + return; | |
303 | + } | |
304 | + | |
305 | + try { | |
306 | + File temp = getTempFile(originalFile); | |
307 | + | |
308 | + // copy the file to avoid locking the file unnecessarily | |
309 | + LFileCopy.copy(originalFile, temp); | |
310 | + | |
311 | + // rename to secondary temp file (and pass it to WSF) | |
312 | + temp.renameTo(temporaryFile2); | |
313 | + | |
314 | + // make temp file hidden on Windows | |
315 | + addHiddenFileAttribute(temporaryFile2); | |
316 | + | |
317 | + // update lastModified value | |
318 | + this.originalFileLastModified = originalFile.lastModified(); | |
319 | + } catch (IOException ex) { | |
320 | + Log.log(ex); | |
321 | + } | |
322 | + } | |
323 | + | |
324 | + private boolean isOriginalFileUpdated() { | |
325 | + return this.originalFileLastModified != this.originalFile.lastModified(); | |
326 | + } | |
327 | + | |
328 | + // バッファあふれ非対応のため、少量のテキスト(だいたい 500文字ていど)が | |
329 | + // 予想される場合のみ利用してください。 | |
330 | + // また同期実行です。プロセスの終了を待機してから制御を返します。 | |
331 | + protected static class Command { | |
332 | + | |
333 | + private int exitCode = 0; | |
334 | + private String stdout = ""; | |
335 | + private String stderr = ""; | |
336 | + | |
337 | + public int getExitCode() { | |
338 | + return exitCode; | |
339 | + } | |
340 | + | |
341 | + public String getStdout() { | |
342 | + return stdout; | |
343 | + } | |
344 | + | |
345 | + public String getStderr() { | |
346 | + return stderr; | |
347 | + } | |
348 | + | |
349 | + public int exec(String... command) | |
350 | + throws IOException, InterruptedException { | |
351 | + return startProcessAndWait(Arrays.asList(command)); | |
352 | + } | |
353 | + | |
354 | + public int execDOS(String... command) | |
355 | + throws IOException, InterruptedException { | |
356 | + List<String> commands = new ArrayList<String>(command.length + 2); | |
357 | + commands.add("cmd.exe"); | |
358 | + commands.add("/c"); | |
359 | + commands.addAll(Arrays.asList(command)); | |
360 | + | |
361 | + return startProcessAndWait(commands); | |
362 | + } | |
363 | + | |
364 | + public int execWSF(String job, String... command) | |
365 | + throws IOException, InterruptedException { | |
366 | + String script = getWSF().getCanonicalPath(); | |
367 | + List<String> commands = new ArrayList<String>(command.length + 4); | |
368 | + commands.add("cscript.exe"); | |
369 | + commands.add("//nologo"); | |
370 | + commands.add("//Job:" + job); | |
371 | + commands.add(script); | |
372 | + commands.addAll(Arrays.asList(command)); | |
373 | + | |
374 | + return startProcessAndWait(commands); | |
375 | + } | |
376 | + | |
377 | + private int startProcessAndWait(List<String> command) | |
378 | + throws IOException, InterruptedException { | |
379 | + ProcessBuilder pb = new ProcessBuilder(command); | |
380 | + Process process = pb.start(); | |
381 | + exitCode = process.waitFor(); // 0: succeed | |
382 | + stdout = getString(process.getInputStream()); | |
383 | + stderr = getString(process.getErrorStream()); | |
384 | + return exitCode; | |
385 | + } | |
386 | + | |
387 | + private String getString(InputStream is) throws IOException { | |
388 | + byte[] b = new byte[1024]; | |
389 | + int size = is.read(b); | |
390 | + if (size > 0) { | |
391 | + return new String(b, 0, size); | |
392 | + } else { | |
393 | + return ""; | |
394 | + } | |
395 | + } | |
396 | + | |
397 | + } | |
398 | +} |
@@ -0,0 +1,102 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2013 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
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.osdn.users.yutang.omegat.plugin.foldermenu.filepreview; | |
18 | + | |
19 | +import java.io.File; | |
20 | +import java.io.IOException; | |
21 | +import org.omegat.util.FileUtil; | |
22 | +import org.omegat.util.Log; | |
23 | +import org.omegat.util.StaticUtils; | |
24 | + | |
25 | +/** | |
26 | + * Cleanup temp files | |
27 | + * | |
28 | + * @author Yu Tang | |
29 | + */ | |
30 | +public class TempFileCleaner { | |
31 | + | |
32 | + private static final String LOG_FILE_NAME = "FilePreviewTempFiles.log"; | |
33 | + private static final File logFile; | |
34 | + | |
35 | + private TempFileCleaner() { /* not allow instanciation. static only. */ } | |
36 | + | |
37 | + static { | |
38 | + logFile = new File(StaticUtils.getConfigDir(), LOG_FILE_NAME); | |
39 | + } | |
40 | + | |
41 | + public static void cleanup() { | |
42 | + // load temp file list from log file | |
43 | + String[] list = readTempFileList().split("\\n"); | |
44 | + String content = ""; | |
45 | + | |
46 | + // try to delete them | |
47 | + for (String path: list) { | |
48 | + if (! path.isEmpty()) { | |
49 | + File f = new File(path); | |
50 | + if (f.isFile()) { | |
51 | + if (! f.delete()) { | |
52 | + f.deleteOnExit(); | |
53 | + content += path + "\n"; | |
54 | + } | |
55 | + } | |
56 | + } | |
57 | + } | |
58 | + | |
59 | + // save back to log file or delete log if empty | |
60 | + writeTempFileList(content); | |
61 | + } | |
62 | + | |
63 | + public static void addToList(String[] filePaths) { | |
64 | + // load temp file list from log file | |
65 | + String list = readTempFileList(); | |
66 | + | |
67 | + // add the file to the list | |
68 | + for (String path: filePaths) | |
69 | + list += path + "\n"; | |
70 | + | |
71 | + // save back to log file or delete log if empty | |
72 | + writeTempFileList(list); | |
73 | + } | |
74 | + | |
75 | + // 末尾改行付きのリストを返します。 | |
76 | + private static String readTempFileList() { | |
77 | + String ret = ""; | |
78 | + if (logFile.isFile()) { | |
79 | + try { | |
80 | + ret = FileUtil.readTextFile(logFile); | |
81 | + if (!ret.isEmpty() && !ret.endsWith("\n")) | |
82 | + ret += "\n"; | |
83 | + } catch (IOException ex) { | |
84 | + Log.log(ex); | |
85 | + } | |
86 | + } | |
87 | + return ret; | |
88 | + } | |
89 | + | |
90 | + private static void writeTempFileList(final String content) { | |
91 | + if (content.isEmpty()) { | |
92 | + if (logFile.isFile()) | |
93 | + logFile.delete(); | |
94 | + } else { | |
95 | + try { | |
96 | + FileUtil.writeTextFile(logFile, content); | |
97 | + } catch (IOException ex) { | |
98 | + Log.log(ex); | |
99 | + } | |
100 | + } | |
101 | + } | |
102 | +} |
@@ -0,0 +1,221 @@ | ||
1 | +/************************************************************************** | |
2 | + FolderMenu - easy access to project folders from menu. | |
3 | + | |
4 | + Copyright (C) 2013 Yu Tang | |
5 | + Home page: http://sourceforge.jp/users/yu-tang/ | |
6 | + Support center: http://sourceforge.jp/users/yu-tang/pf/ | |
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.osdn.users.yutang.omegat.plugin.foldermenu.filepreview; | |
18 | + | |
19 | +import java.io.File; | |
20 | +import java.io.IOException; | |
21 | +import java.util.HashMap; | |
22 | +import javax.swing.SwingUtilities; | |
23 | +import org.omegat.core.Core; | |
24 | +import org.omegat.core.CoreEvents; | |
25 | +import org.omegat.core.events.IApplicationEventListener; | |
26 | +import org.omegat.core.events.IProjectEventListener; | |
27 | +import org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE; | |
28 | +import static org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE.CLOSE; | |
29 | +import static org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE.COMPILE; | |
30 | + | |
31 | +/** | |
32 | + * must call init() before using this class. | |
33 | + * | |
34 | + * @author Yu Tang | |
35 | + */ | |
36 | + | |
37 | +public class FilePreview { | |
38 | + | |
39 | + // key = target file's canonical path | |
40 | + private static final HashMap<String, IPreview> previews = new HashMap<String, IPreview>(); | |
41 | + | |
42 | + private static IProjectEventListener projectEventListener = null; | |
43 | + private static IApplicationEventListener applicationEventListener = null; | |
44 | + | |
45 | + static { | |
46 | + // cleanup left temp files if they exists | |
47 | + TempFileCleaner.cleanup(); | |
48 | + | |
49 | + // call each Preview#init() | |
50 | + WordPreview.init(); | |
51 | + | |
52 | + //@@TODO WSF reload 時にselectionがテキストボックスの場合、restore に失敗するバグ | |
53 | + } | |
54 | + | |
55 | + public static boolean delete(final File originalFile) throws IOException { | |
56 | + String key = originalFile.getCanonicalPath(); | |
57 | + IPreview deleted = previews.remove(key); | |
58 | + if (previews.isEmpty()) | |
59 | + unhookProjectChangeEvent(); | |
60 | + return (deleted != null); | |
61 | + } | |
62 | + | |
63 | + public static void init() { | |
64 | + // force executing static initializer | |
65 | + } | |
66 | + | |
67 | + public static boolean open(File file) throws IOException { | |
68 | + // not available for directory | |
69 | + if (! file.isFile()) | |
70 | + return false; | |
71 | + | |
72 | + // does file exists inside of the target folder? | |
73 | + if (! isUnderTargetFolder(file)) | |
74 | + return false; | |
75 | + | |
76 | + // file type or environment is not supported | |
77 | + if (! available(file)) | |
78 | + return false; | |
79 | + | |
80 | + // Preview instance is already there? | |
81 | + String key = file.getCanonicalPath(); | |
82 | + if (previews.containsKey(key)) { | |
83 | + previews.get(key).activate(); | |
84 | + return true; | |
85 | + } | |
86 | + | |
87 | + // open it | |
88 | + IPreview p = new WordPreview(file); | |
89 | + p.open(); | |
90 | + hookProjectChangeEvent(); | |
91 | + hookApplicationChangeEvent(); | |
92 | + previews.put(key, p); | |
93 | + | |
94 | + // add temp files to cleaner list | |
95 | + TempFileCleaner.addToList(p.getTempFiles()); | |
96 | + | |
97 | + return true; | |
98 | + } | |
99 | + | |
100 | + public static int size(Class<?> classObj) { | |
101 | + if (classObj == null) { | |
102 | + return previews.size(); | |
103 | + } else { | |
104 | + int i = 0; | |
105 | + for (Object o: previews.values()) { | |
106 | + if (classObj.isInstance(o)) | |
107 | + i++; | |
108 | + } | |
109 | + return i; | |
110 | + } | |
111 | + } | |
112 | + | |
113 | + private static boolean available(File file) { | |
114 | + return WordPreview.isAvailable(file); | |
115 | + } | |
116 | + | |
117 | + /** hook project change event */ | |
118 | + private static void hookProjectChangeEvent() { | |
119 | + if (projectEventListener != null) | |
120 | + return; | |
121 | + | |
122 | + projectEventListener= new IProjectEventListener() { | |
123 | + | |
124 | + @Override | |
125 | + public void onProjectChanged(PROJECT_CHANGE_TYPE eventType) { | |
126 | + switch (eventType) { | |
127 | + case CLOSE: | |
128 | + onProjectClose(); | |
129 | + break; | |
130 | + case COMPILE: | |
131 | + onProjectCompile(); | |
132 | + break; | |
133 | + } | |
134 | + } | |
135 | + | |
136 | + }; | |
137 | + | |
138 | + CoreEvents.registerProjectChangeListener(projectEventListener); | |
139 | + } | |
140 | + | |
141 | + /** unhook project change event */ | |
142 | + private static void unhookProjectChangeEvent() { | |
143 | + if (projectEventListener == null) | |
144 | + return; | |
145 | + | |
146 | + CoreEvents.unregisterProjectChangeListener(projectEventListener); | |
147 | + projectEventListener= null; | |
148 | + } | |
149 | + | |
150 | + /** hook application change event */ | |
151 | + private static void hookApplicationChangeEvent() { | |
152 | + if (applicationEventListener != null) | |
153 | + return; | |
154 | + | |
155 | + applicationEventListener= new IApplicationEventListener() { | |
156 | + | |
157 | + @Override | |
158 | + public void onApplicationStartup() { | |
159 | + /* do nothing */ | |
160 | + } | |
161 | + | |
162 | + @Override | |
163 | + public void onApplicationShutdown() { | |
164 | + closeAllPreviews(); | |
165 | + } | |
166 | + | |
167 | + }; | |
168 | + | |
169 | + CoreEvents.registerApplicationEventListener(applicationEventListener); | |
170 | + } | |
171 | + | |
172 | + /** unhook project change event */ | |
173 | + private static void unhookApplicationChangeEvent() { | |
174 | + if (applicationEventListener == null) | |
175 | + return; | |
176 | + | |
177 | + CoreEvents.unregisterApplicationEventListener(applicationEventListener); | |
178 | + applicationEventListener= null; | |
179 | + } | |
180 | + | |
181 | + private static void onProjectClose() { | |
182 | + closeAllPreviews(); | |
183 | + | |
184 | + // イベントリスナーの登録解除をここで発行するとスレッドエラーになるので | |
185 | + // 後で実行する。 | |
186 | + SwingUtilities.invokeLater(new Runnable() { | |
187 | + @Override | |
188 | + public void run() { | |
189 | + unhookProjectChangeEvent(); | |
190 | + unhookApplicationChangeEvent(); | |
191 | + } | |
192 | + }); | |
193 | + } | |
194 | + | |
195 | + private static void onProjectCompile() { | |
196 | + reloadAllPreviews(); | |
197 | + } | |
198 | + | |
199 | + private static boolean isUnderTargetFolder(final File file) throws IOException { | |
200 | + // does file exists inside of the target folder? | |
201 | + String targetRoot = Core.getProject().getProjectProperties().getTargetRoot(); | |
202 | + return file.getCanonicalPath().startsWith(targetRoot); | |
203 | + } | |
204 | + | |
205 | + private static void closeAllPreviews() { | |
206 | + if (! previews.isEmpty()) { | |
207 | + for (IPreview preview: previews.values()) { | |
208 | + preview.close(); | |
209 | + } | |
210 | + } | |
211 | + } | |
212 | + | |
213 | + private static void reloadAllPreviews() { | |
214 | + if (! previews.isEmpty()) { | |
215 | + for (IPreview preview: previews.values()) { | |
216 | + preview.reload(); | |
217 | + } | |
218 | + } | |
219 | + } | |
220 | + | |
221 | +} |