Implements an editor which allows the user to edit Jitsi's configuration properties from within the application. (Marin Dzhigarov)

cusax-fix 4815
Lyubomir Marinov 13 years ago
parent 9105fe7a21
commit b4c90af949

@ -1079,7 +1079,7 @@
bundle-globalshortcut,bundle-plugin-msofficecomm,bundle-libjitsi,
bundle-customcontactactions, bundle-phonenumbercontactsource,
bundle-demuxcontactsource, bundle-desktoputil,
bundle-globaldisplaydetails"/>
bundle-globaldisplaydetails,bundle-plugin-propertieseditor"/>
<!--BUNDLE-SC-LAUNCHER-->
<target name="bundle-sc-launcher">
@ -2941,4 +2941,14 @@ javax.swing.event, javax.swing.border"/>
prefix="net/java/sip/communicator/impl/globaldisplaydetails" />
</jar>
</target>
<!--BUNDLE-PLUGIN-PROPERTIESEDITOR-->
<target name="bundle-plugin-propertieseditor">
<!-- Creates a bundle for the plugin Configuration Properties Editor.-->
<jar compress="false" destfile="${bundles.dest}/propertieseditor.jar"
manifest="${src}/net/java/sip/communicator/plugin/propertieseditor/propertieseditor.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/plugin/propertieseditor"
prefix="net/java/sip/communicator/plugin/propertieseditor"/>
</jar>
</target>
</project>

@ -184,7 +184,8 @@ felix.auto.start.67= \
reference:file:sc-bundles/plugin-contactsourceconfig.jar \
reference:file:sc-bundles/plugin-certconfig.jar \
reference:file:sc-bundles/phonenumbercontactsource.jar \
reference:file:sc-bundles/demuxcontactsource.jar
reference:file:sc-bundles/demuxcontactsource.jar \
reference:file:sc-bundles/propertieseditor.jar
# Level 68 is for profiler4j. Either don't use it or change the build.xml file
# accordingly.

@ -512,6 +512,7 @@ service.gui.UNKNOWN=Unknown user
service.gui.UNKNOWN_STATUS=Unknown state
service.gui.UNREGISTERED_MESSAGE=Unable to connect the following account: User name: {0}, Server name: {1}. You are currently offline.
service.gui.USE_PROVISIONING=Use online provisioning
service.gui.VALUE=Value
service.gui.VIDEO_CALL=&Video call
service.gui.VIA=via
service.gui.VIA_SMS=Via SMS
@ -1703,6 +1704,17 @@ plugin.certconfig.REVOCATION_OCSP_ENABLED=OCSP (Online Certificate Status Protoc
# Phone number contact source plugin
plugin.phonenumbercontactsource.DISPLAY_NAME=Phone numbers
# properties editor
plugin.propertieseditor.TITLE=Property Editor
plugin.propertieseditor.NEW_PROPERTY_TITLE=Add new property
plugin.propertieseditor.CHECK_BOX=Show this warning next time
plugin.propertieseditor.DESCRIPTION=The following button allows modifying Jitsi configuration properties. \
Changing these advanced settings can be harmful to the stability, security, \
and performance of this application. You should only continue if you are sure \
of what you are doing.
plugin.propertieseditor.IM_AWARE=I am aware of the risks
plugin.propertieseditor.NEED_RESTART=Note: some properties might need a restart before new settings will take effect.
#Thunderbird address book plugin
plugin.thunderbird.CONFIG_FORM_TITLE=Thunderbird
plugin.thunderbird.ENABLED=Enabled

@ -0,0 +1,98 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
import net.java.sip.communicator.impl.gui.main.call.*;
import net.java.sip.communicator.plugin.desktoputil.plaf.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
/**
*
* @author Marin Dzhigarov
*/
public class ContactSearchFieldUI
extends SearchFieldUI
implements Skinnable
{
/**
* Creates a UI for a SearchFieldUI.
*
* @param c the text field
* @return the UI
*/
public static ComponentUI createUI(JComponent c)
{
return new ContactSearchFieldUI();
}
public ContactSearchFieldUI()
{
// Indicates if the big call button outside the search is enabled.
String callButtonEnabledString
= UtilActivator.getResources().getSettingsString(
"impl.gui.CALL_BUTTON_ENABLED");
if ((callButtonEnabledString != null)
&& (callButtonEnabledString.length() > 0))
{
// If the outside call button is enabled the call button in this
// search field is disabled.
isCallButtonEnabled
= !Boolean.parseBoolean(callButtonEnabledString);
}
loadSkin();
}
/**
* Paints the background of the associated component.
*
* @param g the <tt>Graphics</tt> object used for painting
*/
@Override
protected void customPaintBackground(Graphics g)
{
isCallButtonEnabled = CallManager.getTelephonyProviders().size() > 0;
super.customPaintBackground(g);
}
/**
* Creates a call when the mouse is clicked on the call icon.
*
* @param ev the mouse event that has prompted us to create the call.
*/
@Override
protected void updateCallIcon(MouseEvent ev)
{
super.updateCallIcon(ev);
if ((ev.getID() == MouseEvent.MOUSE_CLICKED) && isCallIconVisible)
{
Rectangle callButtonRect = getCallButtonRect();
int x = ev.getX();
int y = ev.getY();
if (callButtonRect.contains(x, y))
{
JTextComponent c = getComponent();
String searchText = c.getText();
if (searchText != null)
CallManager.createCall(searchText, c);
}
}
}
}

@ -25,6 +25,7 @@
*
* @author Yana Stamcheva
* @author Adam Netocny
* @author Marin Dzhigarov
*/
public class SearchField
extends SIPCommTextField
@ -35,37 +36,38 @@ public class SearchField
/**
* Class id key used in UIDefaults.
*/
private static final String uiClassID =
SearchField.class.getName() + "FieldUI";
private static final String uiClassID
= SearchField.class.getName() + "FieldUI";
/**
* Adds the ui class to UIDefaults.
*/
static
{
UIManager.getDefaults().put(uiClassID,
SearchFieldUI.class.getName());
UIManager.getDefaults().put(
uiClassID,
ContactSearchFieldUI.class.getName());
}
/**
* The main application window.
* The contact list on which we apply the filter.
*/
private final MainFrame mainFrame;
private ContactList contactList;
/**
* The contact list on which we apply the filter.
* The current filter query.
*/
private ContactList contactList;
private FilterQuery currentFilterQuery = null;
/**
* The filter to apply on search.
* The main application window.
*/
private final ContactListSearchFilter searchFilter;
private final MainFrame mainFrame;
/**
* The current filter query.
* The filter to apply on search.
*/
private FilterQuery currentFilterQuery = null;
private final ContactListSearchFilter searchFilter;
/**
* Creates the <tt>SearchField</tt>.
@ -85,10 +87,11 @@ public SearchField( MainFrame frame,
this.mainFrame = frame;
this.searchFilter = searchFilter;
if(getUI() instanceof SearchFieldUI)
if (getUI() instanceof ContactSearchFieldUI)
{
((SearchFieldUI)getUI()).setDeleteButtonEnabled(true);
((SearchFieldUI)getUI()).setCallButtonEnabled(isCallButtonEnabled);
((ContactSearchFieldUI) getUI()).setDeleteButtonEnabled(true);
((ContactSearchFieldUI) getUI())
.setCallButtonEnabled(isCallButtonEnabled);
}
this.setBorder(null);
@ -115,28 +118,6 @@ public void actionPerformed(ActionEvent e)
loadSkin();
}
/**
* Handles the change when a char has been inserted in the field.
*/
public void textInserted()
{
// Should explicitly check if there's a text, because the default text
// triggers also an insertUpdate event.
String filterString = this.getText();
if (filterString == null || filterString.length() <= 0)
return;
updateContactListView();
}
/**
* Handles the change when a char has been removed from the field.
*/
public void textRemoved()
{
updateContactListView();
}
/**
* Do not need this for the moment.
* @param e the <tt>DocumentEvent</tt> that notified us
@ -144,52 +125,6 @@ public void textRemoved()
@Override
public void changedUpdate(DocumentEvent e) {}
/**
* Schedules an update if necessary.
*/
private void updateContactListView()
{
String filterString = getText();
boolean isDefaultFilter = false;
searchFilter.setFilterString(filterString.trim());
// First finish the last filter.
if (currentFilterQuery != null)
filterQueryFinished(currentFilterQuery, true);
if (filterString != null && filterString.length() > 0)
{
currentFilterQuery = contactList.applyFilter(searchFilter);
}
else
{
currentFilterQuery = contactList.applyDefaultFilter();
isDefaultFilter = true;
}
if (currentFilterQuery != null && !currentFilterQuery.isCanceled())
{
// If we already have a result here we update the interface.
// In the case of default filter we don't need to know if the
// query has succeeded, as event if it isn't we would like to
// remove the unknown contact view.
if (isDefaultFilter || currentFilterQuery.isSucceeded())
enableUnknownContactView(false);
else
// Otherwise we will listen for events for changes in status
// of this query.
currentFilterQuery.setQueryListener(this);
}
else
{
// If the query is null or is canceled, we would simply check the
// contact list content.
filterQueryFinished(currentFilterQuery, !contactList.isEmpty());
}
}
/**
* Sets the unknown contact view to the main contact list window.
*
@ -208,16 +143,6 @@ public void run()
});
}
/**
* Sets the contact list, in which the search is performed.
*
* @param contactList the contact list in which the search is performed
*/
public void setContactList(ContactList contactList)
{
this.contactList = contactList;
}
/**
* Indicates that the given <tt>query</tt> has finished with failure, i.e.
* no results for the filter were found.
@ -231,6 +156,24 @@ public void filterQueryFailed(FilterQuery query)
filterQueryFinished(query, false);
}
/**
* Performs all needed updates when a filter query has finished.
*
* @param query the query that has finished
* @param hasResults indicates if the query has results
*/
private void filterQueryFinished(FilterQuery query, boolean hasResults)
{
// If the unknown contact view was previously enabled, but we
// have found matching contacts we enter the normal view.
enableUnknownContactView(!hasResults);
if (hasResults)
contactList.selectFirstContact();
query.setQueryListener(null);
}
/**
* Indicates that the given <tt>query</tt> has finished with success, i.e.
* the filter has returned results.
@ -244,15 +187,6 @@ public void filterQuerySucceeded(FilterQuery query)
filterQueryFinished(query, true);
}
/**
* Reloads text field UI defs.
*/
public void loadSkin()
{
if(getUI() instanceof SearchFieldUI)
((SearchFieldUI)getUI()).loadSkin();
}
/**
* Returns the name of the L&F class that renders this component.
*
@ -267,20 +201,89 @@ public String getUIClassID()
}
/**
* Performs all needed updates when a filter query has finished.
* Reloads text field UI defs.
*/
public void loadSkin()
{
if (getUI() instanceof ContactSearchFieldUI)
((ContactSearchFieldUI) getUI()).loadSkin();
}
/**
* Sets the contact list, in which the search is performed.
*
* @param query the query that has finished
* @param hasResults indicates if the query has results
* @param contactList the contact list in which the search is performed
*/
private void filterQueryFinished(FilterQuery query, boolean hasResults)
public void setContactList(ContactList contactList)
{
// If the unknown contact view was previously enabled, but we
// have found matching contacts we enter the normal view.
enableUnknownContactView(!hasResults);
this.contactList = contactList;
}
if (hasResults)
contactList.selectFirstContact();
/**
* Handles the change when a char has been inserted in the field.
*/
public void textInserted()
{
// Should explicitly check if there's a text, because the default text
// triggers also an insertUpdate event.
String filterString = this.getText();
if (filterString == null || filterString.length() <= 0)
return;
query.setQueryListener(null);
updateContactListView();
}
/**
* Handles the change when a char has been removed from the field.
*/
public void textRemoved()
{
updateContactListView();
}
/**
* Schedules an update if necessary.
*/
private void updateContactListView()
{
String filterString = getText();
boolean isDefaultFilter = false;
searchFilter.setFilterString(filterString.trim());
// First finish the last filter.
if (currentFilterQuery != null)
filterQueryFinished(currentFilterQuery, true);
if (filterString != null && filterString.length() > 0)
{
currentFilterQuery = contactList.applyFilter(searchFilter);
}
else
{
currentFilterQuery = contactList.applyDefaultFilter();
isDefaultFilter = true;
}
if (currentFilterQuery != null && !currentFilterQuery.isCanceled())
{
// If we already have a result here we update the interface.
// In the case of default filter we don't need to know if the
// query has succeeded, as event if it isn't we would like to
// remove the unknown contact view.
if (isDefaultFilter || currentFilterQuery.isSucceeded())
enableUnknownContactView(false);
else
// Otherwise we will listen for events for changes in status
// of this query.
currentFilterQuery.setQueryListener(this);
}
else
{
// If the query is null or is canceled, we would simply check the
// contact list content.
filterQueryFinished(currentFilterQuery, !contactList.isEmpty());
}
}
}

@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.contactlist;
package net.java.sip.communicator.plugin.desktoputil.plaf;
import java.awt.*;
import java.awt.event.*;
@ -13,13 +13,11 @@
import javax.swing.plaf.*;
import javax.swing.text.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.call.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.desktoputil.plaf.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
import org.jitsi.service.resources.*;
/**
* The <tt>SearchTextFieldUI</tt> is the one responsible for the search field
* look & feel. It draws a search icon inside the field and adjusts the bounds
@ -27,15 +25,22 @@
*
* @author Yana Stamcheva
* @author Adam Netocny
* @author Marin Dzhigarov
*/
public class SearchFieldUI
extends SIPCommTextFieldUI
implements Skinnable
{
/**
* The icon indicating that this is a search field.
* Creates a UI for a SearchFieldUI.
*
* @param c the text field
* @return the UI
*/
private ImageIcon searchIcon;
public static ComponentUI createUI(JComponent c)
{
return new SearchFieldUI();
}
/**
* The default icon of the call button.
@ -43,9 +48,9 @@ public class SearchFieldUI
private Image callIcon;
/**
* The separator icon shown between the call icon and the close.
* The pressed icon of the call button.
*/
private Image separatorIcon;
private Image callPressedIcon;
/**
* The roll over icon of the call button.
@ -53,76 +58,49 @@ public class SearchFieldUI
private Image callRolloverIcon;
/**
* The pressed icon of the call button.
* The call button tool tip string.
*/
private Image callPressedIcon;
private final String callString = DesktopUtilActivator.getResources()
.getI18NString("service.gui.CALL");
/**
* Indicates if the mouse is currently over the call button.
* Indicates if the call button is enabled in this search field.
*/
private boolean isCallMouseOver = false;
protected boolean isCallButtonEnabled = true;
/**
* Indicates if the mouse is currently over the call button.
* Indicates if the call icon is currently visible.
*/
private boolean isCallMousePressed = false;
protected boolean isCallIconVisible = false;
/**
* The call button tool tip string.
* Indicates if the mouse is currently over the call button.
*/
private final String callString
= GuiActivator.getResources().getI18NString("service.gui.CALL");
private boolean isCallMouseOver = false;
/**
* Indicates if the call icon is currently visible.
* Indicates if the mouse is currently over the call button.
*/
private boolean isCallIconVisible = false;
private boolean isCallMousePressed = false;
/**
* Indicates if the call button is enabled in this search field.
* The icon indicating that this is a search field.
*/
private boolean isCallButtonEnabled = true;
private ImageIcon searchIcon;
/**
* Creates a <tt>SIPCommTextFieldUI</tt>.
* The separator icon shown between the call icon and the close.
*/
public SearchFieldUI()
{
// Indicates if the big call button outside the search is enabled.
String callButtonEnabledString = UtilActivator.getResources()
.getSettingsString("impl.gui.CALL_BUTTON_ENABLED");
if (callButtonEnabledString != null
&& callButtonEnabledString.length() > 0)
{
// If the outside call button is enabled the call button in this
// search field is disabled.
isCallButtonEnabled
= !new Boolean(callButtonEnabledString).booleanValue();
}
loadSkin();
}
private Image separatorIcon;
/**
* Enables/disabled the call button in the search field.
*
* @param isEnabled indicates if the call button is enabled
* Creates a <tt>GenericSearchFieldUI</tt>.
*/
public void setCallButtonEnabled(boolean isEnabled)
public SearchFieldUI()
{
this.isCallButtonEnabled = isEnabled;
}
isCallButtonEnabled = false;
/**
* Implements parent paintSafely method and enables antialiasing.
* @param g the <tt>Graphics</tt> object that notified us
*/
@Override
protected void paintSafely(Graphics g)
{
customPaintBackground(g);
super.paintSafely(g);
loadSkin();
}
/**
@ -144,11 +122,10 @@ protected void customPaintBackground(Graphics g)
int dy = (c.getY() + c.getHeight()) / 2
- searchIcon.getIconHeight()/2;
g2.drawImage(searchIcon.getImage(), 3, dy + 1, null);
g2.drawImage(searchIcon.getImage(), 3, dy, null);
if (c.getText() != null
&& c.getText().length() > 0
&& CallManager.getTelephonyProviders().size() > 0
&& isCallButtonEnabled)
{
// Paint call button.
@ -180,6 +157,25 @@ else if (isCallMouseOver)
}
}
/**
* Calculates the call button rectangle.
*
* @return the call button rectangle
*/
protected Rectangle getCallButtonRect()
{
Component c = getComponent();
Rectangle rect = c.getBounds();
int dx = getDeleteButtonRect().x - callRolloverIcon.getWidth(null) - 8;
int dy = (rect.y + rect.height) / 2 - callRolloverIcon.getHeight(null)/2;
return new Rectangle( dx,
dy,
callRolloverIcon.getWidth(null),
callRolloverIcon.getHeight(null));
}
/**
* If we are in the case of disabled delete button, we simply call the
* parent implementation of this method, otherwise we recalculate the editor
@ -210,6 +206,32 @@ protected Rectangle getVisibleEditorRect()
return null;
}
/**
* Reloads UI icons.
*/
@Override
public void loadSkin()
{
super.loadSkin();
ResourceManagementService r = DesktopUtilActivator.getResources();
searchIcon = r.getImage("service.gui.icons.SEARCH_ICON");
if (isCallButtonEnabled)
{
callIcon
= r.getImage("service.gui.buttons.SEARCH_CALL_ICON").getImage();
callRolloverIcon
= r.getImage("service.gui.buttons.SEARCH_CALL_ROLLOVER_ICON")
.getImage();
callPressedIcon
= r.getImage("service.gui.buttons.SEARCH_CALL_PRESSED_ICON")
.getImage();
separatorIcon
= r.getImage("service.gui.icons.SEARCH_SEPARATOR").getImage();
}
}
/**
* Updates the call button when the mouse was clicked.
* @param e the <tt>MouseEvent</tt> that notified us of the click
@ -223,6 +245,19 @@ public void mouseClicked(MouseEvent e)
updateCallIcon(e);
}
/**
* Updates the delete icon when the mouse is dragged over.
* @param e the <tt>MouseEvent</tt> that notified us
*/
@Override
public void mouseDragged(MouseEvent e)
{
super.mouseDragged(e);
if(isCallButtonEnabled)
updateCallIcon(e);
}
/**
* Updates the call button when the mouse is enters the component area.
* @param e the <tt>MouseEvent</tt> that notified us
@ -249,6 +284,19 @@ public void mouseExited(MouseEvent e)
updateCallIcon(e);
}
/**
* Updates the delete icon when the mouse is moved over.
* @param e the <tt>MouseEvent</tt> that notified us
*/
@Override
public void mouseMoved(MouseEvent e)
{
super.mouseMoved(e);
if(isCallButtonEnabled)
updateCallIcon(e);
}
@Override
public void mousePressed(MouseEvent e)
{
@ -268,29 +316,24 @@ public void mouseReleased(MouseEvent e)
}
/**
* Updates the delete icon when the mouse is dragged over.
* @param e the <tt>MouseEvent</tt> that notified us
* Implements parent paintSafely method and enables antialiasing.
* @param g the <tt>Graphics</tt> object that notified us
*/
@Override
public void mouseDragged(MouseEvent e)
protected void paintSafely(Graphics g)
{
super.mouseDragged(e);
if(isCallButtonEnabled)
updateCallIcon(e);
customPaintBackground(g);
super.paintSafely(g);
}
/**
* Updates the delete icon when the mouse is moved over.
* @param e the <tt>MouseEvent</tt> that notified us
* Enables/disabled the call button in the search field.
*
* @param isEnabled indicates if the call button is enabled
*/
@Override
public void mouseMoved(MouseEvent e)
public void setCallButtonEnabled(boolean isEnabled)
{
super.mouseMoved(e);
if(isCallButtonEnabled)
updateCallIcon(e);
this.isCallButtonEnabled = isEnabled;
}
/**
@ -301,7 +344,7 @@ public void mouseMoved(MouseEvent e)
* @param evt the mouse event that has prompted us to update the delete
* icon.
*/
private void updateCallIcon(MouseEvent evt)
protected void updateCallIcon(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
@ -336,12 +379,6 @@ private void updateCallIcon(MouseEvent evt)
// Update the default cursor.
getComponent().setCursor(Cursor.getDefaultCursor());
// Perform call action when the call button is clicked.
if (evt.getID() == MouseEvent.MOUSE_CLICKED)
{
CallManager.createCall(searchText, c);
}
}
else
{
@ -359,63 +396,4 @@ private void updateCallIcon(MouseEvent evt)
getComponent().repaint();
}
/**
* Calculates the call button rectangle.
*
* @return the call button rectangle
*/
protected Rectangle getCallButtonRect()
{
Component c = getComponent();
Rectangle rect = c.getBounds();
int dx = getDeleteButtonRect().x - callRolloverIcon.getWidth(null) - 8;
int dy = (rect.y + rect.height) / 2 - callRolloverIcon.getHeight(null)/2;
return new Rectangle( dx,
dy,
callRolloverIcon.getWidth(null),
callRolloverIcon.getHeight(null));
}
/**
* Reloads UI icons.
*/
@Override
public void loadSkin()
{
super.loadSkin();
searchIcon = UtilActivator.getResources()
.getImage("service.gui.icons.SEARCH_ICON");
if (isCallButtonEnabled)
{
callIcon = UtilActivator.getResources()
.getImage("service.gui.buttons.SEARCH_CALL_ICON").getImage();
callRolloverIcon = UtilActivator.getResources()
.getImage("service.gui.buttons.SEARCH_CALL_ROLLOVER_ICON")
.getImage();
callPressedIcon = UtilActivator.getResources()
.getImage("service.gui.buttons.SEARCH_CALL_PRESSED_ICON")
.getImage();
separatorIcon = UtilActivator.getResources()
.getImage("service.gui.icons.SEARCH_SEPARATOR").getImage();
}
}
/**
* Creates a UI for a SearchFieldUI.
*
* @param c the text field
* @return the UI
*/
public static ComponentUI createUI(JComponent c)
{
return new SearchFieldUI();
}
}

@ -0,0 +1,158 @@
/*
* Jitsi, 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.propertieseditor;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
/**
* The panel containing all buttons for the <tt>PropertiesEditorPanel</tt>.
*
* @author Marin Dzhigarov
*/
public class ButtonsPanel
extends TransparentPanel
implements ActionListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 1L;
private ConfigurationService confService
= PropertiesEditorActivator.getConfigurationService();
private ResourceManagementService resourceManagementService
= PropertiesEditorActivator.getResourceManagementService();
/**
* The delete button.
*/
private JButton deleteButton = new JButton(
resourceManagementService.getI18NString("service.gui.DELETE"));
/**
* The new button.
*/
private JButton newButton = new JButton(
resourceManagementService.getI18NString("service.gui.NEW"));
/**
* The panel, containing all buttons.
*/
private JPanel buttonsPanel
= new TransparentPanel(new GridLayout(0, 1, 8, 8));
/**
* The props table.
*/
private JTable propsTable;
/**
* Instance of the search box panel.
*/
private SearchField searchField;
/**
* Creates an instance of <tt>ButtonsPanel</tt>.
* @param propsTable the table containing all properties.
* @param searchBox the search box panel containing the search box text
* field.
*/
public ButtonsPanel(JTable propsTable, SearchField searchField)
{
this.propsTable = propsTable;
this.searchField = searchField;
this.setLayout(new BorderLayout());
this.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
this.newButton.setOpaque(false);
this.deleteButton.setOpaque(false);
this.buttonsPanel.add(newButton);
this.buttonsPanel.add(deleteButton);
this.add(buttonsPanel, BorderLayout.NORTH);
this.newButton.addActionListener(this);
this.deleteButton.addActionListener(this);
//default as nothing is selected
defaultButtonState();
}
/**
* Default state of buttons, as nothing is selected
*/
public void defaultButtonState()
{
enableDeleteButton(false);
}
/**
* Enable or disable the delete button.
*
* @param enable TRUE - to enable the delete button, FALSE - to disable it
*/
public void enableDeleteButton(boolean enable)
{
this.deleteButton.setEnabled(enable);
}
/**
* Performs corresponding actions, when a button is pressed.
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed(ActionEvent e)
{
JButton sourceButton = (JButton) e.getSource();
if (sourceButton.equals(newButton))
{
NewPropertyDialog dialog = new NewPropertyDialog();
dialog.pack();
dialog.setLocation(
Toolkit.getDefaultToolkit().getScreenSize().width/2
- dialog.getWidth()/2,
Toolkit.getDefaultToolkit().getScreenSize().height/2
- dialog.getHeight()/2
);
dialog.setVisible(true);
} else if (sourceButton.equals(deleteButton))
{
int viewRow = propsTable.getSelectedRow();
int modelRow =
propsTable.convertRowIndexToModel(viewRow);
String selectedProperty
= (String)propsTable.getModel().getValueAt(modelRow, 0);
confService.removeProperty(selectedProperty);
propsTable.clearSelection();
defaultButtonState();
/**
* Resets the text in the search box text field in order to fire
* a new value change event for the FilterRow to update the view.
*/
String text = searchField.getText();
searchField.setText(text);
}
}
}

@ -0,0 +1,21 @@
/*
* Jitsi, 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.propertieseditor;
/**
* The Constants of this package.
*
* @author Marin Dzhigarov
*
*/
public class Constants
{
/**
* Property indicating whether or not to show the <tt>WarningPanel</tt>
*/
public static String SHOW_WARNING_MSG_PROP =
"net.java.sip.communicator.plugin.propertieseditor.showWarningMsg";
}

@ -0,0 +1,179 @@
/*
* Jitsi, 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.propertieseditor;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
/**
* @author Marin Dzhigarov
*/
public class NewPropertyDialog
extends SIPCommDialog
implements ActionListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 1L;
private ConfigurationService confService = PropertiesEditorActivator
.getConfigurationService();
private ResourceManagementService resourceManagementService =
PropertiesEditorActivator.getResourceManagementService();
/**
* The ok button.
*/
private JButton okButton = new JButton(
resourceManagementService.getI18NString("service.gui.OK"));
/**
* The cancel button.
*/
private JButton cancelButton = new JButton(
resourceManagementService.getI18NString("service.gui.CANCEL"));
/**
* The property name text field.
*/
private JTextField propertyNameTextField = new JTextField();
/**
* The property value text field.
*/
private JTextField propertyValueTextField = new JTextField();
/**
* The property name label.
*/
private JLabel propertyNameLabel = new JLabel(
resourceManagementService.getI18NString("service.gui.NAME") + ": ");
/**
* The property value label.
*/
private JLabel propertyValueLabel = new JLabel(
resourceManagementService.getI18NString("service.gui.VALUE") + ": ");
/**
* The panel containing all buttons.
*/
private JPanel buttonsPanel = new TransparentPanel(new FlowLayout(
FlowLayout.CENTER));
/**
* The panel containing the property value and name panels.
*/
private JPanel dataPanel = new TransparentPanel(new GridBagLayout());
/**
* Creates an instance of <tt>NewPropertyDialog</tt>.
*/
public NewPropertyDialog()
{
setTitle(resourceManagementService
.getI18NString("plugin.propertieseditor.NEW_PROPERTY_TITLE"));
JPanel fields = new TransparentPanel(new BorderLayout());
fields.setPreferredSize(new Dimension(450, 150));
this.getContentPane().add(fields);
fields.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
fields.add(dataPanel, BorderLayout.NORTH);
fields.add(buttonsPanel, BorderLayout.SOUTH);
this.buttonsPanel.add(okButton);
this.buttonsPanel.add(cancelButton);
okButton.setEnabled(false);
this.okButton.addActionListener(this);
this.cancelButton.addActionListener(this);
GridBagConstraints first = new GridBagConstraints();
first.gridx = 0;
first.gridy = 0;
first.weightx = 0;
first.anchor = GridBagConstraints.LINE_START;
first.gridwidth = 1;
first.insets = new Insets(2, 4, 2, 4);
first.fill = GridBagConstraints.HORIZONTAL;
GridBagConstraints second = new GridBagConstraints();
second.gridx = 1;
second.gridy = 0;
second.weightx = 2;
second.anchor = GridBagConstraints.LINE_START;
second.gridwidth = 1; // GridBagConstraints.REMAINDER;
second.insets = first.insets;
second.fill = GridBagConstraints.HORIZONTAL;
dataPanel.add(propertyNameLabel, first);
dataPanel.add(propertyNameTextField, second);
first.gridy = ++second.gridy;
dataPanel.add(propertyValueLabel, first);
dataPanel.add(propertyValueTextField, second);
propertyNameTextField.getDocument().addDocumentListener(
new DocumentListener()
{
public void insertUpdate(DocumentEvent e)
{
okButton.setEnabled(true);
}
public void removeUpdate(DocumentEvent e)
{
if (propertyNameTextField.getText().length() == 0)
okButton.setEnabled(false);
}
public void changedUpdate(DocumentEvent e)
{
}
});
}
/**
* Performs corresponding actions, when a button is pressed.
*
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed(ActionEvent e)
{
JButton sourceButton = (JButton) e.getSource();
if (sourceButton.equals(okButton))
{
confService.setProperty(propertyNameTextField.getText(),
propertyValueTextField.getText());
}
dispose();
}
/**
* Presses programmatically the cancel button, when Esc key is pressed.
*
* @param isEscaped indicates if the Esc button was pressed on close
*/
protected void close(boolean isEscaped)
{
cancelButton.doClick();
}
}

@ -0,0 +1,129 @@
/*
* Jitsi, 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.propertieseditor;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.ResourceManagementService;
import java.util.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
/**
* The <tt>BundleActivator</tt> of the PropertiesEditor plugin.
*
* @author Marin Dzhigarov
* @author Pawel Domas
*/
public class PropertiesEditorActivator
implements BundleActivator
{
/**
* The bundle context.
*/
public static BundleContext bundleContext;
/**
* Starts this bundle and adds the
* <td>PropertiesEditorPanel</tt> contained in it to the configuration
* window obtained from the <tt>UIService</tt>.
* @param bc the <tt>BundleContext</tt>
* @throws Exception if one of the operation executed in the start method
* fails
*/
public void start(BundleContext bc) throws Exception
{
bundleContext = bc;
Dictionary<String, String> properties = new Hashtable<String, String>();
properties.put(ConfigurationForm.FORM_TYPE,
ConfigurationForm.ADVANCED_TYPE);
bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
StartingPanel.class.getName(),
getClass().getClassLoader(),
"",
"plugin.propertieseditor.TITLE",
1002, true),
properties);
}
/**
* Stops this bundles.
* @param bc the <tt>BundleContext</tt>
* @throws Exception if one of the operation executed in the stop method
* fails
*/
public void stop(BundleContext bc) throws Exception {}
/**
* The ui service
*/
private static UIService uiService;
/**
* Returns the <tt>UIService</tt> obtained from the bundle context.
*
* @return the <tt>UIService</tt> obtained from the bundle context.
*/
public static UIService getUIService()
{
if (uiService == null)
{
ServiceReference uiReference =
bundleContext.getServiceReference(UIService.class.getName());
uiService =
(UIService) bundleContext.getService(uiReference);
}
return uiService;
}
/**
* The configuration service.
*/
private static ConfigurationService configService;
/**
* Returns the <tt>ConfigurationService</tt> obtained from the bundle context.
*
* @return the <tt>ConfigurationService</tt> obtained from the bundle context.
*/
public static ConfigurationService getConfigurationService()
{
if (configService == null)
{
configService = ServiceUtils.getService(
bundleContext,
ConfigurationService.class);
}
return configService;
}
/**
* The resource management service.
*/
private static ResourceManagementService resourceManagementService;
/**
* Returns the <tt>ResourceManagementService</tt> obtained from the bundle context.
*
* @return the <tt>ResourceManagementService</tt> obtained from the bundle context.
*/
public static ResourceManagementService getResourceManagementService() {
if (resourceManagementService == null) {
resourceManagementService = ServiceUtils.getService(
bundleContext,
ResourceManagementService.class);
}
return resourceManagementService;
}
}

@ -0,0 +1,137 @@
/*
* Jitsi, 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.propertieseditor;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.resources.*;
/**
* @author Marin Dzhigarov
* @author Pawel Domas
*
*/
public class PropertiesEditorPanel
extends TransparentPanel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 1L;
private ResourceManagementService resourceManagementService =
PropertiesEditorActivator.getResourceManagementService();
/**
* The panel containing the props table and the buttons panel
*/
private JPanel centerPanel;
/**
* The props table.
*/
private JTable propsTable;
/**
* The buttons panel.
*/
private ButtonsPanel buttonsPanel;
/**
* Creates an instance <tt>PropertiesEditorPanel</tt>.
*/
public PropertiesEditorPanel()
{
super(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
/**
* Instantiates the properties table and adds selection model and
* listener and adds a row sorter to the table model
*/
propsTable = new JTable(getTableModel());
propsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
PropsListSelectionListener selectionListener =
new PropsListSelectionListener();
propsTable.getSelectionModel().addListSelectionListener(
selectionListener);
propsTable.getColumnModel().getSelectionModel()
.addListSelectionListener(selectionListener);
TableRowSorter<TableModel> sorter =
new TableRowSorter<TableModel>(propsTable.getModel());
propsTable.setRowSorter(sorter);
JScrollPane scrollPane = new JScrollPane(propsTable);
SearchField searchField = new SearchField("", sorter);
buttonsPanel = new ButtonsPanel(propsTable, searchField);
centerPanel = new TransparentPanel(new BorderLayout());
centerPanel.add(scrollPane, BorderLayout.CENTER);
centerPanel.add(buttonsPanel, BorderLayout.EAST);
JLabel needRestart =
new JLabel(
resourceManagementService
.getI18NString("plugin.propertieseditor.NEED_RESTART"));
needRestart.setForeground(Color.RED);
TransparentPanel searchPanel =
new TransparentPanel(new BorderLayout(5, 0));
searchPanel.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
searchPanel.add(searchField, BorderLayout.CENTER);
add(searchPanel, BorderLayout.NORTH);
add(centerPanel, BorderLayout.CENTER);
add(needRestart, BorderLayout.SOUTH);
}
/**
* The table model of the props table.
*/
private PropsTableModel tableModel;
/**
* Returns the table model of the props table.
*
* @return The <tt>PropsTableModel</tt> of the props table.
*/
private PropsTableModel getTableModel()
{
if (tableModel == null)
tableModel = new PropsTableModel();
return tableModel;
}
/**
* Listens for events triggered when a selection is made in the props list.
*/
private class PropsListSelectionListener
implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent e)
{
int selectedRow = propsTable.getSelectedRow();
if (selectedRow == -1)
{
buttonsPanel.defaultButtonState();
return;
}
buttonsPanel.enableDeleteButton(true);
}
}
}

@ -0,0 +1,139 @@
/*
* Jitsi, 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.propertieseditor;
import java.beans.*;
import javax.swing.event.*;
import javax.swing.table.*;
import org.jitsi.service.configuration.*;
/**
* @author Marin Dzhigarov
* @author Pawel Domas
*
*/
public class PropsTableModel
implements TableModel,
PropertyChangeListener
{
/**
* The configuration service.
*/
private ConfigurationService confService = PropertiesEditorActivator.getConfigurationService();
/**
* Creates an instance of <tt>PropsTableModel</tt>.
*/
PropsTableModel() {}
public void Register()
{
confService.addPropertyChangeListener(this);
}
public void Unregister()
{
confService.removePropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent evt)
{
for (TableModelListener l : listeners.getListeners(TableModelListener.class))
{
l.tableChanged(new TableModelEvent(this));
}
}
public int getRowCount()
{
return confService.getAllPropertyNames().size();
}
/**
* Returns the count of table columns.
* @return int the count of table columns
*/
public int getColumnCount()
{
return 2;
}
/**
* Returns the column name given column index.
* @param columnIndex The column index.
* @return The column name.
*/
public String getColumnName(int columnIndex)
{
if(columnIndex == 0)
{
return "Property";
} else
{
return "Value";
}
}
/**
* Returns the class of the column given a column index
*/
public Class<?> getColumnClass(int columnIndex)
{
return String.class;
}
/**
* Returns true if the given cell is edittable.
* Edittable cells in this model are cells with column index 1.
* @param rowIndex The row index.
* @param columnIndex The column index.
* @return True if the column index is 1
*/
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return columnIndex == 1;
}
/**
* Returns the value in the cell given by row and column.
*/
public Object getValueAt(int rowIndex, int columnIndex)
{
if (columnIndex == 0)
{
return confService.getAllPropertyNames().get(rowIndex);
} else
{
return confService.getProperty(confService.getAllPropertyNames().get(rowIndex));
}
}
/**
* Sets aValue at a cell with coordinates [rowIndex, columnIndex]
* @param aValue The given value.
* @param rowIndex The row index that the value will be set to.
* @param columnIndex The column index that the value will be set to.
*/
public void setValueAt(Object aValue, int rowIndex, int columnIndex)
{
String property = confService.getAllPropertyNames().get(rowIndex);
confService.setProperty(property, aValue);
}
private EventListenerList listeners = new EventListenerList();
public void addTableModelListener(TableModelListener l)
{
listeners.add(TableModelListener.class, l);
}
public void removeTableModelListener(TableModelListener l)
{
listeners.remove(TableModelListener.class, l);
}
}

@ -0,0 +1,158 @@
/*
* Jitsi, 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.propertieseditor;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.desktoputil.plaf.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
/**
* The field used for searching in the properties table.
*
* @author Marin Dzhigarov
*
*/
public class SearchField
extends SIPCommTextField
implements Skinnable
{
/**
* Serial Version UID.
*/
private static final long serialVersionUID = 1L;
/**
* Class id key used in UIDefaults.
*/
private static final String uiClassID = SearchField.class.getName()
+ "FieldUI";
/**
* The object used for logging.
*/
private Logger logger = Logger.getLogger(SearchField.class);
TableRowSorter<TableModel> sorter;
/**
* Adds the ui class to UIDefaults.
*/
static
{
UIManager.getDefaults().put(uiClassID,
SearchFieldUI.class.getName());
}
/**
* Creates an instance <tt>SearchField</tt>.
*
* @param text the text we would like to enter by default
* @param sorter the sorter which will be used for filtering.
*/
public SearchField(String text, final TableRowSorter<TableModel> sorter)
{
super(text);
if (getUI() instanceof SearchFieldUI)
{
((SearchFieldUI) getUI()).setDeleteButtonEnabled(true);
((SearchFieldUI) getUI()).setCallButtonEnabled(false);
}
this.setBorder(null);
this.setOpaque(false);
this.setPreferredSize(new Dimension(100, 25));
this.setDragEnabled(true);
InputMap imap =
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
ActionMap amap = getActionMap();
amap.put("escape", new AbstractAction()
{
/**
* Serial Version UID.
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e)
{
setText("");
}
});
getDocument().addDocumentListener(new DocumentListener()
{
public void insertUpdate(DocumentEvent e)
{
RowFilter<TableModel, Object> rf = null;
try
{
rf = RowFilter.regexFilter(getText(), 0);
}
catch (java.util.regex.PatternSyntaxException exception)
{
logger.info("Failed to compile regex.", exception);
return;
}
sorter.setRowFilter(rf);
}
public void removeUpdate(DocumentEvent e)
{
RowFilter<TableModel, Object> rf = null;
try
{
rf = RowFilter.regexFilter(getText(), 0);
}
catch (java.util.regex.PatternSyntaxException exception)
{
logger.info("Failed to compile regex.", exception);
return;
}
sorter.setRowFilter(rf);
}
public void changedUpdate(DocumentEvent e)
{
}
});
loadSkin();
}
/**
* Returns the name of the L&F class that renders this component.
*
* @return the string "TreeUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID()
{
return uiClassID;
}
/**
* Reloads text field UI defs.
*/
public void loadSkin()
{
if (getUI() instanceof SearchFieldUI)
{
((SearchFieldUI) getUI()).loadSkin();
}
}
}

@ -0,0 +1,60 @@
/*
* Jitsi, 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.propertieseditor;
import java.awt.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
/**
* The <tt>StartingPanel</tt> wraps the <tt>WarningPanel</tt> and
* <tt>PropertiesEditorPanel</tt>. Its main purpose is to choose which one of
* the panels to set visible.
*
* @author Marin Dzhigarov
*/
public class StartingPanel
extends TransparentPanel
{
/**
* Serial Version UID.
*/
private static final long serialVersionUID = 1L;
private ConfigurationService confService = PropertiesEditorActivator
.getConfigurationService();
/*
* The WarningPanel
*/
WarningPanel warningPanel = new WarningPanel(this);
/**
* The PropertiesEditorPanel
*/
PropertiesEditorPanel propertiesEditorPanel = new PropertiesEditorPanel();
/**
* Creates an instance <tt>StartingPanel</tt>
*/
public StartingPanel()
{
super(new BorderLayout());
boolean showWarning =
confService.getBoolean(Constants.SHOW_WARNING_MSG_PROP, true);
if (showWarning)
{
add(warningPanel, BorderLayout.CENTER);
}
else
{
add(propertiesEditorPanel, BorderLayout.CENTER);
}
}
}

@ -0,0 +1,98 @@
/*
* Jitsi, 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.propertieseditor;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
/**
* The <tt>WarningPanel</tt> allows users to change Jitsi configuration
* properties at runtime. It wraps the <tt>PropertiesEditorPanel</tt> in order
* to provide some more explanations and make complex configurations available
* only to advanced users.
*
* @author Marin Dzhigarov
*/
public class WarningPanel
extends TransparentPanel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 1L;
private ResourceManagementService resourceManagementService =
PropertiesEditorActivator.getResourceManagementService();
private ConfigurationService confService = PropertiesEditorActivator
.getConfigurationService();
private JCheckBox checkBox;
/**
* Creates an instance <tt>WarningPanel</tt>
*
* @param startingPanel
*/
public WarningPanel(final StartingPanel startingPanel)
{
super(new BorderLayout());
this.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JPanel mainPanel = new TransparentPanel(new BorderLayout(0, 10));
add(mainPanel, BorderLayout.NORTH);
JTextPane warningMsg = new JTextPane();
warningMsg.setEditable(false);
warningMsg.setOpaque(false);
warningMsg.setText(resourceManagementService
.getI18NString("plugin.propertieseditor.DESCRIPTION"));
checkBox =
new JCheckBox(
resourceManagementService
.getI18NString("plugin.propertieseditor.CHECK_BOX"));
checkBox.setOpaque(false);
checkBox.setSelected(true);
mainPanel.add(warningMsg, BorderLayout.NORTH);
mainPanel.add(checkBox, BorderLayout.CENTER);
JButton btn =
new JButton(
resourceManagementService
.getI18NString("plugin.propertieseditor.IM_AWARE"));
btn.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
confService.setProperty(Constants.SHOW_WARNING_MSG_PROP,
new Boolean(checkBox.isSelected()));
startingPanel.removeAll();
startingPanel.add(startingPanel.propertiesEditorPanel,
BorderLayout.CENTER);
startingPanel.propertiesEditorPanel.setVisible(true);
startingPanel.revalidate();
startingPanel.repaint();
}
});
JPanel buttonPanel =
new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
buttonPanel.add(btn);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
}
}

@ -0,0 +1,22 @@
Bundle-Activator: net.java.sip.communicator.plugin.propertieseditor.PropertiesEditorActivator
Bundle-Description: A panel that allows users to configure properties
Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
org.jitsi.service.configuration,
org.jitsi.service.resources,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.gui.event,
net.java.sip.communicator.util,
net.java.sip.communicator.util.skin,
net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.desktoputil.event,
net.java.sip.communicator.plugin.desktoputil.plaf,
javax.swing,
javax.swing.event,
javax.swing.table,
javax.swing.text,
javax.swing.border,
javax.swing.plaf

@ -6,7 +6,6 @@
*/
package net.java.sip.communicator.util;
//import java.awt.image.*;
import java.util.*;
import net.java.sip.communicator.service.gui.*;

Loading…
Cancel
Save