Java tutorial
/* * Copyright 2013 Hewlett-Packard Development Company, L.P * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hp.alm.ali.idea.content.taskboard; import com.hp.alm.ali.idea.cfg.AliProjectConfiguration; import com.hp.alm.ali.idea.cfg.TaskBoardConfiguration; import com.hp.alm.ali.idea.services.ActiveItemService; import com.hp.alm.ali.idea.ui.EntityLabel; import com.hp.alm.ali.idea.services.EntityService; import com.hp.alm.ali.idea.ui.ScrollablePanel; import com.hp.alm.ali.idea.action.ActionUtil; import com.hp.alm.ali.idea.services.EntityLabelService; import com.hp.alm.ali.idea.ui.Highlightable; import com.hp.alm.ali.idea.ui.SimpleHighlight; import com.hp.alm.ali.idea.ui.editor.TaskEditor; import com.hp.alm.ali.idea.model.Entity; import com.intellij.openapi.actionSystem.ActionPopupMenu; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; import com.intellij.util.ui.UIUtil; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NonNls; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; public class BacklogItemPanel extends ScrollablePanel implements Highlightable, DataProvider { public static final String ITEM_NEW = "New"; public static final String ITEM_IN_PROGRESS = "In Progress"; public static final String ITEM_IN_TESTING = "In Testing"; public static final String ITEM_DONE = "Done"; public static final Dimension DIMENSION = new Dimension(300, 160); private Project project; private EntityLabelService entityLabelService; private EntityService entityService; private ActiveItemService activeItemService; private TaskBoardConfiguration taskBoardConfiguration; private TaskBoardFlow taskBoardFlow; private AliProjectConfiguration aliProjectConfiguration; private Map<String, TaskContainerPanel> taskContainers; private JComponent taskContent; private Map<Integer, TaskPanel> tasks; private Header header; private Content content; private JTextPane entityName; private Entity item; private SimpleHighlight simpleHighlight; private TaskBoardFilter filter; public BacklogItemPanel(Project project, Entity item, TaskBoardFilter filter) { super(new BorderLayout()); this.project = project; this.item = item; this.filter = filter; entityLabelService = project.getComponent(EntityLabelService.class); entityService = project.getComponent(EntityService.class); activeItemService = project.getComponent(ActiveItemService.class); taskBoardConfiguration = project.getComponent(TaskBoardConfiguration.class); taskBoardFlow = project.getComponent(TaskBoardFlow.class); aliProjectConfiguration = project.getComponent(AliProjectConfiguration.class); header = new Header(); header.setBorder(new EmptyBorder(0, 5, 0, 5)); add(header, BorderLayout.NORTH); entityName = new JTextPane(); entityName.setBackground(getBackground()); entityName.setEditable(false); add(entityName, BorderLayout.CENTER); content = new Content(); content.setBorder(new EmptyBorder(0, 5, 10, 5)); add(content, BorderLayout.SOUTH); tasks = new HashMap<Integer, TaskPanel>(); taskContainers = new HashMap<String, TaskContainerPanel>(); taskContainers.put(TaskPanel.TASK_NEW, new TaskContainerPanel(this, TaskPanel.TASK_NEW, item)); taskContainers.put(TaskPanel.TASK_IN_PROGRESS, new TaskContainerPanel(this, TaskPanel.TASK_IN_PROGRESS, item)); taskContainers.put(TaskPanel.TASK_COMPLETED, new TaskContainerPanel(this, TaskPanel.TASK_COMPLETED, item)); taskContent = new JPanel(new GridLayout(1, 3)); taskContent.add(getTaskContainer(TaskPanel.TASK_NEW)); taskContent.add(getTaskContainer(TaskPanel.TASK_IN_PROGRESS)); taskContent.add(getTaskContainer(TaskPanel.TASK_COMPLETED)); Color gridColor = UIManager.getDefaults().getColor("Table.gridColor"); taskContent.setBorder(BorderFactory.createMatteBorder(0, 1, 1, 0, gridColor)); setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, gridColor)); // we don't use gap in grid layout to avoid trailing line (on the right) getTaskContainer(TaskPanel.TASK_IN_PROGRESS) .setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, gridColor)); getTaskContainer(TaskPanel.TASK_COMPLETED) .setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, gridColor)); simpleHighlight = new SimpleHighlight(entityName); setPreferredSize(DIMENSION); update(item); } public void update(Entity item) { this.item = item; header.update(); content.update(); entityName.setText(item.getPropertyValue("entity-name")); applyFilter(); } public void updateTask(final Entity task, final boolean created) { TaskPanel taskPanel = tasks.get(task.getId()); if (taskPanel == null) { taskPanel = new TaskPanel(task, project, this); tasks.put(task.getId(), taskPanel); getTaskContainer(task.getPropertyValue("status")).addTask(taskPanel); } taskPanel.update(task); applyFilter(); final TaskPanel fTaskPanel = taskPanel; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // task panel is (most of the time) not painted properly when doing full reload (refresh in the Settings dialog) // if the task is filtered out, only half of the task rectangle has the correct alpha // additional repaint (later) seems to fix the issue fTaskPanel.repaint(); if (created) { TaskContainerPanel taskContainer = (TaskContainerPanel) fTaskPanel.getParent(); taskContainer.scrollRectToVisible(fTaskPanel.getBounds()); } } }); } public void moveTask(final Entity task, final String newStatus) { final TaskPanel taskPanel = tasks.get(task.getId()); task.setProperty("status", newStatus); ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { HashSet<String> properties = new HashSet<String>(); properties.add("status"); if (TaskPanel.TASK_IN_PROGRESS.equals(newStatus)) { // when moving task to progress if (taskBoardConfiguration.isAssignTask() && task.getPropertyValue("assigned-to").isEmpty()) { // assign them to me if they are unassigned task.setProperty("assigned-to", aliProjectConfiguration.getUsername()); properties.add("assigned-to"); } if (taskBoardConfiguration.isActivateItem()) { // activate work item UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { Entity workItem = new Entity(item.getPropertyValue("entity-type"), Integer.valueOf(item.getPropertyValue("entity-id"))); activeItemService.activate(workItem, true, false); } }); } } final Entity updatedTask = entityService.updateEntity(task, properties, false, true); if (updatedTask == null) { return; // update failed } taskBoardFlow.onTaskUpdated(updatedTask, item); UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { taskPanel.update(updatedTask); } }); } }); } public TaskContainerPanel getTaskContainer(String status) { return taskContainers.get(status); } private Double getValue(Entity entity, String property) { try { return Double.valueOf(entity.getPropertyValue(property)); } catch (NumberFormatException e) { return 0.0; } } public JComponent getTaskContent() { return taskContent; } public void applyFilter() { Map<Entity, Boolean> matches = matches(); if (matches.containsValue(true)) { setHighlight(this, matches.get(item), filter.getFilter()); for (TaskPanel taskPanel : tasks.values()) { Entity task = taskPanel.getTask(); setHighlight(taskPanel, matches.get(task), filter.getFilter()); } getTaskContent().setVisible(true); setVisible(true); } else { getTaskContent().setVisible(false); setVisible(false); } } private void setHighlight(Highlightable panel, boolean match, String filter) { panel.setFilter(filter); panel.setMatch(match); } private Map<Entity, Boolean> matches() { HashMap<Entity, Boolean> ret = new HashMap<Entity, Boolean>(); boolean typeMatch; if (item.getPropertyValue("entity-type").equals("requirement")) { typeMatch = filter.isUserStories(); } else { typeMatch = filter.isDefects(); } if (!filter.getStatus().contains(item.getPropertyValue("status"))) { typeMatch = false; } if (!filter.isBlocked() && !item.getPropertyValue("blocked").isEmpty()) { typeMatch = false; } ret.put(item, typeMatch && filterMatches(filter.getFilter(), item, "entity-name") && ownerMatches(filter.getAssignedTo(), item, "owner")); for (TaskPanel taskPanel : tasks.values()) { Entity task = taskPanel.getTask(); ret.put(task, typeMatch && filterMatches(filter.getFilter(), task, "description") && ownerMatches(filter.getAssignedTo(), task, "assigned-to")); } return ret; } private boolean filterMatches(String filter, Entity entity, String property) { if (filter == null || filter.isEmpty()) { return true; } if (StringUtils.containsIgnoreCase(entity.getPropertyValue(property), filter)) { return true; } return false; } private boolean ownerMatches(String assignedTo, Entity entity, String property) { if (assignedTo == null) { return true; } return assignedTo.equals(entity.getPropertyValue(property)); } @Override public void setFilter(String filter) { simpleHighlight.setFilter(filter); } @Override public void setMatch(boolean match) { } public TaskPanel getTaskPanel(Entity task) { return getTaskPanel(task.getId()); } public TaskPanel getTaskPanel(int id) { return tasks.get(id); } public void retainTasks(Set<Integer> taskIds) { boolean modified = false; for (Iterator<Integer> it = tasks.keySet().iterator(); it.hasNext();) { int taskId = it.next(); if (!taskIds.contains(taskId)) { TaskPanel taskPanel = tasks.get(taskId); TaskContainerPanel taskContainer = getTaskContainer(taskPanel.getStatus()); taskContainer.remove(taskPanel); taskContainer.repaint(); it.remove(); modified = true; } } if (modified) { applyFilter(); } } public void removeTaskPanel(TaskPanel taskPanel) { TaskContainerPanel taskContainer = getTaskContainer(taskPanel.getStatus()); taskContainer.remove(taskPanel); taskContainer.repaint(); tasks.remove(taskPanel.getTask().getId()); applyFilter(); } public Entity getItem() { return item; } @Override public Object getData(@NonNls String s) { if ("entity-list".equals(s)) { Entity entity = new Entity(item.getPropertyValue("entity-type"), Integer.valueOf(item.getPropertyValue("entity-id"))); entity.mergeRelatedEntity(item); return Arrays.asList(entity); } return null; } private class RbiStatus extends JPanel { private JLabel value; public RbiStatus() { super(new FlowLayout(FlowLayout.LEFT, 0, 0)); setOpaque(false); add(new JLabel("Status: ")); value = new JLabel(); add(value); } public void setValue(String status) { value.setText(status); } } private class Content extends JPanel { private Gauge gauge; private RbiStatus status; private JLabel remainingLabel; public Content() { super(new BorderLayout()); setOpaque(false); JPanel north = new JPanel(new BorderLayout()); north.setOpaque(false); gauge = new Gauge(0); north.add(gauge, BorderLayout.CENTER); add(north, BorderLayout.NORTH); JPanel south = new JPanel(new BorderLayout()); south.setOpaque(false); status = new RbiStatus(); south.add(status, BorderLayout.WEST); remainingLabel = new JLabel(); remainingLabel.setBorder(new EmptyBorder(0, 0, 0, 3)); south.add(remainingLabel, BorderLayout.EAST); add(south, BorderLayout.SOUTH); update(); } public void update() { Double estimated = getValue(item, "estimated"); Double remaining = getValue(item, "remaining"); if (estimated > 0.0) { gauge.setValue((estimated - remaining) / estimated); } else { gauge.setValue(0); } status.setValue(item.getPropertyValue("status")); if (remaining > 0.0) { remainingLabel.setText(Math.round(remaining) + " hours remaining"); remainingLabel.setVisible(true); } else { remainingLabel.setVisible(false); } } } private class Header extends JPanel { private JLabel blocked; public Header() { super(new BorderLayout()); setOpaque(false); JPanel westPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); blocked = new JLabel(IconLoader.getIcon("/blocked.png")); blocked.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2)); westPanel.add(blocked); westPanel.add(new EntityLabel(item.getPropertyValue("entity-type"), entityLabelService, " | ID " + item.getPropertyValue("entity-id"))); add(westPanel, BorderLayout.WEST); JPanel toolbar = new JPanel(); toolbar.setOpaque(false); LinkLabel addLink = new LinkLabel("", IconLoader.getIcon("/general/add.png")); addLink.setToolTipText("Add Task"); addLink.setListener(new LinkListener() { @Override public void linkSelected(LinkLabel linkLabel, Object o) { TaskEditor editor = new TaskEditor(project, item.getId()); editor.execute(); } }, null); toolbar.add(addLink); final LinkLabel moreLink = new LinkLabel("", IconLoader.getIcon("/actions/forward.png")); moreLink.setToolTipText("More Actions"); moreLink.setListener(new LinkListener() { @Override public void linkSelected(LinkLabel linkLabel, Object o) { ActionPopupMenu actionPopup = ActionUtil.createEntityActionPopup("taskboard"); actionPopup.getComponent().show(moreLink, 0, 0); } }, null); toolbar.add(moreLink); add(toolbar, BorderLayout.EAST); update(); } public void update() { String reason = item.getPropertyValue("blocked"); if (!reason.isEmpty()) { blocked.setToolTipText("Blocking reason: " + reason); blocked.setVisible(true); } else { blocked.setVisible(false); } } } }