aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip
diff options
context:
space:
mode:
authorYana Stamcheva <yana@jitsi.org>2011-07-27 19:23:47 +0000
committerYana Stamcheva <yana@jitsi.org>2011-07-27 19:23:47 +0000
commit801a79ca9dcd4758344cf0d56085a7fd29f34d3f (patch)
treed8df9465b77233390d8f7e73fb73c8c5491b035d /src/net/java/sip
parente46f74f442136d50bb98e1f62041d10087b272e1 (diff)
downloadjitsi-801a79ca9dcd4758344cf0d56085a7fd29f34d3f.zip
jitsi-801a79ca9dcd4758344cf0d56085a7fd29f34d3f.tar.gz
jitsi-801a79ca9dcd4758344cf0d56085a7fd29f34d3f.tar.bz2
Enables spell check plugin and adds some improvements provided by Purvesh Sahoo.
Diffstat (limited to 'src/net/java/sip')
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java23
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/menus/WritePanelRightButtonMenu.java29
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/ChatAttachments.java140
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/DocUnderliner.java205
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/LanguageSelectionField.java508
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/Parameters.java83
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/Resources.java47
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/SpellCheckActivator.java71
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/SpellChecker.java126
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java411
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/Word.java37
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf4
12 files changed, 1410 insertions, 274 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
index 3ded2ff..3ea9afb 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
@@ -720,9 +720,26 @@ public class ChatWritePanel
Point p = e.getPoint();
SwingUtilities.convertPointToScreen(p, e.getComponent());
- rightButtonMenu.setInvoker(editorPane);
- rightButtonMenu.setLocation(p.x, p.y);
- rightButtonMenu.setVisible(true);
+ //SPELLCHECK
+ ArrayList <JMenuItem> contributedMenuEntries
+ = new ArrayList<JMenuItem>();
+
+ for(ChatMenuListener listener : this.menuListeners)
+ {
+ contributedMenuEntries.addAll(
+ listener.getMenuElements(this.chatPanel, e));
+ }
+
+ for(JMenuItem item : contributedMenuEntries)
+ {
+ rightButtonMenu.add(item);
+ }
+
+ JPopupMenu rightMenu
+ = rightButtonMenu.makeMenu(contributedMenuEntries);
+ rightMenu.setInvoker(editorPane);
+ rightMenu.setLocation(p.x, p.y);
+ rightMenu.setVisible(true);
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/menus/WritePanelRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/chat/menus/WritePanelRightButtonMenu.java
index 5f96820..e8ba640 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/menus/WritePanelRightButtonMenu.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/menus/WritePanelRightButtonMenu.java
@@ -7,6 +7,7 @@
package net.java.sip.communicator.impl.gui.main.chat.menus;
import java.awt.event.*;
+import java.util.*;
import javax.swing.*;
@@ -150,4 +151,32 @@ public class WritePanelRightButtonMenu
closeMenuItem.setIcon(new ImageIcon(
ImageLoader.getImage(ImageLoader.CLOSE_ICON)));
}
+
+ /**
+ * Provides a popup menu with custom entries followed by default
+ * operation entries ( copy, paste ,close)
+ *
+ * @param entries custom menu entries to be added
+ * @return right click menu
+ */
+ public JPopupMenu makeMenu(List <JMenuItem> entries) {
+
+ JPopupMenu rightMenu = new JPopupMenu();
+
+ for(JMenuItem entry : entries) {
+ rightMenu.add(entry);
+ }
+
+ if(!entries.isEmpty()) rightMenu.addSeparator();
+
+ rightMenu.add(copyMenuItem);
+ rightMenu.add(cutMenuItem);
+ rightMenu.add(pasteMenuItem);
+
+ rightMenu.addSeparator();
+
+ rightMenu.add(closeMenuItem);
+
+ return rightMenu;
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/ChatAttachments.java b/src/net/java/sip/communicator/plugin/spellcheck/ChatAttachments.java
index e9f0104..75f23ff 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/ChatAttachments.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/ChatAttachments.java
@@ -1,8 +1,7 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
@@ -13,33 +12,48 @@ import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
-import net.java.sip.communicator.service.gui.Chat;
-import net.java.sip.communicator.service.gui.event.ChatMenuListener;
-import net.java.sip.communicator.util.Logger;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.gui.event.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
import org.dts.spell.dictionary.*;
/**
* Wrapper for handling the multiple listeners associated with chats for the
* spell checker.
- *
+ *
* @author Damian Johnson
+ * @author Purvesh Sahoo
*/
class ChatAttachments
{
- private static final Logger logger
- = Logger.getLogger(ChatAttachments.class);
- private static final ImageIcon ADD_WORD_ICON
- = Resources.getImage(Resources.ADD_WORD_ICON);
+ private static final Logger logger = Logger
+ .getLogger(ChatAttachments.class);
+
+ private static final ImageIcon ADD_WORD_ICON = Resources
+ .getImage(Resources.ADD_WORD_ICON);
+
private final Chat chat;
- private final DocUnderliner docListener; //The red-squibble drawing code
+
+ private final DocUnderliner docListener; // The red-squibble drawing code
+
private final CaretListener caretListener;
+
private final ChatMenuListener menuListener;
+
private boolean isEnabled = true;
+
private SpellDictionary dict;
+
private boolean isAttached = false;
- ChatAttachments(Chat chat, SpellDictionary dict)
+ private final ResourceManagementService resources = Resources
+ .getResources();
+
+ private SpellCheckerConfigDialog dialog;
+
+ ChatAttachments(Chat chat, final SpellDictionary dict)
{
this.chat = chat;
this.dict = dict;
@@ -56,8 +70,7 @@ class ChatAttachments
{
// thrown by spell checker API if problem occurs
logger.error(
- "Spell checker dictionary failed to be accessed",
- exc);
+ "Spell checker dictionary failed to be accessed", exc);
return false;
}
}
@@ -77,21 +90,61 @@ class ChatAttachments
this.menuListener = new ChatMenuListener()
{
- public List <JMenuItem> getMenuElements(Chat chat, MouseEvent event) //Overridden Here
+
+ public List<JMenuItem> getMenuElements(final Chat chat,
+ MouseEvent event)
{
+
if (isEnabled && event.getSource() instanceof JTextComponent)
{
JTextComponent comp = (JTextComponent) event.getSource();
int index = comp.viewToModel(event.getPoint());
+ try
+ {
+ String compText =
+ comp.getDocument().getText(0,
+ comp.getDocument().getLength());
+
+ if (index != -1 && compText.length() != 0)
+ {
+
+ return getCorrections(Word.getWord(
+ comp.getDocument().getText(0,
+ comp.getDocument().getLength()), index,
+ false));
+
+ }
- if (index != -1 && comp.getText().length() != 0)
+ }
+ catch (BadLocationException e)
{
- return getCorrections(Word.getWord(comp.getText(),
- index, false));
+ // TODO Auto-generated catch block
+ e.printStackTrace();
}
}
- return new ArrayList <JMenuItem>();
+ JMenuItem spellCheck =
+ new JMenuItem(
+ resources.getI18NString("plugin.spellcheck.MENU"));
+
+ ArrayList<JMenuItem> spellCheckItem =
+ new ArrayList<JMenuItem>();
+ spellCheckItem.add(spellCheck);
+ spellCheck.addActionListener(new ActionListener()
+ {
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if(dialog != null) {
+ dialog.dispose();
+ }
+ dialog =
+ new SpellCheckerConfigDialog(chat, null, dict);
+ dialog.setVisible(true);
+ }
+ });
+
+ return spellCheckItem;
}
};
}
@@ -106,6 +159,7 @@ class ChatAttachments
this.chat.addChatEditorDocumentListener(this.docListener);
this.chat.addChatEditorCaretListener(this.caretListener);
this.chat.addChatEditorMenuListener(this.menuListener);
+
}
}
@@ -119,6 +173,7 @@ class ChatAttachments
this.chat.removeChatEditorDocumentListener(this.docListener);
this.chat.removeChatEditorCaretListener(this.caretListener);
this.chat.removeChatEditorMenuListener(this.menuListener);
+
}
}
@@ -146,22 +201,23 @@ class ChatAttachments
}
// provides popup menu entries (mostly separated for readability)
- private ArrayList <JMenuItem> getCorrections(final Word clickedWord)
+ private ArrayList<JMenuItem> getCorrections(final Word clickedWord)
{
- ArrayList <JMenuItem> correctionEntries = new ArrayList <JMenuItem>();
+ ArrayList<JMenuItem> correctionEntries = new ArrayList<JMenuItem>();
synchronized (this.dict)
{
if (!this.dict.isCorrect(clickedWord.getText()))
{
- List <String> corrections =
- this.dict.getSuggestions(clickedWord.getText());
+ List<String> corrections =
+ this.dict.getSuggestions(clickedWord.getText());
for (String correction : corrections)
{
JMenuItem newEntry = new JMenuItem(correction);
newEntry.addActionListener(new CorrectionListener(
- clickedWord, correction));
+ clickedWord, correction));
correctionEntries.add(newEntry);
+
}
// entry to add word
@@ -181,16 +237,38 @@ class ChatAttachments
catch (SpellDictionaryException exc)
{
String msg =
- "Unable to add word to personal dictionary";
+ "Unable to add word to personal dictionary";
logger.error(msg, exc);
}
}
});
correctionEntries.add(addWord);
+
}
- }
+
+ JMenuItem spellCheck =
+ new JMenuItem(
+ resources.getI18NString("plugin.spellcheck.MENU"));
+ correctionEntries.add(spellCheck);
+ spellCheck.addActionListener(new ActionListener()
+ {
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if(dialog != null) {
+ dialog.dispose();
+ }
+
+ dialog =
+ new SpellCheckerConfigDialog(chat, clickedWord,
+ dict);
+ dialog.setVisible(true);
+ }
+ });
+ }
return correctionEntries;
+
}
// Applies corrections from popup menu to chat
@@ -198,6 +276,7 @@ class ChatAttachments
implements ActionListener
{
private Word clickedWord;
+
private String correction;
CorrectionListener(Word clickedWord, String correction)
@@ -209,11 +288,12 @@ class ChatAttachments
public void actionPerformed(ActionEvent event)
{
StringBuffer newMessage = new StringBuffer(chat.getMessage());
+
int endIndex =
- this.clickedWord.getStart()
- + this.clickedWord.getText().length();
+ this.clickedWord.getStart()
+ + this.clickedWord.getText().length();
newMessage.replace(this.clickedWord.getStart(), endIndex,
- this.correction);
+ this.correction);
chat.setMessage(newMessage.toString());
}
}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/DocUnderliner.java b/src/net/java/sip/communicator/plugin/spellcheck/DocUnderliner.java
index 6935b68..6ca51c0 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/DocUnderliner.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/DocUnderliner.java
@@ -1,8 +1,7 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
@@ -18,74 +17,83 @@ import net.java.sip.communicator.util.Logger;
* Notifies subclasses when words are changed and lets them decide if text
* should be underlined with a red squiggle. Text appended to the end isn't
* formatted until the word's completed.
+ *
* @author Damian Johnson
*/
abstract class DocUnderliner
implements DocumentListener
{
private static final Logger logger = Logger.getLogger(DocUnderliner.class);
+
private static final Color UNDERLINE_COLOR = new Color(255, 100, 100);
+
private static final DefaultHighlighter.DefaultHighlightPainter UNDERLINER;
+
private final Highlighter docHighlighter;
+
private final CaretListener endChecker;
+
private boolean isEnabled = true;
static
{
UNDERLINER =
- new DefaultHighlighter.DefaultHighlightPainter(UNDERLINE_COLOR)
+ new DefaultHighlighter.DefaultHighlightPainter(UNDERLINE_COLOR)
+ {
+ public Shape paintLayer(Graphics g, int offs0, int offs1,
+ Shape area, JTextComponent comp, View view)
{
- public Shape paintLayer(Graphics g, int offs0, int offs1,
- Shape area, JTextComponent comp, View view)
- {
- Color color = getColor();
- if (color == null) g.setColor(comp.getSelectionColor());
- else g.setColor(color);
+ Color color = getColor();
+ if (color == null)
+ g.setColor(comp.getSelectionColor());
+ else
+ g.setColor(color);
- if (offs0 == view.getStartOffset()
- && offs1 == view.getEndOffset())
+ if (offs0 == view.getStartOffset()
+ && offs1 == view.getEndOffset())
+ {
+ // contained in view, can just use bounds
+ drawWavyLine(g, area.getBounds());
+ return area;
+ }
+ else
+ {
+ // should only render part of View
+ try
{
- // contained in view, can just use bounds
- drawWavyLine(g, area.getBounds());
- return area;
+ Shape shape =
+ view.modelToView(offs0, Position.Bias.Forward,
+ offs1, Position.Bias.Backward, area);
+ drawWavyLine(g, shape.getBounds());
+ return shape.getBounds();
}
- else
+ catch (BadLocationException exc)
{
- // should only render part of View
- try
- {
- Shape shape =
- view.modelToView(offs0,
- Position.Bias.Forward, offs1,
- Position.Bias.Backward, area);
- drawWavyLine(g, shape.getBounds());
- return shape.getBounds();
- }
- catch (BadLocationException exc)
- {
- String msg =
- "Bad bounds (programmer error in spell checker)";
- logger.error(msg, exc);
- return area; // can't render
- }
+ String msg =
+ "Bad bounds (programmer error in spell checker)";
+ logger.error(msg, exc);
+ return area; // can't render
}
}
+ }
- private void drawWavyLine(Graphics g, Rectangle bounds)
- {
- int y = (int) (bounds.getY() + bounds.getHeight());
- int x1 = (int) bounds.getX();
- int x2 = (int) (bounds.getX() + bounds.getWidth());
+ private void drawWavyLine(Graphics g, Rectangle bounds)
+ {
+ int y = (int) (bounds.getY() + bounds.getHeight());
+ int x1 = (int) bounds.getX();
+ int x2 = (int) (bounds.getX() + bounds.getWidth());
- boolean upperCurve = true;
- for (int i = x1; i < x2 - 2; i += 3)
- {
- if (upperCurve) g.drawArc(i, y - 2, 3, 3, 0, 180);
- else g.drawArc(i, y - 2, 3, 3, 180, 180);
- upperCurve = !upperCurve;
- }
+ boolean upperCurve = true;
+ for (int i = x1; i < x2 - 2; i += 3)
+ {
+ if (upperCurve)
+ g.drawArc(i, y - 2, 3, 3, 0, 180);
+ else
+ g.drawArc(i, y - 2, 3, 3, 180, 180);
+ upperCurve = !upperCurve;
}
- };
+ }
+ };
}
{
@@ -105,7 +113,7 @@ abstract class DocUnderliner
{
String text = comp.getText();
Word changed =
- Word.getWord(text, text.length() - 1, false);
+ Word.getWord(text, text.length() - 1, false);
format(changed);
promptRepaint();
}
@@ -120,6 +128,7 @@ abstract class DocUnderliner
* Queries to see if a word should be underlined. This is called on every
* internal change and whenever a word's completed so it should be a
* lightweight process.
+ *
* @param word word to be checked
* @return true if the word should be underlined, false otherwise
*/
@@ -127,6 +136,7 @@ abstract class DocUnderliner
/**
* Provides the index of the character the cursor is in front of.
+ *
* @return index of caret
*/
abstract int getCaretPosition();
@@ -146,23 +156,23 @@ abstract class DocUnderliner
editorPane.setPreferredSize(new Dimension(400, 500));
final DocUnderliner formatter =
- new DocUnderliner(editorPane.getHighlighter())
+ new DocUnderliner(editorPane.getHighlighter())
+ {
+ boolean getFormatting(String word)
{
- boolean getFormatting(String word)
- {
- return word.contains("foo");
- }
+ return word.contains("foo");
+ }
- int getCaretPosition()
- {
- return editorPane.getCaretPosition();
- }
+ int getCaretPosition()
+ {
+ return editorPane.getCaretPosition();
+ }
- void promptRepaint()
- {
- editorPane.repaint();
- }
- };
+ void promptRepaint()
+ {
+ editorPane.repaint();
+ }
+ };
editorPane.getDocument().addDocumentListener(formatter);
editorPane.addCaretListener(formatter.getEndChecker());
@@ -178,7 +188,8 @@ abstract class DocUnderliner
public void insertUpdate(DocumentEvent event)
{
- if (!this.isEnabled) return;
+ if (!this.isEnabled)
+ return;
try
{
@@ -201,7 +212,7 @@ abstract class DocUnderliner
// new character at end (ensure it isn't initially
// underlined)
clearUnderlining(event.getOffset(),
- event.getOffset() + 1);
+ event.getOffset() + 1);
}
}
else
@@ -211,9 +222,11 @@ abstract class DocUnderliner
// change within word
Word changed;
int previousIndex = Math.max(0, event.getOffset() - 1);
- if (Character.isLetter(text.charAt(previousIndex))) changed =
+ if (Character.isLetter(text.charAt(previousIndex)))
+ changed =
Word.getWord(text, event.getOffset(), true);
- else changed =
+ else
+ changed =
Word.getWord(text, event.getOffset(), false);
format(changed);
}
@@ -221,11 +234,9 @@ abstract class DocUnderliner
{
// dividing a word - need to check both sides
Word firstWord =
- Word.getWord(text, event.getOffset(), true);
+ Word.getWord(text, event.getOffset(), true);
Word secondWord =
- Word
- .getWord(text, event.getOffset() + 1,
- false);
+ Word.getWord(text, event.getOffset() + 1, false);
format(firstWord);
format(secondWord);
}
@@ -241,9 +252,8 @@ abstract class DocUnderliner
{
format(changed);
int end =
- Math.min(changed.getStart()
- + changed.getText().length() + 1, text
- .length());
+ Math.min(changed.getStart()
+ + changed.getText().length() + 1, text.length());
changed = Word.getWord(text, end, false);
wordStart = end;
}
@@ -260,7 +270,8 @@ abstract class DocUnderliner
public void removeUpdate(DocumentEvent event)
{
- if (!this.isEnabled) return;
+ if (!this.isEnabled)
+ return;
try
{
@@ -270,8 +281,7 @@ abstract class DocUnderliner
{
Word changed;
if (event.getOffset() == 0
- || !Character.isLetter(text
- .charAt(event.getOffset() - 1)))
+ || !Character.isLetter(text.charAt(event.getOffset() - 1)))
{
changed = Word.getWord(text, event.getOffset(), false);
}
@@ -293,11 +303,13 @@ abstract class DocUnderliner
}
public void changedUpdate(DocumentEvent e)
- {}
+ {
+ }
/**
* Provides a listener that prompts the last word to be checked when the
* cursor moves away from it.
+ *
* @return listener for caret position that formats last word when
* appropriate
*/
@@ -308,24 +320,26 @@ abstract class DocUnderliner
/**
* Formats the word with the appropriate underlining (or lack thereof).
+ *
* @param word word to be formatted
*/
public void format(Word word)
{
- if (!this.isEnabled) return;
+ if (!this.isEnabled)
+ return;
String text = word.getText();
if (text.length() > 0)
{
clearUnderlining(word.getStart(), word.getStart() + text.length());
- if (getFormatting(text)) underlineRange(word.getStart(), word
- .getStart()
- + text.length());
+ if (getFormatting(text))
+ underlineRange(word.getStart(), word.getStart() + text.length());
}
}
/**
* Sets a range in the editor to be underlined.
+ *
* @param start start of range to be underlined
* @param end end of range to be underlined
*/
@@ -335,8 +349,8 @@ abstract class DocUnderliner
{
try
{
- if (this.isEnabled) this.docHighlighter.addHighlight(start,
- end, UNDERLINER);
+ if (this.isEnabled)
+ this.docHighlighter.addHighlight(start, end, UNDERLINER);
}
catch (BadLocationException exc)
{
@@ -350,6 +364,7 @@ abstract class DocUnderliner
* Clears any underlining that spans to include the given range. Since
* formatting is defined by ranges this will likely clear more than the
* defined range.
+ *
* @param start start of range in which to clear underlining
* @param end end of range in which to clear underlining
*/
@@ -361,12 +376,12 @@ abstract class DocUnderliner
if (this.isEnabled)
{
for (Highlighter.Highlight highlight : this.docHighlighter
- .getHighlights())
+ .getHighlights())
{
if ((highlight.getStartOffset() <= start && highlight
- .getEndOffset() > start)
- || (highlight.getStartOffset() < end && highlight
- .getEndOffset() >= end))
+ .getEndOffset() > start)
+ || (highlight.getStartOffset() < end && highlight
+ .getEndOffset() >= end))
{
this.docHighlighter.removeHighlight(highlight);
}
@@ -380,18 +395,23 @@ abstract class DocUnderliner
if (this.isEnabled != enable)
{
this.isEnabled = enable;
- if (this.isEnabled) reset(message);
- else this.docHighlighter.removeAllHighlights();
+ if (this.isEnabled)
+ reset(message);
+ else
+ this.docHighlighter.removeAllHighlights();
promptRepaint();
}
}
/**
* Clears underlining and re-evaluates message's contents
+ *
* @param message textual contents of document
*/
- public void reset(String message) {
- if (!this.isEnabled) return;
+ public void reset(String message)
+ {
+ if (!this.isEnabled)
+ return;
// clears previous underlined sections
this.docHighlighter.removeAllHighlights();
@@ -405,9 +425,8 @@ abstract class DocUnderliner
{
format(changed);
int end =
- Math.min(changed.getStart()
- + changed.getText().length() + 1, message
- .length());
+ Math.min(changed.getStart() + changed.getText().length()
+ + 1, message.length());
changed = Word.getWord(message, end, false);
wordStart = end;
}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/LanguageSelectionField.java b/src/net/java/sip/communicator/plugin/spellcheck/LanguageSelectionField.java
new file mode 100644
index 0000000..2986ed2
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/spellcheck/LanguageSelectionField.java
@@ -0,0 +1,508 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.spellcheck;
+
+import java.awt.*;
+import java.awt.image.*;
+
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.plugin.spellcheck.Parameters.Default;
+import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.gui.Container;
+import net.java.sip.communicator.service.protocol.Contact;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.util.swing.SwingWorker;
+
+/**
+ * Combo box providing a listing of all available locales with corresponding
+ * country flags. Selecting a new field causes that locale's dictionary to be
+ * downloaded, if not available. The spell checker then use the selected
+ * language for further checking.
+ *
+ * @author Damian Johnson
+ * @author Yana Stamcheva
+ */
+public class LanguageSelectionField
+ extends SIPCommMenuBar
+ implements PluginComponent
+{
+ private static final HashMap<SpellChecker, LanguageSelectionField>
+ CLASS_INSTANCES =
+ new HashMap<SpellChecker, LanguageSelectionField>();
+
+ // parallel maps containing cached instances of country flags
+ private static final HashMap<Parameters.Locale, ImageIcon>
+ AVAILABLE_FLAGS = new HashMap<Parameters.Locale, ImageIcon>();
+
+ private static final HashMap<Parameters.Locale, ImageIcon>
+ UNAVAILABLE_FLAGS = new HashMap<Parameters.Locale, ImageIcon>();
+
+ private static final Logger logger = Logger
+ .getLogger(LanguageSelectionField.class);
+
+ private static final ImageIcon BLANK_FLAG_ICON = Resources
+ .getImage("blankFlag");
+
+ private final ListCellRenderer languageSelectionRenderer;
+
+ private final HashMap<Parameters.Locale, Boolean> localeAvailabilityCache =
+ new HashMap<Parameters.Locale, Boolean>();
+
+ private final SpellChecker spellChecker;
+
+ private final SIPCommMenu menu = new SelectorMenu();
+
+ private final ArrayList<Parameters.Locale> localeList =
+ new ArrayList<Parameters.Locale>();
+
+ /**
+ * Provides instance of this class associated with a spell checker. If ones
+ * already been created then this instance is used.
+ *
+ * @param checker spell checker field is to be associated with
+ * @return spell checker locale selection field
+ */
+ public synchronized static LanguageSelectionField makeSelectionField(
+ SpellChecker checker)
+ {
+ // singleton constructor to ensure only one combo box is associated with
+ // each checker
+ if (CLASS_INSTANCES.containsKey(checker))
+ return CLASS_INSTANCES.get(checker);
+ else
+ {
+ LanguageSelectionField instance =
+ new LanguageSelectionField(checker);
+ CLASS_INSTANCES.put(checker, instance);
+ return instance;
+ }
+ }
+
+ private LanguageSelectionField(SpellChecker checker)
+ {
+ this.spellChecker = checker;
+
+ setPreferredSize(new Dimension(30, 28));
+ setMaximumSize(new Dimension(30, 28));
+ setMinimumSize(new Dimension(30, 28));
+
+ this.menu.setPreferredSize(new Dimension(30, 45));
+ this.menu.setMaximumSize(new Dimension(30, 45));
+
+ this.add(menu);
+
+ this.setBorder(null);
+ this.menu.add(createEnableCheckBox());
+ this.menu.addSeparator();
+ this.menu.setBorder(null);
+ this.menu.setOpaque(false);
+ this.setOpaque(false);
+
+ DefaultListModel model = new DefaultListModel();
+ final JList list = new JList(model);
+
+ this.languageSelectionRenderer = new LanguageListRenderer();
+
+ for (Parameters.Locale locale : Parameters.getLocales())
+ {
+
+ if (!localeAvailabilityCache.containsKey(locale))
+ {
+ localeAvailabilityCache.put(locale,
+ spellChecker.isLocaleAvailable(locale));
+ }
+
+ model.addElement(locale);
+ localeList.add(locale);
+ }
+
+ JScrollPane scroll = new JScrollPane(list);
+ scroll.setBorder(null);
+
+ String localeIso = Parameters.getDefault(Default.LOCALE);
+ Parameters.Locale loc = Parameters.getLocale(localeIso);
+
+ list.setCellRenderer(languageSelectionRenderer);
+ list.setSelectedIndex(localeList.indexOf(loc) + 1);
+
+ list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ list.addListSelectionListener(new ListSelectionListener()
+ {
+
+ public void valueChanged(ListSelectionEvent e)
+ {
+
+ if (!e.getValueIsAdjusting())
+ {
+ final JList source = (JList) e.getSource();
+ final Parameters.Locale locale =
+ (Parameters.Locale) source.getSelectedValue();
+
+ source.setEnabled(false);
+
+ // Indicate to the user that the language is currently
+ // loading.
+ locale.setLoading(true);
+
+ new SetSpellChecker(locale, source).start();
+ }
+ }
+ });
+
+ menu.add(scroll);
+
+ ImageIcon flagIcon =
+ getLocaleIcon(checker.getLocale(),
+ localeAvailabilityCache.get(checker.getLocale()));
+ SelectedObject selectedObject =
+ new SelectedObject(flagIcon, checker.getLocale());
+ menu.setSelected(selectedObject);
+ }
+
+ /**
+ * Clears any cached data used by the field so it reflects the current state
+ * of its associated spell checker.
+ */
+ // public void revalidate()
+ // {
+ // this.localeAvailabilityCache.clear();
+ // this.field.setSelectedItem(this.spellChecker.getLocale());
+ // }
+
+ public String getConstraints()
+ {
+ return Container.RIGHT;
+ }
+
+ public Container getContainer()
+ {
+ return Container.CONTAINER_CHAT_TOOL_BAR;
+ }
+
+ public String getName()
+ {
+ return "Spell Checker Toggle";
+ }
+
+ public int getPositionIndex()
+ {
+ return -1;
+ }
+
+ public boolean isNativeComponent()
+ {
+ return false;
+ }
+
+ public void setCurrentContact(MetaContact metaContact)
+ {
+
+ }
+
+ public void setCurrentContactGroup(MetaContactGroup metaGroup)
+ {
+
+ }
+
+ private static ImageIcon getLocaleIcon(Parameters.Locale locale,
+ boolean isAvailable)
+ {
+ if (isAvailable && AVAILABLE_FLAGS.containsKey(locale))
+ return AVAILABLE_FLAGS.get(locale);
+ else if (!isAvailable && UNAVAILABLE_FLAGS.containsKey(locale))
+ return UNAVAILABLE_FLAGS.get(locale);
+ else
+ {
+ // load resource
+ ImageIcon localeFlag;
+
+ try
+ {
+ int commaIndex = locale.getIsoCode().indexOf(",");
+ String countryCode =
+ locale.getIsoCode().substring(commaIndex + 1);
+ localeFlag = Resources.getFlagImage(countryCode);
+
+ BufferedImage flagBuffer = copy(localeFlag.getImage());
+ setFaded(flagBuffer);
+ ImageIcon unavailableLocaleFlag = new ImageIcon(flagBuffer);
+
+ AVAILABLE_FLAGS.put(locale, localeFlag);
+ UNAVAILABLE_FLAGS.put(locale, unavailableLocaleFlag);
+ return isAvailable ? localeFlag : unavailableLocaleFlag;
+ }
+ catch (IOException exc)
+ {
+ AVAILABLE_FLAGS.put(locale, BLANK_FLAG_ICON);
+ UNAVAILABLE_FLAGS.put(locale, BLANK_FLAG_ICON);
+ return BLANK_FLAG_ICON;
+ }
+ }
+ }
+
+ /**
+ * Creates a deep copy of an image.
+ *
+ * @param image picture to be processed
+ * @return copy of the image
+ */
+ private static BufferedImage copy(Image image)
+ {
+ int width = image.getWidth(null);
+ int height = image.getHeight(null);
+
+ BufferedImage copy;
+ try
+ {
+ PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
+ pg.grabPixels();
+ ColorModel cm = pg.getColorModel();
+
+ WritableRaster raster =
+ cm.createCompatibleWritableRaster(width, height);
+ boolean isRasterPremultiplied = cm.isAlphaPremultiplied();
+ copy = new BufferedImage(cm, raster, isRasterPremultiplied, null);
+ }
+ catch (InterruptedException e)
+ {
+ copy =
+ new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ Graphics2D g2 = copy.createGraphics();
+ g2.setComposite(AlphaComposite.Src); // Preserves color of
+ // transparent pixels
+ g2.drawImage(image, 0, 0, null);
+ g2.dispose();
+ return copy;
+ }
+
+ /**
+ * Removes all color from an image and makes it partly translucent. Original
+ * grayscale method written by Marty Stepp.
+ *
+ * @param image picture to be processed
+ */
+ private static void setFaded(BufferedImage image)
+ {
+ int width = image.getWidth();
+ int height = image.getHeight();
+
+ for (int row = 0; row < width; ++row)
+ {
+ for (int col = 0; col < height; ++col)
+ {
+ int c = image.getRGB(row, col);
+
+ int r =
+ (((c >> 16) & 0xff) + ((c >> 8) & 0xff) + (c & 0xff)) / 3;
+
+ int newRgb = (0xff << 24) | (r << 16) | (r << 8) | r;
+ newRgb &= (1 << 24) - 1; // Blanks alpha value
+ newRgb |= 128 << 24; // Resets it to the alpha of 128
+ image.setRGB(row, col, newRgb);
+ }
+ }
+ }
+
+ public void setCurrentContact(Contact contact)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ private class SelectorMenu
+ extends SIPCommMenu
+ {
+ Image image = Resources.getImage("service.gui.icons.DOWN_ARROW_ICON")
+ .getImage();
+
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ g.drawImage(image, getWidth() - image.getWidth(this) - 1,
+ (getHeight() - image.getHeight(this) - 1) / 2, this);
+ }
+ }
+
+ /**
+ * Returns the enable spell check checkbox.
+ *
+ * @return the created checkbox
+ */
+ private JCheckBox createEnableCheckBox()
+ {
+ final JCheckBox checkBox = new SIPCommCheckBox(
+ Resources.getString("plugin.spellcheck.ENABLE_SPELL_CHECK"));
+
+ checkBox.setSelected(spellChecker.isEnabled());
+ checkBox.setIconTextGap(0);
+ checkBox.addChangeListener(new ChangeListener()
+ {
+ public void stateChanged(ChangeEvent evt)
+ {
+ spellChecker.setEnabled(checkBox.isSelected());
+ }
+ });
+
+ return checkBox;
+ }
+
+ private class SetSpellChecker extends SwingWorker
+ {
+ private final Parameters.Locale locale;
+
+ private final JList sourceList;
+
+ private boolean skipFiring = false;
+
+ public SetSpellChecker( Parameters.Locale locale,
+ JList sourceList)
+ {
+ this.locale = locale;
+ this.sourceList = sourceList;
+ }
+
+ /**
+ * Called on the event dispatching thread (not on the worker thread)
+ * after the <code>construct</code> method has returned.
+ */
+ public void finished()
+ {
+ if (getValue() != null)
+ {
+ sourceList.setEnabled(true);
+
+ localeAvailabilityCache.put(locale, true);
+
+ ImageIcon flagIcon = getLocaleIcon(locale,
+ localeAvailabilityCache.get(locale));
+
+ SelectedObject selectedObject =
+ new SelectedObject(flagIcon, locale);
+
+ menu.setSelected(selectedObject);
+ }
+ else
+ {
+ // reverts selection
+ skipFiring = true;
+
+ // source.setSelectedItem(spellChecker.getLocale());
+ ImageIcon flagIcon =
+ getLocaleIcon(locale,
+ localeAvailabilityCache.get(locale));
+
+ SelectedObject selectedObject =
+ new SelectedObject(flagIcon, locale);
+
+ menu.setSelected(selectedObject);
+
+ skipFiring = false;
+
+ sourceList.setEnabled(true);
+ }
+
+ // Indicate to the user that the language is currently
+ // loading.
+ locale.setLoading(false);
+ }
+
+ /**
+ * Download the dictionary.
+ */
+ public Object construct() throws Exception
+ {
+ try
+ {
+ // prevents potential infinite loop during errors
+ if (this.skipFiring)
+ return null;
+
+ spellChecker.setLocale(locale);
+
+ return locale;
+ }
+ catch (Exception exc)
+ {
+ logger.warn(
+ "Unable to retrieve dictionary for " + locale, exc);
+
+ // warns that it didn't work
+ PopupDialog dialog =
+ SpellCheckActivator.getUIService()
+ .getPopupDialog();
+ String message
+ = Resources.getString(
+ "plugin.spellcheck.DICT_ERROR");
+ if (exc instanceof IOException)
+ {
+ message = Resources.getString(
+ "plugin.spellcheck.DICT_RETRIEVE_ERROR")
+ + ":\n" + locale.getDictUrl();
+ }
+ else if (exc instanceof IllegalArgumentException)
+ {
+ message = Resources.getString(
+ "plugin.spellcheck.DICT_PROCESS_ERROR");
+ }
+
+ dialog.showMessagePopupDialog(
+ message,
+ Resources
+ .getString("plugin.spellcheck.DICT_ERROR_TITLE"),
+ PopupDialog.WARNING_MESSAGE);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * A custom renderer for languages list, transforming a Locale to a row
+ * with an icon and text.
+ */
+ private class LanguageListRenderer
+ extends DefaultListCellRenderer
+ {
+ public Component getListCellRendererComponent(JList list,
+ Object value, int index, boolean isSelected,
+ boolean cellHasFocus)
+ {
+ Parameters.Locale locale = (Parameters.Locale) value;
+
+ if (!localeAvailabilityCache.containsKey(locale))
+ {
+ localeAvailabilityCache.put(locale,
+ spellChecker.isLocaleAvailable(locale));
+ }
+
+ ImageIcon flagIcon =
+ getLocaleIcon(locale, localeAvailabilityCache.get(locale));
+
+ String localeLabel = locale.getLabel();
+
+ if (locale.isLoading())
+ setText("<html>" + localeLabel
+ + " <font color='gray'><i>loading...</i></font><html>");
+ else
+ setText(localeLabel);
+
+ setIcon(flagIcon);
+
+ return this;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/Parameters.java b/src/net/java/sip/communicator/plugin/spellcheck/Parameters.java
index 7c3db38..2dd458a 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/Parameters.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/Parameters.java
@@ -1,8 +1,7 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
@@ -20,27 +19,32 @@ import org.xml.sax.SAXException;
/**
* Information provided via the spellchecer's xml parameters.
- *
+ *
* @author Damian Johnson
*/
class Parameters
{
private static final Logger logger = Logger.getLogger(Parameters.class);
- private static final String RESOURCE_LOC
- = "/resources/config/spellcheck/parameters.xml";
+ private static final String RESOURCE_LOC =
+ "resources/config/spellcheck/parameters.xml";
+
private static final String NODE_DEFAULTS = "defaults";
+
private static final String NODE_LOCALES = "locales";
- private static final HashMap <Default, String> DEFAULTS
- = new HashMap <Default, String>();
- private static final ArrayList <Locale> LOCALES = new ArrayList <Locale>();
+
+ private static final HashMap<Default, String> DEFAULTS =
+ new HashMap<Default, String>();
+
+ private static final ArrayList<Locale> LOCALES = new ArrayList<Locale>();
static
{
try
{
- URL url = SpellCheckActivator.bundleContext
- .getBundle().getResource(RESOURCE_LOC);
+ URL url =
+ SpellCheckActivator.bundleContext.getBundle().getResource(
+ RESOURCE_LOC);
InputStream stream = url.openStream();
@@ -48,10 +52,10 @@ class Parameters
throw new IOException();
// strict parsing options
- DocumentBuilderFactory factory
- = DocumentBuilderFactory.newInstance();
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
- factory.setValidating(true);
+ factory.setValidating(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
@@ -103,7 +107,7 @@ class Parameters
/**
* Retrieves default values from xml.
- *
+ *
* @param list the configuration list
*/
private static void parseDefaults(NodeList list)
@@ -128,6 +132,7 @@ class Parameters
/**
* Populates LOCALES list with contents of xml.
+ *
* @param list the configuration list
*/
private static void parseLocales(NodeList list)
@@ -138,10 +143,9 @@ class Parameters
NamedNodeMap attributes = node.getAttributes();
String label = ((Attr) attributes.getNamedItem("label")).getValue();
String code =
- ((Attr) attributes.getNamedItem("isoCode")).getValue();
+ ((Attr) attributes.getNamedItem("isoCode")).getValue();
String dictLocation =
- ((Attr) attributes.getNamedItem("dictionaryUrl"))
- .getValue();
+ ((Attr) attributes.getNamedItem("dictionaryUrl")).getValue();
try
{
LOCALES.add(new Locale(label, code, new URL(dictLocation)));
@@ -149,13 +153,14 @@ class Parameters
catch (MalformedURLException exc)
{
logger.warn("Unable to parse dictionary location of " + label
- + " (" + dictLocation + ")", exc);
+ + " (" + dictLocation + ")", exc);
}
}
}
/**
* Provides the value of a particular default field, null if undefined.
+ *
* @param field default field to retrieve
* @return value corresponding to default field
*/
@@ -166,6 +171,7 @@ class Parameters
/**
* Provides locale with a given iso code. Null if undefined.
+ *
* @param isoCode iso code of locale to be retrieved
* @return locale with corresponding iso code
*/
@@ -173,7 +179,8 @@ class Parameters
{
for (Locale locale : LOCALES)
{
- if (locale.getIsoCode().equals(isoCode)) return locale;
+ if (locale.getIsoCode().equals(isoCode))
+ return locale;
}
return null;
@@ -181,11 +188,12 @@ class Parameters
/**
* Provides locales in which dictionary resources are available.
+ *
* @return locations with dictionary resources
*/
- public static ArrayList <Locale> getLocales()
+ public static ArrayList<Locale> getLocales()
{
- return new ArrayList <Locale>(LOCALES);
+ return new ArrayList<Locale>(LOCALES);
}
/**
@@ -194,9 +202,13 @@ class Parameters
public static class Locale
{
private final String label;
+
private final String isoCode;
+
private final URL dictLocation;
+ private boolean isLoading = false;
+
private Locale(String label, String isoCode, URL dictLocation)
{
this.label = label;
@@ -206,6 +218,7 @@ class Parameters
/**
* Provides user readable name of language.
+ *
* @return name of language presented to user
*/
public String getLabel()
@@ -216,6 +229,7 @@ class Parameters
/**
* Provides ISO code as defined by:<br />
* http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
+ *
* @return iso code
*/
public String getIsoCode()
@@ -226,6 +240,7 @@ class Parameters
/**
* Provides the url where the dictionary resource can be found for this
* language.
+ *
* @return url of dictionary resource
*/
public URL getDictUrl()
@@ -233,6 +248,29 @@ class Parameters
return this.dictLocation;
}
+ /**
+ * Sets the loading property. Indicates if this locale is currently
+ * loaded in the list.
+ *
+ * @param loading indicates if this locale is currently loading in the
+ * locales list
+ */
+ public void setLoading(boolean loading)
+ {
+ this.isLoading = loading;
+ }
+
+ /**
+ * Indicates if this locale is currenly loading in the list of locales.
+ *
+ * @return <tt>true</tt> if the locale is loading, <tt>false</tt> -
+ * otherwise
+ */
+ public boolean isLoading()
+ {
+ return isLoading;
+ }
+
@Override
public String toString()
{
@@ -256,6 +294,7 @@ class Parameters
/**
* Returns the enum representation of a string. This is case sensitive.
+ *
* @param str toString representation of a default field
* @return default field associated with a string
* @throws IllegalArgumentException if argument is not represented by a
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/Resources.java b/src/net/java/sip/communicator/plugin/spellcheck/Resources.java
index 61da50e..e7a5cc2 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/Resources.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/Resources.java
@@ -1,8 +1,7 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
@@ -20,7 +19,7 @@ import org.osgi.framework.*;
/**
* The <tt>Resources</tt> class manages the access to the internationalization
* properties files and the image resources used in this plugin.
- *
+ *
* @author Damian Johnson
* @author Yana Stamcheva
*/
@@ -34,40 +33,38 @@ public class Resources
* Location of flag resources.
*/
private static final String FLAG_PATH =
- "resources/images/plugin/spellchecker/flags/";
+ "resources/images/plugin/spellcheck/flags/";
/**
* The spell check plugin icon, shown in the configuration form.
*/
- public static final String PLUGIN_ICON
- = "plugin.spellcheck.PLUGIN_ICON";
+ public static final String PLUGIN_ICON = "plugin.spellcheck.PLUGIN_ICON";
/**
* The add word icon.
*/
- public static final String ADD_WORD_ICON
- = "plugin.spellcheck.ADD_WORD_ICON";
+ public static final String ADD_WORD_ICON =
+ "plugin.spellcheck.ADD_WORD_ICON";
/**
* The personal dictionary icon.
*/
- public static final String PERSONAL_DICTIONARY
- = "plugin.spellcheck.PERSONAL_DIR";
+ public static final String PERSONAL_DICTIONARY =
+ "plugin.spellcheck.PERSONAL_DIR";
/**
* The word include icon.
*/
- public static final String WORD_INCLUDE
- = "plugin.spellcheck.WORD_INCLUDE";
+ public static final String WORD_INCLUDE = "plugin.spellcheck.WORD_INCLUDE";
/**
* The word exclude icon.
*/
- public static final String WORD_EXCLUDE
- = "plugin.spellcheck.WORD_EXCLUDE";
+ public static final String WORD_EXCLUDE = "plugin.spellcheck.WORD_EXCLUDE";
/**
* Returns an internationalized string corresponding to the given key.
+ *
* @param key The key of the string.
* @return An internationalized string corresponding to the given key.
*/
@@ -78,6 +75,7 @@ public class Resources
/**
* Loads an image from a given image identifier.
+ *
* @param imageID The identifier of the image.
* @return The image for the given identifier.
*/
@@ -88,7 +86,7 @@ public class Resources
/**
* Loads a flag image from a given image identifier.
- *
+ *
* @param resource iso code for flag to be retrieved.
* @return icon reflecting iso code
* @throws IOException if no such resource is available
@@ -108,6 +106,7 @@ public class Resources
/**
* Loads an image from a given image identifier.
+ *
* @param imageID The identifier of the image.
* @return The image for the given identifier.
*/
@@ -119,21 +118,21 @@ public class Resources
/**
* Returns the <tt>ResourceManagementService</tt> through which we obtain
* resources like images and localized texts.
- *
+ *
* @return the <tt>ResourceManagementService</tt>
*/
- private static ResourceManagementService getResources()
+ public static ResourceManagementService getResources()
{
if (resourceService != null)
return resourceService;
- ServiceReference configServiceRef
- = SpellCheckActivator.bundleContext.getServiceReference(
- ResourceManagementService.class.getName());
+ ServiceReference configServiceRef =
+ SpellCheckActivator.bundleContext
+ .getServiceReference(ResourceManagementService.class.getName());
- resourceService
- = (ResourceManagementService) SpellCheckActivator.bundleContext
- .getService(configServiceRef);
+ resourceService =
+ (ResourceManagementService) SpellCheckActivator.bundleContext
+ .getService(configServiceRef);
return resourceService;
}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckActivator.java b/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckActivator.java
index dd0b414..f4427b8 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckActivator.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckActivator.java
@@ -1,11 +1,12 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
+import java.util.*;
+
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.fileaccess.*;
import net.java.sip.communicator.service.gui.*;
@@ -14,7 +15,7 @@ import org.osgi.framework.*;
/**
* Enabling and disabling osgi functionality for the spell checker.
- *
+ *
* @author Damian Johnson
*/
public class SpellCheckActivator
@@ -32,38 +33,30 @@ public class SpellCheckActivator
/**
* Called when this bundle is started.
+ *
* @param context The execution context of the bundle being started.
*/
public void start(BundleContext context) throws Exception
{
bundleContext = context;
-// Disables spell checker until we fix also the configuration form in
-// order to be able to change the language.
-//
-// this.checker.start(context);
-
-// SpellCheckerConfigForm checkerManager =
-// new SpellCheckerConfigForm(this.checker);
-// context.registerService(ConfigurationForm.class.getName(),
-// checkerManager, null);
-//
-// // adds button to toggle spell checker
-// Hashtable <String, String> containerFilter =
-// new Hashtable <String, String>();
-// containerFilter.put(Container.CONTAINER_ID,
-// Container.CONTAINER_CHAT_TOOL_BAR.getID());
-// context.registerService(PluginComponent.class.getName(),
-// new CheckerToggleButton(this.checker), containerFilter);
-//
-// // adds field to change language
-// context.registerService(PluginComponent.class.getName(),
-// LanguageSelectionField.makeSelectionField(this.checker),
-// containerFilter);
+ this.checker.start(context);
+
+ // adds button to toggle spell checker
+ Hashtable<String, String> containerFilter =
+ new Hashtable<String, String>();
+ containerFilter.put(Container.CONTAINER_ID,
+ Container.CONTAINER_CHAT_TOOL_BAR.getID());
+
+ // adds field to change language
+ context.registerService(PluginComponent.class.getName(),
+ LanguageSelectionField.makeSelectionField(this.checker),
+ containerFilter);
}
/**
* Returns the <tt>UIService</tt>.
+ *
* @return the <tt>UIService</tt>
*/
public static UIService getUIService()
@@ -72,8 +65,8 @@ public class SpellCheckActivator
return uiService;
// retrieves needed services
- ServiceReference uiServiceRef
- = bundleContext.getServiceReference(UIService.class.getName());
+ ServiceReference uiServiceRef =
+ bundleContext.getServiceReference(UIService.class.getName());
uiService = (UIService) bundleContext.getService(uiServiceRef);
@@ -82,6 +75,7 @@ public class SpellCheckActivator
/**
* Returns the <tt>FileAccessService</tt>.
+ *
* @return the <tt>FileAccessService</tt>
*/
public static FileAccessService getFileAccessService()
@@ -89,17 +83,18 @@ public class SpellCheckActivator
if (faService != null)
return faService;
- ServiceReference faServiceReference
- = bundleContext.getServiceReference(
- FileAccessService.class.getName());
- faService
- = (FileAccessService) bundleContext.getService(faServiceReference);
+ ServiceReference faServiceReference =
+ bundleContext
+ .getServiceReference(FileAccessService.class.getName());
+ faService =
+ (FileAccessService) bundleContext.getService(faServiceReference);
return faService;
}
/**
* Returns the <tt>ConfigurationService</tt>.
+ *
* @return the <tt>ConfigurationService</tt>
*/
public static ConfigurationService getConfigService()
@@ -107,12 +102,12 @@ public class SpellCheckActivator
if (configService != null)
return configService;
- ServiceReference configServiceRef
- = bundleContext.getServiceReference(
- ConfigurationService.class.getName());
+ ServiceReference configServiceRef =
+ bundleContext.getServiceReference(ConfigurationService.class
+ .getName());
- configService = (ConfigurationService) bundleContext
- .getService(configServiceRef);
+ configService =
+ (ConfigurationService) bundleContext.getService(configServiceRef);
return configService;
}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/SpellChecker.java b/src/net/java/sip/communicator/plugin/spellcheck/SpellChecker.java
index 8138806..24f253e 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/SpellChecker.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/SpellChecker.java
@@ -1,8 +1,7 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
@@ -22,7 +21,7 @@ import org.osgi.framework.*;
* Model for spell checking capabilities. This allows for the on-demand
* retrieval of dictionaries in other languages which are cached with the user's
* configurations.
- *
+ *
* @author Damian Johnson
*/
class SpellChecker
@@ -30,12 +29,12 @@ class SpellChecker
{
private static final Logger logger = Logger.getLogger(SpellChecker.class);
- private static final String LOCALE_CONFIG_PARAM
- = "net.java.sip.communicator.plugin.spellchecker.LOCALE";
+ private static final String LOCALE_CONFIG_PARAM =
+ "net.java.sip.communicator.plugin.spellchecker.LOCALE";
// default bundled dictionary
- private static final String DEFAULT_DICT_PATH
- = "/resources/config/spellcheck/en_US.zip";
+ private static final String DEFAULT_DICT_PATH =
+ "/resources/config/spellcheck/";
// location where dictionaries are stored
private static final String DICT_DIR = "spellingDictionaries/";
@@ -50,24 +49,29 @@ class SpellChecker
* will cause an internal NullPointerException in the spell checker.
*/
private File personalDictLocation;
+
private File dictLocation;
+
private SpellDictionary dict;
+
private Parameters.Locale locale; // dictionary locale
// chat instances the spell checker is currently attached to
- private ArrayList <ChatAttachments> attachedChats =
- new ArrayList <ChatAttachments>();
+ private ArrayList<ChatAttachments> attachedChats =
+ new ArrayList<ChatAttachments>();
+
private boolean isEnabled = true;
/**
* Associates spell checking capabilities with all chats. This doesn't do
* anything if this is already running.
+ *
* @param bc execution context of the bundle
*/
synchronized void start(BundleContext bc) throws Exception
{
- FileAccessService faService
- = SpellCheckActivator.getFileAccessService();
+ FileAccessService faService =
+ SpellCheckActivator.getFileAccessService();
// checks if DICT_DIR exists to see if this is the first run
File dictionaryDir = faService.getPrivatePersistentFile(DICT_DIR);
@@ -76,33 +80,44 @@ class SpellChecker
{
dictionaryDir.mkdir();
- // copy default dictionary so it doesn't need to be downloaded
- URL dictURL = SpellCheckActivator.bundleContext
- .getBundle().getResource(DEFAULT_DICT_PATH);
+ // copy default dictionaries so they don't need to be downloaded
+ @SuppressWarnings ("unchecked")
+ Enumeration<URL> dictUrls
+ = SpellCheckActivator.bundleContext.getBundle()
+ .findEntries(DEFAULT_DICT_PATH,
+ "*.zip",
+ false);
- if (dictURL != null)
+ if (dictUrls != null)
{
- InputStream source = dictURL.openStream();
+ while (dictUrls.hasMoreElements())
+ {
+ URL dictUrl = dictUrls.nextElement();
- int filenameStart = DEFAULT_DICT_PATH.lastIndexOf('/') + 1;
- String filename = DEFAULT_DICT_PATH.substring(filenameStart);
- File dictLocation
- = faService.getPrivatePersistentFile(DICT_DIR + filename);
- copyDictionary(source, dictLocation);
+ InputStream source = dictUrl.openStream();
+
+ int filenameStart = dictUrl.getPath().lastIndexOf('/') + 1;
+ String filename = dictUrl.getPath().substring(filenameStart);
+
+ File dictLocation =
+ faService.getPrivatePersistentFile(DICT_DIR + filename);
+
+ copyDictionary(source, dictLocation);
+ }
}
}
// gets resource for personal dictionary
- this.personalDictLocation
- = faService.getPrivatePersistentFile(DICT_DIR + PERSONAL_DICT_NAME);
+ this.personalDictLocation =
+ faService.getPrivatePersistentFile(DICT_DIR + PERSONAL_DICT_NAME);
if (!personalDictLocation.exists())
personalDictLocation.createNewFile();
// gets dictionary locale
- String localeIso
- = SpellCheckActivator.getConfigService()
- .getString(LOCALE_CONFIG_PARAM);
+ String localeIso =
+ SpellCheckActivator.getConfigService().getString(
+ LOCALE_CONFIG_PARAM);
if (localeIso == null)
{
@@ -114,8 +129,9 @@ class SpellChecker
}
Parameters.Locale tmp = Parameters.getLocale(localeIso);
- if (tmp == null) throw new Exception(
- "No dictionary resources defined for locale: " + localeIso);
+ if (tmp == null)
+ throw new Exception("No dictionary resources defined for locale: "
+ + localeIso);
this.locale = tmp; // needed for synchronization lock
setLocale(tmp); // initializes dictionary and saves locale config
@@ -169,18 +185,19 @@ class SpellChecker
/**
* Provides the user's list of words to be ignored by the spell checker.
+ *
* @return user's word list
*/
- ArrayList <String> getPersonalWords()
+ ArrayList<String> getPersonalWords()
{
synchronized (this.personalDictLocation)
{
try
{
// Retrieves contents of the custom dictionary
- ArrayList <String> customWords = new ArrayList <String>();
+ ArrayList<String> customWords = new ArrayList<String>();
Scanner customDictScanner =
- new Scanner(this.personalDictLocation);
+ new Scanner(this.personalDictLocation);
while (customDictScanner.hasNextLine())
{
customWords.add(customDictScanner.nextLine());
@@ -191,7 +208,7 @@ class SpellChecker
catch (FileNotFoundException exc)
{
logger.error("Unable to read custom dictionary", exc);
- return new ArrayList <String>();
+ return new ArrayList<String>();
}
}
}
@@ -199,9 +216,10 @@ class SpellChecker
/**
* Writes custom dictionary and updates spell checker to utilize new
* listing.
+ *
* @param words words to be ignored by the spell checker
*/
- void setPersonalWords(List <String> words)
+ void setPersonalWords(List<String> words)
{
synchronized (this.personalDictLocation)
{
@@ -209,8 +227,8 @@ class SpellChecker
{
// writes new word list
BufferedWriter writer =
- new BufferedWriter(new FileWriter(
- this.personalDictLocation));
+ new BufferedWriter(
+ new FileWriter(this.personalDictLocation));
for (String customWord : words)
{
@@ -224,10 +242,10 @@ class SpellChecker
synchronized (this.attachedChats)
{
InputStream dictInput =
- new FileInputStream(this.dictLocation);
+ new FileInputStream(this.dictLocation);
this.dict =
- new OpenOfficeSpellDictionary(dictInput,
- this.personalDictLocation);
+ new OpenOfficeSpellDictionary(dictInput,
+ this.personalDictLocation);
// updates chats
for (ChatAttachments chat : this.attachedChats)
@@ -239,7 +257,7 @@ class SpellChecker
catch (IOException exc)
{
logger.error("Unable to access personal spelling dictionary",
- exc);
+ exc);
}
}
}
@@ -247,6 +265,7 @@ class SpellChecker
/**
* Provides the locale of the dictionary currently being used by the spell
* checker.
+ *
* @return locale of current dictionary
*/
Parameters.Locale getLocale()
@@ -261,6 +280,7 @@ class SpellChecker
* Resets spell checker to use a different locale's dictionary. This uses
* the local copy of the dictionary if available, otherwise it's downloaded
* and saved for future use.
+ *
* @param locale locale of dictionary to be used
* @throws Exception problem occurring in utilizing locale's dictionary
*/
@@ -273,31 +293,30 @@ class SpellChecker
int filenameStart = path.lastIndexOf('/') + 1;
String filename = path.substring(filenameStart);
- File dictLocation
- = SpellCheckActivator.getFileAccessService()
+ File dictLocation =
+ SpellCheckActivator.getFileAccessService()
.getPrivatePersistentFile(DICT_DIR + filename);
// downloads dictionary if unavailable (not cached)
if (!dictLocation.exists())
- copyDictionary(locale.getDictUrl()
- .openStream(), dictLocation);
+ copyDictionary(locale.getDictUrl().openStream(), dictLocation);
// resets dictionary being used to include changes
synchronized (this.attachedChats)
{
InputStream dictInput = new FileInputStream(dictLocation);
- SpellDictionary dict
- = new OpenOfficeSpellDictionary(dictInput,
- this.personalDictLocation);
+ SpellDictionary dict =
+ new OpenOfficeSpellDictionary(dictInput,
+ this.personalDictLocation);
this.dict = dict;
this.dictLocation = dictLocation;
this.locale = locale;
// saves locale choice to configuration properties
- SpellCheckActivator.getConfigService()
- .setProperty(LOCALE_CONFIG_PARAM, locale.getIsoCode());
+ SpellCheckActivator.getConfigService().setProperty(
+ LOCALE_CONFIG_PARAM, locale.getIsoCode());
// updates chats
for (ChatAttachments chat : this.attachedChats)
@@ -310,6 +329,7 @@ class SpellChecker
/**
* Determines if locale's dictionary is locally available or not.
+ *
* @param locale locale to be checked
* @return true if local resources for dictionary are available and
* accessible, false otherwise
@@ -321,8 +341,8 @@ class SpellChecker
String filename = path.substring(filenameStart);
try
{
- File dictLocation
- = SpellCheckActivator.getFileAccessService()
+ File dictLocation =
+ SpellCheckActivator.getFileAccessService()
.getPrivatePersistentFile(DICT_DIR + filename);
return dictLocation.exists();
@@ -358,7 +378,8 @@ class SpellChecker
// copies dictionary to appropriate location, closing the stream afterward
private void copyDictionary(InputStream input, File dest)
- throws IOException, FileNotFoundException
+ throws IOException,
+ FileNotFoundException
{
byte[] buf = new byte[1024];
FileOutputStream output = new FileOutputStream(dest);
@@ -377,6 +398,7 @@ class SpellChecker
* Determines if spell checker dictionary works. Backend API often fails
* when used so this tests that the current dictionary is able to process
* words.
+ *
* @return true if current dictionary can check words, false otherwise
*/
private boolean isDictionaryValid(SpellDictionary dict)
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java b/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java
new file mode 100644
index 0000000..266be20
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java
@@ -0,0 +1,411 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.spellcheck;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+import org.dts.spell.dictionary.*;
+
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.Logger;
+import net.java.sip.communicator.util.swing.*;
+
+/**
+ * The spell check dialog that would be opened from the right click menu in the
+ * chat window.
+ *
+ * @author Purvesh Sahoo
+ */
+public class SpellCheckerConfigDialog
+ extends SIPCommDialog
+ implements ActionListener
+{
+ private static final Logger logger = Logger
+ .getLogger(SpellCheckerConfigDialog.class);
+
+ /**
+ * UI Components
+ */
+ private JTextComponent currentWord;
+
+ private JList suggestionList;
+
+ private JScrollPane suggestionScroll;
+
+ private JButton changeButton;
+
+ private JButton nextButton;
+
+ private JButton addButton;
+
+ private JPanel checkPanel;
+
+ private JPanel buttonsPanel;
+
+ private JPanel topPanel;
+
+ private JPanel suggestionPanel;
+
+ private SpellDictionary dict;
+
+ private Chat chat;
+
+ private final ResourceManagementService resources = Resources
+ .getResources();
+
+ private String word;
+
+ private int index;
+
+ private Word clickedWord;
+
+ public SpellCheckerConfigDialog(Chat chat, Word clickedWord,
+ SpellDictionary dict)
+ {
+
+ super(false);
+
+ this.dict = dict;
+ this.chat = chat;
+
+ initComponents(clickedWord);
+
+ this.setTitle(resources.getI18NString("plugin.spellcheck.TITLE"));
+ this.setMinimumSize(new Dimension(450, 320));
+ this.setPreferredSize(new Dimension(450, 320));
+ this.setResizable(false);
+
+ JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
+ mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+ mainPanel.add(topPanel);
+
+ this.getContentPane().add(mainPanel);
+
+ this.pack();
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Dimension screenSize = toolkit.getScreenSize();
+
+ int x = (screenSize.width - this.getWidth()) / 2;
+ int y = (screenSize.height - this.getHeight()) / 2;
+
+ this.setLocation(x, y);
+
+ if (!currentWord.getText().equals(" ")
+ && this.dict.isCorrect(currentWord.getText()))
+ {
+ nextButton.doClick();
+ }
+ }
+
+ /**
+ * Initialises the UI components.
+ */
+ private void initComponents(final Word clickWord)
+ {
+
+ clickedWord =
+ (clickWord == null) ? Word.getWord(" ", 1, false) : clickWord;
+
+ topPanel = new TransparentPanel(new BorderLayout());
+ topPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
+ topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS));
+
+ checkPanel = new TransparentPanel(new BorderLayout(10, 10));
+ checkPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
+ checkPanel.setLayout(new BoxLayout(checkPanel, BoxLayout.X_AXIS));
+
+ currentWord = new JTextField(clickedWord.getText());
+
+ currentWord.setAlignmentX(LEFT_ALIGNMENT);
+ currentWord.setMaximumSize(new Dimension(550, 30));
+
+ currentWord.setText(clickedWord.getText());
+ currentWord.selectAll();
+
+ // JPanel wordPanel = new TransparentPanel(new BorderLayout());
+ // wordPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
+ // wordPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 5));
+ // wordPanel.add(currentWord);
+
+ buttonsPanel =
+ new TransparentPanel(new FlowLayout(FlowLayout.RIGHT, 0, 10));
+ changeButton =
+ new JButton(
+ resources.getI18NString("plugin.spellcheck.dialog.REPLACE"));
+ changeButton.setMnemonic(resources
+ .getI18nMnemonic("plugin.spellcheck.dialog.REPLACE"));
+
+ changeButton.addActionListener(new ActionListener()
+ {
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if (suggestionList.getSelectedValue() != null)
+ {
+
+ StringBuffer newMessage =
+ new StringBuffer(chat.getMessage());
+ int endIndex;
+
+ if (word != null)
+ {
+ endIndex = index + currentWord.getText().length();
+ newMessage.replace(index, endIndex,
+ (String) suggestionList.getSelectedValue());
+ word = (String) suggestionList.getSelectedValue();
+ }
+ else
+ {
+ endIndex =
+ clickedWord.getStart()
+ + clickedWord.getText().length();
+ newMessage.replace(clickedWord.getStart(), endIndex,
+ (String) suggestionList.getSelectedValue());
+ }
+ currentWord.setText((String) suggestionList
+ .getSelectedValue());
+ chat.setMessage(newMessage.toString());
+
+ }
+ }
+ });
+ changeButton.setEnabled(false);
+
+ nextButton =
+ new JButton(
+ resources.getI18NString("plugin.spellcheck.dialog.FIND"));
+ nextButton.setMnemonic(resources
+ .getI18nMnemonic("plugin.spellcheck.dialog.FIND"));
+
+ nextButton.addActionListener(new ActionListener()
+ {
+
+ public Word getNextWord()
+ {
+
+ Word nextWord;
+ int wordIndex;
+
+ if (word == null)
+ {
+ if (currentWord.getText().equals(" "))
+ {
+ String words[] = chat.getMessage().split(" ");
+ currentWord.setText(words[0]);
+
+ }
+
+ wordIndex =
+ chat.getMessage().indexOf(currentWord.getText());
+ if (dict.isCorrect(currentWord.getText()))
+ currentWord.setText("");
+ }
+ else
+ {
+ wordIndex = chat.getMessage().indexOf(word, index);
+ }
+
+ Word presentWord =
+ Word.getWord(chat.getMessage(), wordIndex, false);
+
+ if (presentWord.getEnd() == chat.getMessage().length())
+ {
+ nextWord = Word.getWord(chat.getMessage(), 1, false);
+
+ }
+ else
+ {
+ nextWord =
+ Word.getWord(chat.getMessage(),
+ presentWord.getEnd() + 1, false);
+ }
+
+ index = nextWord.getStart();
+ word = nextWord.getText();
+
+ return nextWord;
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ Word nextWord = getNextWord();
+ int breakIndex = nextWord.getStart();
+
+ while (dict.isCorrect(nextWord.getText())
+ && nextWord.getEnd() + 1 != breakIndex)
+ {
+ nextWord = getNextWord();
+
+ }
+
+ if (!dict.isCorrect(nextWord.getText()))
+ {
+ word = nextWord.getText();
+ currentWord.setText(nextWord.getText());
+
+ String clickedWord = currentWord.getText();
+ setSuggestionModel(clickedWord);
+ }
+
+ }
+ });
+
+ buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.Y_AXIS));
+ buttonsPanel.add(changeButton);
+ buttonsPanel.add(nextButton);
+
+ checkPanel.add(currentWord, BorderLayout.NORTH);
+ checkPanel.add(Box.createHorizontalStrut(10));
+ checkPanel.add(buttonsPanel, BorderLayout.EAST);
+
+ topPanel.add(checkPanel, BorderLayout.NORTH);
+ topPanel.add(Box.createVerticalStrut(10));
+
+ DefaultListModel dataModel = new DefaultListModel();
+ suggestionList = new JList(dataModel);
+
+ suggestionScroll = new JScrollPane(suggestionList);
+ suggestionScroll.setAlignmentX(LEFT_ALIGNMENT);
+
+ if (!dict.isCorrect(clickedWord.getText()))
+ setSuggestionModel(clickedWord.getText());
+
+ suggestionList.addListSelectionListener(new ListSelectionListener()
+ {
+
+ public void valueChanged(ListSelectionEvent e)
+ {
+
+ if (!e.getValueIsAdjusting())
+ {
+ changeButton.setEnabled(true);
+ }
+ }
+ });
+
+ MouseListener clickListener = new MouseAdapter()
+ {
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() == 2)
+ {
+
+ StringBuffer newMessage =
+ new StringBuffer(chat.getMessage());
+ int endIndex;
+
+ if (word != null)
+ {
+ endIndex = index + currentWord.getText().length();
+ newMessage.replace(index, endIndex,
+ (String) suggestionList.getSelectedValue());
+ word = (String) suggestionList.getSelectedValue();
+ }
+ else
+ {
+ endIndex =
+ clickedWord.getStart()
+ + clickedWord.getText().length();
+ newMessage.replace(clickedWord.getStart(), endIndex,
+ (String) suggestionList.getSelectedValue());
+ }
+ currentWord.setText((String) suggestionList
+ .getSelectedValue());
+ chat.setMessage(newMessage.toString());
+
+ }
+ }
+ };
+
+ suggestionList.addMouseListener(clickListener);
+
+ addButton =
+ new JButton(resources.getI18NString("plugin.spellcheck.dialog.ADD"));
+ addButton.setMnemonic(resources
+ .getI18nMnemonic("plugin.spellcheck.dialog.ADD"));
+
+ addButton.addActionListener(new ActionListener()
+ {
+
+ public void actionPerformed(ActionEvent e)
+ {
+
+ try
+ {
+ dict.addWord(currentWord.getText());
+ chat.promptRepaint();
+ }
+ catch (SpellDictionaryException exc)
+ {
+ String msg = "Unable to add word to personal dictionary";
+ logger.error(msg, exc);
+ }
+ }
+ });
+
+ suggestionPanel = new TransparentPanel(new BorderLayout(10, 10));
+ suggestionPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
+ suggestionPanel.setLayout(new BoxLayout(suggestionPanel,
+ BoxLayout.X_AXIS));
+ suggestionPanel.add(suggestionScroll);
+ suggestionPanel.add(Box.createHorizontalStrut(10));
+ suggestionPanel.add(addButton);
+
+ topPanel.add(suggestionPanel, BorderLayout.SOUTH);
+
+ }
+
+ /**
+ * Sets the model for the suggestion list
+ *
+ * @param clickedWord
+ */
+ private void setSuggestionModel(String clickedWord)
+ {
+
+ DefaultListModel dataModel = new DefaultListModel();
+ List<String> corrections = this.dict.getSuggestions(clickedWord);
+ for (String correction : corrections)
+ {
+ dataModel.addElement(correction);
+ }
+
+ suggestionList.setModel(dataModel);
+ }
+
+ /**
+ * Returns the selected correction value
+ *
+ * @return selected value from suggestion list
+ */
+ public Object getCorrection()
+ {
+
+ return suggestionList.getSelectedValue();
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void close(boolean escaped)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/Word.java b/src/net/java/sip/communicator/plugin/spellcheck/Word.java
index e7a882a..b2e2b40 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/Word.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/Word.java
@@ -1,35 +1,40 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.spellcheck;
import java.text.BreakIterator;
/**
- * Immutable representation of a word in the context of a document, bundling
- * the bounds with the text.
+ * Immutable representation of a word in the context of a document, bundling the
+ * bounds with the text.
+ *
* @author Damian Johnson
*/
class Word
{
- private static final BreakIterator WORD_ITR
- = BreakIterator.getWordInstance();
+ private static final BreakIterator WORD_ITR = BreakIterator
+ .getWordInstance();
+
private final int start;
+
private final String text;
+
+ private final int end;
/**
* Provides the word before or after a given index. No bounds checking is
* performed.
+ *
* @param text text to be checked
* @param index index in which to begin search (inclusive)
* @param before search is before index if true, after otherwise
* @return index of word boundary
*/
public static synchronized Word getWord(String text, int index,
- boolean before)
+ boolean before)
{
int start, end;
WORD_ITR.setText(text);
@@ -38,21 +43,24 @@ class Word
{
start = WORD_ITR.preceding(index);
end = WORD_ITR.next();
- if (start == BreakIterator.DONE) start = 0;
+ if (start == BreakIterator.DONE)
+ start = 0;
}
else
{
end = WORD_ITR.following(index);
start = WORD_ITR.previous();
- if (end == BreakIterator.DONE) end = text.length() - 1;
+ if (end == BreakIterator.DONE)
+ end = text.length() - 1;
}
- return new Word(start, text.substring(start, end));
+ return new Word(start, end, text.substring(start, end));
}
- private Word(int start, String text)
+ private Word(int start, int end, String text)
{
this.start = start;
+ this.end = end;
this.text = text;
}
@@ -61,6 +69,11 @@ class Word
return this.start;
}
+ public int getEnd()
+ {
+ return this.end;
+ }
+
public String getText()
{
return this.text;
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf b/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf
index e06daec..cf41de6 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf
@@ -10,9 +10,13 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.gui.event,
net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.service.contactlist,
+ net.java.sip.communicator.service.protocol,
javax.swing,
javax.swing.event,
javax.swing.text,
+ javax.swing.text.html,
javax.imageio,
javax.xml.parsers,
org.w3c.dom,