11package com .jvms .i18neditor .editor ;
22
33import java .awt .BorderLayout ;
4+ import java .awt .Component ;
45import java .awt .Container ;
56import java .awt .Desktop ;
67import java .awt .Dimension ;
78import java .awt .Image ;
9+ import java .awt .KeyboardFocusManager ;
810import java .awt .event .KeyAdapter ;
911import java .awt .event .KeyEvent ;
1012import java .awt .event .MouseAdapter ;
@@ -102,6 +104,7 @@ public Editor() {
102104 super ();
103105 setupUI ();
104106 setupFileDrop ();
107+ setupGlobalKeyEventDispatcher ();
105108 }
106109
107110 public void createProject (Path dir , ResourceType type ) {
@@ -372,7 +375,7 @@ public void showRenameTranslationDialog(String key) {
372375 boolean isReplace = newNode .isLeaf () || oldNode .isLeaf ();
373376 boolean confirm = Dialogs .showConfirmDialog (this ,
374377 MessageBundle .get ("dialogs.translation.conflict.title" ),
375- MessageBundle .get ("dialogs.translation.conflict.text." + (isReplace ? "replace" : "merge" )),
378+ MessageBundle .get ("dialogs.translation.conflict.text." + (isReplace ? "replace" : "merge" )),
376379 JOptionPane .WARNING_MESSAGE );
377380 if (confirm ) {
378381 renameTranslationKey (key , newKey );
@@ -403,7 +406,7 @@ public void showDuplicateTranslationDialog(String key) {
403406 boolean isReplace = newNode .isLeaf () || oldNode .isLeaf ();
404407 boolean confirm = Dialogs .showConfirmDialog (this ,
405408 MessageBundle .get ("dialogs.translation.conflict.title" ),
406- MessageBundle .get ("dialogs.translation.conflict.text." + (isReplace ? "replace" : "merge" )),
409+ MessageBundle .get ("dialogs.translation.conflict.text." + (isReplace ? "replace" : "merge" )),
407410 JOptionPane .WARNING_MESSAGE );
408411 if (confirm ) {
409412 duplicateTranslationKey (key , newKey );
@@ -560,6 +563,47 @@ public void launch() {
560563 }
561564 }
562565
566+ public void updateUI () {
567+ TranslationTreeNode selectedNode = translationTree .getSelectedNode ();
568+
569+ resourcesPanel .removeAll ();
570+ resourceFields = resourceFields .stream ().sorted ().collect (Collectors .toList ());
571+ resourceFields .forEach (field -> {
572+ Locale locale = field .getResource ().getLocale ();
573+ String label = locale != null ? locale .getDisplayName () : MessageBundle .get ("resources.locale.default" );
574+ field .setEnabled (selectedNode != null && selectedNode .isEditable ());
575+ field .setRows (settings .getInputHeight ());
576+ resourcesPanel .add (Box .createVerticalStrut (5 ));
577+ resourcesPanel .add (new JLabel (label ));
578+ resourcesPanel .add (Box .createVerticalStrut (5 ));
579+ resourcesPanel .add (field );
580+ resourcesPanel .add (Box .createVerticalStrut (10 ));
581+ });
582+
583+ Container container = getContentPane ();
584+ if (project != null ) {
585+ container .add (contentPane );
586+ container .remove (introText );
587+ List <Resource > resources = project .getResources ();
588+ editorMenu .setEnabled (true );
589+ editorMenu .setEditable (!resources .isEmpty ());
590+ translationTree .setEditable (!resources .isEmpty ());
591+ translationField .setEditable (!resources .isEmpty ());
592+ } else {
593+ container .add (introText );
594+ container .remove (contentPane );
595+ editorMenu .setEnabled (false );
596+ editorMenu .setEditable (false );
597+ translationTree .setEditable (false );
598+ translationField .setEditable (false );
599+ }
600+ translationField .setVisible (settings .isShowKeyField ());
601+
602+ updateTitle ();
603+ validate ();
604+ repaint ();
605+ }
606+
563607 private void clearUI () {
564608 translationField .clear ();
565609 translationTree .clear ();
@@ -584,14 +628,14 @@ private void setupUI() {
584628 translationField = new TranslationField ();
585629 translationField .addKeyListener (new TranslationFieldKeyListener ());
586630 translationField .setBorder (BorderFactory .createCompoundBorder (
587- BorderFactory .createMatteBorder (1 ,0 ,0 ,1 ,LookAndFeel .TEXTFIELD_BORDER_COLOR ),
631+ BorderFactory .createMatteBorder (1 ,0 ,0 ,1 ,LookAndFeel .BORDER_COLOR ),
588632 ((CompoundBorder )translationField .getBorder ()).getInsideBorder ()));
589633
590634 JScrollPane translationsScrollPane = new JScrollPane (translationTree );
591635 translationsScrollPane .getViewport ().setOpaque (false );
592636 translationsScrollPane .setOpaque (false );
593637 translationsScrollPane .setBorder (
594- BorderFactory .createMatteBorder (0 ,0 ,0 ,1 ,LookAndFeel .TEXTFIELD_BORDER_COLOR ));
638+ BorderFactory .createMatteBorder (0 ,0 ,0 ,1 ,LookAndFeel .BORDER_COLOR ));
595639
596640 translationsPanel = new JPanel (new BorderLayout ());
597641 translationsPanel .add (translationsScrollPane );
@@ -654,51 +698,68 @@ public void filesDropped(java.io.File[] files) {
654698 });
655699 }
656700
701+ private void setupGlobalKeyEventDispatcher () {
702+ KeyboardFocusManager .getCurrentKeyboardFocusManager ().addKeyEventDispatcher (e -> {
703+ if (!e .isAltDown () || e .getID () != KeyEvent .KEY_PRESSED ) {
704+ return false ;
705+ }
706+ TreePath selected = translationTree .getSelectionPath ();
707+ if (selected == null ) {
708+ return false ;
709+ }
710+ boolean result = false ;
711+ int row = translationTree .getRowForPath (selected );
712+ switch (e .getKeyCode ()) {
713+ case KeyEvent .VK_RIGHT :
714+ if (translationTree .isExpanded (row )) {
715+ translationTree .setSelectionRow (row +1 );
716+ } else {
717+ translationTree .expandRow (row );
718+ }
719+ result = true ;
720+ break ;
721+ case KeyEvent .VK_LEFT :
722+ if (translationTree .isCollapsed (row )) {
723+ translationTree .setSelectionPath (selected .getParentPath ());
724+ } else {
725+ translationTree .collapseRow (row );
726+ }
727+ result = true ;
728+ break ;
729+ case KeyEvent .VK_UP :
730+ translationTree .setSelectionRow (Math .max (0 , row -1 ));
731+ result = true ;
732+ break ;
733+ case KeyEvent .VK_DOWN :
734+ TreePath next = translationTree .getPathForRow (row +1 );
735+ if (next != null ) {
736+ translationTree .setSelectionPath (next );
737+ }
738+ result = true ;
739+ break ;
740+ }
741+ if (result && !resourceFields .isEmpty ()) {
742+ Component comp = getFocusOwner ();
743+ if (comp != null && (comp instanceof ResourceField || comp .equals (this ))) {
744+ TranslationTreeNode current = translationTree .getSelectedNode ();
745+ if (!current .isLeaf () || current .isRoot ()) {
746+ requestFocusInWindow ();
747+ } else if (comp .equals (this )) {
748+ resourceFields .get (0 ).requestFocusInWindow ();
749+ }
750+ }
751+ }
752+ return result ;
753+ });
754+ }
755+
657756 private void setupResource (Resource resource ) {
658757 resource .addListener (e -> setDirty (true ));
659758 ResourceField field = new ResourceField (resource );
660759 field .addKeyListener (new ResourceFieldKeyListener ());
661760 resourceFields .add (field );
662761 }
663762
664- private void updateUI () {
665- TranslationTreeNode selectedNode = translationTree .getSelectedNode ();
666-
667- resourcesPanel .removeAll ();
668- resourceFields .stream ().sorted ().forEach (field -> {
669- Locale locale = field .getResource ().getLocale ();
670- String label = locale != null ? locale .getDisplayName () : MessageBundle .get ("resources.locale.default" );
671- field .setEditable (selectedNode != null && selectedNode .isEditable ());
672- resourcesPanel .add (Box .createVerticalStrut (5 ));
673- resourcesPanel .add (new JLabel (label ));
674- resourcesPanel .add (Box .createVerticalStrut (5 ));
675- resourcesPanel .add (field );
676- resourcesPanel .add (Box .createVerticalStrut (10 ));
677- });
678-
679- Container container = getContentPane ();
680- if (project != null ) {
681- container .add (contentPane );
682- container .remove (introText );
683- List <Resource > resources = project .getResources ();
684- editorMenu .setEnabled (true );
685- editorMenu .setEditable (!resources .isEmpty ());
686- translationTree .setEditable (!resources .isEmpty ());
687- translationField .setEditable (!resources .isEmpty ());
688- } else {
689- container .add (introText );
690- container .remove (contentPane );
691- editorMenu .setEnabled (false );
692- editorMenu .setEditable (false );
693- translationTree .setEditable (false );
694- translationField .setEditable (false );
695- }
696-
697- updateTitle ();
698- validate ();
699- repaint ();
700- }
701-
702763 private void updateHistory () {
703764 List <String > recentDirs = settings .getHistory ();
704765 if (project != null ) {
@@ -762,6 +823,8 @@ private void storeEditorState() {
762823 props .setProperty ("minify_resources" , settings .isMinifyResources ());
763824 props .setProperty ("resource_name" , settings .getResourceName ());
764825 props .setProperty ("check_version" , settings .isCheckVersionOnStartup ());
826+ props .setProperty ("input_height" , settings .getInputHeight ());
827+ props .setProperty ("key_field" , settings .isShowKeyField ());
765828 if (!settings .getHistory ().isEmpty ()) {
766829 props .setProperty ("history" , settings .getHistory ());
767830 }
@@ -792,6 +855,8 @@ private void restoreEditorState() {
792855 settings .setMinifyResources (props .getBooleanProperty ("minify_resources" , false ));
793856 settings .setResourceName (props .getProperty ("resource_name" , DEFAULT_RESOURCE_NAME ));
794857 settings .setCheckVersionOnStartup (props .getBooleanProperty ("check_version" , true ));
858+ settings .setInputHeight (props .getIntegerProperty ("input_height" , 5 ));
859+ settings .setShowKeyField (props .getBooleanProperty ("key_field" , true ));
795860 }
796861
797862 private class TranslationTreeMouseListener extends MouseAdapter {
@@ -836,7 +901,7 @@ public void valueChanged(TreeSelectionEvent e) {
836901 translationField .setValue (key );
837902 resourceFields .forEach (f -> {
838903 f .setValue (key );
839- f .setEditable (node .isEditable ());
904+ f .setEnabled (node .isEditable ());
840905 });
841906
842907 // Restore scroll position
0 commit comments