diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f6d1fb24..fbfbfa45a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ else() set(SUBSURFACE_PRINTING_SRCS printer.cpp templatelayout.cpp + qt-ui/templateedit.cpp ) set(PRINTING_PKG PrintSupport) set(PRINTING_LIB Qt5::PrintSupport) diff --git a/printer.cpp b/printer.cpp index 79f04e4a0..f8a90f96d 100644 --- a/printer.cpp +++ b/printer.cpp @@ -6,10 +6,11 @@ #include #include -Printer::Printer(QPrinter *printer, print_options *printOptions) +Printer::Printer(QPrinter *printer, print_options *printOptions, template_options *templateOptions) { this->printer = printer; this->printOptions = printOptions; + this->templateOptions = templateOptions; dpi = 0; done = 0; } @@ -26,9 +27,25 @@ void Printer::putProfileImage(QRect profilePlaceholder, QRect viewPort, QPainter void Printer::render() { - QPointer profile = MainWindow::instance()->graphics(); + // apply user settings + int divesPerPage; + if (printOptions->color_selected && printer->colorMode()) { + printer->setColorMode(QPrinter::Color); + } else { + printer->setColorMode(QPrinter::GrayScale); + } + + // get number of dives per page from data-numberofdives attribute in the body of the selected template + bool ok; + divesPerPage = webView->page()->mainFrame()->findFirstElement("body").attribute("data-numberofdives").toInt(&ok); + if (!ok) { + divesPerPage = 1; // print each dive in a single page if the attribute is missing or malformed + //TODO: show warning + } + int Pages = ceil(getTotalWork(printOptions) / (float)divesPerPage); // keep original preferences + QPointer profile = MainWindow::instance()->graphics(); int profileFrameStyle = profile->frameStyle(); int animationOriginal = prefs.animation_speed; double fontScale = profile->getFontPrintScale(); @@ -36,7 +53,7 @@ void Printer::render() // apply printing settings to profile profile->setFrameStyle(QFrame::NoFrame); profile->setPrintMode(true, !printOptions->color_selected); - profile->setFontPrintScale(0.6); + profile->setFontPrintScale(printer->pageLayout().paintRect(QPageLayout::Inch).width() * dpi * 0.001); profile->setToolTipVisibile(false); prefs.animation_speed = 0; @@ -47,17 +64,6 @@ void Printer::render() painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); - int divesPerPage; - switch (printOptions->p_template) { - case print_options::ONE_DIVE: - divesPerPage = 1; - break; - case print_options::TWO_DIVE: - divesPerPage = 2; - break; - } - int Pages = ceil(getTotalWork() / (float)divesPerPage); - // get all refereces to diveprofile class in the Html template QWebElementCollection collection = webView->page()->mainFrame()->findAllElements(".diveprofile"); @@ -111,7 +117,7 @@ void Printer::templateProgessUpdated(int value) void Printer::print() { - TemplateLayout t(printOptions); + TemplateLayout t(printOptions, templateOptions); webView = new QWebView(); connect(&t, SIGNAL(progressUpdated(int)), this, SLOT(templateProgessUpdated(int))); diff --git a/printer.h b/printer.h index cba82e607..4ab65834a 100644 --- a/printer.h +++ b/printer.h @@ -8,6 +8,7 @@ #include "profile/profilewidget2.h" #include "printoptions.h" +#include "templateedit.h" class Printer : public QObject { Q_OBJECT @@ -16,6 +17,7 @@ private: QPrinter *printer; QWebView *webView; print_options *printOptions; + template_options *templateOptions; QSize pageSize; int done; int dpi; @@ -26,7 +28,7 @@ private slots: void templateProgessUpdated(int value); public: - Printer(QPrinter *printer, print_options *printOptions); + Printer(QPrinter *printer, print_options *printOptions, template_options *templateOptions); void print(); signals: diff --git a/printing_templates/custom.html b/printing_templates/custom.html new file mode 100644 index 000000000..52fdb4b49 --- /dev/null +++ b/printing_templates/custom.html @@ -0,0 +1,50 @@ + + + + + +{% block main_rows %} + {% for dive in dives %} +
+
+

This template is empty

+ +
+
+ {% endfor %} +{% endblock %} + + diff --git a/printing_templates/one_dive.html b/printing_templates/one_dive.html index 754dc85bc..d7ae8d477 100644 --- a/printing_templates/one_dive.html +++ b/printing_templates/one_dive.html @@ -5,12 +5,14 @@ background-color: white; padding: 0; margin: 0; - font-size: 1.2vw; + font-size: {{ template_options.font_size }}vw; + line-height: {{ template_options.line_spacing }}; + font-family: {{ template_options.font }}; } h1 { - font-size: 1.2vw; float: left; + font-size: {{ template_options.font_size }}vw; } table { @@ -84,9 +86,13 @@ margin: 1.5%; float: left; } + + .textArea { + line-height: {{ template_options.line_spacing }}; + } - + {% block main_rows %} {% for dive in dives %}
diff --git a/printing_templates/two_dives.html b/printing_templates/two_dives.html index 574579f90..62502272b 100644 --- a/printing_templates/two_dives.html +++ b/printing_templates/two_dives.html @@ -5,10 +5,13 @@ background-color: white; padding: 0px; margin: 0px; + font-size: {{ template_options.font_size }}vw; + line-height: {{ template_options.line_spacing }}; + font-family: {{ template_options.font }}; } h1 { - font-size: 0.9cm; + font-size: {{ template_options.font_size }}vw; float: left; } @@ -20,49 +23,56 @@ margin-top: 0; margin-bottom: 0; overflow: hidden; - border-width: 0px; page-break-inside: avoid; } .innerContainer { height: 85%; - border-style: solid; padding: 0.5%; margin-top: 1%; margin-bottom: 1%; overflow: hidden; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border:max(0.1vw, 1px); + border-style:solid; } .table_class { overflow: hidden; max-width: 25%; min-width: 25%; - box-shadow: 5px 5px 5px #888888; margin: 1.5%; float: left; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border:max(0.1vw, 1px); + border-style:solid; } .notes_table_class { overflow: hidden; max-width: 100%; min-width: 100%; - box-shadow: 5px 5px 5px #888888; margin: 1.5%; float: left; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border:max(0.1vw, 1px); + border-style:solid; } .fieldTitle { background-color: #CfC7C5; overflow: hidden; + padding:0; } .diveProfile { width: 37%; - height: 70%; + height: 95%; margin: 1.5%; float: right; - border-style: solid; - padding: 3mm; } .diveDetails { @@ -80,9 +90,10 @@ } .textArea { - max-height: 43ex; overflow: hidden !important; text-overflow: ellipsis; + max-height: 10.3vw; + line-height: {{ template_options.line_spacing }}; } #footer { @@ -91,14 +102,14 @@ } - + {% block main_rows %} {% for dive in dives %}
- +

Dive No.

@@ -139,7 +150,7 @@
- +

Time.

@@ -184,7 +195,7 @@
- +

Notes

diff --git a/qt-ui/printdialog.cpp b/qt-ui/printdialog.cpp index 6f30f89f5..9ff29e67b 100644 --- a/qt-ui/printdialog.cpp +++ b/qt-ui/printdialog.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #define SETTINGS_GROUP "PrintDialog" @@ -22,6 +23,10 @@ PrintDialog::PrintDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f printOptions.landscape = false; printOptions.p_template = print_options::ONE_DIVE; printOptions.type = print_options::DIVELIST; + templateOptions.font_index = 0; + templateOptions.font_size = 9; + templateOptions.color_palette_index = 0; + templateOptions.line_spacing = 1; } else { s.beginGroup(SETTINGS_GROUP); printOptions.type = (print_options::print_type)s.value("type").toInt(); @@ -30,13 +35,17 @@ PrintDialog::PrintDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f printOptions.landscape = s.value("landscape").toBool(); printOptions.p_template = (print_options::print_template)s.value("template_selected").toInt(); qprinter.setOrientation((QPrinter::Orientation)printOptions.landscape); + templateOptions.font_index = s.value("font").toInt(); + templateOptions.font_size = s.value("font_size").toDouble(); + templateOptions.color_palette_index = s.value("color_palette").toInt(); + templateOptions.line_spacing = s.value("line_spacing").toDouble(); } // create a print options object and pass our options struct - optionsWidget = new PrintOptions(this, &printOptions); + optionsWidget = new PrintOptions(this, &printOptions, &templateOptions); // create a new printer object - printer = new Printer(&qprinter, &printOptions); + printer = new Printer(&qprinter, &printOptions, &templateOptions); QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); @@ -82,21 +91,47 @@ PrintDialog::PrintDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f void PrintDialog::onFinished() { - // save the settings QSettings s; s.beginGroup(SETTINGS_GROUP); + + // save print paper settings s.setValue("type", printOptions.type); s.setValue("print_selected", printOptions.print_selected); s.setValue("color_selected", printOptions.color_selected); s.setValue("template_selected", printOptions.p_template); + + // save template settings + s.setValue("font", templateOptions.font_index); + s.setValue("font_size", templateOptions.font_size); + s.setValue("color_palette", templateOptions.color_palette_index); + s.setValue("line_spacing", templateOptions.line_spacing); } void PrintDialog::previewClicked(void) { + if (printOptions.type == print_options::TABLE || printOptions.type == print_options::STATISTICS) { + QMessageBox msgBox; + msgBox.setText("This feature is not implemented yet"); + msgBox.exec(); + return; + } + + QPrintPreviewDialog previewDialog(&qprinter, this, Qt::Window + | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint + | Qt::WindowTitleHint); + connect(&previewDialog, SIGNAL(paintRequested(QPrinter *)), this, SLOT(onPaintRequested(QPrinter *))); + previewDialog.exec(); } void PrintDialog::printClicked(void) { + if (printOptions.type == print_options::TABLE || printOptions.type == print_options::STATISTICS) { + QMessageBox msgBox; + msgBox.setText("This feature is not implemented yet"); + msgBox.exec(); + return; + } + QPrintDialog printDialog(&qprinter, this); if (printDialog.exec() == QDialog::Accepted) { switch (printOptions.type) { @@ -115,5 +150,9 @@ void PrintDialog::printClicked(void) void PrintDialog::onPaintRequested(QPrinter *printerPtr) { + connect(printer, SIGNAL(progessUpdated(int)), progressBar, SLOT(setValue(int))); + printer->print(); + progressBar->setValue(0); + disconnect(printer, SIGNAL(progessUpdated(int)), progressBar, SLOT(setValue(int))); } #endif diff --git a/qt-ui/printdialog.h b/qt-ui/printdialog.h index a34037442..a00c4c5d9 100644 --- a/qt-ui/printdialog.h +++ b/qt-ui/printdialog.h @@ -6,6 +6,7 @@ #include #include "printoptions.h" #include "printer.h" +#include "templateedit.h" class QProgressBar; class PrintOptions; @@ -24,6 +25,7 @@ private: Printer *printer; QPrinter qprinter; struct print_options printOptions; + struct template_options templateOptions; private slots: diff --git a/qt-ui/printoptions.cpp b/qt-ui/printoptions.cpp index e2684b6ed..0e6a0b320 100644 --- a/qt-ui/printoptions.cpp +++ b/qt-ui/printoptions.cpp @@ -1,20 +1,22 @@ #include "printoptions.h" +#include "templateedit.h" #include -PrintOptions::PrintOptions(QWidget *parent, struct print_options *printOpt) +PrintOptions::PrintOptions(QWidget *parent, struct print_options *printOpt, struct template_options *templateOpt) { hasSetupSlots = false; ui.setupUi(this); if (parent) setParent(parent); - if (!printOpt) + if (!printOpt || !templateOpt) return; - setup(printOpt); + templateOptions = templateOpt; + printOptions = printOpt; + setup(); } -void PrintOptions::setup(struct print_options *printOpt) +void PrintOptions::setup() { - printOptions = printOpt; // print type radio buttons switch (printOptions->type) { case print_options::DIVELIST: @@ -34,6 +36,9 @@ void PrintOptions::setup(struct print_options *printOpt) case print_options::TWO_DIVE: ui.printTemplate->setCurrentIndex(1); break; + case print_options::CUSTOM: + ui.printTemplate->setCurrentIndex(2); + break; } // general print option checkboxes @@ -95,5 +100,15 @@ void PrintOptions::on_printTemplate_currentIndexChanged(int index) case 1: printOptions->p_template = print_options::TWO_DIVE; break; + case 2: + printOptions->p_template = print_options::CUSTOM; + break; } } + +void PrintOptions::on_editButton_clicked() +{ + TemplateEdit te(this, printOptions, templateOptions); + te.exec(); + setup(); +} diff --git a/qt-ui/printoptions.h b/qt-ui/printoptions.h index 13ef4e310..d96b27a53 100644 --- a/qt-ui/printoptions.h +++ b/qt-ui/printoptions.h @@ -13,24 +13,33 @@ struct print_options { } type; enum print_template { ONE_DIVE, - TWO_DIVE + TWO_DIVE, + CUSTOM } p_template; bool print_selected; bool color_selected; bool landscape; }; +struct template_options { + int font_index; + int color_palette_index; + double font_size; + double line_spacing; +}; + // should be based on a custom QPrintDialog class class PrintOptions : public QWidget { Q_OBJECT public: - explicit PrintOptions(QWidget *parent = 0, struct print_options *printOpt = 0); - void setup(struct print_options *printOpt); + explicit PrintOptions(QWidget *parent, struct print_options *printOpt, struct template_options *templateOpt); + void setup(); private: Ui::PrintOptions ui; struct print_options *printOptions; + struct template_options *templateOptions; bool hasSetupSlots; private @@ -41,6 +50,7 @@ slots: void on_radioTablePrint_clicked(bool check); void on_radioDiveListPrint_clicked(bool check); void on_printTemplate_currentIndexChanged(int index); + void on_editButton_clicked(); }; #endif // PRINTOPTIONS_H diff --git a/qt-ui/printoptions.ui b/qt-ui/printoptions.ui index 632b9cdaf..7e66d4cb0 100644 --- a/qt-ui/printoptions.ui +++ b/qt-ui/printoptions.ui @@ -140,6 +140,11 @@ Two dives per page + + + Custom template + + diff --git a/qt-ui/templateedit.cpp b/qt-ui/templateedit.cpp new file mode 100644 index 000000000..82a71ea32 --- /dev/null +++ b/qt-ui/templateedit.cpp @@ -0,0 +1,61 @@ +#include "templateedit.h" +#include "printoptions.h" +#include "ui_templateedit.h" + +TemplateEdit::TemplateEdit(QWidget *parent, struct print_options *printOptions, struct template_options *templateOptions) : + QDialog(parent), + ui(new Ui::TemplateEdit) +{ + ui->setupUi(this); + this->templateOptions = templateOptions; + this->printOptions = printOptions; + + // restore the settings and init the UI + ui->fontSelection->setCurrentIndex(templateOptions->font_index); + ui->fontsize->setValue(templateOptions->font_size); + ui->colorpalette->setCurrentIndex(templateOptions->color_palette_index); + ui->linespacing->setValue(templateOptions->line_spacing); + + if (printOptions->p_template == print_options::ONE_DIVE) { + grantlee_template = TemplateLayout::readTemplate("one_dive.html"); + } else if (printOptions->p_template == print_options::TWO_DIVE) { + grantlee_template = TemplateLayout::readTemplate("two_dives.html"); + } else if (printOptions->p_template == print_options::CUSTOM) { + grantlee_template = TemplateLayout::readTemplate("custom.html"); + } + + ui->plainTextEdit->setPlainText(grantlee_template); +} + +TemplateEdit::~TemplateEdit() +{ + delete ui; +} + +void TemplateEdit::on_fontsize_valueChanged(int font_size) +{ + templateOptions->font_size = font_size; +} + +void TemplateEdit::on_linespacing_valueChanged(double line_spacing) +{ + templateOptions->line_spacing = line_spacing; +} + +void TemplateEdit::on_fontSelection_currentIndexChanged(int index) +{ + templateOptions->font_index = index; +} + +void TemplateEdit::on_colorpalette_currentIndexChanged(int index) +{ + templateOptions->color_palette_index = index; +} + +void TemplateEdit::on_TemplateEdit_finished(int result) +{ + if (grantlee_template.compare(ui->plainTextEdit->toPlainText())) { + printOptions->p_template = print_options::CUSTOM; + TemplateLayout::writeTemplate("custom.html", ui->plainTextEdit->toPlainText()); + } +} diff --git a/qt-ui/templateedit.h b/qt-ui/templateedit.h new file mode 100644 index 000000000..296005652 --- /dev/null +++ b/qt-ui/templateedit.h @@ -0,0 +1,36 @@ +#ifndef TEMPLATEEDIT_H +#define TEMPLATEEDIT_H + +#include +#include "templatelayout.h" + +namespace Ui { +class TemplateEdit; +} + +class TemplateEdit : public QDialog +{ + Q_OBJECT + +public: + explicit TemplateEdit(QWidget *parent, struct print_options *printOptions, struct template_options *templateOptions); + ~TemplateEdit(); +private slots: + void on_fontsize_valueChanged(int font_size); + + void on_linespacing_valueChanged(double line_spacing); + + void on_fontSelection_currentIndexChanged(int index); + + void on_colorpalette_currentIndexChanged(int index); + + void on_TemplateEdit_finished(int result); + +private: + Ui::TemplateEdit *ui; + struct template_options *templateOptions; + struct print_options *printOptions; + QString grantlee_template; +}; + +#endif // TEMPLATEEDIT_H diff --git a/qt-ui/templateedit.ui b/qt-ui/templateedit.ui new file mode 100644 index 000000000..26fe15926 --- /dev/null +++ b/qt-ui/templateedit.ui @@ -0,0 +1,262 @@ + + + TemplateEdit + + + + 0 + 0 + 774 + 433 + + + + Edit Template + + + + + 400 + 380 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 300 + 30 + 441 + 331 + + + + 0 + + + + Style + + + + + 10 + 20 + 401 + 171 + + + + + + + + + Font + + + + + + + + Arial + + + + + Impact + + + + + Georgia + + + + + Courier + + + + + Verdana + + + + + + + + + + + + Font size + + + + + + + 9 + + + 18 + + + + + + + + + + + Color pallet + + + + + + + + Almond + + + + + + + + + + + + Line spacing + + + + + + + 1.000000000000000 + + + 3.000000000000000 + + + 0.250000000000000 + + + 1.250000000000000 + + + + + + + + + + + Template + + + + + 0 + 0 + 441 + 301 + + + + Qt::ScrollBarAsNeeded + + + QPlainTextEdit::NoWrap + + + + + + + + 20 + 60 + 251 + 311 + + + + + about:blank + + + + + + + 30 + 30 + 59 + 14 + + + + Preview + + + + + + QWebView + QWidget +
QtWebKitWidgets/QWebView
+
+
+ + + + buttonBox + accepted() + TemplateEdit + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TemplateEdit + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/templatelayout.cpp b/templatelayout.cpp index 5f47b64a2..9a9dc9656 100644 --- a/templatelayout.cpp +++ b/templatelayout.cpp @@ -4,17 +4,26 @@ #include "helpers.h" #include "display.h" -int getTotalWork() +int getTotalWork(print_options *printOptions) { - // return the correct number depending on all/selected dives - // but don't return 0 as we might divide by this number - return amount_selected ? amount_selected : 1; + if (printOptions->print_selected) { + // return the correct number depending on all/selected dives + // but don't return 0 as we might divide by this number + return amount_selected ? amount_selected : 1; + } + int dives = 0, i; + struct dive *dive; + for_each_dive (i, dive) { + dives++; + } + return dives; } -TemplateLayout::TemplateLayout(print_options *PrintOptions) : +TemplateLayout::TemplateLayout(print_options *PrintOptions, template_options *templateOptions) : m_engine(NULL) { this->PrintOptions = PrintOptions; + this->templateOptions = templateOptions; } TemplateLayout::~TemplateLayout() @@ -25,7 +34,7 @@ TemplateLayout::~TemplateLayout() QString TemplateLayout::generate() { int progress = 0; - int totalWork = getTotalWork(); + int totalWork = getTotalWork(PrintOptions); QString templateName; QString htmlContent; @@ -37,6 +46,7 @@ QString TemplateLayout::generate() m_engine->addTemplateLoader(m_templateLoader); Grantlee::registerMetaType(); + Grantlee::registerMetaType(); QVariantHash mapping; QVariantList diveList; @@ -45,7 +55,7 @@ QString TemplateLayout::generate() int i; for_each_dive (i, dive) { //TODO check for exporting selected dives only - if (!dive->selected) + if (!dive->selected && PrintOptions->print_selected) continue; Dive d(dive); diveList.append(QVariant::fromValue(d)); @@ -53,6 +63,7 @@ QString TemplateLayout::generate() emit progressUpdated(progress * 100.0 / totalWork); } mapping.insert("dives", diveList); + mapping.insert("template_options", QVariant::fromValue(*templateOptions)); Grantlee::Context c(mapping); @@ -60,6 +71,8 @@ QString TemplateLayout::generate() templateName = "one_dive.html"; } else if (PrintOptions->p_template == print_options::TWO_DIVE) { templateName = "two_dives.html"; + } else if (PrintOptions->p_template == print_options::CUSTOM) { + templateName = "custom.html"; } Grantlee::Template t = m_engine->loadByName(templateName); if (!t || t->error()) { @@ -76,6 +89,25 @@ QString TemplateLayout::generate() return htmlContent; } +QString TemplateLayout::readTemplate(QString template_name) +{ + QFile qfile(getSubsurfaceDataPath("printing_templates") + QDir::separator() + template_name); + if (qfile.open(QFile::ReadOnly | QFile::Text)) { + QTextStream in(&qfile); + return in.readAll(); + } + return ""; +} + +void TemplateLayout::writeTemplate(QString template_name, QString grantlee_template) +{ + QFile qfile(getSubsurfaceDataPath("printing_templates") + QDir::separator() + template_name); + if (qfile.open(QFile::ReadWrite | QFile::Text)) { + qfile.write(grantlee_template.toUtf8().data()); + qfile.close(); + } +} + Dive::Dive() : m_number(-1), dive(NULL) diff --git a/templatelayout.h b/templatelayout.h index 21eae1b80..622f7d7a0 100644 --- a/templatelayout.h +++ b/templatelayout.h @@ -5,18 +5,21 @@ #include "mainwindow.h" #include "printoptions.h" -int getTotalWork(); +int getTotalWork(print_options *printOptions); class TemplateLayout : public QObject { Q_OBJECT public: - TemplateLayout(print_options *PrintOptions); + TemplateLayout(print_options *PrintOptions, template_options *templateOptions); ~TemplateLayout(); QString generate(); + static QString readTemplate(QString template_name); + static void writeTemplate(QString template_name, QString grantlee_template); private: Grantlee::Engine *m_engine; print_options *PrintOptions; + template_options *templateOptions; signals: void progressUpdated(int value); @@ -75,6 +78,7 @@ public: }; Q_DECLARE_METATYPE(Dive) +Q_DECLARE_METATYPE(template_options) GRANTLEE_BEGIN_LOOKUP(Dive) if (property == "number") @@ -101,4 +105,25 @@ else if (property == "notes") return object.notes(); GRANTLEE_END_LOOKUP +GRANTLEE_BEGIN_LOOKUP(template_options) +if (property == "font") { + switch (object.font_index) { + case 0: + return "Arial, Helvetica, sans-serif"; + case 1: + return "Impact, Charcoal, sans-serif"; + case 2: + return "Georgia, serif"; + case 3: + return "Courier, monospace"; + case 4: + return "Verdana, Geneva, sans-serif"; + } +} else if (property == "font_size") { + return object.font_size / 9.0; +} else if (property == "line_spacing") { + return object.line_spacing; +} +GRANTLEE_END_LOOKUP + #endif