Skip to content

Instantly share code, notes, and snippets.

@yu-tang
Last active October 23, 2019 09:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yu-tang/a6833d687e436ddd5135 to your computer and use it in GitHub Desktop.
Save yu-tang/a6833d687e436ddd5135 to your computer and use it in GitHub Desktop.

activate_source_text.groovy スクリプト

目的

OmegaT の下記 RFE に対する、スクリプトによる対処方法です。

#821 Showing cursor on the original segment

これは上記 RFE が実装されるまでの暫定対処に過ぎません。 RFE が実装された後には、速やかに本スクリプトをアンインストール してください。

インストール

本スクリプトを一時的に試用する場合は、スクリプトフォルダー (スクリプトウィンドウ上部にパスが表示されています)にスクリプトを コピーしてください。

スクリプトを一回実行すると、そのセッション内(OmegaT を終了するまで) で本機能が有効になります。

本スクリプトを常用する場合は、スクリプトフォルダー配下の application_startup サブフォルダー(存在しない場合は作成してください) にスクリプトをコピーしてください。

OmegaT 起動時に自動実行されるため、手動実行は不要になります。

アンインストール

本スクリプトをスクリプトフォルダーから削除してください。

なお本機能が有効になっている場合は、スクリプトの削除と関係なく、 該当セッション中は有効のままです。

無効にしたい場合は、OmegaT を再起動してください。

使い方

本スクリプトを実行した後は、以下の手順で使用できます。

編集ウィンドウ上で [F2] キーを押すと、アクティブな分節の原文欄に カーソルが移動し、原文作業モードに移行します。

原文作業モードでは、テキストの範囲選択はもちろんのこと、 テキストの削除や挿入も可能です。そのため、 その場で必要に応じて原文を加工してからコピーすることができます。

原文の変更は一時的なものです。原文作業モードから復帰すると、 原文の変更はすべて元に戻ります。 原文ファイル自体を編集して保存できるわけではありませんので、ご注意ください。

原文作業モードの有効範囲は、アクティブな分節の原文に限定されます。 原文作業モード中に他の(非アクティブな)分節の原文に移動することはできません。

原文作業モードからは、次のいずれかの操作で復帰できます:

  • [Esc] キー、[F2] キー、[Enter] キーのいずれかを押下する
  • 原文テキスト以外の場所(黄色くハイライトされていない場所)をクリックする

このうち、[F2] キーと [Enter] キーで復帰した場合は、 訳文のカーソル位置に原文の選択テキストが自動挿入されます。 したがって、カーソル位置に原文(の一部)を貼り付けたい場合は、 原文作業モードでわざわざコピーする必要はありません。 単にテキストを選択して、[F2] キーか [Enter] キーで抜けるだけです。 クリップボードは使用しませんので、操作の前後でクリップボードの内容に変更はありません。

[Esc] キーかマウスクリックによって復帰した場合、テキストは自動挿入されません (キャンセル操作として扱われます)。

原文作業モードではキーボードショートカットが制限されますが、Ver.0.2 から以下のキーボードショートカットは使用できるようになりました。

  • Ctrl + F による検索ウィンドウの表示
  • Ctrl + Shift + G による用語登録ダイアログの表示

仕様制限

原文作業モードでは、OmegaT 特有の機能が一部制限されます。

たとえばタグの保護機能などです。タグも含めて、すべて通常テキストとして扱われます。

またアクティブな分節の原文が画面上に表示されていない場合(部分的な場合を含む)は、 [F2] キーを押しても原文作業モードに移行しない場合があります (スクリプトウィンドウにエラーが出力されます)。

既知のバグ

行の折り返し位置が、原文作業モード移行前後で異なる場合があります。

事象としては把握していますが、優先度が低いため修正の予定は決まっていません。

/* :name=Acivate source text :description=Acivate source text on the Editor with keyboard shortcut
*
* The workaround by script for RFE #821:
* Showing cursor on the original segment
* http://sourceforge.net/p/omegat/feature-requests/821/
*
* @author Yu Tang
* @date 2015-08-31
* @version 0.2
*/
// *******************
// BEGIN USER SETTINGS
//********************
FONT_BOLD = true // or false
// *****************************************************
// END USER SETTINGS, NOTHING FURTHER NEEDS TO BE EDITED
// *****************************************************
import groovy.transform.Field
import java.awt.ComponentOrientation
import java.awt.Dimension
import java.awt.event.ActionEvent
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import java.awt.event.WindowFocusListener
import java.awt.Font
import java.awt.Point
import java.awt.Rectangle
import java.awt.Toolkit
import java.awt.event.InputEvent
import javax.swing.border.EmptyBorder
import javax.swing.JDialog
import javax.swing.JEditorPane
import javax.swing.JRootPane
import javax.swing.JViewport
import javax.swing.SwingUtilities
import org.omegat.core.Core
import org.omegat.core.CoreEvents
import org.omegat.core.events.IProjectEventListener
import org.omegat.core.events.IProjectEventListener.PROJECT_CHANGE_TYPE
import org.omegat.core.search.SearchMode
import org.omegat.gui.editor.EditorUtils
import org.omegat.gui.editor.SegmentBuilder
import org.omegat.gui.search.SearchWindowController
import org.omegat.util.gui.StaticUIUtils
import org.omegat.util.gui.Styles
import org.omegat.util.gui.UIThreadsUtil
import org.omegat.util.StaticUtils
@Field final String SCRIPT_NAME = 'activate_source_text'
KeyListener createEditorKeyListener() {
[
keyPressed : {
if (StaticUtils.isKey(it, KeyEvent.VK_F2, 0)) {
showDialog()
}
}
] as KeyAdapter
}
KeyListener createDialogEditorKeyListener() {
[
keyPressed : { KeyEvent e ->
String selection = e.source.selectedText
switch(true) {
case StaticUtils.isKey(e, KeyEvent.VK_ENTER, 0):
case StaticUtils.isKey(e, KeyEvent.VK_F2, 0):
// insert selected text to the editor
if (selection) {
editor.insertText selection
}
// close the dialog
JDialog dialog = getDialogAncestor(e.source)
def closeAction = dialog.rootPane.actionMap.get("ESCAPE")
def action = new ActionEvent(e.source, ActionEvent.ACTION_PERFORMED, "ESCAPE")
closeAction.actionPerformed action
break
case StaticUtils.isKey(e, KeyEvent.VK_F, Toolkit.defaultToolkit.menuShortcutKeyMask):
// open search window
SearchWindowController search = new SearchWindowController(mainWindow, selection, SearchMode.SEARCH)
mainWindow.addSearchWindow search
break
case StaticUtils.isKey(e, KeyEvent.VK_G, Toolkit.defaultToolkit.menuShortcutKeyMask | InputEvent.SHIFT_MASK):
// open add glossary term dialog
Core.glossary.showCreateGlossaryEntryDialog()
if (selection) {
Core.glossary.createGlossaryEntryDialog.sourceText.text = selection
//Core.glossary.createGlossaryEntryDialog.targetText.text = selection
//Core.glossary.createGlossaryEntryDialog.commentText.text = selection
}
break
}
}
] as KeyAdapter
}
JDialog getDialogAncestor(comp) {
def win = SwingUtilities.getWindowAncestor(comp)
while (win == null || !win instanceof JDialog) {
win = SwingUtilities.getWindowAncestor(win)
}
win
}
void showDialog() {
try {
def ste = editor.currentEntry
if (ste == null) {
return
}
JDialog dialog = createDialog(ste.srcText)
StaticUIUtils.setEscapeClosable dialog
setLostFocusClosable dialog
UIThreadsUtil.executeInSwingThread { dialog.setVisible true } as Runnable
} catch(ex) {
console.println "$SCRIPT_NAME >> $ex"
}
}
void setLostFocusClosable(JDialog dialog) {
def closeAction = dialog.rootPane.actionMap.get("ESCAPE")
def focusListener = [
windowGainedFocus : {},
windowLostFocus : {
def action = new ActionEvent(it.source, ActionEvent.ACTION_PERFORMED, "ESCAPE")
closeAction.actionPerformed action
}
] as WindowFocusListener
dialog.addWindowFocusListener focusListener
}
JDialog createDialog(String text) {
JDialog dialog = new JDialog(mainWindow)
dialog.setUndecorated true
dialog.rootPane.setWindowDecorationStyle JRootPane.PLAIN_DIALOG
JEditorPane pane = createEditorPane(text)
pane.addKeyListener createDialogEditorKeyListener()
dialog.add pane
dialog.pack()
dialog.setBounds sourceSegmentRect
dialog
}
JEditorPane createEditorPane(String text) {
JEditorPane pane = new JEditorPane('text/plain', text)
pane.with {
setDragEnabled true
setComponentOrientation sourceOrientation
setFont FONT_BOLD ? editor.font.deriveFont(Font.BOLD) : editor.font
setForeground Styles.EditorColor.COLOR_ACTIVE_SOURCE_FG.color
setBackground Styles.EditorColor.COLOR_ACTIVE_SOURCE.color
setCaretPosition 0
def b = editor.editor.border
def border = new EmptyBorder(0, b.left, 0, b.right) // top and bottom = 0
setBorder border
}
pane
}
ComponentOrientation getSourceOrientation() {
editor.sourceLangIsRTL \
? ComponentOrientation.RIGHT_TO_LEFT
: ComponentOrientation.LEFT_TO_RIGHT
}
Rectangle getSourceSegmentRect() {
int activeSegment = editor.displayedEntryIndex
JViewport viewport = editor.scrollPane.viewport
Rectangle viewRect = viewport.viewRect
SegmentBuilder sb = editor.m_docSegList[activeSegment]
int startSourcePosition = sb.startSourcePosition
int startTranslationPosition = sb.startTranslationPosition
if (startTranslationPosition == -1) {
startTranslationPosition = startSourcePosition + sb.sourceText.size() + 1 // + 1 for line break
}
Point sourceLocation = editor.editor.modelToView(startSourcePosition).location
Point transLocation = editor.editor.modelToView(startTranslationPosition).location
if (!viewRect.contains(sourceLocation)) { // location is NOT viewable
throw new RuntimeException("Source segment must be viewable");
}
// create new Rectangle for source segment
int x = viewRect.x
int y = sourceLocation.y
int width = viewRect.width
int height = transLocation.y - y
Point point = new Point(x, y)
SwingUtilities.convertPointToScreen point, viewport.view
Rectangle rect = new Rectangle(point.@x, point.@y, width, height)
}
CoreEvents.registerProjectChangeListener new F2Controller(createEditorKeyListener())
"${SCRIPT_NAME}.groovy is available in the current session."
// controller class
class F2Controller implements IProjectEventListener {
KeyListener _listener
F2Controller(KeyListener listener) {
_listener = listener
if (Core.project.isProjectLoaded()) {
installKeyListener()
}
}
void onProjectChanged(PROJECT_CHANGE_TYPE eventType) {
switch(eventType) {
case PROJECT_CHANGE_TYPE.CREATE:
case PROJECT_CHANGE_TYPE.LOAD:
// すぐリスナー登録するとエディターがドキュメントを開く前で
// タイミングが合わないので、遅延登録する
Runnable doRun = { installKeyListener() } as Runnable
SwingUtilities.invokeLater doRun
break
case PROJECT_CHANGE_TYPE.CLOSE:
uninstallKeyListener()
break
}
}
void installKeyListener() {
Core.editor.editor.addKeyListener _listener
}
void uninstallKeyListener() {
Core.editor.editor.removeKeyListener _listener
}
}
@kosivantsov
Copy link

There's a tiny problem with the Metal LAF, at least on Linux. It has to do with spawned source pane's placement. When it spawns, the last line isn't visible, so if the segment is only one line long, I see only the border. The pane is resizable, but I would much rather just have it guess the segment length properly. If the segment is longer than just a few lines, then the pane covers some of the target. My rude fix for that was editing line 203 to move the pane 40 pixels higher and make it 40 pixels taller ( Rectangle rect = new Rectangle(point.@x, point.@y-40, width, height+40)), but it's rather an ugly workaround, as it would fail for others who use different fonts.

After comparing with other LAF's and trying it on Windows, I see that the pane is decorated when Metal LAF is used, and the decoration steals from the overall geometry.

@kosivantsov
Copy link

I found the fix. Line 147 should read:

dialog.rootPane.setWindowDecorationStyle JRootPane.NONE
It fixes it for Metal LAF and works as expected for the other LAF's, at least on Linux. See here: http://nadeausoftware.com/articles/2009/02/windows_java_tip_how_control_window_decorations#Usinglookandfeelspecificwindowdecorations

@kosivantsov
Copy link

this is what i did to make it read-only, but still show the caret:
add after line 159:

        setEditable false
        getCaret().setVisible true

@dsmiraglio
Copy link

Hi,
I just switched to Linux and saw the same problem described by Kos on Lubuntu. I corrected line 147 on my OmegaT and now the script is fine. Can you please correct the script on this page, so people that download your script can have immediately the best layout? I have just published a post about this script and added a link to this page (see http://www.language-lane.com/blog/?e=34). I could publish the corrected script on my blog, but I think it is better to have one source for it, so we don't create innumerable and confusing versions (and then it is certainly fairer if people wanting the script download it from the creator's page).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment