blob: 9806e06fbdcb87f7901caeaa252ef3d7c5cef987 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 Thomas Wolf <thomas.wolf@paranor.ch>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.egit.ui.internal.components;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jface.util.Util;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
/**
* Specialized label provider to put native SWT {@link Control}s into a column
* of a JFace {@link org.eclipse.jface.viewers.TableViewer TableViewer}.
*/
public abstract class ControlLabelProvider extends ColumnLabelProvider {
private final Map<TableItem, Editor> editors = new HashMap<>();
@Override
public void dispose() {
editors.clear();
super.dispose();
}
@Override
public String getText(Object element) {
return null;
}
@Override
public void update(ViewerCell cell) {
super.update(cell);
Object obj = cell.getElement();
Widget w = cell.getViewerRow().getItem();
if (w instanceof TableItem) {
TableItem item = (TableItem) w;
Table table = item.getParent();
Editor editor = editors.get(item);
if (editor == null) {
Control control = setEditor(cell, table, null, obj);
if (control == null) {
return;
}
control.pack();
editor = new Editor(table);
editor.horizontalAlignment = SWT.CENTER;
editor.verticalAlignment = SWT.CENTER;
Point size = control.getSize();
editor.minimumWidth = size.x;
editor.minimumHeight = size.y;
editors.put(item, editor);
editor.setEditor(control, item, cell.getColumnIndex());
editor.connect();
} else {
Control existing = editor.getEditor();
Control control = setEditor(cell, table, existing, obj);
if (control != existing) {
if (!existing.isDisposed()) {
existing.dispose();
}
if (control == null) {
editor.dispose();
return;
}
control.pack();
editor.setEditor(control);
}
}
}
}
/**
* Creates a new {@link Control}, or updates an existing one.
*
* @param cell
* that is being dealt with
* @param parent
* to use if a new control is created
* @param control
* an already existing widget to be updated, or {@code null} if a
* new widget should be created
* @param element
* being shown
* @return the {@link Control} to show, or {@code null} if no control is to
* be shown.
*/
public abstract Control setEditor(ViewerCell cell, Composite parent,
Control control, Object element);
private class Editor extends TableEditor {
private DisposeListener disposer;
private final Table table;
public Editor(Table table) {
super(table);
this.table = table;
}
@Override
public void layout() {
if (Util.isGtk() && SWT.getVersion() <= 4924) {
// Layout is relative to the table's clientArea, which includes
// the header if one is shown. Results in editors being shown
// over the column headers.
//
// This is a work-around for bug 535978; would be needed only on
// SWT versions < 4924r7.
TableItem item = getItem();
if (item != null) {
Rectangle rect = item.getBounds();
if (table.getHeaderVisible()) {
Control editor = getEditor();
if (editor != null && !editor.isDisposed()) {
editor.setVisible(
rect.y >= table.getHeaderHeight());
}
}
}
}
super.layout();
}
public void connect() {
TableItem item = getItem();
if (item != null) {
disposer = e -> {
Control editor = getEditor();
if (editor != null && !editor.isDisposed()) {
editor.dispose();
}
dispose();
};
item.addDisposeListener(disposer);
}
}
private void disconnect() {
if (disposer != null) {
TableItem item = getItem();
if (item != null) {
editors.remove(item);
item.removeDisposeListener(disposer);
}
disposer = null;
}
}
@Override
public void dispose() {
disconnect();
super.dispose();
}
}
}