Меня попросили реализовать нередактируемый раздел, такой как те, которые в файлах Java не позволяют редактировать код Матиссом. Я не должен был позволять пользователю редактировать некоторые переменные, синтаксис которых был похож на $ {ABC}.
Я скопировал код, который используется для BeanInfo, особенно «BIEditorSupport.java». Ниже приведены шаги для создания нового типа файла и добавления к нему защищенных разделов. Конечно, его можно настроить по собственному желанию.
Меня также попросили добавить всплывающие действия в код для редактирования содержимого охраняемых разделов, вероятно, я напишу об этом в другом уроке.
Спасибо Маттео Ди Джовинаццо и Паоло Репеле за их обзор кода.
Примечание . Полный пример кода можно скачать здесь .
- Создайте новое «приложение платформы NetBeans». Назовите его «GuardedSectionSuite», подойдет любое другое имя. Для этого в меню «Файл» выберите «Новый проект …» / «Модули NetBeans» / «Приложение платформы NetBeans». Завершите работу мастера, затем щелкните правой кнопкой мыши узел пакета, выберите «Свойства», затем выберите «Библиотеки». В кластере «ide» проверьте узел «Editor Guarded Sections».
- Добавьте новый модуль. Разверните узел набора. Щелкните правой кнопкой мыши узел «Модули». Выберите «Добавить новый …». Вызовите модуль «GuardedSectionModule», например. Добавьте новый модуль в комплект. Нажмите «Далее». Убедитесь, что установлен флажок «Создать слой XML». Нажмите «Готово». Щелкните правой кнопкой мыши на новом узле модуля и выберите «Свойства», а затем «Библиотеки». Нажмите «Добавить зависимость», а затем добавьте зависимости «Общие запросы API», «Разделы, защищенные редактором», «UI Utilities API», если вы не добавите это, у вас возникнут проблемы при запуске пакета.
- Распознать новый тип файла. Щелкните правой кнопкой мыши на новом узле модуля и выберите «Новый» / «Другой». Выберите «Разработка модуля» и «Тип файла». Заполните текстовое поле, расширение — это расширение, используемое для распознавания файла, а тип MIME будет идентификатором этого файла. Нажмите «Далее». Опять заполните поля, значок не важен. Нажмите «Готово».
- Напиши код. Изменить «ScantiDataObject.java» Заменить эту строку:
cookies.add((Node.Cookie)DataEditorSupport.create(this, getPrimaryEntry(), cookies));
с этим
cookies.add(new ScantiDesignEditorSupport(this, getCookieSet()));
Создайте новый класс Java и назовите его «ScantiDesignEditorSupport». Этот класс позаботится о сохранении и загрузке файла и косвенно вызовет «GuardedSectionProvider» в этих случаях. Не забудьте изменить его, если у вас есть тип MIME, отличный от «text / x-scanti». Скопируйте этот код внутри «ScantiDesignEditorSupport»:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import javax.swing.text.BadLocationException;
import javax.swing.text.EditorKit;
import javax.swing.text.StyledDocument;
import org.netbeans.api.editor.guards.GuardedSectionManager;
import org.netbeans.api.queries.FileEncodingQuery;
import org.netbeans.spi.editor.guards.GuardedEditorSupport;
import org.netbeans.spi.editor.guards.GuardedSectionsFactory;
import org.netbeans.spi.editor.guards.GuardedSectionsProvider;
import org.openide.cookies.EditCookie;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.OpenCookie;
import org.openide.cookies.PrintCookie;
import org.openide.cookies.SaveCookie;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.loaders.MultiDataObject;
import org.openide.nodes.CookieSet;
import org.openide.text.DataEditorSupport;
import org.openide.windows.CloneableOpenSupport;
public class ScantiDesignEditorSupport extends DataEditorSupport
implements OpenCookie, EditCookie, EditorCookie, PrintCookie, EditorCookie.Observable {
private MyGuardedEditor guardedEditor;
public ScantiDesignEditorSupport(DataObject obj, CookieSet cookieSet) {
super(obj, new Environment(obj, cookieSet));
setMIMEType("text/x-scanti");
}
/**
* gets the GuardedSectionManager from a given document
* Useful to get a list of Guarded Sections inside a document
* @param doc the document
* @return a GuardedSectionManager
*/
public GuardedSectionManager getGuardedSectionManager(StyledDocument doc) {
return GuardedSectionManager.getInstance(doc);
}
public GuardedSectionManager getGuardedSectionManager() {
try {
StyledDocument doc = openDocument();
return GuardedSectionManager.getInstance(doc);
} catch (IOException ex) {
throw new IllegalStateException("cannot open document", ex); // NOI18N
}
}
@Override
protected void loadFromStreamToKit(StyledDocument doc, InputStream stream, EditorKit kit)
throws IOException, BadLocationException {
guardedEditor = null;
GuardedSectionsProvider guardedProvider = getGuardedProvider(doc);
if (guardedProvider != null) {
guardedEditor.document = doc;
Charset c = FileEncodingQuery.getEncoding(this.getDataObject().getPrimaryFile());
Reader reader = guardedProvider.createGuardedReader(stream, c);
try {
kit.read(reader, doc, 0);
} finally {
reader.close();
}
} else {
super.loadFromStreamToKit(doc, stream, kit);
}
}
private GuardedSectionsProvider getGuardedProvider(StyledDocument doc) {
GuardedSectionsProvider guardedProvider = null;
if (guardedEditor == null) {
guardedEditor = new MyGuardedEditor(doc);
String mimeType = ((DataEditorSupport.Env) env).getMimeType();
GuardedSectionsFactory gFactory = GuardedSectionsFactory.find(mimeType);
if (gFactory != null) {
guardedProvider = gFactory.create(guardedEditor);
}
}
return guardedProvider;
}
@Override
protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, OutputStream stream)
throws IOException, BadLocationException {
GuardedSectionsProvider guardedProvider = getGuardedProvider(doc);
if (guardedProvider != null) {
Charset c = FileEncodingQuery.getEncoding(this.getDataObject().getPrimaryFile());
Writer writer = guardedProvider.createGuardedWriter(stream, c);
try {
kit.write(writer, doc, 0, doc.getLength());
} finally {
writer.close();
}
} else {
super.saveFromKitToStream(doc, kit, stream);
}
}
@Override
public void saveDocument() throws IOException {
super.saveDocument();
}
@Override
protected boolean notifyModified() {
if (!super.notifyModified()) {
return false;
}
((Environment) this.env).addSaveCookie();
return true;
}
@Override
protected void notifyUnmodified() {
super.notifyUnmodified();
((Environment) this.env).removeSaveCookie();
}
@Override
protected void notifyClosed() {
super.notifyClosed();
}
static class MyGuardedEditor implements GuardedEditorSupport {
protected StyledDocument document;
public MyGuardedEditor(StyledDocument document) {
this.document = document;
}
@Override
public StyledDocument getDocument() {
return document;
}
}
static ScantiDesignEditorSupport findEditor(DataObject dobj) {
return dobj.getLookup().lookup(ScantiDesignEditorSupport.class);
}
private static final class Environment extends DataEditorSupport.Env {
private static final long serialVersionUID = -1;
private final transient CookieSet cookieSet;
private transient SaveSupport saveCookie = null;
private final class SaveSupport implements SaveCookie {
@Override
public void save() throws java.io.IOException {
DataObject dobj = getDataObject();
((DataEditorSupport) findCloneableOpenSupport()).saveDocument();
dobj.setModified(false);
}
}
public Environment(DataObject obj, CookieSet cookieSet) {
super(obj);
this.cookieSet = cookieSet;
}
@Override
protected FileObject getFile() {
return this.getDataObject().getPrimaryFile();
}
@Override
protected FileLock takeLock() throws java.io.IOException {
return ((MultiDataObject) this.getDataObject()).getPrimaryEntry().takeLock();
}
public
@Override
CloneableOpenSupport findCloneableOpenSupport() {
return findEditor(this.getDataObject());
}
public void addSaveCookie() {
DataObject javaData = this.getDataObject();
if (javaData.getCookie(SaveCookie.class) == null) {
if (this.saveCookie == null) {
this.saveCookie = new SaveSupport();
}
this.cookieSet.add(this.saveCookie);
javaData.setModified(true);
}
}
public void removeSaveCookie() {
DataObject javaData = this.getDataObject();
if (javaData.getCookie(SaveCookie.class) != null) {
this.cookieSet.remove(this.saveCookie);
javaData.setModified(false);
}
}
}
} - Создайте новый класс Java. Назовите это «ScantiGuardedSectionsFactory». Вставьте этот код внутри:
import org.netbeans.spi.editor.guards.GuardedEditorSupport;
import org.netbeans.spi.editor.guards.GuardedSectionsFactory;
import org.netbeans.spi.editor.guards.GuardedSectionsProvider;
public class ScantiGuardedSectionsFactory extends GuardedSectionsFactory{
@Override
public GuardedSectionsProvider create(GuardedEditorSupport ges) {
return new ScantiGuardedSectionsProvider(ges);
}
} - Наконец, создайте класс Java, который выполняет эту работу. Назовите это «ScantiGuardedSectionsProvider». Метод readSection считывает содержимое файла и извлекает из него разделы. Возвращаемый объект Result содержит массив символов и список разделов. Я думаю, что отображаемый текст можно изменить, вернув другой массив. То же самое можно сказать и о методе writeSections. Это полезно, если вы хотите пометить свой раздел текстом, который вы не хотите показывать пользователю.
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;
import org.netbeans.api.editor.guards.GuardedSection;
import org.netbeans.api.editor.guards.SimpleSection;
import org.netbeans.spi.editor.guards.GuardedEditorSupport;
import org.netbeans.spi.editor.guards.support.AbstractGuardedSectionsProvider;
import org.openide.util.Exceptions;
public class ScantiGuardedSectionsProvider extends AbstractGuardedSectionsProvider {
public ScantiGuardedSectionsProvider(GuardedEditorSupport editor) {
super(editor);
}
@Override
public char[] writeSections(List list, char[] chars) {
return chars;
}
@Override
public Result readSections(char[] chars) {
List sections = new ArrayList();
StringBuilder sb = new StringBuilder();
int start = 0;
int len = 0;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
switch (c) {
case '}': // I have found the closing brace
if (len == 2) {
try {
Logger.getLogger(ScantiGuardedSectionsProvider.class.getName()).log(Level.INFO, "Appending Section {0}", sb.toString());
SimpleSection section = createSimpleSection(sb.toString(), start, i);
sections.add(section);
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
sb = new StringBuilder();
len = 0;
}
break;
case '$': // I have found the first character
if (len == 0) {
len++;
}
start = i;
break;
case '{': // secondcharacter
if (len == 1) {
len++;
}
break;
default: // I create the variable name
if (len == 2) {
sb.append(c);
}
break;
} // end of switch
}
Result res = new Result(chars, sections);
return res;
}
} - Отредактируйте «layer.xml», чтобы зарегистрировать фабрику. Добавьте эти теги:
<folder name="Editors">
<folder name="text">
<folder name="x-scanti">
<file name="org-mycompany-guardedsection-ScantiGuardedSections.instance">
<attr name="instanceCreate" newvalue="org.mycompany.guardedsection.ScantiGuardedSectionsFactory"/>
<attr name="instanceOf" stringvalue="org.netbeans.spi.editor.guards.GuardedSectionsFactory"/>
</file>
</folder>
</folder>
</folder> - Запустите модуль. Создайте новый файл и напишите в нем текст, убедившись, что в нем есть что-то вроде $ {ABC}. Сохраните файл с расширением «.scanti», закройте его и снова откройте, и защищенные разделы будут применены.