Merge branch 'master' into geps/gep-032-database-backend

This commit is contained in:
Doug Blank 2015-05-27 16:00:10 -04:00
commit 6f671d8bff
11 changed files with 421 additions and 81 deletions

View File

@ -50,8 +50,12 @@ class PlaceName(SecondaryObject, DateBase):
Create a new PlaceName instance, copying from the source if present.
"""
DateBase.__init__(self, source)
self.value = ''
self.lang = ''
if source:
self.value = source.value
self.lang = source.lang
else:
self.value = ''
self.lang = ''
def serialize(self):
"""

View File

@ -23,7 +23,7 @@
import unittest
from .. import (Person, Surname, Name, NameType, Family, FamilyRelType,
Event, EventType, Source, Place, Citation, Date,
Event, EventType, Source, Place, PlaceName, Citation, Date,
Repository, RepositoryType, MediaObject, Note, NoteType,
StyledText, StyledTextTag, StyledTextTagType, Tag,
ChildRef, ChildRefType, Attribute, MediaRef, AttributeType,
@ -1391,100 +1391,108 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
self.phoenix.set_title('Place 1')
self.titanic = Place(self.phoenix)
self.ref_obj = Place(self.phoenix)
self.amsterdam = PlaceName()
self.amsterdam.set_value('Amsterdam')
self.rotterdam = PlaceName()
self.rotterdam.set_value('Rotterdam')
self.utrecht = PlaceName()
self.utrecht.set_value('Utrecht')
self.leiden = PlaceName()
self.leiden.set_value('Leiden')
def test_merge_primary_identical(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.titanic.set_title('Place 2')
self.titanic.set_name('Amsterdam')
self.titanic.set_name(self.amsterdam)
self.titanic.set_type(PlaceType.CITY)
self.ref_obj.set_name('Amsterdam')
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_primary_different(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.titanic.set_title('Place 2')
self.titanic.set_name('Rotterdam')
self.titanic.set_name(self.rotterdam)
self.titanic.set_type(PlaceType.CITY)
self.ref_obj.set_name('Amsterdam')
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name('Rotterdam')
self.ref_obj.add_alternative_name(self.rotterdam)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_both_different(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.phoenix.add_alternative_name('Utrecht')
self.phoenix.add_alternative_name(self.utrecht)
self.titanic.set_title('Place 2')
self.titanic.set_name('Rotterdam')
self.titanic.set_name(self.rotterdam)
self.titanic.set_type(PlaceType.CITY)
self.titanic.add_alternative_name('Leiden')
self.ref_obj.set_name('Amsterdam')
self.titanic.add_alternative_name(self.leiden)
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name('Amsterdam')
self.ref_obj.add_alternative_name('Rotterdam')
self.ref_obj.add_alternative_name('Utrecht')
self.ref_obj.add_alternative_name('Leiden')
self.ref_obj.add_alternative_name(self.amsterdam)
self.ref_obj.add_alternative_name(self.rotterdam)
self.ref_obj.add_alternative_name(self.utrecht)
self.ref_obj.add_alternative_name(self.leiden)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_alternative_identical(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.phoenix.add_alternative_name('Rotterdam')
self.phoenix.add_alternative_name(self.rotterdam)
self.titanic.set_title('Place 2')
self.titanic.set_name('Amsterdam')
self.titanic.set_name(self.amsterdam)
self.titanic.set_type(PlaceType.CITY)
self.titanic.add_alternative_name('Rotterdam')
self.ref_obj.set_name('Amsterdam')
self.titanic.add_alternative_name(self.rotterdam)
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name('Rotterdam')
self.ref_obj.add_alternative_name(self.rotterdam)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_alternative_different(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.phoenix.add_alternative_name('Rotterdam')
self.phoenix.add_alternative_name(self.rotterdam)
self.titanic.set_title('Place 2')
self.titanic.set_name('Amsterdam')
self.titanic.set_name(self.amsterdam)
self.titanic.set_type(PlaceType.CITY)
self.titanic.add_alternative_name('Utrecht')
self.ref_obj.set_name('Amsterdam')
self.titanic.add_alternative_name(self.utrecht)
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name('Rotterdam')
self.ref_obj.add_alternative_name('Utrecht')
self.ref_obj.add_alternative_name(self.rotterdam)
self.ref_obj.add_alternative_name(self.utrecht)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_prialt_identical(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.phoenix.add_alternative_name('Rotterdam')
self.phoenix.add_alternative_name(self.rotterdam)
self.titanic.set_title('Place 2')
self.titanic.set_name('Rotterdam')
self.titanic.set_name(self.rotterdam)
self.titanic.set_type(PlaceType.CITY)
self.ref_obj.set_name('Amsterdam')
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name('Rotterdam')
self.ref_obj.add_alternative_name(self.rotterdam)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_prialt2(self):
self.phoenix.set_name('Amsterdam')
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.phoenix.add_alternative_name('Rotterdam')
self.phoenix.add_alternative_name(self.rotterdam)
self.titanic.set_title('Place 2')
self.titanic.set_name('Rotterdam')
self.titanic.set_name(self.rotterdam)
self.titanic.set_type(PlaceType.CITY)
self.titanic.add_alternative_name('Amsterdam')
self.ref_obj.set_name('Amsterdam')
self.titanic.add_alternative_name(self.amsterdam)
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name('Rotterdam')
self.ref_obj.add_alternative_name(self.rotterdam)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())

View File

@ -52,7 +52,7 @@ from .displaytabs import (PlaceRefEmbedList, PlaceNameEmbedList,
GalleryTab, NoteTab, WebEmbedList, PlaceBackRefList)
from ..widgets import (MonitoredEntry, PrivacyButton, MonitoredTagList,
MonitoredDataType)
from gramps.gen.errors import ValidationError
from gramps.gen.errors import ValidationError, WindowActiveError
from gramps.gen.utils.place import conv_lat_lon
from gramps.gen.display.place import displayer as place_displayer
from gramps.gen.config import config
@ -119,6 +119,9 @@ class EditPlace(EditPrimary):
self.db.readonly,
changed=self.name_changed)
edit_button = self.top.get_object("name_button")
edit_button.connect('clicked', self.edit_place_name)
self.gid = MonitoredEntry(self.top.get_object("gid"),
self.obj.set_gramps_id,
self.obj.get_gramps_id, self.db.readonly)
@ -252,6 +255,18 @@ class EditPlace(EditPrimary):
self._setup_notebook_tabs(notebook)
def edit_place_name(self, obj):
try:
from . import EditPlaceName
EditPlaceName(self.dbstate, self.uistate, self.track,
self.obj.get_name(), self.edit_callback)
except WindowActiveError:
return
def edit_callback(self, obj):
value = self.obj.get_name().get_value()
self.top.get_object("name_entry").set_text(value)
def save(self, *obj):
self.ok_button.set_sensitive(False)

View File

@ -33,7 +33,7 @@ from .displaytabs import (PlaceRefEmbedList, PlaceNameEmbedList,
GalleryTab, NoteTab, WebEmbedList, PlaceBackRefList)
from gramps.gen.lib import NoteType
from gramps.gen.db import DbTxn
from gramps.gen.errors import ValidationError
from gramps.gen.errors import ValidationError, WindowActiveError
from gramps.gen.utils.place import conv_lat_lon
from gramps.gen.display.place import displayer as place_displayer
from gramps.gen.config import config
@ -119,6 +119,9 @@ class EditPlaceRef(EditReference):
self.db.readonly,
changed=self.name_changed)
edit_button = self.top.get_object("name_button")
edit_button.connect('clicked', self.edit_place_name)
self.gid = MonitoredEntry(self.top.get_object("gid"),
self.source.set_gramps_id,
self.source.get_gramps_id, self.db.readonly)
@ -253,6 +256,18 @@ class EditPlaceRef(EditReference):
self._setup_notebook_tabs(notebook)
def edit_place_name(self, obj):
try:
from . import EditPlaceName
EditPlaceName(self.dbstate, self.uistate, self.track,
self.source.get_name(), self.edit_callback)
except WindowActiveError:
return
def edit_callback(self, obj):
value = self.source.get_name().get_value()
self.top.get_object("name_entry").set_text(value)
def save(self, *obj):
self.ok_button.set_sensitive(False)

View File

@ -304,19 +304,6 @@ You can set these values via the Geography View by searching the place, or via a
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The name of this place.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="place_type">
<property name="visible">True</property>
@ -376,6 +363,50 @@ You can set these values via the Geography View by searching the place, or via a
<property name="width">5</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="UndoableEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The name of this place.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="name_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Invoke place name editor.</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">gtk-edit</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>

View File

@ -119,9 +119,7 @@
<object class="UndoableEntry" id="language">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Mail address.
Note: Use Residence Event for genealogical address data.</property>
<property name="tooltip_text" translatable="yes">Language in which the name is written.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>
@ -169,7 +167,7 @@ Note: Use Residence Event for genealogical address data.</property>
<object class="ValidatableMaskedEntry" id="date_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Date at which the address is valid.</property>
<property name="tooltip_text" translatable="yes">Date range in which the name is valid.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>
@ -182,9 +180,7 @@ Note: Use Residence Event for genealogical address data.</property>
<object class="UndoableEntry" id="value">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Mail address.
Note: Use Residence Event for genealogical address data.</property>
<property name="tooltip_text" translatable="yes" context="place">The name of the place.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>

View File

@ -386,19 +386,6 @@
<property name="width">4</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The name of this place.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="ValidatableMaskedEntry" id="lat_entry">
<property name="visible">True</property>
@ -534,6 +521,50 @@ You can set these values via the Geography View by searching the place, or via a
<property name="width">5</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="UndoableEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The name of this place.</property>
<property name="hexpand">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="name_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Invoke place name editor.</property>
<property name="icon_name">gtk-edit</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>

View File

@ -90,8 +90,8 @@ class MergePlace(ManagedWindow):
self.get_widget(widget_name).set_label(PLACE_NAME)
entry1 = self.get_widget("name1")
entry2 = self.get_widget("name2")
entry1.set_text(self.pl1.get_name())
entry2.set_text(self.pl2.get_name())
entry1.set_text(self.pl1.get_name().get_value())
entry2.set_text(self.pl2.get_name().get_value())
if entry1.get_text() == entry2.get_text():
for widget_name in ('name1', 'name2', 'name_btn1', 'name_btn2'):
self.get_widget(widget_name).set_sensitive(False)

View File

@ -52,7 +52,7 @@ def run(database, document, obj):
tagvalue = ref_obj
tagcheck = _("Ok")
else:
tagvalue = styledtext_tag.value
tagvalue = lvalue
tagcheck = _("Failed: missing object")
else:
tagtype = _("Internet")

View File

@ -0,0 +1,218 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2015 Doug Blank <doug.blank@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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 General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""""""
#------------------------------------------------------------------------
#
# standard python modules
#
#------------------------------------------------------------------------
#------------------------------------------------------------------------
#
# GRAMPS modules
#
#------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.errors import ReportError
from gramps.gen.plug.menu import PersonOption
from gramps.gen.plug.docgen import (IndexMark, FontStyle, ParagraphStyle,
TableStyle, TableCellStyle,
FONT_SANS_SERIF, PARA_ALIGN_CENTER,
INDEX_TYPE_TOC)
from gramps.gen.plug.report import Report
from gramps.gen.plug.report import utils as ReportUtils
from gramps.gen.plug.report import MenuReportOptions
from gramps.gen.plug.report import stdoptions
from gramps.gen.simple import SimpleAccess
#------------------------------------------------------------------------
#
# NoteLinkReport
#
#------------------------------------------------------------------------
class NoteLinkReport(Report):
"""
This report
"""
def write_report(self):
"""
The routine that actually creates the report.
At this point, the document is opened and ready for writing.
"""
sdb = SimpleAccess(self.database)
self.doc.start_paragraph("NoteLink-Title")
title = _("Note Link Check Report")
mark = IndexMark(title, INDEX_TYPE_TOC, 1)
self.doc.write_text(title, mark)
self.doc.end_paragraph()
self.doc.start_table('NoteLinkTable','NoteLink-Table')
self.doc.start_row()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal-Bold')
self.doc.write_text(_("Note ID"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal-Bold')
self.doc.write_text(_("Link Type"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal-Bold')
self.doc.write_text(_("Links To"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal-Bold')
self.doc.write_text(_("Status"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
for note in self.database.iter_notes():
for (ldomain, ltype, lprop, lvalue) in note.get_links():
if ldomain == "gramps":
tagtype = _(ltype)
ref_obj = sdb.get_link(ltype, lprop, lvalue)
if ref_obj:
tagvalue = sdb.describe(ref_obj)
tagcheck = _("Ok")
else:
tagvalue = "%s://%s/%s/%s" % (ldomain, ltype, lprop, lvalue)
tagcheck = _("Failed")
else:
tagtype = _("Internet")
tagvalue = lvalue
tagcheck = ""
self.doc.start_row()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal')
self.doc.write_text(note.gramps_id)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal')
self.doc.write_text(tagtype)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal')
self.doc.write_text(tagvalue)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('NoteLink-TableCell')
self.doc.start_paragraph('NoteLink-Normal')
self.doc.write_text(tagcheck)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
self.doc.end_table()
#------------------------------------------------------------------------
#
# NoteLinkOptions
#
#------------------------------------------------------------------------
class NoteLinkOptions(MenuReportOptions):
def add_menu_options(self, menu):
"""
Add options to the menu for the tag report.
"""
pass
def make_default_style(self,default_style):
"""Make the default output style for the Note Link Report."""
# Paragraph Styles
f = FontStyle()
f.set_size(16)
f.set_type_face(FONT_SANS_SERIF)
f.set_bold(1)
p = ParagraphStyle()
p.set_header_level(1)
p.set_bottom_border(1)
p.set_top_margin(ReportUtils.pt2cm(3))
p.set_bottom_margin(ReportUtils.pt2cm(3))
p.set_font(f)
p.set_alignment(PARA_ALIGN_CENTER)
p.set_description(_("The style used for the title of the page."))
default_style.add_paragraph_style("NoteLink-Title", p)
font = FontStyle()
font.set(face=FONT_SANS_SERIF, size=14, italic=1)
para = ParagraphStyle()
para.set_font(font)
para.set_header_level(2)
para.set_top_margin(0.25)
para.set_bottom_margin(0.25)
para.set_description(_('The style used for the section headers.'))
default_style.add_paragraph_style("NoteLink-Heading", para)
font = FontStyle()
font.set_size(12)
p = ParagraphStyle()
p.set(first_indent=-0.75, lmargin=.75)
p.set_font(font)
p.set_top_margin(ReportUtils.pt2cm(3))
p.set_bottom_margin(ReportUtils.pt2cm(3))
p.set_description(_('The basic style used for the text display.'))
default_style.add_paragraph_style("NoteLink-Normal", p)
font = FontStyle()
font.set_size(12)
font.set_bold(True)
p = ParagraphStyle()
p.set(first_indent=-0.75, lmargin=.75)
p.set_font(font)
p.set_top_margin(ReportUtils.pt2cm(3))
p.set_bottom_margin(ReportUtils.pt2cm(3))
p.set_description(_('The basic style used for table headings.'))
default_style.add_paragraph_style("NoteLink-Normal-Bold", p)
#Table Styles
cell = TableCellStyle()
default_style.add_cell_style('NoteLink-TableCell', cell)
table = TableStyle()
table.set_width(100)
table.set_columns(4)
table.set_column_width(0, 10)
table.set_column_width(1, 15)
table.set_column_width(2, 65)
table.set_column_width(3, 10)
default_style.add_table_style('NoteLink-Table',table)

View File

@ -420,3 +420,25 @@ plg.category = CATEGORY_TEXT
plg.reportclass = 'RecordsReport'
plg.optionclass = 'RecordsReportOptions'
plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_CLI, REPORT_MODE_BKI]
#------------------------------------------------------------------------
#
# Records Report
#
#------------------------------------------------------------------------
plg = newplugin()
plg.id = 'notelinkreport'
plg.name = _("Note Link Report")
plg.description = _("Shows status of links in notes")
plg.version = '1.0'
plg.gramps_target_version = MODULE_VERSION
plg.status = STABLE
plg.fname = 'notelinkreport.py'
plg.ptype = REPORT
plg.authors = ["Doug Blank"]
plg.authors_email = ["doug.blank@gmail.com"]
plg.category = CATEGORY_TEXT
plg.reportclass = 'NoteLinkReport'
plg.optionclass = 'NoteLinkOptions'
plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_CLI, REPORT_MODE_BKI]