• R/O
  • SSH
  • HTTPS

コミット

よく使われているワード(クリックで追加)

javaandroidc++linuxc#objective-ccocoa誰得qtrubybathyscaphegamepythonphpguiwindowsc翻訳omegattwitterframeworkbtronarduinovb.net計画中(planning stage)directxpreviewertestゲームエンジンdom

OmegaT のメニューバーにフォルダーツリー参照用のメニューを追加します。


コミットメタ情報

リビジョン67 (tree)
日時2015-06-29 23:45:17
作者yu-tang

ログメッセージ

Change package jp/sourceforge/... to jp/osdn/... and some refactoring

変更サマリ

差分

--- trunk/src-stubs/org/omegat/util/StringUtil.java (nonexistent)
+++ trunk/src-stubs/org/omegat/util/StringUtil.java (revision 67)
@@ -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+}
--- trunk/src-stubs/org/omegat/util/OStrings.java (nonexistent)
+++ trunk/src-stubs/org/omegat/util/OStrings.java (revision 67)
@@ -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+}
--- trunk/manifest.mf (revision 66)
+++ trunk/manifest.mf (revision 67)
@@ -6,5 +6,5 @@
66 Permissions: all-permissions
77 Class-Path: lib/lib-mnemonics.jar
88 OmegaT-Plugins:
9- jp.sourceforge.users.yutang.omegat.plugin.foldermenu.FolderMenu
9+ jp.osdn.users.yutang.omegat.plugin.foldermenu.FolderMenu
1010 OmegaT-Plugin: true
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/L10n.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/L10n.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/ShellLinkMenu.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/ShellLinkMenu.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/MenuManager.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/MenuManager.java (nonexistent)
@@ -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
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/FolderMenu.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/FolderMenu.java (nonexistent)
@@ -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
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/FilePreview.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/FilePreview.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/IPreview.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/IPreview.java (nonexistent)
@@ -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- }
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/WordPreview.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/WordPreview.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/TempFileCleaner.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/filepreview/TempFileCleaner.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/MenuHelper.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/MenuHelper.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/FilterHelper.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/FilterHelper.java (nonexistent)
@@ -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-}
--- trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/ShellLinkMenuItem.java (revision 66)
+++ trunk/src/jp/sourceforge/users/yutang/omegat/plugin/foldermenu/ShellLinkMenuItem.java (nonexistent)
@@ -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-}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/FilterHelper.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/FilterHelper.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/FolderMenuListener.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/FolderMenuListener.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/Listeners.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/Listeners.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/L10n.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/L10n.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/MenuFactory.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/MenuFactory.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/FolderMenu.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/FolderMenu.java (revision 67)
@@ -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
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/IPreview.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/IPreview.java (revision 67)
@@ -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+ }
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/WordPreview.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/WordPreview.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/TempFileCleaner.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/TempFileCleaner.java (revision 67)
@@ -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+}
--- trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/FilePreview.java (nonexistent)
+++ trunk/src/jp/osdn/users/yutang/omegat/plugin/foldermenu/filepreview/FilePreview.java (revision 67)
@@ -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+}