/*
* Funambol is a mobile platform developed by Funambol, Inc.
* Copyright (C) 2010 Funambol, Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* 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 Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*
* You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
* 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by Funambol" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by Funambol".
*/
package de.chbosync.android.syncmlclient.activities.settings;
import java.util.Enumeration;
import java.util.Hashtable;
import android.app.Activity;
import android.content.Context;
import android.view.Gravity;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.funambol.client.configuration.Configuration;
import com.funambol.client.localization.Localization;
import com.funambol.client.source.AppSyncSource;
import com.funambol.client.source.AppSyncSourceConfig;
import com.funambol.client.ui.Bitmap;
import com.funambol.client.ui.SettingsUISyncSource;
import com.funambol.sync.SourceConfig;
import com.funambol.sync.SyncSource;
import com.funambol.util.Log;
import de.chbosync.android.syncmlclient.R;
import de.chbosync.android.syncmlclient.controller.AndroidController;
public class AndroidSettingsUISyncSource extends RelativeLayout
implements SettingsUISyncSource {
private static final String TAG = "AndroidSettingsUISyncSource";
private static final int ENABLED_TEXT_COLOR = 0xFF000000;
private static final int DISABLED_TEXT_COLOR = 0xFFCCCCCC;
protected AppSyncSource appSyncSource;
private ImageView sourceIconView;
private TextView titleTextView;
protected Spinner syncModeSpinner;
private boolean syncModeSet = false;
private int originalSyncMode;
private String originalRemoteUri;
private static final int TOP_PADDING = 12;
private static final int BOTTOM_PADDING = 12;
private static final int LEFT_PADDING = 12;
private static final int RIGHT_PADDING = 12;
private static final int ICON_TOP_PADDING = 0;
private static final int ICON_BOTTOM_PADDING = 6;
private static final int ICON_LEFT_PADDING = 0;
private static final int ICON_RIGHT_PADDING = 0;
private static final int TITLE_LEFT_PADDING = 12;
private static final int TITLE_BOTTOM_PADDING = 6;
private int enabledTextColor = ENABLED_TEXT_COLOR;
private int disabledTextColor = DISABLED_TEXT_COLOR;
private Bitmap enabledIcon;
private Bitmap disabledIcon;
private int[] availableSyncModes = new int[0];
private Hashtable<Integer, String> sourceSyncModesReference = new Hashtable<Integer, String>();
protected LinearLayout mainLayout;
protected Localization loc;
public AndroidSettingsUISyncSource(Activity activity) {
super(activity);
AndroidController ac = AndroidController.getInstance();
loc = ac.getLocalization();
// Init the sourceSyncModes reference
sourceSyncModesReference.put(SyncSource.NO_SYNC,
loc.getLanguage("sync_direction_do_nothing"));
sourceSyncModesReference.put(SyncSource.INCREMENTAL_SYNC,
loc.getLanguage("sync_direction_two_way"));
sourceSyncModesReference.put(SyncSource.INCREMENTAL_UPLOAD,
loc.getLanguage("sync_direction_upload_only"));
sourceSyncModesReference.put(SyncSource.INCREMENTAL_DOWNLOAD,
loc.getLanguage("sync_direction_download_only"));
sourceIconView = new ImageView(activity, null, R.style.sync_icon);
sourceIconView.setPadding(adaptSizeToDensity(ICON_LEFT_PADDING),
adaptSizeToDensity(ICON_TOP_PADDING),
adaptSizeToDensity(ICON_RIGHT_PADDING),
adaptSizeToDensity(ICON_BOTTOM_PADDING));
sourceIconView.setAdjustViewBounds(true);
sourceIconView.setScaleType(ImageView.ScaleType.FIT_XY);
titleTextView = new TextView(activity, null, R.style.sync_title);
titleTextView.setPadding(adaptSizeToDensity(TITLE_LEFT_PADDING), 0, 0,
adaptSizeToDensity(TITLE_BOTTOM_PADDING));
titleTextView.setTextAppearance(activity, R.style.funambol_title);
syncModeSpinner = new Spinner(activity);
syncModeSpinner.setPrompt(loc.getLanguage("sync_direction_prompt"));
syncModeSpinner.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
public void setEnabledIcon(Bitmap image) {
enabledIcon = image;
}
public void setDisabledIcon(Bitmap image) {
disabledIcon = image;
}
public void setTitle(String title) {
titleTextView.setText(title);
}
public void setAvailableSyncModes(int[] modes) {
availableSyncModes = modes;
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
getContext(), android.R.layout.simple_spinner_item);
// Add the sync modes to the spinner adapter
for(int i=0; i<modes.length; i++) {
String mode = sourceSyncModesReference.get(modes[i]);
if(mode != null) {
adapter.add(mode);
} else {
Log.error(TAG, "Unknown sync mode: " + modes[i]);
}
}
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
syncModeSpinner.setAdapter(adapter);
}
public void setSyncMode(int mode) {
setSyncModeIfAvailable(mode);
if(!syncModeSet) {
// No suitable sync mode found, set as "do nothing"
setSyncModeIfAvailable(SyncSource.NO_SYNC);
}
}
private void setSyncModeIfAvailable(int mode) {
for(int i=0; i<availableSyncModes.length; i++) {
if(availableSyncModes[i] == mode) {
syncModeSpinner.setSelection(i);
originalSyncMode = mode;
syncModeSet = true;
return;
}
}
}
public int getSyncMode() {
int position = syncModeSpinner.getSelectedItemPosition();
return availableSyncModes[position];
}
public void setRemoteUri(String remoteUri) {
originalRemoteUri = remoteUri;
}
public String getRemoteUri() {
return originalRemoteUri;
}
public boolean hasChanges() {
return (syncModeSet && (getSyncMode() != originalSyncMode));
}
public void loadSettings(Configuration configuration) {
boolean isEnabled = appSyncSource.isWorking() &&
appSyncSource.getConfig().getEnabled();
Hashtable settings = appSyncSource.getSettings();
if (settings != null) {
Enumeration settingKeys = settings.keys();
while(settingKeys.hasMoreElements()) {
Integer setting = (Integer)settingKeys.nextElement();
switch(setting.intValue()) {
// Sync mode setting
case AppSyncSource.SYNC_MODE_SETTING:
int syncMode = isEnabled ?
appSyncSource.getConfig().getSyncMode() :
SyncSource.NO_SYNC;
setAvailableSyncModes((int[])settings.get(setting));
setSyncMode(syncMode);
break;
}
}
}
}
public void saveSettings(Configuration conf) {
if(syncModeSet) {
int syncMode = getSyncMode();
AppSyncSourceConfig config = appSyncSource.getConfig();
SyncSource source = appSyncSource.getSyncSource();
SourceConfig sc = source.getConfig();
sc.setSyncMode(syncMode);
boolean enabled = syncMode != SyncSource.NO_SYNC;
config.setEnabled(enabled);
config.setSyncType(syncMode);
}
}
/**
* @return the AppSyncSource this item represents
*/
public AppSyncSource getSource() {
return appSyncSource;
}
/**
* Set the AppSyncSource this item represents
*
* @param source
*/
public void setSource(AppSyncSource source) {
appSyncSource = source;
}
@Override
public void setEnabled(boolean enabled) {
int id;
int color;
if(enabled) {
id = (Integer)enabledIcon.getOpaqueDescriptor();
color = enabledTextColor;
} else {
id = (Integer)disabledIcon.getOpaqueDescriptor();
color = disabledTextColor;
}
sourceIconView.setImageResource(id);
titleTextView.setTextColor(color);
syncModeSpinner.setEnabled(enabled);
syncModeSpinner.setFocusable(enabled);
}
public void layout() {
// Sets the linear layout for the icon and the title
TitleLayout ll1 = new TitleLayout(getContext(), sourceIconView, titleTextView);
// All items in ll1 are vertically centered
ll1.setGravity(Gravity.CENTER_VERTICAL);
ll1.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
ll1.addView(sourceIconView);
ll1.addView(titleTextView);
// Container layout for all the items
if (mainLayout == null) {
mainLayout = new LinearLayout(getContext());
mainLayout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
mainLayout.setPadding(adaptSizeToDensity(LEFT_PADDING),
adaptSizeToDensity(TOP_PADDING),
adaptSizeToDensity(RIGHT_PADDING),
adaptSizeToDensity(BOTTOM_PADDING));
mainLayout.setOrientation(LinearLayout.VERTICAL);
}
mainLayout.addView(ll1);
if(syncModeSet) {
mainLayout.addView(syncModeSpinner);
}
this.addView(mainLayout);
}
private int adaptSizeToDensity(int size) {
return (int)(size*getContext().getResources().getDisplayMetrics().density);
}
/**
* This is the layout manager for the button. It works under the assumtpion
* that 2 views are added. The first one being an ImageView (source icon),
* the second one being a TextView (the title).
* The main purpose of this component, is to limit the size of
* the source icon, according to the size of the text field. In
* particular the height of this field is used to bound the maxSize for the
* icon.
*/
private class TitleLayout extends LinearLayout {
private boolean first = true;
private ImageView imageView;
private TextView textView;
public TitleLayout(Context context, ImageView imageView, TextView textView) {
super(context);
this.imageView = imageView;
this.textView = textView;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// First of all measure the text part
textView.measure(widthMeasureSpec, heightMeasureSpec);
// Now limit the max size for the icon and then compute its measure
int height = textView.getMeasuredHeight();
// We allow 120% of the text size
height = (12 * height) / 10;
imageView.setMaxWidth(height);
imageView.setMaxHeight(height);
imageView.measure(widthMeasureSpec, heightMeasureSpec);
// Now compute this item measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}