/*
* AndFHEM - Open Source Android application to control a FHEM home automation
* server.
*
* Copyright (c) 2011, Matthias Klass or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE
* for more details.
*
* You should have received a copy of the GNU GENERAL PUBLIC LICENSE
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package li.klass.fhem.adapter.rooms;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.TextView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import li.klass.fhem.R;
import li.klass.fhem.adapter.devices.core.DeviceAdapter;
import li.klass.fhem.domain.core.DeviceFunctionality;
import li.klass.fhem.domain.core.DeviceType;
import li.klass.fhem.domain.core.FhemDevice;
import li.klass.fhem.domain.core.RoomDeviceList;
import li.klass.fhem.util.ApplicationProperties;
import li.klass.fhem.widget.GridViewWithSectionsAdapter;
import li.klass.fhem.widget.deviceFunctionality.DeviceGroupHolder;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static li.klass.fhem.constants.PreferenceKeys.DEVICE_COLUMN_WIDTH;
import static li.klass.fhem.constants.PreferenceKeys.SHOW_HIDDEN_DEVICES;
public class DeviceGridAdapter<T extends FhemDevice<T>> extends GridViewWithSectionsAdapter<String, T> {
public static final int DEFAULT_COLUMN_WIDTH = 1000;
private final ApplicationProperties applicationProperties;
protected RoomDeviceList roomDeviceList;
private int lastParentHeight;
private List<String> deviceGroupParents = newArrayList();
private List<String> parents = newArrayList();
private Set<String> hiddenParents = newHashSet();
private Map<String, List<T>> parentChildMap = newHashMap();
private Map<Class, Integer> viewTypeMap = newHashMap();
private long lastUpdate;
private static final Logger LOG = LoggerFactory.getLogger(DeviceGridAdapter.class);
private GroupComparator groupComparator;
public DeviceGridAdapter(Context context, RoomDeviceList roomDeviceList, ApplicationProperties applicationProperties) {
super(context);
int currentViewType = 1;
for (DeviceType type : DeviceType.values()) {
if (type.getAdapter() != null && type.getAdapter().getOverviewViewHolderClass() != null) {
Class viewTypeHolderClass = type.getAdapter().getOverviewViewHolderClass();
if (!viewTypeMap.containsKey(viewTypeHolderClass)) {
viewTypeMap.put(viewTypeHolderClass, currentViewType++);
}
}
}
this.applicationProperties = applicationProperties;
restoreParents();
if (roomDeviceList != null) {
updateData(roomDeviceList, -1);
}
}
/**
* Load deviceGroupParents from the serialized state. This includes all visible devices from
* the {@link li.klass.fhem.constants.PreferenceKeys#DEVICE_FUNCTIONALITY_ORDER_VISIBLE}
* property.
*/
public void restoreParents() {
deviceGroupParents.clear();
DeviceGroupHolder holder = new DeviceGroupHolder(applicationProperties);
for (DeviceFunctionality visible : holder.getVisible(context)) {
deviceGroupParents.add(visible.getCaptionText(context));
}
for (DeviceFunctionality invisible : holder.getInvisible(context)) {
hiddenParents.add(invisible.getCaptionText(context));
}
groupComparator = new GroupComparator(DeviceFunctionality.UNKNOWN.getCaptionText(context), deviceGroupParents);
LOG.trace("restoreParents - set visible deviceGroupParents: {}" + deviceGroupParents);
}
@SuppressWarnings("unchecked")
public void updateData(RoomDeviceList roomDeviceList, long lastUpdate) {
if (roomDeviceList == null) return;
LOG.info(TAG, "updateData(lastUpdate={})", lastUpdate);
this.lastUpdate = lastUpdate;
parents.clear();
parents.addAll(deviceGroupParents);
Set<String> customParents = newHashSet();
boolean showHiddenDevices = applicationProperties.getBooleanSharedPreference(SHOW_HIDDEN_DEVICES, false, context);
Set<FhemDevice> allDevices = roomDeviceList.getAllDevices();
for (FhemDevice device : allDevices) {
LOG.trace("updateData - contained device {}", device.getName());
if (device.isInRoom("hidden") && !showHiddenDevices) {
roomDeviceList.removeDevice(device, context);
} else {
customParents.addAll(device.getInternalDeviceGroupOrGroupAttributes(context));
}
}
customParents.removeAll(parents);
Collections.sort(newArrayList(customParents));
parents.addAll(customParents);
parents.removeAll(roomDeviceList.getHiddenGroups());
parents.removeAll(hiddenParents);
Collections.sort(parents, groupComparator);
parentChildMap = newHashMap();
this.roomDeviceList = roomDeviceList;
super.updateData();
}
@Override
protected T getChildForParentAndChildPosition(String parent, int childPosition) {
if (childPosition < 0) return null;
List<T> childrenForDeviceType = getChildrenForDeviceGroup(parent);
if (childPosition >= childrenForDeviceType.size()) {
return null;
} else {
return childrenForDeviceType.get(childPosition);
}
}
@SuppressWarnings("unchecked")
private List<T> getChildrenForDeviceGroup(String deviceGroup) {
if (roomDeviceList == null) {
return newArrayList();
} else if (!parentChildMap.containsKey(deviceGroup)) {
parentChildMap.put(deviceGroup, (List<T>) roomDeviceList.getDevicesOfFunctionality(deviceGroup));
}
return parentChildMap.get(deviceGroup);
}
@Override
protected View getParentView(String parent, int parentOffset, View view, ViewGroup viewGroup) {
if (view == null) {
view = layoutInflater.inflate(R.layout.room_detail_parent, viewGroup, false);
assert view != null;
ParentViewHolder viewHolder = new ParentViewHolder();
viewHolder.setDeviceType((TextView) view.findViewById(R.id.deviceType));
view.setTag(viewHolder);
}
ParentViewHolder holder = (ParentViewHolder) view.getTag();
TextView textView = holder.getDeviceType();
if (parentOffset != 0) {
textView.setText("");
} else {
textView.setText(parent);
}
int widthMeasureSpec = View.MeasureSpec.UNSPECIFIED;
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);
int measuredHeight = view.getMeasuredHeight();
if (lastParentHeight < measuredHeight) {
lastParentHeight = measuredHeight;
}
view.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, lastParentHeight));
return view;
}
@Override
public int getItemViewType(int position) {
int parentBasePosition = getParentBasePosition(position);
if (parentBasePosition != -1) {
return 0;
} else {
FhemDevice item = (FhemDevice) getItem(position);
if (item != null) {
DeviceAdapter adapter = DeviceType.getAdapterFor(item);
if (adapter != null && adapter.getOverviewViewHolderClass() != null) {
return viewTypeMap.get(adapter.getOverviewViewHolderClass());
}
}
}
return IGNORE_ITEM_VIEW_TYPE;
}
@Override
public int getViewTypeCount() {
return viewTypeMap.size() + 1;
}
@Override
protected View getChildView(final String parent, int parentPosition,
T child, View view, ViewGroup viewGroup) {
final DeviceAdapter deviceAdapter = DeviceType.getAdapterFor(child);
if (deviceAdapter == null) {
LOG.debug("getChildView - unsupported device type {}", child);
View ret = layoutInflater.inflate(android.R.layout.simple_list_item_1, null);
assert ret != null;
ret.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
return ret;
}
if (!deviceAdapter.supports(child.getClass())) {
String text = "getChildView - adapter was found for device type, but it will not support the device: "
+ child;
LOG.error(text);
throw new IllegalArgumentException(text);
}
deviceAdapter.attach(context);
view = deviceAdapter.createOverviewView(layoutInflater, view, child, lastUpdate);
view.setLayoutParams(new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
);
return view;
}
@Override
protected List<String> getDeviceGroupParents() {
List<String> viewableParents = newArrayList();
for (String group : parents) {
if (getChildrenCountForParent(group) <= 0) {
LOG.trace("getDeviceGroupParents - group {} has no children, filtered!", group);
} else {
viewableParents.add(group);
}
}
return viewableParents;
}
@Override
protected int getChildrenCountForParent(String parent) {
return getChildrenForDeviceGroup(parent).size();
}
@Override
protected int getRequiredColumnWidth() {
int width = applicationProperties.getIntegerSharedPreference(DEVICE_COLUMN_WIDTH, DEFAULT_COLUMN_WIDTH, context);
LOG.debug("getRequiredColumnWidth - column width: {}", width);
return width;
}
}