Esempio n. 1
0
void HTMLExporter::exportBasket(Basket *basket, bool isSubBasket)
{
    if (!basket->isLoaded()) {
        basket->load();
    }

    // Compute the absolute & relative paths for this basket:
    filesFolderPath   = i18nc("HTML export folder (files)", "%1_files", filePath) + "/";
    if (isSubBasket) {
        basketFilePath    = basketsFolderPath + basket->folderName().left(basket->folderName().length() - 1) + ".html";
        filesFolderName   = "../";
        dataFolderName    = basket->folderName().left(basket->folderName().length() - 1) + "-" + i18nc("HTML export folder (data)", "data") + "/";
        dataFolderPath    = basketsFolderPath + dataFolderName;
        basketsFolderName = "";
    } else {
        basketFilePath    = filePath;
        filesFolderName   = i18nc("HTML export folder (files)", "%1_files", KUrl(filePath).fileName()) + "/";
        dataFolderName    = filesFolderName + i18nc("HTML export folder (data)",    "data")  + "/";
        dataFolderPath    = filesFolderPath + i18nc("HTML export folder (data)",    "data")  + "/";
        basketsFolderName = filesFolderName + i18nc("HTML export folder (baskets)", "baskets")  + "/";
    }
    iconsFolderName   = (isSubBasket ? "../" : filesFolderName) + i18nc("HTML export folder (icons)",   "icons")   + "/"; // eg.: "foo.html_files/icons/"   or "../icons/"
    imagesFolderName  = (isSubBasket ? "../" : filesFolderName) + i18nc("HTML export folder (images)",  "images")  + "/"; // eg.: "foo.html_files/images/"  or "../images/"

    kDebug() << "Exporting ================================================";
    kDebug() << "  filePath:" << filePath;
    kDebug() << "  basketFilePath:" << basketFilePath;
    kDebug() << "  filesFolderPath:" << filesFolderPath;
    kDebug() << "  filesFolderName:" << filesFolderName;
    kDebug() << "  iconsFolderPath:" << iconsFolderPath;
    kDebug() << "  iconsFolderName:" << iconsFolderName;
    kDebug() << "  imagesFolderPath:" << imagesFolderPath;
    kDebug() << "  imagesFolderName:" << imagesFolderName;
    kDebug() << "  dataFolderPath:" << dataFolderPath;
    kDebug() << "  dataFolderName:" << dataFolderName;
    kDebug() << "  basketsFolderPath:" << basketsFolderPath;
    kDebug() << "  basketsFolderName:" << basketsFolderName;

    // Create the data folder for this basket:
    QDir dir;
    dir.mkdir(dataFolderPath);

    backgroundColorName = basket->backgroundColor().name().toLower().mid(1);

    // Generate basket icons:
    QString basketIcon16 = iconsFolderName + copyIcon(basket->icon(), 16);
    QString basketIcon32 = iconsFolderName + copyIcon(basket->icon(), 32);

    // Generate the [+] image for groups:
    QPixmap expandGroup(Note::EXPANDER_WIDTH, Note::EXPANDER_HEIGHT);
    expandGroup.fill(basket->backgroundColor());
    QPainter painter(&expandGroup);
    Note::drawExpander(&painter, 0, 0, basket->backgroundColor(), /*expand=*/true, basket);
    painter.end();
    expandGroup.save(imagesFolderPath + "expand_group_" + backgroundColorName + ".png", "PNG");

    // Generate the [-] image for groups:
    QPixmap foldGroup(Note::EXPANDER_WIDTH, Note::EXPANDER_HEIGHT);
    foldGroup.fill(basket->backgroundColor());
    painter.begin(&foldGroup);
    Note::drawExpander(&painter, 0, 0, basket->backgroundColor(), /*expand=*/false, basket);
    painter.end();
    foldGroup.save(imagesFolderPath + "fold_group_" + backgroundColorName + ".png", "PNG");

    // Open the file to write:
    QFile file(basketFilePath);
    if (!file.open(QIODevice::WriteOnly))
        return;
    stream.setDevice(&file);
    stream.setCodec("UTF-8");

    // Compute the colors to draw dragient for notes:
    QColor topBgColor;
    QColor bottomBgColor;
    Note::getGradientColors(basket->backgroundColor(), &topBgColor, &bottomBgColor);
    // Compute the gradient image for notes:
    QString gradientImageFileName = Basket::saveGradientBackground(basket->backgroundColor(), basket->Q3ScrollView::font(), imagesFolderPath);

    // Output the header:
    QString borderColor = Tools::mixColor(basket->backgroundColor(), basket->textColor()).name();
    stream <<
           "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
           "<html>\n"
           " <head>\n"
           "  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
           "  <meta name=\"Generator\" content=\"" << KGlobal::mainComponent().aboutData()->programName() << " " << VERSION << " http://basket.kde.org/\">\n"
           "  <style type=\"text/css\">\n"
//		"   @media print {\n"
//		"    span.printable { display: inline; }\n"
//		"   }\n"
           "   body { margin: 10px; font: 11px sans-serif; }\n" // TODO: Use user font
           "   h1 { text-align: center; }\n"
           "   img { border: none; vertical-align: middle; }\n";
    if (withBasketTree) {
        stream <<
               "   .tree { margin: 0; padding: 1px 0 1px 1px; width: 150px; _width: 149px; overflow: hidden; float: left; }\n"
               "   .tree ul { margin: 0 0 0 10px; padding: 0; }\n"
               "   .tree li { padding: 0; margin: 0; list-style: none; }\n"
               "   .tree a { display: block; padding: 1px; height: 16px; text-decoration: none;\n"
               "             white-space: nowrap; word-wrap: normal; text-wrap: suppress; color: black; }\n"
               "   .tree span { -moz-border-radius: 6px; display: block; float: left;\n"
               "                line-height: 16px; height: 16px; vertical-align: middle; padding: 0 1px; }\n"
               "   .tree img { vertical-align: top; padding-right: 1px; }\n"
               "   .tree .current { background-color: " << kapp->palette().color(QPalette::Highlight).name() << "; "
               "-moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; color: " << kapp->palette().color(QPalette::Highlight).name() << "; }\n"
               "   .basketSurrounder { margin-left: 152px; _margin: 0; _float: right; }\n";
    }
    stream <<
           "   .basket { background-color: " << basket->backgroundColor().name() << "; border: solid " << borderColor << " 1px; "
           "font: " << Tools::cssFontDefinition(basket->Q3ScrollView::font()) << "; color: " << basket->textColor().name() << "; padding: 1px; width: 100%; }\n"
           "   table.basket { border-collapse: collapse; }\n"
           "   .basket * { padding: 0; margin: 0; }\n"
           "   .basket table { width: 100%; border-spacing: 0; _border-collapse: collapse; }\n"
           "   .column { vertical-align: top; }\n"
           "   .columnHandle { width: " << Note::RESIZER_WIDTH << "px; background: transparent url('" << imagesFolderName << "column_handle_" << backgroundColorName << ".png') repeat-y; }\n"
           "   .group { margin: 0; padding: 0; border-collapse: collapse; width: 100% }\n"
           "   .groupHandle { margin: 0; width: " << Note::GROUP_WIDTH << "px; text-align: center; }\n"
           "   .note { padding: 1px 2px; background: " << bottomBgColor.name() << " url('" << imagesFolderName << gradientImageFileName << "')"
           " repeat-x; border-top: solid " << topBgColor.name() <<
           " 1px; border-bottom: solid " << Tools::mixColor(topBgColor, bottomBgColor).name() <<
           " 1px; width: 100%; }\n"
           "   .tags { width: 1px; white-space: nowrap; }\n"
           "   .tags img { padding-right: 2px; }\n"
           << LinkLook::soundLook->toCSS("sound", basket->textColor())
           << LinkLook::fileLook->toCSS("file", basket->textColor())
           << LinkLook::localLinkLook->toCSS("local", basket->textColor())
           << LinkLook::networkLinkLook->toCSS("network", basket->textColor())
           << LinkLook::launcherLook->toCSS("launcher", basket->textColor())
           <<
           "   .unknown { margin: 1px 2px; border: 1px solid " << borderColor << "; -moz-border-radius: 4px; }\n";
    QList<State*> states = basket->usedStates();
    QString statesCss;
    for (State::List::Iterator it = states.begin(); it != states.end(); ++it)
        statesCss += (*it)->toCSS(imagesFolderPath, imagesFolderName, basket->Q3ScrollView::font());
    stream <<
           statesCss <<
           "   .credits { text-align: right; margin: 3px 0 0 0; _margin-top: -17px; font-size: 80%; color: " << borderColor << "; }\n"
           "  </style>\n"
           "  <title>" << Tools::textToHTMLWithoutP(basket->basketName()) << "</title>\n"
           "  <link rel=\"shortcut icon\" type=\"image/png\" href=\"" << basketIcon16 << "\">\n";
    // Create the column handle image:
    QPixmap columnHandle(Note::RESIZER_WIDTH, 50);
    painter.begin(&columnHandle);
    Note::drawInactiveResizer(&painter, 0, 0, columnHandle.height(), basket->backgroundColor(), /*column=*/true);
    painter.end();
    columnHandle.save(imagesFolderPath + "column_handle_" + backgroundColorName + ".png", "PNG");

    stream <<
           " </head>\n"
           " <body>\n"
           "  <h1><img src=\"" << basketIcon32 << "\" width=\"32\" height=\"32\" alt=\"\"> " << Tools::textToHTMLWithoutP(basket->basketName()) << "</h1>\n";

    if (withBasketTree)
        writeBasketTree(basket);

    // If filtering, only export filtered notes, inform to the user:
    // TODO: Filtering tags too!!
    // TODO: Make sure only filtered notes are exported!
//	if (decoration()->filterData().isFiltering)
//		stream <<
//			"  <p>" << i18n("Notes matching the filter &quot;%1&quot;:").arg(Tools::textToHTMLWithoutP(decoration()->filterData().string)) << "</p>\n";

    stream <<
           "  <div class=\"basketSurrounder\">\n";

    if (basket->isColumnsLayout())
        stream <<
               "   <table class=\"basket\">\n"
               "    <tr>\n";
    else
        stream <<
               "   <div class=\"basket\" style=\"position: relative; height: " << basket->contentsHeight() << "px; width: " << basket->contentsWidth() << "px; min-width: 100%;\">\n";

    for (Note *note = basket->firstNote(); note; note = note->next())
        exportNote(note, /*indent=*/(basket->isFreeLayout() ? 4 : 5));

    // Output the footer:
    if (basket->isColumnsLayout())
        stream <<
               "    </tr>\n"
               "   </table>\n";
    else
        stream <<
               "   </div>\n";
    stream << QString(
               "  </div>\n"
               "  <p class=\"credits\">%1</p>\n").arg(
               i18n("Made with <a href=\"http://basket.kde.org/\">%1</a> %2, a KDE tool to take notes and keep information at hand.",
                    KGlobal::mainComponent().aboutData()->programName(), VERSION));

    // Copy a transparent GIF image in the folder, needed for the JavaScript hack:
    QString gifFileName = "spacer.gif";
    QFile transGIF(imagesFolderPath + gifFileName);
    if (!transGIF.exists() && transGIF.open(QIODevice::WriteOnly)) {
        QDataStream streamGIF(&transGIF);
        // This is a 1px*1px transparent GIF image:
        const char blankGIF[] = {
            0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0a, 0x00, 0x0a, 0x00,
            0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21,
            0xfe, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
            0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47,
            0x49, 0x4d, 0x50, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00,
            0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a,
            0x00, 0x00, 0x02, 0x08, 0x8c, 0x8f, 0xa9, 0xcb, 0xed, 0x0f,
            0x63, 0x2b, 0x00, 0x3b
        };
        streamGIF.writeRawData(blankGIF, 74);
        transGIF.close();
    }
    stream <<
           "  <!--[if lt IE 7]>\n"
           "   <script>\n"
           "    function fixPng(img) {\n"
           "     if (!img.style.filter) {\n"
           "      img.style.filter = \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='\" + img.src + \"')\";\n"
           "      img.src = \"" << imagesFolderName << gifFileName << "\";\n"
           "     }\n"
           "    }\n"
           "    for (i = document.images.length - 1; i >= 0; i -= 1) {\n"
           "     var img = document.images[i];\n"
           "     if (img.src.substr(img.src.length - 4) == \".png\")\n"
           "      if (img.complete)\n"
           "       fixPng(img);\n"
           "      else\n"
           "       img.attachEvent(\"onload\", function() { fixPng(window.event.srcElement); });\n"
           "    }\n"
           "   </script>\n"
           "  <![endif]-->\n"
           " </body>\n"
           "</html>\n";

    file.close();
    stream.setDevice(0);
    progress->setValue(progress->value()+1); // Basket exportation finished

    // Recursively export child baskets:
    BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
    if (item->childCount() >=0) {
        for (int i=0; i < item->childCount(); i++) {
            exportBasket(((BasketListViewItem *)item->child(i))->basket(), /*isSubBasket=*/true);
        }
    }
}
Esempio n. 2
0
void HTMLExporter::exportNote(Note *note, int indent)
{
    QString spaces;

    if (note->isColumn()) {
        QString width = "";
        if (false/*TODO: DEBUG AND REENABLE: hasResizer()*/) {
            // As we cannot be precise in CSS (say eg. "width: 50%-40px;"),
            // we output a percentage that is approximatively correct.
            // For instance, we compute the currently used percentage of width in the basket
            // and try make make it the same on a 1024*768 display in a Web browser:
            int availableSpaceForColumnsInThisBasket = note->basket()->contentsWidth() - (note->basket()->columnsCount() - 1) * Note::RESIZER_WIDTH;
            int availableSpaceForColumnsInBrowser    = 1024    /* typical screen width */
                    - 25    /* window border and scrollbar width */
                    - 2 * 5 /* page margin */
                    - (note->basket()->columnsCount() - 1) * Note::RESIZER_WIDTH;
            if (availableSpaceForColumnsInThisBasket <= 0)
                availableSpaceForColumnsInThisBasket = 1;
            int widthValue = (int)(availableSpaceForColumnsInBrowser * (double) note->groupWidth() / availableSpaceForColumnsInThisBasket);
            if (widthValue <= 0)
                widthValue = 1;
            if (widthValue > 100)
                widthValue = 100;
            width = QString(" width=\"%1%\"").arg(QString::number(widthValue));
        }
        stream << spaces.fill(' ', indent) << "<td class=\"column\"" << width << ">\n";

        // Export child notes:
        for (Note *child = note->firstChild(); child; child = child->next()) {
            stream << spaces.fill(' ', indent + 1);
            exportNote(child, indent + 1);
            stream << '\n';
        }

        stream << spaces.fill(' ', indent) << "</td>\n";
        if (note->hasResizer())
            stream << spaces.fill(' ', indent) << "<td class=\"columnHandle\"></td>\n";
        return;
    }

    QString freeStyle;
    if (note->isFree())
        freeStyle = " style=\"position: absolute; left: " + QString::number(note->x()) + "px; top: " + QString::number(note->y()) + "px; width: " + QString::number(note->groupWidth()) + "px\"";

    if (note->isGroup()) {
        stream << '\n' << spaces.fill(' ', indent) << "<table" << freeStyle << ">\n"; // Note content is expected to be on the same HTML line, but NOT groups
        int i = 0;
        for (Note *child = note->firstChild(); child; child = child->next()) {
            stream << spaces.fill(' ', indent);
            if (i == 0)
                stream << " <tr><td class=\"groupHandle\"><img src=\"" << imagesFolderName << (note->isFolded() ? "expand_group_" : "fold_group_") << backgroundColorName << ".png"
                       << "\" width=\"" << Note::EXPANDER_WIDTH << "\" height=\"" << Note::EXPANDER_HEIGHT << "\"></td>\n";
            else if (i == 1)
                stream << " <tr><td class=\"freeSpace\" rowspan=\"" << note->countDirectChilds() << "\"></td>\n";
            else
                stream << " <tr>\n";
            stream << spaces.fill(' ', indent) << "  <td>";
            exportNote(child, indent + 3);
            stream << "</td>\n"
                   << spaces.fill(' ', indent) << " </tr>\n";
            ++i;
        }
        stream << '\n' << spaces.fill(' ', indent) << "</table>\n" /*<< spaces.fill(' ', indent - 1)*/;
    } else {
        // Additionnal class for the content (link, netword, color...):
        QString additionnalClasses = note->content()->cssClass();
        if (!additionnalClasses.isEmpty())
            additionnalClasses = " " + additionnalClasses;
        // Assign the style of each associted tags:
        for (State::List::Iterator it = note->states().begin(); it != note->states().end(); ++it)
            additionnalClasses += " tag_" + (*it)->id();
        //stream << spaces.fill(' ', indent);
        stream << "<table class=\"note" << additionnalClasses << "\"" << freeStyle << "><tr>";
        if (note->emblemsCount() > 0) {
            stream << "<td class=\"tags\"><nobr>";
            for (State::List::Iterator it = note->states().begin(); it != note->states().end(); ++it)
                if (!(*it)->emblem().isEmpty()) {
                    int emblemSize = 16;
                    QString iconFileName = copyIcon((*it)->emblem(), emblemSize);
                    stream << "<img src=\"" << iconsFolderName << iconFileName
                           << "\" width=\"" << emblemSize << "\" height=\"" << emblemSize
                           << "\" alt=\"" << (*it)->textEquivalent() << "\" title=\"" << (*it)->fullName() << "\">";
                }
            stream << "</nobr></td>";
        }
        stream << "<td>";
        note->content()->exportToHTML(this, indent);
        stream << "</td></tr></table>";
    }
}
Esempio n. 3
0
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    EdamProtocol *edam = EdamProtocol::GetInstance();

    ui->setupUi(this);

    pdfCache * pdf = new pdfCache(this);

    CustomNetworkAccessManager *nm = new CustomNetworkAccessManager(ui->editor->page()->networkAccessManager(), this, pdf);
    edam->setCNAM(nm);
    ui->editor->page()->setNetworkAccessManager(nm);

    Speller::setSettings(new DBSpellSettings(this, ui->editor));

    ui->editor->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->editor->load(QUrl("qrc:///html/noteajax.html"));

    jsB = new jsBridge(this, pdf);
    jsB->setWebView(ui->editor);
    enmlWritter = new enml2(this);

    connect(ui->editor->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJSObject()));

    loaded = false;
    editingEnabled = false;


    tagsActions = new QActionGroup(this);
    newTag = new TagLabel(this);
    newTag->hide();
    ui->tagsBar->addWidget(newTag);

    appIcon = QIcon(":img/hippo64.png");

    trayIcon = NULL;

    bool sysTrayEnabled = sql::readSyncStatus("systemTray", true).toBool();

    if (QSystemTrayIcon::isSystemTrayAvailable() && sysTrayEnabled)
        enableSystemTrayIcon(true);

    connect(edam, SIGNAL(AuthenticateFailed()), this, SLOT(authentificationFailed()));
    connect(edam, SIGNAL(syncFinished()), this, SLOT(syncFinished()));
    connect(edam, SIGNAL(syncStarted(int)), this, SLOT(syncStarted(int)));
    connect(edam, SIGNAL(noteGuidChanged(QString,QString)), this, SLOT(changeNoteGuid(QString,QString)));
    connect(ui->notebooks, SIGNAL(itemSelectionChanged()), this, SLOT(switchNotebook()));
    connect(ui->tags, SIGNAL(itemSelectionChanged()), this, SLOT(switchTag()));
    connect(ui->tags, SIGNAL(tagAdded(QString,QString)), this, SLOT(addTag(QString,QString)));
    connect(ui->tags, SIGNAL(tagsUpdated()), this, SLOT(updateTagsToolBar()));
    connect(ui->tags, SIGNAL(tagsUpdated()), this, SLOT(switchTag()));
    connect(ui->NotesList, SIGNAL(noteSwitched()), this, SLOT(switchNote()));
    connect(ui->action_Abaut, SIGNAL(triggered()), this, SLOT(loadAboutInfo()));
    connect(ui->actionClose, SIGNAL(triggered()), this, SLOT(closeWindow()));
    connect(ui->actionNew_Note, SIGNAL(triggered()), this, SLOT(newNote()));
    connect(ui->actionSync, SIGNAL(triggered()), this, SLOT(sync()));
    connect(ui->noteTitle, SIGNAL(textEdited(QString)), this, SLOT(noteTitleChange(QString)));
    connect(ui->actionAccount_info, SIGNAL(triggered()), this, SLOT(showUserInfo()));
    connect(ui->editor->page(), SIGNAL(linkClicked(QUrl)), this, SLOT(openURL(QUrl)));
    connect(ui->editor->page(), SIGNAL(microFocusChanged()), this, SLOT(updateEditButtonsState()));
    connect(ui->editor, SIGNAL(selectionChanged()), this, SLOT(updateSelectionButtonsState()));
    connect(ui->editor->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
    connect(ui->editor, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(editorContextMenuRequested(QPoint)));
    connect(ui->editor, SIGNAL(fileInserted(QString)), this, SLOT(insertFile(QString)));
    connect(ui->notebooks, SIGNAL(noteMoved(QString,QString)), this, SLOT(moveNote(QString,QString)));
    connect(ui->notebooks, SIGNAL(noteDeleted(QString)), this, SLOT(deleteNote(QString)));
    connect(ui->notebooks, SIGNAL(noteRestored(QString,QString)), this, SLOT(restoreNote(QString,QString)));
    connect(ui->NotesList, SIGNAL(noteDeleted(QString)), this, SLOT(deleteNote(QString)));
    connect(ui->NotesList, SIGNAL(noteRestored(QString)), this, SLOT(restoreNote(QString)));
    connect(ui->NotesList, SIGNAL(noteCreated()), this, SLOT(newNote()));
    connect(ui->NotesList, SIGNAL(reloaded()), this, SLOT(updateCurrentNoteName()));
    connect(ui->editButton, SIGNAL(toggled(bool)), this, SLOT(setEditable(bool)));
    connect(ui->actionDelete_Note, SIGNAL(triggered()), this, SLOT(deleteNote()));
    connect(ui->toolBox, SIGNAL(currentChanged(int)), this, SLOT(changeTab(int)));
    connect(ui->editor->page(), SIGNAL(linkHovered(QString,QString,QString)), this, SLOT(linkHovered(QString,QString,QString)));
    connect(jsB, SIGNAL(hintMessage(QString,int)), ui->statusbar, SLOT(showMessage(QString,int)));
    connect(jsB, SIGNAL(noteChanged(QString)), this, SLOT(updateTagsToolBar(QString)));
    connect(jsB, SIGNAL(activeNoteSelectionChanged(bool)), ui->actionDelete_Note, SLOT(setEnabled(bool)));
    connect(jsB, SIGNAL(activeNoteSelectionChanged(bool)), ui->editButton, SLOT(setEnabled(bool)));
    connect(jsB, SIGNAL(editingStarted(bool)), ui->editButton, SLOT(setChecked(bool)));
    connect(jsB, SIGNAL(titleUpdated(QString,QString)), this, SLOT(updateNoteTitle(QString,QString)));
    connect(jsB, SIGNAL(conflictAdded(qint64,QString,bool)), this, SLOT(addConflict(qint64,QString,bool)));
    connect(jsB, SIGNAL(noteSelectionChanged(bool)), ui->actionNote_Info, SLOT(setEnabled(bool)));
    connect(jsB, SIGNAL(noteSelectionChanged(bool)), ui->actionExport, SLOT(setEnabled(bool)));
    connect(jsB, SIGNAL(noteSelectionChanged(bool)), ui->actionPrint, SLOT(setEnabled(bool)));
    connect(ui->editor, SIGNAL(tagUpdated(QString,bool)), this, SLOT(updateTag(QString,bool)));
    connect(tagsActions, SIGNAL(triggered(QAction*)), this, SLOT(tagClicked(QAction*)));
    connect(newTag, SIGNAL(tagCreated(QString)), this, SLOT(createTag(QString)));
    connect(ui->actionKeep_only_this_Version, SIGNAL(triggered()), this, SLOT(keepThisVersion()));
    connect(ui->actionNote_Info, SIGNAL(triggered()), this, SLOT(showNoteInfo()));
    connect(ui->actionExport, SIGNAL(triggered()), this, SLOT(exportNote()));
    connect(ui->actionPrint, SIGNAL(triggered()), this, SLOT(print()));
    connect(this, SIGNAL(titleChanged(QString,QString)), jsB, SIGNAL(titleChanged(QString,QString)));


    setWindowIcon(appIcon);
    setWindowTitle("Hippo Notes");

    setTabOrder(ui->noteTitle, ui->editor);

    ui->notebooks->setSortingEnabled(true);
    ui->notebooks->sortByColumn(0, Qt::AscendingOrder);
    ui->editBar->setVisible(false);

    ui->mainToolBar->addAction(ui->actionNew_Note);
    ui->mainToolBar->addAction(ui->actionSync);

    QFontComboBox *font = new QFontComboBox(this);
    font->setDisabled(true);
    font->setFontFilters(QFontComboBox::ScalableFonts);
    font->setEditable(false);
    connect(this, SIGNAL(editButtonsStateChanged(bool)), font, SLOT(setEnabled(bool)));
    connect(this, SIGNAL(updateFont(QFont)), font, SLOT(setCurrentFont(QFont)));
    connect(font, SIGNAL(activated(QString)), this, SLOT(changeFont(QString)));
    ui->editBar->addWidget(font);

    QComboBox *fontSize = new QComboBox(this);
    fontSize->setDisabled(true);
    fontSize->setEditable(false);
    for (int i = 1; i <= 7; i++)
        fontSize->addItem(QString::number(i));
    connect(this, SIGNAL(editButtonsStateChanged(bool)), fontSize, SLOT(setEnabled(bool)));
    connect(this, SIGNAL(updateFontSize(int)), fontSize, SLOT(setCurrentIndex(int)));
    connect(fontSize, SIGNAL(activated(QString)), this, SLOT(changeFontSize(QString)));
    ui->editBar->addWidget(fontSize);

    QAction *boldIco = ui->editor->pageAction(QWebPage::ToggleBold);
    boldIco->setIcon(QIcon::fromTheme("format-text-bold"));
    ui->editBar->addAction(boldIco);

    QAction *italicIco = ui->editor->pageAction(QWebPage::ToggleItalic);
    italicIco->setIcon(QIcon::fromTheme("format-text-italic"));
    ui->editBar->addAction(italicIco);

    QAction *underlineIco = ui->editor->pageAction(QWebPage::ToggleUnderline);
    underlineIco->setIcon(QIcon::fromTheme("format-text-underline"));
    ui->editBar->addAction(underlineIco);

    QAction *strikethroughIco = ui->editor->pageAction(QWebPage::ToggleStrikethrough);
    strikethroughIco->setIcon(QIcon::fromTheme("format-text-strikethrough"));
    ui->editBar->addAction(strikethroughIco);

    ui->editBar->addSeparator();

    QAction *undoIco = ui->editor->pageAction(QWebPage::Undo);
    undoIco->setIcon(QIcon::fromTheme("edit-undo"));
    undoIco->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z));
    ui->editBar->addAction(undoIco);
    ui->menu_Edit->addAction(undoIco);

    QAction *redoIco = ui->editor->pageAction(QWebPage::Redo);
    redoIco->setIcon(QIcon::fromTheme("edit-redo"));
    redoIco->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z));
    ui->editBar->addAction(redoIco);
    ui->menu_Edit->addAction(redoIco);

    ui->editBar->addSeparator();

    QAction *rformatIco = ui->editor->pageAction(QWebPage::RemoveFormat);
    rformatIco->setIcon(QIcon::fromTheme("edit-clear"));
    ui->editBar->addAction(rformatIco);

    ui->editBar->addSeparator();

    QAction *leftIco = ui->editor->pageAction(QWebPage::AlignLeft);
    leftIco->setIcon(QIcon::fromTheme("format-justify-left"));
    ui->editBar->addAction(leftIco);

    QAction *centerIco = ui->editor->pageAction(QWebPage::AlignCenter);
    centerIco->setIcon(QIcon::fromTheme("format-justify-center"));
    ui->editBar->addAction(centerIco);

    QAction *rightIco = ui->editor->pageAction(QWebPage::AlignRight);
    rightIco->setIcon(QIcon::fromTheme("format-justify-right"));
    ui->editBar->addAction(rightIco);

    QAction *fillIco = ui->editor->pageAction(QWebPage::AlignJustified);
    fillIco->setIcon(QIcon::fromTheme("format-justify-fill"));
    ui->editBar->addAction(fillIco);

    ui->editBar->addSeparator();

    QAction *indentIco = ui->editor->pageAction(QWebPage::Indent);
    indentIco->setIcon(QIcon::fromTheme("format-indent-more"));
    ui->editBar->addAction(indentIco);

    QAction *outdentIco = ui->editor->pageAction(QWebPage::Outdent);
    outdentIco->setIcon(QIcon::fromTheme("format-indent-less"));
    ui->editBar->addAction(outdentIco);

    QAction *superscriptIco = ui->editor->pageAction(QWebPage::ToggleSuperscript);
    superscriptIco->setIcon(QIcon::fromTheme("format-text-superscript"));
    ui->editBar->addAction(superscriptIco);

    QAction *subscriptIco = ui->editor->pageAction(QWebPage::ToggleSubscript);
    subscriptIco->setIcon(QIcon::fromTheme("format-text-subscript"));
    ui->editBar->addAction(subscriptIco);

    QAction *unorderedIco = ui->editor->pageAction(QWebPage::InsertUnorderedList);
    unorderedIco->setIcon(QIcon::fromTheme("format-list-unordered"));
    ui->editBar->addAction(unorderedIco);

    QAction *orderedIco = ui->editor->pageAction(QWebPage::InsertOrderedList);
    orderedIco->setIcon(QIcon::fromTheme("format-list-ordered"));
    ui->editBar->addAction(orderedIco);

    QAction *lineIco = new QAction("Insert horizontal line", this);
    lineIco->setIcon(QIcon::fromTheme("insert-horizontal-rule"));
    lineIco->setDisabled(true);
    connect(this, SIGNAL(editButtonsStateChanged(bool)), lineIco, SLOT(setEnabled(bool)));
    connect(lineIco, SIGNAL(triggered()), this, SLOT(insertHorizontalLine()));
    ui->editBar->addAction(lineIco);

    ui->menu_Edit->addSeparator();

    QAction *cutIco = ui->editor->pageAction(QWebPage::Cut);
    cutIco->setIcon(QIcon::fromTheme("edit-cut"));
    cutIco->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X));
    ui->menu_Edit->addAction(cutIco);

    QAction *copyIco = ui->editor->pageAction(QWebPage::Copy);
    copyIco->setIcon(QIcon::fromTheme("edit-copy"));
    copyIco->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
    ui->menu_Edit->addAction(copyIco);

    QAction *pasteIco = ui->editor->pageAction(QWebPage::Paste);
    pasteIco->setIcon(QIcon::fromTheme("edit-paste"));
    pasteIco->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V));
    ui->menu_Edit->addAction(pasteIco);

    QAction *pasteSpecialIco = ui->editor->pageAction(QWebPage::PasteAndMatchStyle);
    pasteSpecialIco->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V));
    ui->menu_Edit->addAction(pasteSpecialIco);

    ui->menu_Edit->addSeparator();

    QAction *insertUrlIco = new QAction("Create link", this);
    insertUrlIco->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
    insertUrlIco->setDisabled(true);
    insertUrlIco->setIcon(QIcon::fromTheme("insert-link"));
    connect(this, SIGNAL(selectionButtonsStateChanged(bool)), insertUrlIco, SLOT(setDisabled(bool)));
    connect(insertUrlIco, SIGNAL(triggered()), this, SLOT(insertUrl()));
    ui->menu_Edit->addAction(insertUrlIco);

    QAction *todoIco = new QAction("Insert To-do Checkbox", this);
    todoIco->setIcon(QIcon::fromTheme("checkbox"));
    todoIco->setDisabled(true);
    connect(this, SIGNAL(editButtonsStateChanged(bool)), todoIco, SLOT(setEnabled(bool)));
    connect(todoIco, SIGNAL(triggered()), jsB, SIGNAL(insertToDo()));
    ui->menu_Edit->addAction(todoIco);

    QAction *insertImage = new QAction("Insert Image", this);
    insertImage->setIcon(QIcon::fromTheme("insert-image"));
    insertImage->setDisabled(true);
    connect(this, SIGNAL(editButtonsStateChanged(bool)), insertImage, SLOT(setEnabled(bool)));
    connect(insertImage, SIGNAL(triggered()), this, SLOT(insertImg()));
    ui->menu_Edit->addAction(insertImage);

    QAction *insertFile = new QAction("Insert File", this);
    insertFile->setDisabled(true);
    connect(this, SIGNAL(editButtonsStateChanged(bool)), insertFile, SLOT(setEnabled(bool)));
    connect(insertFile, SIGNAL(triggered()), this, SLOT(insertFile()));
    ui->menu_Edit->addAction(insertFile);

    QAction *encryptIco = new QAction("Encrypt Selected Text...", this);
    encryptIco->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_X));
    encryptIco->setDisabled(true);
    encryptIco->setIcon(QIcon::fromTheme("document-edit-encrypt"));
    connect(this, SIGNAL(selectionButtonsStateChanged(bool)), encryptIco, SLOT(setDisabled(bool)));
    connect(encryptIco, SIGNAL(triggered()), jsB, SIGNAL(encryptText()));
    ui->menu_Edit->addAction(encryptIco);

    ui->menu_Edit->addSeparator();

    QAction *options = new QAction("&Options...", this);
    options->setIcon(QIcon::fromTheme("preferences-other"));
    connect(options, SIGNAL(triggered()), this, SLOT(showOptions()));
    ui->menu_Edit->addAction(options);


    clearConflictBar();
    connect(jsB, SIGNAL(showConflict()), ui->conflictBar, SLOT(show()));
    connect(jsB, SIGNAL(showConflict()), ui->conflictBarBottom, SLOT(show()));

    conflictsGroup = new QActionGroup(this);
    connect(conflictsGroup, SIGNAL(triggered(QAction*)), this, SLOT(changeNoteVersion(QAction*)));

    searchIndex = new SearchIndex(this);
    connect(ui->searchButton, SIGNAL(clicked()), this, SLOT(search()));
    connect(edam, SIGNAL(syncFinished()), searchIndex, SLOT(buildSearchIndex()));
    connect(jsB, SIGNAL(noteUpdated(QString)), searchIndex, SLOT(updateNoteIndex(QString)));
    connect(edam, SIGNAL(noteUpdated(QString)), searchIndex, SLOT(dropNoteIndex(QString)));
    connect(ui->searchInput, SIGNAL(returnPressed()), this, SLOT(search()));

    QByteArray mainWindowGeometry = sql::readSyncStatus("mainWindowGeometry").toString().toLatin1();
    if (!mainWindowGeometry.isEmpty())
        restoreGeometry(QByteArray::fromBase64(mainWindowGeometry));

    QByteArray mainWidgetsSplitterState = sql::readSyncStatus("mainWidgetsSplitterState").toString().toLatin1();
    if (!mainWidgetsSplitterState.isEmpty())
        ui->mainWidgetsSplitter->restoreState(QByteArray::fromBase64(mainWidgetsSplitterState));

    //showWindow();
    edam->init();
}