diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget')
5 files changed, 382 insertions, 116 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java index 1cf510d3a..7b21c189d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java @@ -18,8 +18,10 @@ package org.sufficientlysecure.keychain.ui.widget; public interface Editor { public interface EditorListener { - public void onDeleted(Editor editor); + public void onDeleted(Editor editor, boolean wasNewItem); + public void onEdited(); } public void setEditorListener(EditorListener listener); + public boolean needsSaving(); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 7e0acfa28..0dfc6dc5e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -16,6 +16,20 @@ package org.sufficientlysecure.keychain.ui.widget; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import java.util.Vector; + +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.openpgp.PGPKeyFlags; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSecretKey; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.util.Choice; import android.annotation.TargetApi; import android.app.DatePickerDialog; import android.app.Dialog; @@ -26,7 +40,13 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.*; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.DatePicker; +import android.widget.LinearLayout; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; @@ -47,11 +67,30 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { BootstrapButton mDeleteButton; TextView mAlgorithm; TextView mKeyId; - Spinner mUsage; TextView mCreationDate; BootstrapButton mExpiryDateButton; GregorianCalendar mCreatedDate; GregorianCalendar mExpiryDate; + GregorianCalendar mOriginalExpiryDate = null; + CheckBox mChkCertify; + CheckBox mChkSign; + CheckBox mChkEncrypt; + CheckBox mChkAuthenticate; + int mUsage; + int mOriginalUsage; + boolean mIsNewKey; + + private CheckBox.OnCheckedChangeListener mCheckChanged = new CheckBox.OnCheckedChangeListener() + { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) + { + if (mEditorListener != null) { + mEditorListener.onEdited(); + } + } + }; + private int mDatePickerResultCount = 0; private DatePickerDialog.OnDateSetListener mExpiryDateSetListener = @@ -61,7 +100,18 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { if (mDatePickerResultCount++ == 0) { GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("UTC")); date.set(year, monthOfYear, dayOfMonth); - setExpiryDate(date); + if (mOriginalExpiryDate != null) { + long numDays = (date.getTimeInMillis() / 86400000) - (mOriginalExpiryDate.getTimeInMillis() / 86400000); + if (numDays == 0) + setExpiryDate(mOriginalExpiryDate); + else + setExpiryDate(date); + } else { + setExpiryDate(date); + } + if (mEditorListener != null) { + mEditorListener.onEdited(); + } } } }; @@ -83,21 +133,17 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { mKeyId = (TextView) findViewById(R.id.keyId); mCreationDate = (TextView) findViewById(R.id.creation); mExpiryDateButton = (BootstrapButton) findViewById(R.id.expiry); - mUsage = (Spinner) findViewById(R.id.usage); - Choice choices[] = { - new Choice(Id.choice.usage.sign_only, getResources().getString( - R.string.choice_sign_only)), - new Choice(Id.choice.usage.encrypt_only, getResources().getString( - R.string.choice_encrypt_only)), - new Choice(Id.choice.usage.sign_and_encrypt, getResources().getString( - R.string.choice_sign_and_encrypt)), }; - ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getContext(), - android.R.layout.simple_spinner_item, choices); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mUsage.setAdapter(adapter); mDeleteButton = (BootstrapButton) findViewById(R.id.delete); mDeleteButton.setOnClickListener(this); + mChkCertify = (CheckBox) findViewById(R.id.chkCertify); + mChkCertify.setOnCheckedChangeListener(mCheckChanged); + mChkSign = (CheckBox) findViewById(R.id.chkSign); + mChkSign.setOnCheckedChangeListener(mCheckChanged); + mChkEncrypt = (CheckBox) findViewById(R.id.chkEncrypt); + mChkEncrypt.setOnCheckedChangeListener(mCheckChanged); + mChkAuthenticate = (CheckBox) findViewById(R.id.chkAuthenticate); + mChkAuthenticate.setOnCheckedChangeListener(mCheckChanged); setExpiryDate(null); @@ -125,6 +171,9 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { // Note: Ignore results after the first one - android sends multiples. if (mDatePickerResultCount++ == 0) { setExpiryDate(null); + if (mEditorListener != null) { + mEditorListener.onEdited(); + } } } }); @@ -155,12 +204,14 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { public void setCanEdit(boolean bCanEdit) { if (!bCanEdit) { mDeleteButton.setVisibility(View.INVISIBLE); - mUsage.setEnabled(false); mExpiryDateButton.setEnabled(false); + mChkSign.setEnabled(false); //certify is always disabled + mChkEncrypt.setEnabled(false); + mChkAuthenticate.setEnabled(false); } } - public void setValue(PGPSecretKey key, boolean isMasterKey, int usage) { + public void setValue(PGPSecretKey key, boolean isMasterKey, int usage, boolean isNewKey) { mKey = key; mIsMasterKey = isMasterKey; @@ -175,47 +226,45 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { Vector<Choice> choices = new Vector<Choice>(); boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT); boolean isDSAKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.DSA); - if (!isElGamalKey) { - choices.add(new Choice(Id.choice.usage.sign_only, getResources().getString( - R.string.choice_sign_only))); + if (isElGamalKey) { + mChkSign.setVisibility(View.INVISIBLE); + TableLayout table = (TableLayout)findViewById(R.id.table_keylayout); + TableRow row = (TableRow)findViewById(R.id.row_sign); + table.removeView(row); } - if (!mIsMasterKey && !isDSAKey) { - choices.add(new Choice(Id.choice.usage.encrypt_only, getResources().getString( - R.string.choice_encrypt_only))); + if (isDSAKey) { + mChkEncrypt.setVisibility(View.INVISIBLE); + TableLayout table = (TableLayout)findViewById(R.id.table_keylayout); + TableRow row = (TableRow)findViewById(R.id.row_encrypt); + table.removeView(row); } - if (!isElGamalKey && !isDSAKey) { - choices.add(new Choice(Id.choice.usage.sign_and_encrypt, getResources().getString( - R.string.choice_sign_and_encrypt))); + if (!mIsMasterKey) { + mChkCertify.setVisibility(View.INVISIBLE); + TableLayout table = (TableLayout)findViewById(R.id.table_keylayout); + TableRow row = (TableRow)findViewById(R.id.row_certify); + table.removeView(row); + } else { + TextView mLabelUsage2= (TextView) findViewById(R.id.label_usage2); + mLabelUsage2.setVisibility(View.INVISIBLE); } - ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getContext(), - android.R.layout.simple_spinner_item, choices); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mUsage.setAdapter(adapter); - - // Set value in choice dropdown to key int selectId = 0; - if (PgpKeyHelper.isEncryptionKey(key)) { - if (PgpKeyHelper.isSigningKey(key)) { - selectId = Id.choice.usage.sign_and_encrypt; - } else { - selectId = Id.choice.usage.encrypt_only; - } + mIsNewKey = isNewKey; + if (isNewKey) { + mUsage = usage; + mChkCertify.setChecked((usage &= KeyFlags.CERTIFY_OTHER) == KeyFlags.CERTIFY_OTHER); + mChkSign.setChecked((usage &= KeyFlags.SIGN_DATA) == KeyFlags.SIGN_DATA); + mChkEncrypt.setChecked(((usage &= KeyFlags.ENCRYPT_COMMS) == KeyFlags.ENCRYPT_COMMS) || + ((usage &= KeyFlags.ENCRYPT_STORAGE) == KeyFlags.ENCRYPT_STORAGE)); + mChkAuthenticate.setChecked((usage &= KeyFlags.AUTHENTICATION) == KeyFlags.AUTHENTICATION); } else { - // set usage if it is predefined - if (usage != -1) { - selectId = usage; - } else { - selectId = Id.choice.usage.sign_only; - } - - } - - for (int i = 0; i < choices.size(); ++i) { - if (choices.get(i).getId() == selectId) { - mUsage.setSelection(i); - break; - } + mUsage = PgpKeyHelper.getKeyUsage(key); + mOriginalUsage = mUsage; + if (key.isMasterKey()) + mChkCertify.setChecked(PgpKeyHelper.isCertificationKey(key)); + mChkSign.setChecked(PgpKeyHelper.isSigningKey(key)); + mChkEncrypt.setChecked(PgpKeyHelper.isEncryptionKey(key)); + mChkAuthenticate.setChecked(PgpKeyHelper.isAuthenticationKey(key)); } GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); @@ -228,6 +277,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } else { cal.setTime(PgpKeyHelper.getExpiryDate(key)); setExpiryDate(cal); + mOriginalExpiryDate = cal; } } @@ -241,7 +291,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { if (v == mDeleteButton) { parent.removeView(this); if (mEditorListener != null) { - mEditorListener.onDeleted(this); + mEditorListener.onDeleted(this, mIsNewKey); } } } @@ -273,7 +323,41 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } public int getUsage() { - return ((Choice) mUsage.getSelectedItem()).getId(); + mUsage = (mUsage & ~KeyFlags.CERTIFY_OTHER) | (mChkCertify.isChecked() ? KeyFlags.CERTIFY_OTHER : 0); + mUsage = (mUsage & ~KeyFlags.SIGN_DATA) | (mChkSign.isChecked() ? KeyFlags.SIGN_DATA : 0); + mUsage = (mUsage & ~KeyFlags.ENCRYPT_COMMS) | (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_COMMS : 0); + mUsage = (mUsage & ~KeyFlags.ENCRYPT_STORAGE) | (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_STORAGE : 0); + mUsage = (mUsage & ~KeyFlags.AUTHENTICATION) | (mChkAuthenticate.isChecked() ? KeyFlags.AUTHENTICATION : 0); + + return mUsage; + } + + public boolean needsSaving() + { + if (mIsNewKey) + return true; + + boolean retval = (getUsage() != mOriginalUsage); + + boolean dateChanged; + boolean mOEDNull = (mOriginalExpiryDate == null); + boolean mEDNull = (mExpiryDate == null); + if (mOEDNull != mEDNull) { + dateChanged = true; + } else { + if(mOEDNull) //both null, no change + dateChanged = false; + else + dateChanged = ((mExpiryDate.compareTo(mOriginalExpiryDate)) != 0); + } + retval |= dateChanged; + + return retval; + } + + public boolean getIsNewKey() + { + return mIsNewKey; } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java index f92c7532a..171763672 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java @@ -66,11 +66,16 @@ public class KeyServerEditor extends LinearLayout implements Editor, OnClickList if (v == mDeleteButton) { parent.removeView(this); if (mEditorListener != null) { - mEditorListener.onDeleted(this); + mEditorListener.onDeleted(this, false); } } } + @Override + public boolean needsSaving() { + return false; + } + public void setEditorListener(EditorListener listener) { mEditorListener = listener; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 1ef178f15..6c7737e6d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -16,6 +16,23 @@ package org.sufficientlysecure.keychain.ui.widget; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +import org.spongycastle.openpgp.PGPKeyFlags; +import org.spongycastle.openpgp.PGPSecretKey; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; +import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; +import org.sufficientlysecure.keychain.util.Choice; + +import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; @@ -44,23 +61,31 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.util.Choice; -import java.util.Vector; -public class SectionView extends LinearLayout implements OnClickListener, EditorListener { + +public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor { private LayoutInflater mInflater; private BootstrapButton mPlusButton; private ViewGroup mEditors; private TextView mTitle; private int mType = 0; + private EditorListener mEditorListener = null; private Choice mNewKeyAlgorithmChoice; private int mNewKeySize; + private boolean oldItemDeleted = false; + private ArrayList<String> mDeletedIDs = new ArrayList<String>(); + private ArrayList<PGPSecretKey> mDeletedKeys = new ArrayList<PGPSecretKey>(); private boolean mCanEdit = true; private ActionBarActivity mActivity; private ProgressDialogFragment mGeneratingDialog; + public void setEditorListener(EditorListener listener) { + mEditorListener = listener; + } + public SectionView(Context context) { super(context); mActivity = (ActionBarActivity) context; @@ -124,8 +149,26 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor /** * {@inheritDoc} */ - public void onDeleted(Editor editor) { + public void onDeleted(Editor editor, boolean wasNewItem) { + oldItemDeleted |= !wasNewItem; + if (oldItemDeleted) { + if (mType == Id.type.user_id) + mDeletedIDs.add(((UserIdEditor)editor).getOriginalID()); + else if (mType == Id.type.key) + mDeletedKeys.add(((KeyEditor)editor).getValue()); + + } this.updateEditorsVisible(); + if (mEditorListener != null) { + mEditorListener.onEdited(); + } + } + + @Override + public void onEdited() { + if (mEditorListener != null) { + mEditorListener.onEdited(); + } } protected void updateEditorsVisible() { @@ -133,6 +176,94 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE); } + public boolean needsSaving() + { + //check each view for needs saving, take account of deleted items + boolean ret = oldItemDeleted; + for (int i = 0; i < mEditors.getChildCount(); ++i) { + Editor editor = (Editor) mEditors.getChildAt(i); + ret |= editor.needsSaving(); + if (mType == Id.type.user_id) + ret |= ((UserIdEditor)editor).primarySwapped(); + } + return ret; + } + + public boolean primaryChanged() + { + boolean ret = false; + for (int i = 0; i < mEditors.getChildCount(); ++i) { + Editor editor = (Editor) mEditors.getChildAt(i); + if (mType == Id.type.user_id) + ret |= ((UserIdEditor)editor).primarySwapped(); + } + return ret; + } + + public String getOriginalPrimaryID() + { //NB: this will have to change when we change how Primary IDs are chosen, and so we need to be + // careful about where Master key capabilities are stored... multiple primaries and + // revoked ones make this harder than the simple case we are continuing to assume here + for (int i = 0; i < mEditors.getChildCount(); ++i) { + Editor editor = (Editor) mEditors.getChildAt(i); + if (mType == Id.type.user_id) { + if(((UserIdEditor)editor).getIsOriginallyMainUserID()) { + return ((UserIdEditor)editor).getOriginalID(); + } + } + } + return null; + } + + public ArrayList<String> getOriginalIDs() + { + ArrayList<String> orig = new ArrayList<String>(); + if (mType == Id.type.user_id) { + for (int i = 0; i < mEditors.getChildCount(); ++i) { + UserIdEditor editor = (UserIdEditor) mEditors.getChildAt(i); + if (editor.isMainUserId()) + orig.add(0, editor.getOriginalID()); + else + orig.add(editor.getOriginalID()); + } + return orig; + } else { + return null; + } + } + + public ArrayList<String> getDeletedIDs() + { + return mDeletedIDs; + } + + public ArrayList<PGPSecretKey> getDeletedKeys() + { + return mDeletedKeys; + } + + public List<Boolean> getNeedsSavingArray() + { + ArrayList<Boolean> mList = new ArrayList<Boolean>(); + for (int i = 0; i < mEditors.getChildCount(); ++i) { + Editor editor = (Editor) mEditors.getChildAt(i); + mList.add(editor.needsSaving()); + } + return mList; + } + + public List<Boolean> getNewKeysArray() + { + ArrayList<Boolean> mList = new ArrayList<Boolean>(); + if (mType == Id.type.key) { + for (int i = 0; i < mEditors.getChildCount(); ++i) { + KeyEditor editor = (KeyEditor) mEditors.getChildAt(i); + mList.add(editor.getIsNewKey()); + } + } + return mList; + } + /** * {@inheritDoc} */ @@ -143,10 +274,11 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor UserIdEditor view = (UserIdEditor) mInflater.inflate( R.layout.edit_key_user_id_item, mEditors, false); view.setEditorListener(this); - if (mEditors.getChildCount() == 0) { - view.setIsMainUserId(true); - } + view.setValue("", mEditors.getChildCount() == 0, true); mEditors.addView(view); + if (mEditorListener != null) { + mEditorListener.onEdited(); + } break; } @@ -185,10 +317,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor UserIdEditor view = (UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, mEditors, false); view.setEditorListener(this); - view.setValue(userId); - if (mEditors.getChildCount() == 0) { - view.setIsMainUserId(true); - } + view.setValue(userId, mEditors.getChildCount() == 0, false); view.setCanEdit(mCanEdit); mEditors.addView(view); } @@ -196,7 +325,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor this.updateEditorsVisible(); } - public void setKeys(Vector<PGPSecretKey> list, Vector<Integer> usages) { + public void setKeys(Vector<PGPSecretKey> list, Vector<Integer> usages, boolean newKeys) { if (mType != Id.type.key) { return; } @@ -209,7 +338,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor false); view.setEditorListener(this); boolean isMasterKey = (mEditors.getChildCount() == 0); - view.setValue(list.get(i), isMasterKey, usages.get(i)); + view.setValue(list.get(i), isMasterKey, usages.get(i), newKeys); view.setCanEdit(mCanEdit); mEditors.addView(view); } @@ -289,8 +418,14 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false); view.setEditorListener(SectionView.this); - view.setValue(newKey, newKey.isMasterKey(), -1); + int usage = 0; + if (mEditors.getChildCount() == 0) + usage = PGPKeyFlags.CAN_CERTIFY; + view.setValue(newKey, newKey.isMasterKey(), usage, true); mEditors.addView(view); SectionView.this.updateEditorsVisible(); + if (mEditorListener != null) { + mEditorListener.onEdited(); + } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java index ed81b162e..d4b15613a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java @@ -16,6 +16,11 @@ package org.sufficientlysecure.keychain.ui.widget; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import android.content.Context; import android.text.Editable; import android.text.TextWatcher; @@ -26,28 +31,23 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.*; import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ContactHelper; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class UserIdEditor extends LinearLayout implements Editor, OnClickListener { private EditorListener mEditorListener = null; private BootstrapButton mDeleteButton; private RadioButton mIsMainUserId; + private String mOriginalID; private EditText mName; + private String mOriginalName; private AutoCompleteTextView mEmail; + private String mOriginalEmail; private EditText mComment; - - public static class NoNameException extends Exception { - static final long serialVersionUID = 0xf812773343L; - - public NoNameException(String message) { - super(message); - } - } + private String mOriginalComment; + private boolean mOriginallyMainUserID; + private boolean mIsNewId; public void setCanEdit(boolean bCanEdit) { if (!bCanEdit) { @@ -59,14 +59,6 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene } } - public static class NoEmailException extends Exception { - static final long serialVersionUID = 0xf812773344L; - - public NoEmailException(String message) { - super(message); - } - } - public static class InvalidEmailException extends Exception { static final long serialVersionUID = 0xf812773345L; @@ -83,6 +75,24 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene super(context, attrs); } + TextWatcher mTextWatcher = new TextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void afterTextChanged(Editable s) + { + if (mEditorListener != null) { + mEditorListener.onEdited(); + } + } + }; + @Override protected void onFinishInflate() { setDrawingCacheEnabled(true); @@ -94,8 +104,10 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene mIsMainUserId.setOnClickListener(this); mName = (EditText) findViewById(R.id.name); + mName.addTextChangedListener(mTextWatcher); mEmail = (AutoCompleteTextView) findViewById(R.id.email); mComment = (EditText) findViewById(R.id.comment); + mComment.addTextChangedListener(mTextWatcher); mEmail.setThreshold(1); // Start working from first character @@ -127,36 +139,45 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene // remove drawable if email is empty mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } + if (mEditorListener != null) { + mEditorListener.onEdited(); + } } }); super.onFinishInflate(); } - public void setValue(String userId) { + public void setValue(String userId, boolean isMainID, boolean isNewId) { + mName.setText(""); + mOriginalName = ""; mComment.setText(""); + mOriginalComment = ""; mEmail.setText(""); - - Pattern withComment = Pattern.compile("^(.*) [(](.*)[)] <(.*)>$"); - Matcher matcher = withComment.matcher(userId); - if (matcher.matches()) { - mName.setText(matcher.group(1)); - mComment.setText(matcher.group(2)); - mEmail.setText(matcher.group(3)); - return; + mOriginalEmail = ""; + mIsNewId = isNewId; + mOriginalID = userId; + + String[] result = PgpKeyHelper.splitUserId(userId); + if (result[0] != null) { + mName.setText(result[0]); + mOriginalName = result[0]; } - - Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$"); - matcher = withoutComment.matcher(userId); - if (matcher.matches()) { - mName.setText(matcher.group(1)); - mEmail.setText(matcher.group(2)); - return; + if (result[1] != null) { + mEmail.setText(result[1]); + mOriginalEmail = result[1]; + } + if (result[2] != null) { + mComment.setText(result[2]); + mOriginalComment = result[2]; } + + mOriginallyMainUserID = isMainID; + setIsMainUserId(isMainID); } - public String getValue() throws NoNameException, NoEmailException { + public String getValue() { String name = ("" + mName.getText()).trim(); String email = ("" + mEmail.getText()).trim(); String comment = ("" + mComment.getText()).trim(); @@ -173,16 +194,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene // ok, empty one... return userId; } - - // otherwise make sure that name and email exist - if (name.equals("")) { - throw new NoNameException("need a name"); - } - - if (email.equals("")) { - throw new NoEmailException("need an email"); - } - + //TODO: check gpg accepts an entirely empty ID packet. specs say this is allowed return userId; } @@ -192,7 +204,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene boolean wasMainUserId = mIsMainUserId.isChecked(); parent.removeView(this); if (mEditorListener != null) { - mEditorListener.onDeleted(this); + mEditorListener.onDeleted(this, mIsNewId); } if (wasMainUserId && parent.getChildCount() > 0) { UserIdEditor editor = (UserIdEditor) parent.getChildAt(0); @@ -207,6 +219,9 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene editor.setIsMainUserId(false); } } + if (mEditorListener != null) { + mEditorListener.onEdited(); + } } } @@ -221,4 +236,29 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene public void setEditorListener(EditorListener listener) { mEditorListener = listener; } + + @Override + public boolean needsSaving() { + boolean retval = false; //(mOriginallyMainUserID != isMainUserId()); + retval |= !(mOriginalName.equals( ("" + mName.getText()).trim() ) ); + retval |= !(mOriginalEmail.equals( ("" + mEmail.getText()).trim() ) ); + retval |= !(mOriginalComment.equals( ("" + mComment.getText()).trim() ) ); + retval |= mIsNewId; + return retval; + } + + public boolean getIsOriginallyMainUserID() + { + return mOriginallyMainUserID; + } + + public boolean primarySwapped() + { + return (mOriginallyMainUserID != isMainUserId()); + } + + public String getOriginalID() + { + return mOriginalID; + } } |