📄 entryeditor.java
字号:
/*
* Copyright 2006 Marcel Schoffelmeer
*
* 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.s10r.manager;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.EditorPart;
import com.s10r.manager.actions.AssignLabelAction;
import com.s10r.manager.actions.CopyIdToClipboardAction;
import com.s10r.manager.actions.CopyPasswordToClipboardAction;
import com.s10r.manager.actions.CopyUrlToClipboardAction;
import com.s10r.manager.actions.NewLabelAction;
import com.s10r.manager.actions.NewPasswordEntryAction;
import com.s10r.manager.actions.OpenUrlAction;
import com.s10r.manager.actions.RemoveAllLabelsAction;
import com.s10r.manager.actions.RemoveLabelAction;
import com.s10r.manager.dialogs.DialogType;
import com.s10r.manager.dialogs.EditLabelDialog;
import com.s10r.manager.dialogs.EditPasswordDialog;
import com.s10r.manager.dialogs.GeneralPreferencePage;
import com.s10r.manager.dialogs.GetPasswordDialog;
import com.s10r.manager.dialogs.MergeDialog;
import com.s10r.manager.dialogs.SetPasswordDialog;
import com.s10r.manager.model.ItemContainer;
import com.s10r.manager.model.ItemLabel;
import com.s10r.manager.model.ManagerItem;
import com.s10r.manager.model.PasswordEntry;
import com.s10r.manager.model.Storage;
import com.s10r.util.DuplicateChecker;
import com.s10r.util.Observer;
import com.s10r.util.PasswordGenerator;
import com.s10r.util.UpdateEvent;
/**
* An editor that presents a chat with a specified participant.
*
* TODO: figure out how to save/restore table column widths a la view init with
* memento.
*
*/
public class EntryEditor extends EditorPart implements Observer
{
public static String ID = "com.s10r.manager.entryeditor";
public static final String NAME_COLUMN = "name";
public static final String ID_COLUMN = "id";
public static final String PASSWORD_COLUMN = "password";
public static final String DESCRIPTION_COLUMN = "description";
public static final String USAGE_CNT_COLUMN = "usage cnt";
public static final String LAST_USED_COLUMN = "last used";
public static final String LAST_UPDATED_COLUMN = "last updated";
public static final String LAST_UPDATED_ON_SITE_COLUMN = "age";
public static final String URL_COLUMN = "url";
public static final String LABELS_COLUMN = "labels";
private TableViewer viewer;
private boolean dirty;
private static final String INPUT_MODE = "inputmode";
private static final String INPUT_POSITION = "inputposition";
ItemContainer managerItems = new ItemContainer();
// TODO: the input is managed by the superclass
EntryEditorInput editorInput;
private IAdapterFactory adapterFactory = new ManagerAdapterFactory();
private int newEntryCnt = 0;
private int newLabelCnt = 0;
private Map<String, StatusLineContribution> statusFields = null;
private ActivationListener activationListener = null;
private MyViewerFilter viewerFilter;
private MenuManager assignToLabelMenu;
private MenuManager removeLabelMenu;
/**
* The content provider class is responsible for providing objects to the
* view. It can wrap existing objects in adapters or simply return objects
* as-is. These objects may be sensitive to the current input of the view,
* or ignore it and always show the same content (like Task List, for
* example).
*/
class ViewContentProvider implements IStructuredContentProvider
{
public void inputChanged(Viewer v, Object oldInput, Object newInput)
{
}
public void dispose()
{
}
public Object[] getElements(Object parent)
{
return managerItems.toArray();
}
}
@Override
public void doSave(IProgressMonitor monitor)
{
// if the editor contains an untitled file input, ask the user
// for a file path to write to using saveAs
if (editorInput.isUntitled())
{
doSaveAs();
return;
}
verifyEditorInputForSaving();
Storage.save(managerItems, editorInput.getPath(), editorInput
.getPassword());
// tell the editor we've become clean since we saved
setDirty(false);
}
private void verifyEditorInputForSaving()
{
if (editorInput.getPassword() == null)
{
throw new IllegalArgumentException(
"can't save: editorInput password is null");
}
if (editorInput.getPath() == null)
{
throw new IllegalArgumentException(
"can't save: editorInput path is null");
}
}
/**
* Asks the user for the location to write to, and a password (if not
* already known (if a previously protected file has been opened the
* password is saved)). Finally doSave is called which will make use of the
* provided location/password (stored in the editorInput member).
*/
@Override
public void doSaveAs()
{
FileDialog fd = new FileDialog(getEditorSite().getShell(), SWT.SAVE);
fd.setText("Save");
// fd.setFilterPath("C:/");
String[] filterNames = { "Manager files", "All files" };
String[] filterExt = { "*.mgr", "*.*" };
fd.setFilterExtensions(filterExt);
fd.setFilterNames(filterNames);
String filePath = fd.open();
if (filePath == null)
{
return;
}
if (filePath != null)
{
editorInput.setFile(new File(filePath));
// now that we have set a file name it's not untitled anymore
editorInput.setUntitled(false);
if (editorInput.getPassword() == null)
{
SetPasswordDialog dlg = new SetPasswordDialog(getSite()
.getShell(), "Set password (to encrypt "
+ editorInput.getName() + ")");
int ret = dlg.open();
if (ret == Window.CANCEL)
{
return;
}
editorInput.setPassword(dlg.getPassword());
}
}
// sanity check
verifyEditorInputForSaving();
Storage.save(managerItems, editorInput.getPath(), editorInput
.getPassword());
// tell the editor we've become clean since we saved
setDirty(false);
// tell the editor the input has changed
// TODO: this doesn't update the title of the editor
// can't use setTitle either as it has been deprecated.
// setInputWithNotify only checks for a new object, not property changes
// so create a copy and try and see if this updates the name of the part
editorInput = editorInput.copy();
setInputWithNotify(editorInput);
// ok, fine: we'll set it ourselves then...
this.setPartName(editorInput.getName());
}
@Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException
{
// TODO: is this kosher? (making the assumption here that
// the input is of this type?
editorInput = (EntryEditorInput) input;
setSite(site);
setInput(input);
setPartName(input.getName());
// TODO: better check: invalid password vs other file io issues
// for example: check for non-existence or access denied
// if the input is untitled we don't have to load the content
if (!editorInput.isUntitled())
{
boolean retryOpen = true;
while (retryOpen)
{
GetPasswordDialog passwordDialog = new GetPasswordDialog(
getSite().getShell(), editorInput.getFile());
int ret = passwordDialog.open();
if (ret == Window.CANCEL)
{
retryOpen = false;
// close this editor as we couldn't load the content
getSite().getPage().closeEditor(this, false);
}
else
// OK
{
String password = passwordDialog.getValue();
// hold on to the password so we don't have to ask for it
// again when saving
editorInput.setPassword(password);
try
{
managerItems = Storage.load(editorInput.getFile(),
password);
retryOpen = false;
}
catch (Exception e)
{
MessageDialog.openError(getSite().getShell(),
"Open failed.",
"Could not open password file: "
+ editorInput.getFile().getPath());
}
}
}
}
activationListener = new ActivationListener();
getSite().getWorkbenchWindow().getPartService().addPartListener(
activationListener);
}
@Override
public boolean isDirty()
{
return dirty;
}
/**
* Enables the SaveAs action for this editor.
*
* @return
*/
@Override
public boolean isSaveAsAllowed()
{
return true;
}
@Override
public void createPartControl(Composite parent)
{
// GridLayout layout = new GridLayout();
// layout.marginWidth = 0;
// layout.marginHeight = 0;
// parent.setLayout(layout);
createTableViewer(parent);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider(managerItems));
viewer.setInput(getEditorSite());
getSite().setSelectionProvider(viewer);
IAction deleteAction = new Action()
{
@Override
public void run()
{
ISelection selection = viewer.getSelection();
if (selection instanceof IStructuredSelection)
{
// TODO: allow multi-delete
ManagerItem item = (ManagerItem) ((IStructuredSelection) selection)
.getFirstElement();
if (item == null)
{
// TODO: if this happens, the code needs to be updated
// to make sure delete is disabled (should not be able
// to invoke delete when nothing is selected)
throw new NullPointerException("selected item is null");
}
if (item instanceof ItemLabel)
{
deleteLabel((ItemLabel) item);
}
else
{
managerItems.remove(item);
}
}
}
};
getEditorSite().getActionBars().setGlobalActionHandler(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -