blob: f192c8a8e79c1384072be7700145872f305b9be9 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.progress.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import org.netbeans.modules.progress.spi.InternalHandle;
import org.netbeans.modules.progress.spi.UIInternalHandle;
import org.openide.util.Mutex;
/**
* @author mkleint
*/
public class PopupPane extends JScrollPane {
private JPanel view;
private Set<ListComponent> listComponents;
private ListComponent selected;
public PopupPane() {
listComponents = new HashSet<ListComponent>();
view = new JPanel();
GridLayout grid = new GridLayout(0, 1);
grid.setHgap(0);
grid.setVgap(0);
view.setLayout(grid);
view.setBorder(BorderFactory.createEmptyBorder());
setName("progresspopup"); //NOI18N
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
setViewportView(view);
setFocusable(true);
setRequestFocusEnabled(true);
Action down = new MoveDownAction();
getActionMap().put("Move-Down", down);
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Move-Down");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Move-Down");
Action up = new MoveUpAction();
getActionMap().put("Move-Up", up);
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Move-Up");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Move-Up");
Action cancel = new CancelAction();
getActionMap().put("Cancel-Task", cancel);
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "Cancel-Task");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "Cancel-Task");
Action select = new SelectAction();
getActionMap().put("select-task", select);
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "select-task");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "select-task");
setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
}
public void addListComponent(final ListComponent lst) {
Mutex.EVENT.readAccess(new Runnable() {
public @Override void run() {
listComponents.add(lst);
if (view.getComponentCount() > 0) {
JComponent previous = (JComponent)view.getComponent(view.getComponentCount() - 1);
previous.setBorder(new BottomLineBorder());
}
lst.setBorder(BorderFactory.createEmptyBorder());
view.add(lst);
if (listComponents.size() > 3) {
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
} else {
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
}
}
});
}
public void removeListComponent(final InternalHandle handle) {
Mutex.EVENT.readAccess(new Runnable() {
public @Override void run() {
Iterator<ListComponent> it = listComponents.iterator();
while (it.hasNext()) {
ListComponent comp = it.next();
if (comp.getHandle() == handle) {
view.remove(comp);
it.remove();
break;
}
}
if (listComponents.size() > 3) {
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
} else {
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
}
}
});
}
public @Override Dimension getPreferredSize() {
int count = view.getComponentCount();
int height = count > 0 ? view.getComponent(0).getPreferredSize().height : 0;
int offset = count > 3 ? height * 3 + 5 : (count * height) + 5;
// 22 is the width of the additional scrollbar
return new Dimension(count >3 ? ListComponent.ITEM_WIDTH + 22
: ListComponent.ITEM_WIDTH + 2, offset);
}
/**
* bold font is now used not only for explicitly selected items, but for any
* change in currently selected task.
*/
public void updateBoldFont(final InternalHandle handle) {
Mutex.EVENT.readAccess(new Runnable() {
public @Override void run() {
for (ListComponent comp : listComponents) {
comp.markAsActive(handle == comp.getHandle());
}
}
});
}
private static class BottomLineBorder implements Border {
private Insets ins = new Insets(0, 0, 1, 0);
private Color col = new Color(221, 229, 248);
public BottomLineBorder () {}
public @Override Insets getBorderInsets(Component c) {
return ins;
}
public @Override boolean isBorderOpaque() {
return false;
}
public @Override void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Color old = g.getColor();
g.setColor(col);
g.drawRect(x, y + height - 2, width, 1);
g.setColor(old);
}
}
private int findIndex(Component comp) {
Component[] comps = view.getComponents();
for (int i = 0; i < comps.length; i++) {
if (comps[i] == comp) {
return i;
}
}
return -1;
}
public @Override void requestFocus() {
//#63666 - don't focus any of the tasks explicitly, wait for user action.
// if (view.getComponentCount() > 1) {
// if (selected == null || !selected.isDisplayable()) {
// selected = (ListComponent)view.getComponent(0);
// }
// selected.requestFocus();
// } else {
super.requestFocus();
// }
}
private class MoveDownAction extends AbstractAction {
MoveDownAction() {
}
public @Override void actionPerformed(ActionEvent actionEvent) {
int index = -1;
if (selected != null) {
index = findIndex(selected);
}
index = index + 1;
if (index >= PopupPane.this.view.getComponentCount()) {
index = 0;
}
selected = (ListComponent)PopupPane.this.view.getComponent(index);
selected.requestFocus();
}
}
private class MoveUpAction extends AbstractAction {
MoveUpAction() {
}
public @Override void actionPerformed(ActionEvent actionEvent) {
int index = PopupPane.this.view.getComponentCount();
if (selected != null) {
index = findIndex(selected);
// selected.setBackground(new Color(249, 249, 249));
}
index = index - 1;
if (index < 0) {
index = PopupPane.this.view.getComponentCount() - 1;
}
selected = (ListComponent)PopupPane.this.view.getComponent(index);
selected.requestFocus();
// selected.setBackground(selectBgColor);
// selected.scrollRectToVisible(selected.getBounds());
}
}
private class CancelAction extends AbstractAction {
public CancelAction () {}
public @Override void actionPerformed(ActionEvent actionEvent) {
if (selected != null) {
Action act = selected.getCancelAction();
if (act != null) {
act.actionPerformed(actionEvent);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}
}
private class SelectAction extends AbstractAction {
public SelectAction () {}
public @Override void actionPerformed(ActionEvent actionEvent) {
if (selected != null) {
selected.getHandle().requestExplicitSelection();
}
}
}
}