Enables spell check plugin and adds some improvements provided by Purvesh Sahoo.

cusax-fix
Yana Stamcheva 14 years ago
parent e46f74f442
commit 801a79ca9d

@ -43,6 +43,12 @@
http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ru_RU_yo.zip
Slovak (Slovakia, alternative)- http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/sk_SK.zip
Swedish (Sweden, alternative)- http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/sv_SE.zip
Some missing dictionaries:
<locale label="Khmer (Cambodia)" isoCode="km,kh" dictionaryUrl=""/>
<locale label="Oriya (India)" isoCode="or,in" dictionaryUrl="or_IN.zip"/>
<locale label="Uzbek (Uzbekistan)" isoCode="uz,uz" dictionaryUrl="uz_UZ.zip"/>
-->
<!--
@ -64,19 +70,16 @@
<locale label="Welsh (Wales)" isoCode="cy,gb" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/cy_GB.zip"/>
<locale label="Northern Sami" isoCode="xx,xx" dictionaryUrl="http://divvun.no/static_files/se.zip"/>
-->
<locale label="Afrikaans (South Africa)" isoCode="af,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/af_ZA.zip"/>
<locale label="Amharic (Ethiopia)" isoCode="am,et" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/am_ET.zip"/>
<locale label="Armenian (Eastern and Western)" isoCode="hy,xx" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/hy_xx.zip"/>
<locale label="Azerbaijani (Azerbaijan)" isoCode="az,az" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/az_AZ.zip"/>
<locale label="Armenian (Eastern and Western)" isoCode="hy,xx" dictionaryUrl="http://dictionaries.jitsi.org/hy_xx.zip"/>
<locale label="Basque" isoCode="eu,xx" dictionaryUrl="http://www.euskara.euskadi.net/r59-738/es/contenidos/informacion/euskarazko_softwarea/es_9568/adjuntos/xuxen/eu-ES-hunspell.zip"/>
<locale label="Bengali (India)" isoCode="bn,in" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/bn_IN.zip"/>
<locale label="Bulgarian (Bulgaria)" isoCode="bg,bg" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/bg_BG.zip"/>
<locale label="Bulgarian (Bulgaria)" isoCode="bg,bg" dictionaryUrl="http://ftp.osuosl.org/pub/openoffice/contrib/dictionaries/bg_BG.zip"/>
<locale label="Catalan" isoCode="ca,es" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ca_ES.zip"/>
<locale label="Croatian (Croatia)" isoCode="hr,hr" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/hr_HR.zip"/>
<locale label="Czech (Czech Republic)" isoCode="cs,cz" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/cs_CZ.zip"/>
<locale label="Dutch (Netherlands)" isoCode="nl,nl" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/nl_NL.zip"/>
<locale label="English (United Kingdom)" isoCode="en,gb" dictionaryUrl="http://en-gb.pyxidium.co.uk/dictionary/en_GB.zip"/>
<locale label="English (United Kingdom)" isoCode="en,gb" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/en_GB.zip"/>
<locale label="English (United States)" isoCode="en,us" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/en_US.zip"/>
<locale label="English (Australia)" isoCode="en,au" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/en_AU.zip"/>
<locale label="English (Canada)" isoCode="en,ca" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/en_CA.zip"/>
@ -84,39 +87,36 @@
<locale label="English (South Africa)" isoCode="en,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/en_ZA.zip"/>
<locale label="Esperanto" isoCode="eo,xx" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/eo.zip"/>
<locale label="Faroese (Faroe Islands)" isoCode="fo,fo" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/fo_FO.zip"/>
<locale label="French (France)" isoCode="fr,fr" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/fr_FR.zip"/>
<locale label="French (France)" isoCode="fr,fr" dictionaryUrl="http://dictionaries.jitsi.org/fr_FR.zip"/>
<locale label="Frisian (Netherlands)" isoCode="fy,nl" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/fy_NL.zip"/>
<locale label="Galician (Spain)" isoCode="gl,es" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/gl_ES.zip"/>
<locale label="German (Germany)" isoCode="de,de" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/de_DE_frami.zip"/>
<locale label="Hebrew (Israel)" isoCode="he,il" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/he_IL.zip"/>
<locale label="Hindi (India)" isoCode="hi,in" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/hi_IN.zip"/>
<locale label="Hindi (India)" isoCode="hi,in" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/hi_IN.zip"/>
<locale label="Indonesian (Indonesia)" isoCode="id,id" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/id_ID.zip"/>
<locale label="Interlingua" isoCode="ia,xx" dictionaryUrl="http://download.savannah.nongnu.org/releases/interlingua/ia_myspell.zip"/>
<locale label="Irish (Ireland)" isoCode="ga,ie" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ga_IE.zip"/>
<locale label="Italian (Italy)" isoCode="it,it" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/it_IT.zip"/>
<locale label="Kashubian (Poland)" isoCode="xx,pl" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/xx_PL.zip"/>
<locale label="Khmer (Cambodia)" isoCode="km,kh" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/km_KH.zip"/>
<locale label="Italian (Italy)" isoCode="it,it" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/it_IT.zip"/>
<locale label="Kinyarwanda (Rwanda)" isoCode="rw,rw" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/rw_RW.zip"/>
<locale label="Kiswahili (East Africa)" isoCode="xx,xx" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/xx_XX.zip"/>
<locale label="Kurdish (Turkey, Syria, Iran, Iraq)" isoCode="ku,tr" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ku_TR.zip"/>
<locale label="Kiswahili (East Africa)" isoCode="xx,xx" dictionaryUrl="http://dictionaries.jitsi.org/xx_XX.zip"/>
<locale label="Latin" isoCode="la,va" dictionaryUrl="http://www.drouizig.org/oo/la_VA.zip"/>
<locale label="Latvian (Latvia)" isoCode="lv,lv" dictionaryUrl="ftp://ftp.stardiv.de/pub/OpenOffice.org/contrib/dictionaries/lv_LV.zip"/>
<locale label="Latvian (Latvia)" isoCode="lv,lv" dictionaryUrl="http://ftp.stardiv.de/pub/OpenOffice.org/contrib/dictionaries/lv_LV.zip"/>
<locale label="Lithuanian (Lithuania)" isoCode="lt,lt" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/lt_LT.zip"/>
<locale label="Malagasy (Madagascar)" isoCode="mg,mg" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/mg_MG.zip"/>
<locale label="Malay (Malaysia)" isoCode="ms,my" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ms_MY.zip"/>
<locale label="Marathi (India)" isoCode="mr,in" dictionaryUrl="http://ftp.stardiv.de/pub/OpenOffice.org/contrib/dictionaries/mr_IN.zip"/>
<locale label="Mongolian (Mongolia)" isoCode="mn,mn" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/mn_MN.zip"/>
<locale label="Mongolian (Mongolia)" isoCode="mn,mn" dictionaryUrl="http://dictionaries.jitsi.org/mn_MN.zip"/>
<locale label="Ndebele (South Africa)" isoCode="nr,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/nr_ZA.zip"/>
<locale label="Nepali (Nepal)" isoCode="ne,np" dictionaryUrl="http://nepalinux.org/downloads/ne_NP_dict.zip"/>
<locale label="Northern Sotho (South Africa)" isoCode="ns,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ns_ZA.zip"/>
<locale label="Norwegian (Norway)" isoCode="nb,no" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/nb_NO.zip"/>
<locale label="Norwegian, Nynorsk (Norway)" isoCode="nn,no" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/nn_NO.zip"/>
<locale label="Occitan (France)" isoCode="oc,fr" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/oc_FR.zip"/>
<locale label="Oriya (India)" isoCode="or,in" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/or_IN.zip"/>
<locale label="Persian (Iran)" isoCode="fa,ir" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/fa_IR.zip"/>
<locale label="Persian (Iran)" isoCode="fa,ir" dictionaryUrl="http://dictionaries.jitsi.org/fa_IR.zip"/>
<locale label="Polish (Poland)" isoCode="pl,pl" dictionaryUrl="http://pl.openoffice.org/pliki/pl_PL.zip"/>
<locale label="Portuguese (Portugal)" isoCode="pt,pt" dictionaryUrl="http://natura.di.uminho.pt/download/sources/Dictionaries/myspell/myspell.pt-latest.zip"/>
<locale label="Punjabi (India)" isoCode="xx,in" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/xx_IN.zip"/>
<locale label="Portuguese (Portugal)" isoCode="pt,pt" dictionaryUrl="http://dictionaries.jitsi.org/pt_PT.zip"/>
<locale label="Punjabi (India)" isoCode="xx,in" dictionaryUrl="http://dictionaries.jitsi.org/xx_IN.zip"/>
<locale label="Romanian (Romania)" isoCode="ro,ro" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ro_RO.zip"/>
<locale label="Russian (Russia)" isoCode="ru,ru" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ru_RU.zip"/>
<locale label="Scottish Gaelic (Scotland)" isoCode="gd,gb" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/gd_GB.zip"/>
@ -129,11 +129,10 @@
<locale label="Swazi/Swati (South Africa)" isoCode="ss,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ss_ZA.zip"/>
<locale label="Swedish (Sweden)" isoCode="sv,se" dictionaryUrl="http://hem.bredband.net/dsso1/sv_SE.zip"/>
<locale label="Tagalog (Philippines)" isoCode="tl,ph" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/tl_PH.zip"/>
<locale label="Tamil (India)" isoCode="ta,in" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/ta_IN.zip"/>
<locale label="Tamil (India)" isoCode="ta,in" dictionaryUrl="http://dictionaries.jitsi.org/ta_IN.zip"/>
<locale label="Tetum (Indonesia)" isoCode="xx,id" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/tet_ID.zip"/>
<locale label="Tsonga (South Africa)" isoCode="ts,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ts_ZA.zip"/>
<locale label="Ukrainian (Ukraine)" isoCode="uk,ua" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/uk_UA.zip"/>
<locale label="Uzbek (Uzbekistan)" isoCode="uz,uz" dictionaryUrl="http://www.atagar.com/misc/transfer/sipDictionaries/uz_UZ.zip"/>
<locale label="Venda (South Africa)" isoCode="ve,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/ve_ZA.zip"/>
<locale label="Vietnamese (Vietnam)" isoCode="vi,vn" dictionaryUrl="http://hunspell-spellcheck-vi.googlecode.com/files/vi_VN.zip"/>
<locale label="Xhosa (South Africa)" isoCode="xh,za" dictionaryUrl="http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/xh_ZA.zip"/>

@ -532,11 +532,11 @@ plugin.advancedconfig.PLUGIN_ICON=resources/images/plugin/advancedconfig/configI
plugin.chatconfig.PLUGIN_ICON=resources/images/plugin/chatconfig/chatIcon.png
# spellchecker plugin
plugin.spellcheck.PLUGIN_ICON=resources/images/plugin/spellchecker/pluginIcon.png
plugin.spellcheck.ADD_WORD_ICON=resources/images/plugin/spellchecker/addWord.png
plugin.spellcheck.BLANK_FLAG=resources/images/plugin/spellchecker/blankFlag.png
plugin.spellcheck.PERSONAL_DIR=resources/images/plugin/spellchecker/personalDictionary.png
plugin.spellcheck.WORD_INCLUDE=resources/images/plugin/spellchecker/wordInclude.png
plugin.spellcheck.WORD_EXCLUDE=resources/images/plugin/spellchecker/wordExclude.png
plugin.spellcheck.ENABLE=resources/images/plugin/spellchecker/enableSpellchecker.png
plugin.spellcheck.DISABLE=resources/images/plugin/spellchecker/disableSpellchecker.png
plugin.spellcheck.PLUGIN_ICON=resources/images/plugin/spellchec/pluginIcon.png
plugin.spellcheck.ADD_WORD_ICON=resources/images/plugin/spellcheck/addWord.png
plugin.spellcheck.BLANK_FLAG=resources/images/plugin/spellcheck/blankFlag.png
plugin.spellcheck.PERSONAL_DIR=resources/images/plugin/spellcheck/personalDictionary.png
plugin.spellcheck.WORD_INCLUDE=resources/images/plugin/spellcheck/wordInclude.png
plugin.spellcheck.WORD_EXCLUDE=resources/images/plugin/spellcheck/wordExclude.png
plugin.spellcheck.ENABLE=resources/images/plugin/spellcheck/enableSpellchecker.png
plugin.spellcheck.DISABLE=resources/images/plugin/spellcheck/disableSpellchecker.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

@ -1225,6 +1225,7 @@ plugin.chatconfig.replacement.REPLACEMENT_SOURCES=Sources:
plugin.chatconfig.spellcheck.TITLE=SpellCheck
plugin.spellcheck.LANG=Language
plugin.spellcheck.EDIT_PERSONAL_DICT=Edit
plugin.spellcheck.ENABLE_SPELL_CHECK=Enable spell check
#provisioning plugin
plugin.provisioning.PROVISIONING=Provisioning
@ -1269,3 +1270,16 @@ plugin.dnsconfig.lblRedemption.text=Back to primary resolver
plugin.dnsconfig.lblRedemption.description=<html>the number of prompt responses that the primary resolver needs to provide before we turn that backup off again</html>
plugin.dnsconfig.lblPatience.text=Start backup resolver after
plugin.dnsconfig.lblPatience.description=<html>number of ms to wait for a response from primary DNS before starting the backup resolver</html>
#plugin spellcheck
plugin.spellcheck.TITLE=Spelling and Grammar
plugin.spellcheck.MENU=Show Spelling and Grammar
plugin.spellcheck.LANG=Language
plugin.spellcheck.EDIT_PERSONAL_DICT=Edit
plugin.spellcheck.dialog.FIND=Find Next
plugin.spellcheck.dialog.REPLACE=Replace
plugin.spellcheck.dialog.ADD=Add Word
plugin.spellcheck.DICT_ERROR_TITLE=Error Switching Dictionary
plugin.spellcheck.DICT_ERROR=Cannot switch dictionary
plugin.spellcheck.DICT_RETRIEVE_ERROR=Dictionary cannot be fetched from
plugin.spellcheck.DICT_PROCESS_ERROR=Locale not recognized

@ -720,9 +720,26 @@ public void mouseClicked(MouseEvent e)
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);
}
}

@ -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 void loadSkin()
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;
}
}

@ -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.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 @@ boolean getFormatting(String word)
{
// 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 @@ void promptRepaint()
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 @@ synchronized void attachListeners()
this.chat.addChatEditorDocumentListener(this.docListener);
this.chat.addChatEditorCaretListener(this.caretListener);
this.chat.addChatEditorMenuListener(this.menuListener);
}
}
@ -119,6 +173,7 @@ synchronized void detachListeners()
this.chat.removeChatEditorDocumentListener(this.docListener);
this.chat.removeChatEditorCaretListener(this.caretListener);
this.chat.removeChatEditorMenuListener(this.menuListener);
}
}
@ -146,22 +201,23 @@ void setDictionary(SpellDictionary dict)
}
// 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 @@ public void actionPerformed(ActionEvent event)
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 @@ private class CorrectionListener
implements ActionListener
{
private Word clickedWord;
private String correction;
CorrectionListener(Word clickedWord, String correction)
@ -209,11 +288,12 @@ private class CorrectionListener
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());
}
}

@ -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 @@
* 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 @@ public void caretUpdate(CaretEvent event)
{
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 @@ public void caretUpdate(CaretEvent event)
* 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 @@ public void caretUpdate(CaretEvent event)
/**
* Provides the index of the character the cursor is in front of.
*
* @return index of caret
*/
abstract int getCaretPosition();
@ -146,23 +156,23 @@ public static void main(String[] args)
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 @@ void promptRepaint()
public void insertUpdate(DocumentEvent event)
{
if (!this.isEnabled) return;
if (!this.isEnabled)
return;
try
{
@ -201,7 +212,7 @@ public void insertUpdate(DocumentEvent event)
// new character at end (ensure it isn't initially
// underlined)
clearUnderlining(event.getOffset(),
event.getOffset() + 1);
event.getOffset() + 1);
}
}
else
@ -211,9 +222,11 @@ public void insertUpdate(DocumentEvent event)
// 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 @@ public void insertUpdate(DocumentEvent event)
{
// 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 @@ public void insertUpdate(DocumentEvent event)
{
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 @@ public void insertUpdate(DocumentEvent event)
public void removeUpdate(DocumentEvent event)
{
if (!this.isEnabled) return;
if (!this.isEnabled)
return;
try
{
@ -270,8 +281,7 @@ public void removeUpdate(DocumentEvent event)
{
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 @@ public void removeUpdate(DocumentEvent event)
}
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 @@ public CaretListener getEndChecker()
/**
* 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 @@ private void underlineRange(int start, int end)
{
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 @@ private void underlineRange(int start, int end)
* 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 @@ private void clearUnderlining(int start, int end)
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 @@ public void setEnabled(boolean enable, String message)
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 @@ public void reset(String message) {
{
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;
}

@ -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;
}
}
}

@ -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 @@
/**
* 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 @@ else if (node.getNodeName().equals(NODE_LOCALES))
/**
* Retrieves default values from xml.
*
*
* @param list the configuration list
*/
private static void parseDefaults(NodeList list)
@ -128,6 +132,7 @@ private static void parseDefaults(NodeList list)
/**
* Populates LOCALES list with contents of xml.
*
* @param list the configuration list
*/
private static void parseLocales(NodeList list)
@ -138,10 +143,9 @@ private static void parseLocales(NodeList list)
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 @@ private static void parseLocales(NodeList list)
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 @@ public static String getDefault(Default field)
/**
* 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 @@ public static Locale getLocale(String isoCode)
{
for (Locale locale : LOCALES)
{
if (locale.getIsoCode().equals(isoCode)) return locale;
if (locale.getIsoCode().equals(isoCode))
return locale;
}
return null;
@ -181,11 +188,12 @@ public static Locale getLocale(String isoCode)
/**
* 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 @@ public static ArrayList <Locale> getLocales()
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 @@ private Locale(String label, String isoCode, URL dictLocation)
/**
* Provides user readable name of language.
*
* @return name of language presented to user
*/
public String getLabel()
@ -216,6 +229,7 @@ public String getLabel()
/**
* 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 @@ public String getIsoCode()
/**
* 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 @@ public URL getDictUrl()
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 @@ public enum Default
/**
* 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

@ -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 @@
/**
* 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 static String getString(String key)
/**
* 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 static ImageIcon getImage(String imageID)
/**
* 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 static ImageIcon getFlagImage(String resource) throws IOException
/**
* 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 static byte[] getImageInBytes(String imageID)
/**
* 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;
}

@ -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 @@
/**
* 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 static UIService getUIService()
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 static UIService getUIService()
/**
* Returns the <tt>FileAccessService</tt>.
*
* @return the <tt>FileAccessService</tt>
*/
public static FileAccessService getFileAccessService()
@ -89,17 +83,18 @@ public static FileAccessService getFileAccessService()
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 static ConfigurationService getConfigService()
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;
}

@ -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 @@
* 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 @@ synchronized void start(BundleContext bc) throws Exception
{
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 @@ synchronized void start(BundleContext bc) throws Exception
}
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 @@ public void chatCreated(Chat chat)
/**
* 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 @@ ArrayList <String> getPersonalWords()
catch (FileNotFoundException exc)
{
logger.error("Unable to read custom dictionary", exc);
return new ArrayList <String>();
return new ArrayList<String>();
}
}
}
@ -199,9 +216,10 @@ ArrayList <String> getPersonalWords()
/**
* 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 @@ void setPersonalWords(List <String> words)
{
// 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 @@ void setPersonalWords(List <String> words)
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 @@ void setPersonalWords(List <String> words)
catch (IOException exc)
{
logger.error("Unable to access personal spelling dictionary",
exc);
exc);
}
}
}
@ -247,6 +265,7 @@ void setPersonalWords(List <String> words)
/**
* 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 @@ Parameters.Locale getLocale()
* 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 @@ void setLocale(Parameters.Locale locale) throws Exception
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 @@ void setLocale(Parameters.Locale locale) throws Exception
/**
* 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 @@ boolean isLocaleAvailable(Parameters.Locale locale)
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 @@ void setEnabled(boolean enable)
// 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 @@ private void copyDictionary(InputStream input, File dest)
* 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)

@ -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
}
}

@ -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 @@ public static synchronized Word getWord(String text, int index,
{
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 @@ public int getStart()
return this.start;
}
public int getEnd()
{
return this.end;
}
public String getText()
{
return this.text;

@ -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,

Loading…
Cancel
Save