From: <fd...@us...> - 2006-10-30 16:54:43
|
Revision: 126 http://svn.sourceforge.net/columba/?rev=126&view=rev Author: fdietz Date: 2006-10-30 08:53:39 -0800 (Mon, 30 Oct 2006) Log Message: ----------- [intern]moved tagging code from mhub to core framework. Added tagging to contact partially to calendar component Added Paths: ----------- columba/trunk/calendar/src/main/java/org/columba/calendar/ui/action/TagCalendarMenu.java columba/trunk/calendar/src/main/java/org/columba/calendar/ui/tagging/CalendarTagList.java columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualFolder.java columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualItem.java columba/trunk/contact/src/main/java/org/columba/addressbook/gui/action/TagContactMenu.java columba/trunk/contact/src/main/java/org/columba/addressbook/gui/tagging/ContactTagList.java columba/trunk/contact/src/test/java/org/columba/addressbook/folder/VirtualFolderContactTest.java columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TagList.java columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TaggingMenu.java columba/trunk/core/src/main/java/org/columba/core/tagging/TagEvent.java columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagEvent.java columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagListener.java columba/trunk/mail/src/main/java/org/columba/mail/gui/tagging/MailTagList.java Added: columba/trunk/calendar/src/main/java/org/columba/calendar/ui/action/TagCalendarMenu.java =================================================================== --- columba/trunk/calendar/src/main/java/org/columba/calendar/ui/action/TagCalendarMenu.java (rev 0) +++ columba/trunk/calendar/src/main/java/org/columba/calendar/ui/action/TagCalendarMenu.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,126 @@ +package org.columba.calendar.ui.action; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.Iterator; + +import org.columba.api.gui.frame.IFrameMediator; +import org.columba.calendar.base.api.IActivity; +import org.columba.calendar.resourceloader.ResourceLoader; +import org.columba.calendar.ui.calendar.api.ActivitySelectionChangedEvent; +import org.columba.calendar.ui.calendar.api.IActivitySelectionChangedListener; +import org.columba.calendar.ui.frame.CalendarFrameMediator; +import org.columba.core.association.AssociationStore; +import org.columba.core.association.api.IAssociation; +import org.columba.core.gui.tagging.TaggingMenu; +import org.columba.core.tagging.TagManager; +import org.columba.core.tagging.api.ITag; + +public class TagCalendarMenu extends TaggingMenu implements IActivitySelectionChangedListener { + + final static private String SERVICE_ID = "tagging"; + + private String calendarId; + + /** + * @param frameMediator + */ + public TagCalendarMenu(IFrameMediator frameMediator) { + super(frameMediator, ResourceLoader.getString("tagging", + "contact_tag_message"), "menu_tag_message"); + + ((CalendarFrameMediator) frameMediator).getCalendarView().addSelectionChangedListener(this); + + } + + public void selectionChanged(ActivitySelectionChangedEvent object) { + if ( object.getSelection() != null && object.getSelection().length > 0) { + setEnabled(true); + removeAll(); + createSubMenu(); + } else + setEnabled(false); + } + + @Override + protected void assignTag(String tagId) { + IActivity activity = ((CalendarFrameMediator) getFrameMediator()) + .getCalendarView().getSelectedActivity(); + String calendarId = activity.getCalendarId(); + String activityId = activity.getId(); + + AssociationStore.getInstance().addAssociation(SERVICE_ID, tagId, + createURI(calendarId, activityId).toString()); + } + + @Override + protected boolean isTagged(ITag tag) { + IActivity activity = ((CalendarFrameMediator) getFrameMediator()) + .getCalendarView().getSelectedActivity(); + if ( activity == null) return false; + + String calendarId = activity.getCalendarId(); + String activityId = activity.getId(); + + boolean tagged = checkAssocation(calendarId, activityId, tag); + return tagged; + } + + @Override + protected void removeAllTags() { + IActivity activity = ((CalendarFrameMediator) getFrameMediator()) + .getCalendarView().getSelectedActivity(); + String calendarId = activity.getCalendarId(); + String activityId = activity.getId(); + + for (Iterator<ITag> iter = TagManager.getInstance().getAllTags(); iter + .hasNext();) { + ITag tag = iter.next(); + + AssociationStore.getInstance().removeAssociation(SERVICE_ID, + tag.getId(), createURI(calendarId, activityId).toString()); + } + } + + @Override + protected void removeTag(String tagId) { + IActivity activity = ((CalendarFrameMediator) getFrameMediator()) + .getCalendarView().getSelectedActivity(); + String calendarId = activity.getCalendarId(); + String activityId = activity.getId(); + + AssociationStore.getInstance().removeAssociation(SERVICE_ID, tagId, + createURI(calendarId, activityId).toString()); + } + + // create URI representing the contact + public static URI createURI(String folderId, Object contactId) { + URI uri = null; + try { + uri = new URI("columba://org.columba.calendar/" + folderId + "/" + + contactId); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return uri; + } + + // check if contact is tagged + private boolean checkAssocation(String folderId, String eventId, ITag tag) { + URI uri = createURI(folderId, eventId); + Collection<IAssociation> c = AssociationStore.getInstance() + .getAllAssociations(uri.toString()); + + for (IAssociation as : c) { + if (as.getServiceId().equals(SERVICE_ID) + && (as.getMetaDataId() != null) + && (as.getMetaDataId().equals(tag.getId()))) { + return true; + } + } + return false; + } + + +} Added: columba/trunk/calendar/src/main/java/org/columba/calendar/ui/tagging/CalendarTagList.java =================================================================== --- columba/trunk/calendar/src/main/java/org/columba/calendar/ui/tagging/CalendarTagList.java (rev 0) +++ columba/trunk/calendar/src/main/java/org/columba/calendar/ui/tagging/CalendarTagList.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,98 @@ +package org.columba.calendar.ui.tagging; + +import java.util.Collection; + +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import org.columba.api.gui.frame.IFrameMediator; +import org.columba.calendar.ui.frame.CalendarFrameMediator; +import org.columba.core.association.AssociationStore; +import org.columba.core.gui.tagging.TagList; +import org.columba.core.tagging.api.ITag; + +import com.miginfocom.calendar.category.Category; +import com.miginfocom.calendar.category.CategoryDepository; + +public class CalendarTagList extends TagList { + + private static final java.util.logging.Logger LOG = java.util.logging.Logger + .getLogger("org.columba.calendar.ui.tagging"); //$NON-NLS-1$ + + public static final String PROP_FILTERED = "filterRow"; + + private IFrameMediator frameMediator; + + public CalendarTagList(IFrameMediator frameMediator) { + super(); + + this.frameMediator = frameMediator; + + addListSelectionListener(new MyListSelectionListener()); + } + + class MyListSelectionListener implements ListSelectionListener { + MyListSelectionListener() { + } + + public void valueChanged(ListSelectionEvent event) { + // return if selection change is in flux + if (event.getValueIsAdjusting()) { + return; + } + + ITag result = (ITag) getSelectedValue(); + // create a virtual folder with all messages holding this tag + Collection<String> messageList = AssociationStore.getInstance() + .getAssociatedItems("tagging", result.getId()); + for (String id : messageList) { + + // example: + // "columba://org.columba.contact/<folder-id>/<contact-id>" + String s = id.toString(); + + // TODO: @author fdietz replace with regular expression + int activityIndex = s.lastIndexOf('/'); + String contactId = s.substring(activityIndex + 1, s.length()); + int folderIndex = s.lastIndexOf('/', activityIndex - 1); + String folderId = s.substring(folderIndex + 1, activityIndex); + int componentIndex = s.lastIndexOf('/', folderIndex - 1); + String componentId = s.substring(componentIndex + 1, + folderIndex); + + // check if its a contact component + if (componentId.equals("org.columba.calendar")) { + boolean success = false; + Collection<Category> c = CategoryDepository.getRoot() + .getChildrenDeep(); + for (Category category : c) { + String categoryId = (String) category.getId(); + if ( !categoryId.startsWith("tag_")) continue; + + if (categoryId.equals(folderId)) { + // found category -> mark it as selected + category.setPropertyDeep(Category.PROP_IS_HIDDEN, + Boolean.valueOf(false), Boolean.TRUE); + success = true; + } else { + // non-matching found -> mark it as *not* selected + category.setPropertyDeep(Category.PROP_IS_HIDDEN, + Boolean.valueOf(true), Boolean.TRUE); + } + } + + if ( !success) { + // there was no category -> create a new one + Category category = CategoryDepository.getRoot().addSubCategory("tag_"+result.getId(), result.getProperty("name")); + // mark it as selected + category.setPropertyDeep(Category.PROP_IS_HIDDEN, + Boolean.valueOf(false), Boolean.TRUE); + } + } + + // update calendar viewer + ((CalendarFrameMediator) frameMediator).getCalendarView().recreateFilterRows(); + } + } + } +} \ No newline at end of file Added: columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualFolder.java =================================================================== --- columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualFolder.java (rev 0) +++ columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualFolder.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,149 @@ +package org.columba.addressbook.folder.virtual; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import java.util.Vector; + +import javax.swing.ImageIcon; +import javax.swing.tree.TreeNode; + +import org.columba.addressbook.folder.AbstractFolder; +import org.columba.addressbook.folder.IContactStorage; +import org.columba.addressbook.model.ContactModelFactory; +import org.columba.addressbook.model.IContactModel; +import org.columba.addressbook.model.IContactModelPartial; +import org.columba.api.exception.StoreException; + +public class VirtualFolder extends AbstractFolder implements IContactStorage { + + private Map<String, VirtualItem> map = new Hashtable<String, VirtualItem>(); + + public VirtualFolder() { + super("name", "directory"); + } + + public String add(IContactStorage parentStore, String parentId) { + if ( parentStore == null ) throw new IllegalArgumentException("parentStore == null"); + if ( parentId == null ) throw new IllegalArgumentException("parentId == null"); + + VirtualItem item = new VirtualItem(parentStore, parentId); + String uuid = UUID.randomUUID().toString(); + map.put(uuid, item); + + return uuid; + } + + public String add(IContactModel contact) throws StoreException { + throw new IllegalArgumentException("add() not supported"); + } + + public int count() throws StoreException { + return map.size(); + } + + public boolean exists(String id) throws StoreException { + if ( id == null ) throw new IllegalArgumentException("id == null"); + return map.containsKey(id); + } + + /** + * @see org.columba.addressbook.folder.IContactStorage#getHeaderItemList() + * + */ + @Override + public Map<String, IContactModelPartial> getContactItemMap() + throws StoreException { + Map<String, IContactModelPartial> result = new Hashtable<String, IContactModelPartial>(); + + Iterator<Map.Entry<String, VirtualItem>> it = map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, VirtualItem> entry = it.next(); + VirtualItem item = entry.getValue(); + IContactStorage parentStore = item.getParentStore(); + String parentId = item.getParentId(); + + IContactModel model = parentStore.get(parentId); + IContactModelPartial partial = ContactModelFactory + .createContactModelPartial(model, entry.getKey()); + result.put(entry.getKey(), partial); + } + + return result; + } + + public IContactModel get(String id) throws StoreException { + if ( id == null ) throw new IllegalArgumentException("id == null"); + + VirtualItem item = map.get(id); + IContactStorage parentStore = item.getParentStore(); + String parentId = item.getParentId(); + + IContactModel model = parentStore.get(parentId); + return model; + } + + public void modify(String id, IContactModel contact) throws StoreException { + if ( id == null ) throw new IllegalArgumentException("id == null"); + if ( contact == null ) throw new IllegalArgumentException("contact == null"); + + VirtualItem item = map.get(id); + IContactStorage parentStore = item.getParentStore(); + String parentId = item.getParentId(); + + parentStore.modify(parentId, contact); + } + + public void remove(String id) throws StoreException { + if ( id == null ) throw new IllegalArgumentException("id == null"); + + VirtualItem item = map.get(id); + IContactStorage parentStore = item.getParentStore(); + String parentId = item.getParentId(); + + parentStore.remove(parentId); + } + + public ImageIcon getIcon() { + return null; + } + + public String getId() { + return "id"; + } + + public String getName() { + return "vfolder"; + } + + public Enumeration children() { + return new Vector().elements(); + } + + public boolean getAllowsChildren() { + return false; + } + + public TreeNode getChildAt(int childIndex) { + return null; + } + + public int getChildCount() { + return 0; + } + + public int getIndex(TreeNode node) { + return 0; + } + + public TreeNode getParent() { + return null; + } + + public boolean isLeaf() { + return false; + } + +} Added: columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualItem.java =================================================================== --- columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualItem.java (rev 0) +++ columba/trunk/contact/src/main/java/org/columba/addressbook/folder/virtual/VirtualItem.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,25 @@ +package org.columba.addressbook.folder.virtual; + +import org.columba.addressbook.folder.IContactStorage; + +public class VirtualItem { + + private IContactStorage parentStore; + private String parentId; + + public VirtualItem(IContactStorage parentStore, String parentId) { + this.parentStore = parentStore; + this.parentId = parentId; + } + + public String getParentId() { + return parentId; + } + + public IContactStorage getParentStore() { + return parentStore; + } + + + +} Added: columba/trunk/contact/src/main/java/org/columba/addressbook/gui/action/TagContactMenu.java =================================================================== --- columba/trunk/contact/src/main/java/org/columba/addressbook/gui/action/TagContactMenu.java (rev 0) +++ columba/trunk/contact/src/main/java/org/columba/addressbook/gui/action/TagContactMenu.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,167 @@ +package org.columba.addressbook.gui.action; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.Iterator; + +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.TreePath; + +import org.columba.addressbook.facade.IContactItem; +import org.columba.addressbook.folder.IFolder; +import org.columba.addressbook.gui.frame.AddressbookFrameMediator; +import org.columba.addressbook.util.AddressbookResourceLoader; +import org.columba.api.gui.frame.IFrameMediator; +import org.columba.core.association.AssociationStore; +import org.columba.core.association.api.IAssociation; +import org.columba.core.gui.tagging.TaggingMenu; +import org.columba.core.tagging.TagManager; +import org.columba.core.tagging.api.ITag; + +public class TagContactMenu extends TaggingMenu implements + ListSelectionListener, TreeSelectionListener { + + final static private String SERVICE_ID = "tagging"; + + private String folderId; + + private String contactId; + + /** + * @param frameMediator + */ + public TagContactMenu(IFrameMediator frameMediator) { + super(frameMediator, AddressbookResourceLoader.getString("dialog", + "tagging", "contact_tag_message"), "menu_tag_message"); + + // register interest on contact selection changes + ((AddressbookFrameMediator) frameMediator) + .addTableSelectionListener(this); + + // register interest on tree selection changes + ((AddressbookFrameMediator) frameMediator) + .addTreeSelectionListener(this); + } + + /** + */ + public void valueChanged(TreeSelectionEvent e) { + TreePath path = e.getNewLeadSelectionPath(); + + // remember last selected folder treenode + if (path != null) { + IFolder folder = (IFolder) path.getLastPathComponent(); + folderId = folder.getId(); + } + + } + + /** + * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent) + */ + public void valueChanged(ListSelectionEvent event) { + // return if selection change is in flux + if (event.getValueIsAdjusting()) { + return; + } + + Object[] uids = ((AddressbookFrameMediator) getFrameMediator()) + .getTable().getUids(); + + if (uids.length > 0) { + setEnabled(true); + + removeAll(); + createSubMenu(); + } else { + setEnabled(false); + } + } + + @Override + protected void assignTag(String tagId) { + + String[] ids = ((AddressbookFrameMediator) getFrameMediator()) + .getTable().getUids(); + for (int i = 0; i < ids.length; i++) { + String contactId = ids[i]; + AssociationStore.getInstance().addAssociation(SERVICE_ID, tagId, + createURI(folderId, contactId).toString()); + } + } + + @Override + protected boolean isTagged(ITag tag) { + String[] ids = ((AddressbookFrameMediator) getFrameMediator()) + .getTable().getUids(); + boolean tagged = true; + for (int i = 0; i < ids.length; i++) { + String contactId = ids[i]; + + tagged &= checkAssocation(folderId, contactId, tag); + } + + return tagged; + } + + @Override + protected void removeAllTags() { + IContactItem contactItem = ((AddressbookFrameMediator) getFrameMediator()) + .getTable().getSelectedItem(); + String contactId = contactItem.getId(); + + for (Iterator<ITag> iter = TagManager.getInstance().getAllTags(); iter + .hasNext();) { + ITag tag = iter.next(); + + AssociationStore.getInstance().removeAssociation(SERVICE_ID, + tag.getId(), createURI(folderId, contactId).toString()); + } + } + + @Override + protected void removeTag(String tagId) { + + String[] ids = ((AddressbookFrameMediator) getFrameMediator()) + .getTable().getUids(); + for (int i = 0; i < ids.length; i++) { + String contactId = ids[i]; + AssociationStore.getInstance().removeAssociation(SERVICE_ID, tagId, + createURI(folderId, contactId).toString()); + } + + } + + // create URI representing the contact + public static URI createURI(String folderId, Object contactId) { + URI uri = null; + try { + uri = new URI("columba://org.columba.contact/" + folderId + "/" + + contactId); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return uri; + } + + // check if contact is tagged + private boolean checkAssocation(String folderId, String contactId, ITag tag) { + URI uri = createURI(folderId, contactId); + Collection<IAssociation> c = AssociationStore.getInstance() + .getAllAssociations(uri.toString()); + + for (IAssociation as : c) { + if (as.getServiceId().equals(SERVICE_ID) + && (as.getMetaDataId() != null) + && (as.getMetaDataId().equals(tag.getId()))) { + return true; + } + } + return false; + } + +} Added: columba/trunk/contact/src/main/java/org/columba/addressbook/gui/tagging/ContactTagList.java =================================================================== --- columba/trunk/contact/src/main/java/org/columba/addressbook/gui/tagging/ContactTagList.java (rev 0) +++ columba/trunk/contact/src/main/java/org/columba/addressbook/gui/tagging/ContactTagList.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,79 @@ +package org.columba.addressbook.gui.tagging; + +import java.util.Collection; + +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import org.columba.addressbook.folder.IContactStorage; +import org.columba.addressbook.folder.virtual.VirtualFolder; +import org.columba.addressbook.gui.frame.AddressbookFrameMediator; +import org.columba.addressbook.gui.tree.AddressbookTreeModel; +import org.columba.api.gui.frame.IFrameMediator; +import org.columba.core.association.AssociationStore; +import org.columba.core.gui.tagging.TagList; +import org.columba.core.tagging.api.ITag; + +public class ContactTagList extends TagList { + + private static final java.util.logging.Logger LOG = java.util.logging.Logger + .getLogger("org.columba.addressbook.action"); //$NON-NLS-1$ + + private IFrameMediator frameMediator; + + public ContactTagList(IFrameMediator frameMediator) { + super(); + + this.frameMediator = frameMediator; + + addListSelectionListener(new MyListSelectionListener()); + } + + class MyListSelectionListener implements ListSelectionListener { + MyListSelectionListener() { + } + + public void valueChanged(ListSelectionEvent event) { + // return if selection change is in flux + if (event.getValueIsAdjusting()) { + return; + } + + VirtualFolder virtualFolder = new VirtualFolder(); + ITag result = (ITag) getSelectedValue(); + // create a virtual folder with all messages holding this tag + Collection<String> messageList = AssociationStore.getInstance() + .getAssociatedItems("tagging", result.getId()); + for (String id : messageList) { + + // example: + // "columba://org.columba.contact/<folder-id>/<contact-id>" + String s = id.toString(); + + // TODO: @author fdietz replace with regular expression + int contactIndex = s.lastIndexOf('/'); + String contactId = s.substring(contactIndex + 1, s.length()); + int folderIndex = s.lastIndexOf('/', contactIndex - 1); + String folderId = s.substring(folderIndex + 1, contactIndex); + int componentIndex = s.lastIndexOf('/', folderIndex - 1); + String componentId = s.substring(componentIndex + 1, + folderIndex); + + // check if its a contact component + if (componentId.equals("org.columba.contact")) { + IContactStorage parentStore = (IContactStorage) AddressbookTreeModel + .getInstance().getFolder(folderId); + if (parentStore == null) { + LOG.severe("can't find contact store for \""+folderId+"\""); + continue; + } + virtualFolder.add(parentStore, contactId); + } + } + + // update folder selection + ((AddressbookFrameMediator)frameMediator).getTree().setSelectedFolder(virtualFolder); + } + } + +} Added: columba/trunk/contact/src/test/java/org/columba/addressbook/folder/VirtualFolderContactTest.java =================================================================== --- columba/trunk/contact/src/test/java/org/columba/addressbook/folder/VirtualFolderContactTest.java (rev 0) +++ columba/trunk/contact/src/test/java/org/columba/addressbook/folder/VirtualFolderContactTest.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,51 @@ +package org.columba.addressbook.folder; + +import org.columba.addressbook.folder.virtual.VirtualFolder; +import org.columba.addressbook.model.ContactModel; +import org.columba.addressbook.model.EmailModel; +import org.columba.addressbook.model.IContactModel; + +public class VirtualFolderContactTest extends AbstractFolderTstCase { + + public VirtualFolderContactTest(String arg0) { + super(arg0); + } + + + public void testAdd() throws Exception{ + ContactModel c = new ContactModel(); + + c.setNickName("nickname"); + c.addEmail(new EmailModel("na...@ma...", EmailModel.TYPE_HOME)); + String parentId = getSourceFolder().add(c); + + VirtualFolder vf = new VirtualFolder(); + + String id = vf.add(getSourceFolder(), parentId); + + IContactModel c2 = vf.get(id); + + assertEquals("nickname", c2.getNickName()); + } + + public void testModify() throws Exception{ + ContactModel c = new ContactModel(); + + c.setNickName("nickname"); + c.addEmail(new EmailModel("na...@ma...", EmailModel.TYPE_HOME)); + String parentId = getSourceFolder().add(c); + + VirtualFolder vf = new VirtualFolder(); + + String id = vf.add(getSourceFolder(), parentId); + + ContactModel c1 = (ContactModel) vf.get(id); + c1.setNickName("new"); + vf.modify(id, c1); + + IContactModel c2 = vf.get(id); + + assertEquals("new", c2.getNickName()); + } + +} Added: columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TagList.java =================================================================== --- columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TagList.java (rev 0) +++ columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TagList.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,211 @@ +package org.columba.core.gui.tagging; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListModel; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; + +import org.columba.core.tagging.TagManager; +import org.columba.core.tagging.api.ITag; +import org.columba.core.tagging.api.ITagEvent; +import org.columba.core.tagging.api.ITagListener; +import org.jdesktop.swingx.JXList; +import org.jdesktop.swingx.decorator.Highlighter; +import org.jdesktop.swingx.decorator.HighlighterPipeline; +import org.jdesktop.swingx.decorator.RolloverHighlighter; + +public class TagList extends JXList { + + private DefaultListModel listModel; + + public TagList() { + super(); + + // fill list model with tags + listModel = new DefaultListModel(); + Iterator<ITag> it = TagManager.getInstance().getAllTags(); + while (it.hasNext()) { + ITag tag = it.next(); + listModel.addElement(tag); + } + setModel(listModel); + + setCellRenderer(new MyListCellRenderer()); + + setBorder(null); + setHighlighters(new HighlighterPipeline( + new Highlighter[] { new RolloverHighlighter(new Color(248, 248, + 248), Color.white) })); + setRolloverEnabled(true); + + TagManager.getInstance().addTagListener(new MyTagListener()); + } + + public ITag getSelectedTag() { + return (ITag) getSelectedValue(); + } + + public Iterator<ITag> getSelectedTags() { + Object[] values = getSelectedValues(); + Vector<ITag> v = new Vector<ITag>(); + + for (Object o : values) { + v.add((ITag) o); + } + + return v.iterator(); + } + + class MyListCellRenderer extends JPanel implements ListCellRenderer { + + private Border lineBorder = new HeaderSeparatorBorder(new Color(230, + 230, 230)); + + private JLabel nameLabel = new JLabel(); + + private JLabel descriptionLabel = new JLabel(); + + private JLabel idLabel = new JLabel(); + + MyListCellRenderer() { + setLayout(new BorderLayout()); + + add(nameLabel, BorderLayout.WEST); + add(descriptionLabel, BorderLayout.CENTER); + add(idLabel, BorderLayout.EAST); + + setBorder(BorderFactory.createCompoundBorder(lineBorder, + BorderFactory.createEmptyBorder(2, 2, 2, 2))); + + setOpaque(true); + + } + + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + ITag result = (ITag) value; + + idLabel.setText("(id = " + result.getId() + ")"); + idLabel.setForeground(new Color(100, 100, 100)); + nameLabel.setText(result.getProperty("name")); + descriptionLabel.setText(result.getProperty("description")); + + return this; + } + + } + + class HeaderSeparatorBorder extends AbstractBorder { + + protected Color color; + + public HeaderSeparatorBorder(Color color) { + super(); + + this.color = color; + } + + /** + * Paints the border for the specified component with the specified + * position and size. + * + * @param c + * the component for which this border is being painted + * @param g + * the paint graphics + * @param x + * the x position of the painted border + * @param y + * the y position of the painted border + * @param width + * the width of the painted border + * @param height + * the height of the painted border + */ + public void paintBorder(Component c, Graphics g, int x, int y, + int width, int height) { + Color oldColor = g.getColor(); + g.setColor(color); + g.drawLine(x, y + height - 1, x + width - 1, y + height - 1); + + g.setColor(oldColor); + } + + /** + * Returns the insets of the border. + * + * @param c + * the component for which this border insets value applies + */ + public Insets getBorderInsets(Component c) { + return new Insets(0, 0, 1, 0); + } + + /** + * Reinitialize the insets parameter with this Border's current Insets. + * + * @param c + * the component for which this border insets value applies + * @param insets + * the object to be reinitialized + */ + public Insets getBorderInsets(Component c, Insets insets) { + insets.left = insets.top = insets.right = insets.bottom = 1; + return insets; + } + + } + + class MyTagListener implements ITagListener { + MyTagListener() { + } + + public void tagChanged(ITagEvent event) { + String tagId = event.getId(); + updateList(); + } + + public void tagAdded(ITagEvent event) { + String tagId = event.getId(); + updateList(); + } + + public void tagDeleted(ITagEvent event) { + String tagId = event.getId(); + updateList(); + } + + // real stupid recreation of whole list model + // -> replace with id-based listmodel update + private void updateList() { + listModel = new DefaultListModel(); + Iterator<ITag> it = TagManager.getInstance().getAllTags(); + while (it.hasNext()) { + ITag tag = it.next(); + listModel.addElement(tag); + } + setModel(listModel); + } + } +} Added: columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TaggingMenu.java =================================================================== --- columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TaggingMenu.java (rev 0) +++ columba/trunk/core/src/main/java/org/columba/core/gui/tagging/TaggingMenu.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,157 @@ +package org.columba.core.gui.tagging; + +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Iterator; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenuItem; + +import org.columba.api.gui.frame.IFrameMediator; +import org.columba.core.gui.menu.IMenu; +import org.columba.core.main.Bootstrap; +import org.columba.core.resourceloader.GlobalResourceLoader; +import org.columba.core.tagging.TagManager; +import org.columba.core.tagging.api.ITag; +import org.columba.core.tagging.api.ITagEvent; +import org.columba.core.tagging.api.ITagListener; + +/** + * Abstract base class for a tagging menu. + * <p> + * + * @author fdietz + * + * @author frd + */ +public abstract class TaggingMenu extends IMenu { + + public TaggingMenu(IFrameMediator controller, String name, String id) { + super(controller, name, id); + + createSubMenu(); + + // update menu if tags are changed + TagManager.getInstance().addTagListener(new MyTagListener()); + } + + protected void createSubMenu() { + + if (!Bootstrap.ENABLE_TAGS) + return; + + // TODO (@author hubms): implement custom menuitem renderer + JMenuItem item = new JMenuItem(GlobalResourceLoader.getString("dialog", + "tagging", "none")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + // fire callback to remove all tags from selected items + removeAllTags(); + } + }); + add(item); + addSeparator(); + + // don't want to have two separators + boolean tags = false; + + // add all existing tags to the menu + for (Iterator<ITag> iter = TagManager.getInstance().getAllTags(); iter + .hasNext();) { + final ITag tag = iter.next(); + final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(tag + .getProperty("name")); + + // mark tag, if the current selection is tagged with it + final boolean tagged = isTagged(tag); + + // we can add icons or colors later on + // item.setIcon(ImageLoader.getSmallIcon(IconKeys.INTERNET)); + menuItem.setSelected(tagged); + + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (menuItem.isSelected()) + assignTag(tag.getId()); + else + removeTag(tag.getId()); + } + }); + add(menuItem); + + tags = true; + } + + if (tags) + addSeparator(); + + JMenuItem editTagItem = new JMenuItem(GlobalResourceLoader.getString( + "dialog", "tagging", "edit")); + editTagItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + // not implemented yet + } + }); + add(editTagItem); + + } + + // listener updates menu in case the tags where changed + class MyTagListener implements ITagListener { + MyTagListener() { + } + + public void tagChanged(ITagEvent event) { + String tagId = event.getId(); + updateMenu(); + } + + public void tagAdded(ITagEvent event) { + String tagId = event.getId(); + updateMenu(); + } + + public void tagDeleted(ITagEvent event) { + String tagId = event.getId(); + updateMenu(); + } + + // real stupid recreation of whole menu model + private void updateMenu() { + removeAll(); + createSubMenu(); + } + } + + /** **************** overwrite callback methods ************************ */ + + /** + * Check if the current selection has the specific tag assigned to it. + * + * @param tag + * @return + */ + protected abstract boolean isTagged(ITag tag); + + /** + * Method is called if tag should be added to selected elements + * + * @param tagId + */ + protected abstract void assignTag(String tagId); + + /** + * Method is called if tag should be removed from selected elements + * + * @param tagId + */ + protected abstract void removeTag(String tagId); + + /** + * Methid is called if all tags should be removed from the selected elements + * + */ + protected abstract void removeAllTags(); + +} Added: columba/trunk/core/src/main/java/org/columba/core/tagging/TagEvent.java =================================================================== --- columba/trunk/core/src/main/java/org/columba/core/tagging/TagEvent.java (rev 0) +++ columba/trunk/core/src/main/java/org/columba/core/tagging/TagEvent.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,22 @@ +package org.columba.core.tagging; + +import org.columba.core.tagging.api.ITagEvent; + +public class TagEvent implements ITagEvent { + + private Object source; + private String id; + + public TagEvent(Object source, String id) { + this.source = source; + this.id = id; + } + + public String getId() { + return id; + } + + public Object getSource() { + return source; + } +} Added: columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagEvent.java =================================================================== --- columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagEvent.java (rev 0) +++ columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagEvent.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,9 @@ +package org.columba.core.tagging.api; + +public interface ITagEvent { + + public Object getSource(); + + public String getId(); + +} Added: columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagListener.java =================================================================== --- columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagListener.java (rev 0) +++ columba/trunk/core-api/src/main/java/org/columba/core/tagging/api/ITagListener.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,10 @@ +package org.columba.core.tagging.api; + +import java.util.EventListener; + +public interface ITagListener extends EventListener { + + public void tagChanged(ITagEvent event); + public void tagAdded(ITagEvent event); + public void tagDeleted(ITagEvent event); +} Added: columba/trunk/mail/src/main/java/org/columba/mail/gui/tagging/MailTagList.java =================================================================== --- columba/trunk/mail/src/main/java/org/columba/mail/gui/tagging/MailTagList.java (rev 0) +++ columba/trunk/mail/src/main/java/org/columba/mail/gui/tagging/MailTagList.java 2006-10-30 16:53:39 UTC (rev 126) @@ -0,0 +1,132 @@ +package org.columba.mail.gui.tagging; + +import java.util.Collection; +import java.util.Iterator; + +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.tree.MutableTreeNode; + +import org.columba.api.gui.frame.IFrameMediator; +import org.columba.api.plugin.PluginLoadingFailedException; +import org.columba.core.association.AssociationStore; +import org.columba.core.base.UUIDGenerator; +import org.columba.core.command.CommandProcessor; +import org.columba.core.gui.frame.FrameManager; +import org.columba.core.gui.tagging.TagList; +import org.columba.core.tagging.api.ITag; +import org.columba.mail.command.IMailFolderCommandReference; +import org.columba.mail.command.MailFolderCommandReference; +import org.columba.mail.folder.IMailbox; +import org.columba.mail.folder.headercache.CachedHeaderfields; +import org.columba.mail.folder.virtual.VirtualFolder; +import org.columba.mail.gui.frame.TreeViewOwner; +import org.columba.mail.gui.table.command.ViewHeaderListCommand; +import org.columba.mail.gui.tree.FolderTreeModel; +import org.columba.mail.message.ColumbaHeader; +import org.columba.ristretto.message.Header; + +public class MailTagList extends TagList { + + private IFrameMediator frameMediator; + + public MailTagList(IFrameMediator frameMediator) { + super(); + + this.frameMediator = frameMediator; + + addListSelectionListener(new MyListSelectionListener()); + } + + private IMailFolderCommandReference getMessageFromURI(String uri) { + // example: "columba://org.columba.mail/<folder-id>/<message-id>" + String s = uri; + + // TODO: @author fdietz replace with regular expression + int index = s.lastIndexOf('/'); + String messageId = s.substring(index + 1, s.length()); + String folderId = s.substring(s.lastIndexOf('/', index - 1) + 1, index); + + IMailbox folder = (IMailbox) FolderTreeModel.getInstance().getFolder( + folderId); + IMailFolderCommandReference r = new MailFolderCommandReference(folder, + new Object[] { Integer.parseInt(messageId) }); + + return r; + } + + + class MyListSelectionListener implements ListSelectionListener { + MyListSelectionListener() { + } + + public void valueChanged(ListSelectionEvent event) { + // return if selection change is in flux + if (event.getValueIsAdjusting()) { + return; + } + + ITag result = (ITag) getSelectedValue(); + // create a virtual folder with all messages holding this tag + Collection messageList = AssociationStore.getInstance() + .getAssociatedItems("tagging", result.getId()); + + // TODO @author hubms show if there is already a virtual folder for + // this tag + String uuid = new UUIDGenerator().newUUID(); + + // create a virtual folder + VirtualFolder taggedMessageFolder = new VirtualFolder( + "Tag Search Result", "VirtualFolder", uuid); + + // should be a MutableTreeNode + Object root = ((TreeViewOwner) frameMediator).getTreeController() + .getModel().getRoot(); + if (root instanceof MutableTreeNode) + taggedMessageFolder.setParent((MutableTreeNode) root); + + for (Iterator it = messageList.iterator(); it.hasNext();) { + IMailFolderCommandReference r = getMessageFromURI((String) it + .next()); + try { + Header header = ((IMailbox) r.getSourceFolder()) + .getHeaderFields(r.getUids()[0], CachedHeaderfields + .getDefaultHeaderfields()); + ColumbaHeader pHeader = new ColumbaHeader(header); + taggedMessageFolder.add(pHeader, (IMailbox) r + .getSourceFolder(), r.getUids()[0]); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // try { + // taggedMessageFolder.activate(); + // } catch (Exception e1) { + // // TODO Auto-generated catch block + // e1.printStackTrace(); + // } + + // ensure that we are currently in the mail component + IFrameMediator newMediator = null; + try { + newMediator = FrameManager.getInstance().switchView( + frameMediator.getContainer(), "ThreePaneMail"); + } catch (PluginLoadingFailedException e) { + e.printStackTrace(); + } + + // select invisible virtual folder + ((TreeViewOwner) newMediator).getTreeController().setSelected( + taggedMessageFolder); + + // update message list + CommandProcessor.getInstance() + .addOp( + new ViewHeaderListCommand(newMediator, + new MailFolderCommandReference( + taggedMessageFolder))); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |