📄 noteeditor.java
字号:
/* * Copyright (C) 2007 Google Inc. * * 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 com.google.android.notepad;import com.google.provider.NotePad;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.database.Cursor;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.net.ContentURI;import android.os.Bundle;import android.text.TextUtils;import android.util.AttributeSet;import android.util.Log;import android.util.Config;import android.view.KeyEvent;import android.view.Menu;import android.widget.EditText;import java.util.Map;/** * A generic activity for editing a note in a database. This can be used * either to simply view a note (Intent.VIEW_ACTION), view and edit a note * (Intent.EDIT_ACTION), or create a new note (Intent.INSERT_ACTION). */public class NoteEditor extends Activity { private static final String TAG = "Notes"; private static final int NOTE_INDEX = 1; private static final int TITLE_INDEX = 2; private static final int MODIFIED_INDEX = 3; /** * Standard projection for the interesting columns of a normal note. */ private static final String[] PROJECTION = new String[] { NotePad.Notes._ID, // 0 NotePad.Notes.NOTE, // 1 NotePad.Notes.TITLE, // 2 NotePad.Notes.MODIFIED_DATE // 3 }; // This is our state data that is stored when freezing. private static final String ORIGINAL_CONTENT = "origContent"; // Identifiers for our menu items. private static final int REVERT_ID = Menu.FIRST; private static final int DISCARD_ID = Menu.FIRST + 1; private static final int DELETE_ID = Menu.FIRST + 2; // The different distinct states the activity can be run in. private static final int STATE_EDIT = 0; private static final int STATE_INSERT = 1; private int mState; private boolean mNoteOnly = false; private ContentURI mURI; private Cursor mCursor; private EditText mText; private String mOriginalContent; public static class MyEditText extends EditText { private Rect mRect; private Paint mPaint; // we need this constructor for ViewInflate public MyEditText(Context context, AttributeSet attrs, Map params) { super(context, attrs, params); mRect = new Rect(); mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(0xFF0000FF); } @Override protected void onDraw(Canvas canvas) { int count = getLineCount(); Rect r = mRect; Paint paint = mPaint; for (int i = 0; i < count; i++) { int baseline = getLineBounds(i, r); canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint); } super.onDraw(canvas); } } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); final Intent intent = getIntent(); final String type = intent.resolveType(this); // Do some setup based on the action being performed. final String action = intent.getAction(); if (action.equals(Intent.EDIT_ACTION)) { // Requested to edit: set that state, and the data being edited. mState = STATE_EDIT; mURI = intent.getData(); } else if (action.equals(Intent.INSERT_ACTION)) { // Requested to insert: set that state, and create a new entry // in the container. mState = STATE_INSERT; mURI = getContentResolver().insert(intent.getData(), null); // If we were unable to create a new note, then just finish // this activity. A RESULT_CANCELED will be sent back to the // original activity if they requested a result. if (mURI == null) { Log.e("Notes", "Failed to insert new note into " + getIntent().getData()); finish(); return; } // The new entry was created, so assume all will end well and // set the result to be returned. setResult(RESULT_OK, mURI.toString()); } else { // Whoops, unknown action! Bail. Log.e(TAG, "Unknown action, exiting"); finish(); return; } // Set the layout for this activity. You can find it // in res/layout/hello_activity.xml setContentView(R.layout.note_editor); // The text view for our note, identified by its ID in the XML file. mText = (EditText) findViewById(R.id.note); // Get the note! mCursor = managedQuery(mURI, PROJECTION, null, null); // If an instance of this activity had previously stopped, we can // get the original text it started with. if (icicle != null) { mOriginalContent = icicle.getString(ORIGINAL_CONTENT); } } @Override protected void onResume() { super.onResume(); // If we didn't have any trouble retrieving the data, it is now // time to get at the stuff. if (mCursor != null) { // Make sure we are at the one and only row in the cursor. mCursor.first(); // Modify our overall title depending on the mode we are running in. if (mState == STATE_EDIT) { setTitle(getText(R.string.title_edit)); } else if (mState == STATE_INSERT) { setTitle(getText(R.string.title_create)); } // This is a little nasty: we be resumed after previously being // paused/stopped. We want to re-retrieve the data to make sure // we are still accurately showing what is in the cursor... but // we don't want to lose any UI state like the current cursor // position. This trick accomplishes that. In the future we // should have a better API for doing this... Bundle curState = mText.saveState(); String note = mCursor.getString(NOTE_INDEX); mText.setText(note); mText.restoreState(curState); // If we hadn't previously retrieved the original text, do so // now. This allows the user to revert their changes. if (mOriginalContent == null) { mOriginalContent = note; } } else { setTitle(getText(R.string.error_title)); mText.setText(getText(R.string.error_message)); } } @Override protected void onFreeze(Bundle outState) { // Save away the original text, so we still have it if the activity // needs to be killed while paused. outState.putString(ORIGINAL_CONTENT, mOriginalContent); } @Override protected void onPause() { super.onPause(); // The user is going somewhere else, so make sure their current // changes are safely saved away in the provider. We don't need // to do this if only editing. if (mCursor != null) { String text = mText.getText().toString(); int length = text.length(); // If this activity is finished, and there is no text, then we // do something a little special: simply delete the note entry. // Note that we do this both for editing and inserting... it // would be reasonable to only do it when inserting. if (isFinishing() && (length == 0) && !mNoteOnly) { setResult(RESULT_CANCELED); deleteNote(); // Get out updates into the provider. } else { // This stuff is only done when working with a full-fledged note. if (!mNoteOnly) { // Bump the modification time to now. mCursor.updateLong(MODIFIED_INDEX, System.currentTimeMillis()); // If we are creating a new note, then we want to also create // an initial title for it. if (mState == STATE_INSERT) { String title = text.substring(0, Math.min(30, length)); if (length > 30) { int lastSpace = title.lastIndexOf(' '); if (lastSpace > 0) { title = title.substring(0, lastSpace); } } mCursor.updateString(TITLE_INDEX, title); } } // Write our text back into the provider. mCursor.updateString(NOTE_INDEX, text); // Commit all of our changes to persistent storage. Note the // use of managedCommitUpdates() instead of // mCursor.commitUpdates() -- this lets Activity take care of // requerying the new data if needed. managedCommitUpdates(mCursor); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // Build the menus that are shown when editing. if (mState == STATE_EDIT) { menu.add(0, REVERT_ID, R.string.menu_revert).setShortcut( KeyEvent.KEYCODE_0, 0, KeyEvent.KEYCODE_R); if (!mNoteOnly) { menu.add(0, DELETE_ID, R.string.menu_delete).setShortcut( KeyEvent.KEYCODE_1, 0, KeyEvent.KEYCODE_D); } // Build the menus that are shown when inserting. } else { menu.add(0, DISCARD_ID, R.string.menu_discard).setShortcut( KeyEvent.KEYCODE_0, 0, KeyEvent.KEYCODE_D); } // If we are working on a real honest-to-ghod note, then append to the // menu items for any other activities that can do stuff with it // as well. This does a query on the system for any activities that // implement the ALTERNATIVE_ACTION for our data, adding a menu item // for each one that is found. if (!mNoteOnly) { Intent intent = new Intent(null, getIntent().getData()); intent.addCategory(Intent.ALTERNATIVE_CATEGORY); menu.addIntentOptions( Menu.ALTERNATIVE, 0, new ComponentName(this, NoteEditor.class), null, intent, 0, null); } return true; } @Override public boolean onOptionsItemSelected(Menu.Item item) { // Handle all of the possible menu actions. switch (item.getId()) { case DELETE_ID: deleteNote(); finish(); break; case DISCARD_ID: cancelNote(); break; case REVERT_ID: cancelNote(); break; } return super.onOptionsItemSelected(item); } /** * Take care of cancelling work on a note. Deletes the note if we * had created it, otherwise reverts to the original text. */ private final void cancelNote() { if (mCursor != null) { if (mState == STATE_EDIT) { mCursor.updateString(NOTE_INDEX, mOriginalContent); mCursor.commitUpdates(); mCursor.deactivate(); mCursor = null; } else if (mState == STATE_INSERT) { deleteNote(); } } setResult(RESULT_CANCELED); finish(); } /** * Take care of deleting a note. Simply deletes the entry. */ private final void deleteNote() { if (mCursor != null) { mText.setText(""); mCursor.deleteRow(); mCursor.deactivate(); mCursor = null; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -