/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.runtime.properties;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPNamedObject;
import org.jkiss.dbeaver.model.DBPObject;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.edit.DBECommandContext;
import org.jkiss.dbeaver.model.edit.DBECommandReflector;
import org.jkiss.dbeaver.model.edit.DBEObjectEditor;
import org.jkiss.dbeaver.model.edit.DBEObjectMaker;
import org.jkiss.dbeaver.model.edit.prop.DBECommandProperty;
import org.jkiss.dbeaver.model.edit.prop.DBEPropertyHandler;
import org.jkiss.dbeaver.model.impl.DBSObjectCache;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.registry.editor.EntityEditorsRegistry;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
/**
* PropertySourceEditable
*/
public class PropertySourceEditable extends PropertySourceAbstract implements DBPObject, IPropertySourceEditable
{
private static final Log log = Log.getLog(PropertySourceEditable.class);
private DBECommandContext commandContext;
private PropertyChangeCommand lastCommand = null;
//private final List<IPropertySourceListener> listeners = new ArrayList<IPropertySourceListener>();
private final CommandReflector commandReflector = new CommandReflector();
public PropertySourceEditable(DBECommandContext commandContext, Object sourceObject, Object object)
{
super(sourceObject, object, true);
this.commandContext = commandContext;
//this.objectManager = editorInput.getObjectManager(DBEObjectEditor.class);
}
@Override
public boolean isEditable(Object object)
{
DBEObjectEditor objectEditor = getObjectEditor(DBEObjectEditor.class);
return objectEditor != null &&
object instanceof DBPObject && objectEditor.canEditObject((DBPObject) object);
}
private <T> T getObjectEditor(Class<T> managerType)
{
final Object editableValue = getEditableValue();
if (editableValue == null) {
return null;
}
return EntityEditorsRegistry.getInstance().getObjectManager(
editableValue.getClass(),
managerType);
}
@Override
public DBECommandContext getCommandContext()
{
return commandContext;
}
@Override
@SuppressWarnings("unchecked")
public void setPropertyValue(@Nullable DBRProgressMonitor monitor, Object editableValue, ObjectPropertyDescriptor prop, Object newValue)
throws IllegalArgumentException
{
if (prop.getValueTransformer() != null) {
newValue = prop.getValueTransformer().transform(editableValue, newValue);
}
final Object oldValue = getPropertyValue(monitor, editableValue, prop);
if (!updatePropertyValue(monitor, editableValue, prop, newValue, false)) {
return;
}
if (commandContext != null) {
if (lastCommand == null || lastCommand.getObject() != editableValue || lastCommand.property != prop) {
final DBEObjectEditor<DBPObject> objectEditor = getObjectEditor(DBEObjectEditor.class);
if (objectEditor == null) {
log.error("Can't obtain object editor for " + getEditableValue());
return;
}
final DBEPropertyHandler<DBPObject> propertyHandler = objectEditor.makePropertyHandler(
(DBPObject) editableValue,
prop);
PropertyChangeCommand curCommand = new PropertyChangeCommand((DBPObject) editableValue, prop, propertyHandler, oldValue, newValue);
commandContext.addCommand(curCommand, commandReflector);
lastCommand = curCommand;
} else {
lastCommand.setNewValue(newValue);
commandContext.updateCommand(lastCommand, commandReflector);
}
}
// If we perform rename then we should refresh object cache
// To update name-based cache
if (prop.isNameProperty() && editableValue instanceof DBSObject) {
DBEObjectMaker objectManager = getObjectEditor(DBEObjectMaker.class);
if (objectManager != null) {
DBSObjectCache cache = objectManager.getObjectsCache((DBSObject) editableValue);
if (cache != null && cache.isFullyCached()) {
List<? extends DBSObject> cachedObjects = CommonUtils.copyList(cache.getCachedObjects());
cache.setCache(cachedObjects);
}
}
}
/*
// Notify listeners
for (IPropertySourceListener listener : listeners) {
listener.handlePropertyChange(editableValue, prop, newValue);
}
*/
}
private boolean updatePropertyValue(@Nullable DBRProgressMonitor monitor, Object editableValue, ObjectPropertyDescriptor prop, Object value, boolean force)
throws IllegalArgumentException
{
// Write property value
try {
// Check for complex object
// If value should be a named object then try to obtain it from list provider
if (value != null && value.getClass() == String.class) {
final Object[] items = prop.getPossibleValues(editableValue);
if (items != null) {
boolean found = false;
if (items.length > 0) {
for (int i = 0, itemsLength = items.length; i < itemsLength; i++) {
if ((items[i] instanceof DBPNamedObject && value.equals(((DBPNamedObject) items[i]).getName())) ||
(items[i] instanceof Enum && value.equals(((Enum) items[i]).name()))
) {
value = items[i];
found = true;
break;
}
}
}
if (!found) {
if (value.getClass() != prop.getDataType()){
value = null;
}
}
}
}
final Object oldValue = getPropertyValue(monitor, editableValue, prop);
if (CommonUtils.equalObjects(oldValue, value)) {
return false;
}
prop.writeValue(editableValue, value);
// Fire object update event
if (editableValue instanceof DBSObject) {
DBUtils.fireObjectUpdate((DBSObject) editableValue, prop);
}
return true;
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
e = ((InvocationTargetException) e).getTargetException();
}
log.error("Can't write property '" + prop.getDisplayName() + "' value", e);
return false;
}
}
@Override
public boolean isPropertyResettable(Object object, ObjectPropertyDescriptor prop)
{
return (lastCommand != null && lastCommand.property == prop && lastCommand.getObject() == object);
}
@Override
public void resetPropertyValue(@Nullable DBRProgressMonitor monitor, Object object, ObjectPropertyDescriptor prop)
{
// final DBECommandComposite compositeCommand = (DBECommandComposite)getCommandContext().getUserParams().get(obj);
// if (compositeCommand != null) {
// final Object value = compositeCommand.getProperty(prop.getId());
// }
if (lastCommand != null && lastCommand.property == prop) {
setPropertyValue(monitor, object, prop, lastCommand.getOldValue());
}
// final ObjectProps objectProps = getObjectProps(object);
// DBECommandProperty curCommand = objectProps.propValues.get(prop);
// if (curCommand != null) {
// curCommand.resetValue();
// }
log.warn("Property reset not implemented");
}
private class PropertyChangeCommand extends DBECommandProperty<DBPObject> {
ObjectPropertyDescriptor property;
public PropertyChangeCommand(DBPObject editableValue, ObjectPropertyDescriptor property, DBEPropertyHandler<DBPObject> propertyHandler, Object oldValue, Object newValue)
{
super(editableValue, propertyHandler, oldValue, newValue);
this.property = property;
}
@Override
public void updateModel()
{
super.updateModel();
updatePropertyValue(null, getObject(), property, getNewValue(), true);
}
}
private class CommandReflector implements DBECommandReflector<DBPObject, PropertyChangeCommand> {
@Override
public void redoCommand(PropertyChangeCommand command)
{
updatePropertyValue(null, command.getObject(), command.property, command.getNewValue(), false);
/*
// Notify listeners
for (IPropertySourceListener listener : listeners) {
listener.handlePropertyChange(command.getObject(), command.property, command.getNewValue());
}
*/
}
@Override
public void undoCommand(PropertyChangeCommand command)
{
updatePropertyValue(null, command.getObject(), command.property, command.getOldValue(), false);
/*
// Notify listeners
for (IPropertySourceListener listener : listeners) {
listener.handlePropertyChange(command.getObject(), command.property, command.getOldValue());
}
*/
}
}
}