1 package SnowMailClient.keyboard; 2 3 import snow.utils.gui.Icons; 4 import SnowMailClient.Language.*; 5 import snow.lookandfeel.ThemesManager; 6 7 import java.awt.*; 8 import java.awt.event.*; 9 import javax.swing.*; 10 import javax.swing.border.*; 11 import javax.swing.event.*; 12 import java.util.*; 13 import javax.swing.text.*; 14 15 19 public final class KeyboardDialog extends JDialog 20 { 21 private final GridBagLayout gridBag = new GridBagLayout(); 22 private final GridBagConstraints constr = new GridBagConstraints(); 23 private int actualCol = 0; 24 private int numberOfCols = 2; 25 private int nButtons = 0; 26 private KeyboardMap map; 27 private final JLabel completionLabel = new JLabel(Language.translate("Completions: none")); 28 private final JPanel keyboardPanel = new JPanel(); 29 private final JSpinner spinner = new JSpinner(new SpinnerNumberModel(11,1,99,1)); 30 31 private final JComboBox keyboardsCB = new JComboBox(new Object []{ 32 new PolishMap(), 33 new RussianMap(), 34 new LituanianMap(), 35 new ThaiKeyboard() 37 }); 38 39 private final Vector<KeyboardListener> listeners = new Vector<KeyboardListener>(); 40 41 final String title; 42 43 public KeyboardDialog(JFrame parent) 44 { 45 super(parent, Language.translate("Keyboard"), false); 46 this.title = getTitle(); 47 this.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); 48 this.setDefaultLookAndFeelDecorated(true); 49 this.setFocusableWindowState(false); 50 51 this.getContentPane().setLayout(new BorderLayout()); 52 this.getContentPane().add(completionLabel, BorderLayout.SOUTH); 53 this.getContentPane().add(keyboardPanel, BorderLayout.CENTER); 54 55 JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); 56 controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS)); 57 controlPanel.setBorder(new EmptyBorder(3,2,3,2)); 58 59 this.getContentPane().add(controlPanel, BorderLayout.NORTH); 60 controlPanel.add(keyboardsCB); 61 controlPanel.add(Box.createHorizontalGlue()); 62 controlPanel.add(new JLabel(Language.translate("Size")+": ")); 63 controlPanel.add(spinner); 64 65 keyboardsCB.setPreferredSize(new Dimension( 66 (int) keyboardsCB.getPreferredSize().getWidth(), 67 UIManager.getFont("Label.font").getSize())); 68 69 final JButton editButton = new JButton(Language.translate("Edit")); 70 editButton.setFont(ThemesManager.getInstance().getSmallFont()); 71 controlPanel.add(Box.createHorizontalGlue()); 72 editButton.addActionListener(new ActionListener() 74 { 75 public void actionPerformed(ActionEvent ae) 76 { 77 JPopupMenu popup = new JPopupMenu("edit"); 78 JMenuItem miEdit = new JMenuItem( Language.translate("Edit keyboard") ); 79 popup.add(miEdit); 80 miEdit.addActionListener(new ActionListener() 81 { 82 public void actionPerformed(ActionEvent ae) 83 { 84 KeyboardEditor ke = new KeyboardEditor(KeyboardDialog.this); 85 } 86 }); 87 88 JMenuItem miAdd = new JMenuItem( Language.translate("Add new keyboard"), Icons.PlusIcon.shared10 ); 89 popup.add(miAdd); 90 miAdd.addActionListener(new ActionListener() 91 { 92 public void actionPerformed(ActionEvent ae) 93 { 94 String name = JOptionPane.showInputDialog(editButton, Language.translate("Keyboard name: ")); 95 if(name!=null) 96 { 97 KeyboardMap kmap = new KeyboardMap(name, 8); 98 setKeyboard(kmap); 99 } 100 } 101 }); 102 JMenuItem miRemove = new JMenuItem( Language.translate("Remove selected keyboard") ); 103 miRemove.addActionListener(new ActionListener() 105 { 106 public void actionPerformed(ActionEvent ae) 107 { 108 } 109 }); 110 111 popup.show(editButton,10,5); 112 } 113 }); 114 115 keyboardsCB.addActionListener(new ActionListener() 116 { 117 public void actionPerformed(ActionEvent ae) 118 { 119 setKeyboard( (KeyboardMap) keyboardsCB.getSelectedItem() ); 120 pack(); 121 } 122 }); 123 124 spinner.addChangeListener(new ChangeListener() 125 { 126 public void stateChanged(ChangeEvent ce) 127 { 128 int fs = Integer.parseInt(""+spinner.getValue()); 129 Font font = new Font("LucidaSansRegular", Font.PLAIN, fs); 130 for(KeyboardKey k : map.getKeys()) 131 { 132 if(k.button!=null) 133 { 134 k.button.setFont(font); 135 } 136 } 137 pack(); 138 } 139 }); 140 141 spinner.setPreferredSize(new Dimension( 142 (int) spinner.getPreferredSize().getWidth(), 143 (int) keyboardsCB.getPreferredSize().getHeight())); 144 145 146 this.setMinimumSize(new Dimension(30,30)); 149 150 } 152 public KeyboardMap getActualKeyboardMap() { return map; } 153 154 public void setKeyboard(KeyboardMap map) 155 { 156 this.map = map; 157 158 numberOfCols = map.getColumnCount(); 159 nButtons = 0; 160 actualCol = 0; 161 setTitle(map.getName()); 162 163 keyboardPanel.removeAll(); 164 keyboardPanel.setLayout(gridBag); 165 166 for(KeyboardKey key: map.getKeys()) 167 { 168 addButton(key); 169 } 170 } 171 172 public String getCharsetForDisplayedKeyboard() 173 { 174 return map.getCharset(); 175 } 176 177 public void addListener(KeyboardListener kl) 178 { 179 listeners.add(kl); 180 } 181 182 public void removeListener(KeyboardListener kl) 183 { 184 listeners.remove(kl); 185 } 186 187 189 public void setTarget(final JTextPane pane) 190 { 191 if(!pane.isEditable()) return; 192 193 final DefaultStyledDocument doc = (DefaultStyledDocument) pane.getDocument(); 194 195 this.addListener(new KeyboardListener() 198 { 199 public void typed(String text) 200 { 201 try 202 { 203 208 doc.insertString(pane.getCaretPosition(), text, null); 209 } 210 catch(Exception ex) 211 { 212 ex.printStackTrace(); 213 } 214 } 215 }); 216 217 doc.setDocumentFilter(new DocumentFilter() 220 { 221 public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException 222 { 223 fb.insertString(offset, string, attr); 225 resetHighlights(); 226 } 227 228 public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException 229 { 230 fb.remove(offset, length); 232 resetHighlights(); 233 } 234 235 public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException 236 { 237 filterReplace(fb, offset, length, text, attrs); 239 } 240 241 }); 242 243 pane.addKeyListener(new KeyAdapter() 246 { 247 @Override public void keyPressed(KeyEvent ke) 248 { 249 if(ke.getKeyCode()==KeyEvent.VK_ESCAPE) 250 { 251 completionBuffer.resetBuffer(); 253 resetHighlights(); 254 } 255 } 256 }); 257 } 258 259 260 261 263 final private CompletionBuffer completionBuffer = new CompletionBuffer(); 265 266 int previousReplaceOffset=-1; 267 268 273 private void filterReplace(DocumentFilter.FilterBypass fb, int replaceOffset, int replaceLength, String text, AttributeSet attrs) throws BadLocationException 274 { 275 277 fb.replace(replaceOffset, replaceLength, text, attrs); 280 281 if(text.length()>1) return; 284 285 int offset = replaceOffset+text.length(); 287 288 this.completionLabel.setText(Language.translate("Completions: none")); 289 290 if(!this.isVisible()) return; 292 293 resetHighlights(); 294 295 296 if(previousReplaceOffset==-1) 298 { 299 previousReplaceOffset = offset-1; 300 } 301 302 if( completionBuffer.getBufferLength()>0 && previousReplaceOffset!=-1 && offset-previousReplaceOffset!=1) { 306 System.out.println("Reset buffer because offset jump : "+previousReplaceOffset+" "+offset); 308 completionBuffer.resetBuffer(); 309 } 312 previousReplaceOffset = offset; 313 314 315 completionBuffer.addChars(text); 318 319 String typedShortcut = completionBuffer.toString(); 321 322 Vector<KeyboardKey> keys = map.getKeyStartingWithShortcut(typedShortcut); 324 325 326 if(keys.size()==0) 327 { 328 completionBuffer.resetBuffer(); 330 331 for(int end=typedShortcut.length()-1; end>=1; end--) 333 { 334 String sub = typedShortcut.substring(0,end); 335 KeyboardKey matchingKey = map.getKeyWithShortcut(sub); 338 if(matchingKey!=null) 339 { 340 String toRemove = sub; 341 int pos = offset-toRemove.length() -typedShortcut.length() + end ; 342 344 fb.remove(pos, toRemove.length()); 345 346 fb.replace(pos, 0, matchingKey.toString(), attrs); 347 348 completionBuffer.addChars(typedShortcut.substring(end)); 350 highlightKeysStartingWith(completionBuffer.toString()); 354 355 matchingKey = map.getKeyWithShortcut(completionBuffer.toString()); 356 if(matchingKey!=null) 357 { 358 System.out.println("match !"); 359 } 360 361 return; 362 } 363 } 364 365 366 for(int start=1; start<typedShortcut.length(); start++) 368 { 369 String sub = typedShortcut.substring(start); 370 Vector<KeyboardKey> nkeys = map.getKeyStartingWithShortcut(sub); 372 if(nkeys.size()>0) 373 { 374 completionBuffer.addChars(sub); 375 setCandidates(nkeys); 377 return; 378 } 379 } 380 381 382 383 } 384 else if(keys.size()==1) 385 { 386 KeyboardKey matchingKey = map.getKeyWithShortcut(typedShortcut); 388 if(matchingKey!=null) 389 { 390 String key = matchingKey.toString(); 393 394 String toRemove = completionBuffer.toString(); 396 int pos = offset-toRemove.length(); 397 fb.remove(pos, toRemove.length()); 399 400 fb.replace(pos, 0, key, attrs); 402 completionBuffer.resetBuffer(); 403 return; 404 } 405 406 setCandidates(keys); 408 } 409 else 410 { 411 setCandidates(keys); 413 } 414 } 415 416 417 private void highlightKeysStartingWith(String sub) 418 { 419 Vector<KeyboardKey> nkeys = map.getKeyStartingWithShortcut(sub); 420 if(nkeys.size()>0) 421 { 422 setCandidates(nkeys); 423 } 424 } 425 426 427 private void resetHighlights() 428 { 429 if(map!=null) 430 { 431 for(KeyboardKey key: map.getKeys()) 432 { 433 key.setIsCandidate(false); 434 } 435 } 436 } 437 438 439 private void setCandidates(Vector<KeyboardKey> keys) 440 { 441 StringBuffer completion = new StringBuffer (); 442 for(KeyboardKey k: keys) 443 { 444 k.setIsCandidate(true); 445 completion.append(""+k+" = ["); 446 for(String s: k.getAllShortcuts()) 447 { 448 completion.append(""+s+" "); 449 } 450 completion.setLength(completion.length()-4); 452 completion.append("], "); 453 } 454 completion.setLength(completion.length()-6); this.completionLabel.setText(completion.toString()); 456 } 457 458 459 private void addButton(final KeyboardKey key) 460 { 461 nButtons++; 462 463 JComponent toAdd = null; 464 if(key.isSpacer()) 465 { 466 toAdd = new JLabel(""); 467 } 468 else 469 { 470 JButton button = new JButton(""+key.toStringCAPITAL()); 471 key.button = button; 472 toAdd = button; 473 button.addActionListener(new ActionListener() 474 { 475 public void actionPerformed(ActionEvent ae) 476 { 477 if((ae.getModifiers() & ae.SHIFT_MASK) == ae.SHIFT_MASK) 478 { 479 for(KeyboardListener kl: listeners) 480 { 481 kl.typed(""+key.toStringCAPITAL()); 482 } 483 } 484 else 485 { 486 for(KeyboardListener kl: listeners) 487 { 488 kl.typed(""+key.toStringSMALL()); 489 } 490 } 491 } 492 }); 493 494 button.addMouseListener(new MouseAdapter() 495 { 496 @Override public void mouseEntered(MouseEvent me) 497 { 498 setTitle(title+" "+key+" = "+key.toStringAllShortcuts()); 499 500 } 501 502 @Override public void mouseExited(MouseEvent me) 503 { 504 setTitle(title); 505 } 506 }); 507 508 } 509 510 constr.fill = constr.BOTH; 511 512 actualCol++; 513 if(actualCol==numberOfCols) 514 { 515 constr.gridwidth = GridBagConstraints.REMAINDER; 516 actualCol=0; 517 } 518 else 519 { 520 constr.gridwidth = 1; 521 } 522 523 if(nButtons<=map.getVisibleKeys()) 524 { 525 gridBag.setConstraints(toAdd, constr); 526 keyboardPanel.add(toAdd); 527 } 528 529 530 531 } 532 533 public static void main(String [] a) 534 { 535 JFrame f = new JFrame(); 536 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 537 538 JTextPane pane = new JTextPane(); 539 f.setContentPane(new JScrollPane(pane)); 540 pane.setFont(new Font("LucidaSansRegular", Font.PLAIN, 18)); 541 542 f.setDefaultCloseOperation(f.EXIT_ON_CLOSE); 543 f.setSize (300, 100); 544 f.setVisible(true); 545 546 KeyboardDialog kd = new KeyboardDialog(f); 547 kd.setKeyboard(new PolishMap()); 548 kd.setTarget(pane); 549 kd.pack(); 550 kd.setLocation (200, 200); 551 kd.setVisible(true); 552 } 553 554 } | Popular Tags |