// Handle what happens when something is dropped onto a tag item bool NNotebookView::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) { Q_UNUSED(index); // suppress unused variable Q_UNUSED(action); // suppress unused variable // If this is a note-to-tag drop we are assigning tags to a note if (data->hasFormat("application/x-nixnote-note")) { QByteArray d = data->data("application/x-nixnote-note"); QString data(d); // Find the tag lid we dropped onto qint32 bookLid = parent->data(NAME_POSITION, Qt::UserRole).toInt(); if (bookLid <=0) return false; NotebookTable bookTable(global.db); Notebook notebook; bookTable.get(notebook, bookLid); // The string has a long list of note lids. We parse them out & update the note QStringList stringLids = data.split(" "); for (int i=0; i<stringLids.size(); i++) { if (stringLids[i].trimmed() != "") { qint32 noteLid = stringLids.at(i).toInt(); if (noteLid > 0) { NoteTable noteTable(global.db); qint32 currentNotebook = noteTable.getNotebookLid(noteLid); if (currentNotebook != bookLid) { noteTable.updateNotebook(noteLid, bookLid, true); emit(updateNoteList(noteLid, NOTE_TABLE_NOTEBOOK_POSITION, notebook.name.value())); qint64 dt = QDateTime::currentMSecsSinceEpoch(); noteTable.updateDate(noteLid, dt, NOTE_UPDATED_DATE, true); emit(updateNoteList(noteLid, NOTE_TABLE_DATE_UPDATED_POSITION, dt)); } } } } if (stringLids.size() > 0) { emit(updateCounts()); } return true; } return false; }
// Delete an item from the tree. We really just hide it. void NTagView::mergeRequested() { QList<QTreeWidgetItem*> items = selectedItems(); QMessageBox msgBox; msgBox.setIcon(QMessageBox::Question); msgBox.setText(tr("Are you sure you want to merge these tags?")); msgBox.setWindowTitle(tr("Verify Merge")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); int ret = msgBox.exec(); if (ret == QMessageBox::No) return; qint32 lid = items[0]->data(NAME_POSITION, Qt::UserRole).toInt(); NoteTable ntable(global.db); QList<qint32> notes; for (int j=1; j<items.size(); j++) { ntable.findNotesByTag(notes, items[j]->data(NAME_POSITION, Qt::UserRole).toInt()); for (int i=0; i<notes.size(); i++) { if (!ntable.hasTag(notes[i], lid)) { ntable.addTag(notes[i], lid, true); QString tagString = ntable.getNoteListTags(notes[i]); emit(updateNoteList(notes[i], NOTE_TABLE_TAGS_POSITION, tagString)); qint64 dt = QDateTime::currentMSecsSinceEpoch(); ntable.updateDate(notes[i], dt, NOTE_UPDATED_DATE, true); emit(updateNoteList(notes[i], NOTE_TABLE_DATE_UPDATED_POSITION, dt)); } } } // Now delete the old tags. for (int i=1; i<items.size(); i++) { qint32 lid = items[i]->data(NAME_POSITION, Qt::UserRole).toInt(); TagTable table(global.db); table.deleteTag(lid); // Now remove it in the datastore NTagViewItem *ptr = dataStore.take(items[i]->data(NAME_POSITION, Qt::UserRole).toInt()); emit(tagDeleted(lid, ptr->data(NAME_POSITION, Qt::DisplayRole).toString())); delete ptr; } }
// Add a new note to the database qint32 NoteTable::add(qint32 l, Note &t, bool isDirty) { QLOG_DEBUG() << "Adding note: " << QString::fromStdString(t.title); ResourceTable resTable; ConfigStore cs; QSqlQuery query; qint32 position; TagScanner scanner; qint32 lid = l; qint32 notebookLid; query.prepare("Insert into DataStore (lid, key, data) values (:lid, :key, :data)"); if (lid <= 0) lid = cs.incrementLidCounter(); query.bindValue(":lid", lid); query.bindValue(":key", NOTE_GUID); query.bindValue(":data", QString::fromStdString(t.guid)); query.exec(); query.bindValue(":lid", lid); query.bindValue(":key", NOTE_INDEX_NEEDED); query.bindValue(":data", true); query.exec(); if (t.__isset.title) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_TITLE); query.bindValue(":data", QString::fromStdString(t.title.c_str())); query.exec(); } if (t.__isset.content) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_CONTENT); QByteArray b; b.append(QString::fromStdString(t.content).toAscii()); query.bindValue(":data", b); query.exec(); } if (t.__isset.contentHash) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_CONTENT_HASH); query.bindValue(":data", QString::fromStdString(t.contentHash)); query.exec(); } if (t.__isset.contentLength) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_CONTENT_LENGTH); query.bindValue(":data", t.contentLength); query.exec(); } query.bindValue(":lid", lid); query.bindValue(":key", NOTE_UPDATE_SEQUENCE_NUMBER); query.bindValue(":data", t.updateSequenceNum); query.exec(); query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ISDIRTY); query.bindValue(":data", isDirty); query.exec(); if (t.__isset.created) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_CREATED_DATE); query.bindValue(":data", QVariant::fromValue(t.created)); query.exec(); } if (t.__isset.updated) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_UPDATED_DATE); query.bindValue(":data", QVariant::fromValue(t.updated)); query.exec(); } if (t.__isset.deleted) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_DELETED_DATE); query.bindValue(":data", QVariant::fromValue(t.deleted)); query.exec(); } if (t.__isset.active) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ACTIVE); query.bindValue(":data", QVariant::fromValue(t.active)); query.exec(); } if (t.__isset.notebookGuid) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_NOTEBOOK_LID); NotebookTable notebookTable; notebookLid = notebookTable.getLid(QString::fromStdString(t.notebookGuid)); // If not found, we insert one to avoid problems. We'll probably get the real data later if (notebookLid == 0) { notebookLid = cs.incrementLidCounter(); Notebook notebook; notebook.guid = t.notebookGuid; notebook.name = ""; notebook.__isset.guid = true; notebook.__isset.name = true; notebookTable.add(notebookLid, notebook, false, false); } query.bindValue(":data", notebookLid); query.exec(); } for (unsigned int i=0; t.__isset.tagGuids && i<t.tagGuids.size(); i++) { TagTable tagTable; qint32 tagLid = tagTable.getLid(t.tagGuids.at(i)); if (tagLid == 0) { // create a dummy tag to avoid later problems Tag newTag; newTag.guid = t.tagGuids.at(i); newTag.name = ""; newTag.__isset.guid = true; newTag.__isset.name = true; tagLid = cs.incrementLidCounter(); tagTable.add(tagLid, newTag, false, 0); } query.bindValue(":lid", lid); query.bindValue(":key", NOTE_TAG_LID); query.bindValue(":data", tagLid); query.exec(); } for (unsigned int i=0; t.__isset.resources && i<t.resources.size(); i++) { qint32 resLid; Resource *r; r = &t.resources[i]; resLid = resTable.getLid(t.guid,t.resources[i].guid); if (resLid == 0) resLid = cs.incrementLidCounter(); resTable.add(resLid, t.resources[i], isDirty); if (r->__isset.mime) { QString mime = QString::fromStdString(r->mime); if (!mime.startsWith("image/") && mime != "vnd.evernote.ink") { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_HAS_ATTACHMENT); query.bindValue(":data", true); query.exec(); } } } if (t.__isset.attributes) { if (t.attributes.__isset.subjectDate) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_SUBJECT_DATE); query.bindValue(":data", QVariant::fromValue(t.attributes.subjectDate)); query.exec(); } if (t.attributes.__isset.latitude) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_LATITUDE); query.bindValue(":data", QVariant::fromValue(t.attributes.latitude)); query.exec(); } if (t.attributes.__isset.latitude) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_LONGITUDE); query.bindValue(":data", QVariant::fromValue(t.attributes.longitude)); query.exec(); } if (t.attributes.__isset.altitude) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_ALTITUDE); query.bindValue(":data", QVariant::fromValue(t.attributes.altitude)); query.exec(); } if (t.attributes.__isset.author) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_AUTHOR); query.bindValue(":data", QString::fromStdString(t.attributes.author)); query.exec(); } if (t.attributes.__isset.source) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_SOURCE); query.bindValue(":data", QString::fromStdString(t.attributes.source)); query.exec(); } if (t.attributes.__isset.sourceURL) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_SOURCE_URL); query.bindValue(":data", QString::fromStdString(t.attributes.sourceURL)); query.exec(); } if (t.attributes.__isset.sourceApplication) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_SOURCE_APPLICATION); query.bindValue(":data", QString::fromStdString(t.attributes.sourceApplication)); query.exec(); } if (t.attributes.__isset.shareDate) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_SHARE_DATE); query.bindValue(":data",QVariant::fromValue(t.attributes.shareDate)); query.exec(); } if (t.attributes.__isset.placeName) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_PLACE_NAME); query.bindValue(":data", QString::fromStdString(t.attributes.placeName)); query.exec(); } if (t.attributes.__isset.contentClass) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_ATTRIBUTE_CONTENT_CLASS); query.bindValue(":data", QString::fromStdString(t.attributes.contentClass)); query.exec(); } } // No determine some attributes of the note based upon the content // This should probably happen every time a note changes? Or at least something simular: QString content; if (t.__isset.content) content = QString::fromStdString(t.content); else content = ""; position = content.indexOf("<en-crypt"); if (position > 0) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_HAS_ENCRYPT); query.bindValue(":data", true); query.exec(); } position = content.indexOf("<en-todo"); if (position > 0) { position = content.indexOf("<en-todo checked=\"true\""); if (position > 0) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_HAS_TODO_COMPLETED); query.bindValue(":data", true); query.exec(); } position = qMax(content.indexOf("<en-todo checked=\"false\""), content.indexOf("<en-todo>")); if (position > 0) { query.bindValue(":lid", lid); query.bindValue(":key", NOTE_HAS_TODO_UNCOMPLETED); query.bindValue(":data", true); query.exec(); } } updateNoteList(lid, t, isDirty); return lid; }
qint32 NoteTable::duplicateNote(qint32 oldLid) { ConfigStore cs; qint32 newLid = cs.incrementLidCounter(); QSqlQuery query; QString tempTableName = "notecopy" + QString::number(oldLid); query.exec("drop temporary table " +tempTableName); query.prepare("create temporary table " +tempTableName +" as select * from datastore where lid=:oldLid"); query.bindValue(":oldLid", oldLid); query.exec(); query.prepare("Update " +tempTableName +" set lid=:newLid"); query.bindValue(":newLid", newLid); query.exec(); query.exec("insert into datastore select lid, key, data from " +tempTableName); query.exec("drop " +tempTableName); query.prepare("update datastore set data=:data where lid=:lid and key=:key"); query.bindValue(":data", 0); query.bindValue(":lid", newLid); query.bindValue(":key", NOTE_UPDATE_SEQUENCE_NUMBER); query.exec(); Note n; get(n, newLid, false,false); updateNoteList(newLid, n, true); setDirty(newLid, true); // Update all the resources ResourceTable resTable; QList<qint32> lids; resTable.getResourceList(lids, oldLid); for (int i=0; i<lids.size(); i++) { qint32 newResLid = cs.incrementLidCounter(); query.prepare("create temporary table " +tempTableName +" as select * from datastore where lid=:oldLid"); query.bindValue(":oldLid", lids[i]); query.exec(); query.prepare("Update " +tempTableName +" set lid=:newLid"); query.bindValue(":newLid", newResLid); query.exec(); query.exec("insert into datastore select lid, key, data from " +tempTableName); query.exec("drop " +tempTableName); query.prepare("update datastore set data=:data where lid=:lid and key=:key"); query.bindValue(":data", 0); query.bindValue(":lid", newResLid); query.bindValue(":key", RESOURCE_UPDATE_SEQUENCE_NUMBER); query.exec(); query.prepare("update datastore set data=:data where lid=:lid and key=:key"); query.bindValue(":data", 0); query.bindValue(":lid", newResLid); query.bindValue(":key", RESOURCE_NOTE_LID); query.exec(); QStringList filter; QDir resDir(global.fileManager.getDbaDirPath()); filter << QString::number(lids[i])+".*"; QStringList files = resDir.entryList(filter); for (int j=0; j<files.size(); j++) { QFile file(global.fileManager.getDbaDirPath()+files[j]); int pos = files[j].indexOf("."); QString type = files[j].mid(pos); file.open(QIODevice::ReadOnly); file.copy(global.fileManager.getDbaDirPath()+ QString::number(newResLid) +type); file.close(); } } return newLid; }
// Handle what happens when something is dropped onto a tag item bool NTagView::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) { // If this is a note-to-tag drop we are assigning tags to a note if (data->hasFormat("application/x-nixnote-note")) { QByteArray d = data->data("application/x-nixnote-note"); QString data(d); // Find the tag lid we dropped onto qint32 tagLid = parent->data(NAME_POSITION, Qt::UserRole).toInt(); // The string has a long list of note lids. We parse them out & update the note QStringList stringLids = data.split(" "); for (int i=0; i<stringLids.size(); i++) { if (stringLids[i].trimmed() != "") { qint32 noteLid = stringLids.at(i).toInt(); if (noteLid > 0) { NoteTable noteTable(global.db); if (!noteTable.hasTag(noteLid, tagLid)) { noteTable.addTag(noteLid, tagLid, true); QString tagString = noteTable.getNoteListTags(noteLid); emit(updateNoteList(noteLid, NOTE_TABLE_TAGS_POSITION, tagString)); // qint64 dt = QDateTime::currentMSecsSinceEpoch(); // noteTable.updateDate(noteLid, dt, NOTE_UPDATED_DATE, true); // emit(updateNoteList(noteLid, NOTE_TABLE_DATE_UPDATED_POSITION, dt)); } } } } if (stringLids.size() > 0) emit updateCounts(); return true; } // If this is a tag-to-tag drop then we are modifying the hierarchy if (data->hasFormat("application/x-nixnote-tag")) { // If there is no parent, then they are trying to drop to the top level, which isn't permitted if (parent == NULL) return false; // Get the lid we are dropping. QByteArray d = data->data("application/x-nixnote-tag"); qint32 lid = d.toInt(); if (lid == 0) return false; qint32 newParentLid = parent->data(NAME_POSITION, Qt::UserRole).toInt(); qint32 oldParentLid = dataStore[lid]->parentLid; if (newParentLid == oldParentLid) return false; if (newParentLid == lid) return false; NTagViewItem *item = dataStore[lid]; // If we had an old parent, remove the child from it. if (oldParentLid > 0) { NTagViewItem *parent_ptr = dataStore[oldParentLid]; for (int i=0; i<parent_ptr->childrenLids.size(); i++) { if (parent_ptr->childrenLids[i] == lid) { parent_ptr->childrenLids.removeAt(i); i=parent_ptr->childrenLids.size(); } } parent_ptr->removeChild(item); } else { root->removeChild(item); } // Update the actual database Tag tag; TagTable tagTable(global.db); tagTable.get(tag, lid); QString guid; tagTable.getGuid(guid, newParentLid); tag.parentGuid = guid; tagTable.update(tag, true); if (newParentLid>0) { NTagViewItem *parent_ptr = dataStore[newParentLid]; parent_ptr->addChild(item); parent_ptr->childrenLids.append(lid); item->parentLid = newParentLid; item->parentGuid = tag.guid; } else { item->parentLid = 0; item->parentGuid = ""; root->addChild(item); } // Resort the data this->sortByColumn(NAME_POSITION, Qt::AscendingOrder); sortItems(NAME_POSITION, Qt::AscendingOrder); return QTreeWidget::dropMimeData(parent, index, data, action); } return false; }
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { // open database connection db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("/Users/jdoud/dev/brainstorm.sqlite"); if(!db.open()) { qDebug() << db.lastError(); qFatal("Failed to connect."); } // setup UI ui->setupUi(this); ui->toolBar->addWidget(ui->comboFonts); ui->toolBar->addWidget(ui->comboFontSizes); ui->toolBar->addWidget(ui->comboColors); // set text editor defaults ui->textNote->document()->setIndentWidth(20); ui->textNote->setTabStopWidth(20); ui->textNote->setTabChangesFocus(false); ui->actionIncrease_Indent->setShortcut(Qt::Key_Tab); ui->actionDecrease_Indent->setShortcut(Qt::Key_Backtab); // setup comboColors QPixmap pix(16, 16); pix.fill(Qt::white); ui->comboColors->addItem(pix, ""); pix.fill(Qt::black); ui->comboColors->addItem(pix, ""); pix.fill(Qt::red); ui->comboColors->addItem(pix, ""); pix.fill(Qt::blue); ui->comboColors->addItem(pix, ""); pix.fill(Qt::darkGreen); ui->comboColors->addItem(pix, ""); pix.fill(Qt::gray); ui->comboColors->addItem(pix, ""); // create system tray icon createActions(); createTrayIcon(); // create models categoriesModel = new QSqlTableModel(); categoriesModel->setTable("categories"); categoriesModel->setSort(1, Qt::AscendingOrder); categoriesModel->select(); ui->listCategories->setModel(categoriesModel); ui->listCategories->setModelColumn(1); notesModel = new QSqlTableModel(); notesModel->setTable("notes"); ui->listNotes->setModel(notesModel); ui->listNotes->setModelColumn(2); // set splitter size QList<int> sizes; sizes << 230 << 150; ui->splitterLists->setSizes(sizes); sizes.clear(); sizes << 230 << 600; ui->splitterNote->setSizes(sizes); // connect File menu slots connect(ui->actionNew_Category, SIGNAL(triggered()), this, SLOT(newCategory())); connect(ui->actionRename_Category, SIGNAL(triggered()), this, SLOT(renameCategory())); connect(ui->actionDelete_Category, SIGNAL(triggered()), this, SLOT(deleteCategory())); connect(ui->actionNew_Note, SIGNAL(triggered()), this, SLOT(newNote())); connect(ui->actionRename_Note, SIGNAL(triggered()), this, SLOT(renameNote())); connect(ui->actionSave_Note, SIGNAL(triggered()), this, SLOT(saveNote())); connect(ui->actionDelete_Note, SIGNAL(triggered()), this, SLOT(deleteNote())); connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(quit())); // connect Edit menu slots connect(ui->actionFind_Replace, SIGNAL(triggered()), this, SLOT(findAndReplace())); // connect Format menu slots connect(ui->actionBold, SIGNAL(triggered()), this, SLOT(bold())); connect(ui->actionItalic, SIGNAL(triggered()), this, SLOT(italic())); connect(ui->actionUnderline, SIGNAL(triggered()), this, SLOT(underline())); connect(ui->actionStrikethrough, SIGNAL(triggered()), this, SLOT(strikethrough())); connect(ui->actionBullet_List, SIGNAL(triggered()), this, SLOT(bulletList())); connect(ui->actionNumber_List, SIGNAL(triggered()), this, SLOT(numberList())); connect(ui->actionIncrease_Indent, SIGNAL(triggered()), this, SLOT(increaseIndent())); connect(ui->actionDecrease_Indent, SIGNAL(triggered()), this, SLOT(decreaseIndent())); connect(ui->actionShow_Colors, SIGNAL(triggered()), this, SLOT(showColors())); connect(ui->actionShow_Fonts, SIGNAL(triggered()), this, SLOT(showFonts())); connect(ui->actionIncrease_Font, SIGNAL(triggered()), this, SLOT(increaseFont())); connect(ui->actionDecrease_Font, SIGNAL(triggered()), this, SLOT(decreaseFont())); connect(ui->actionReset_Font, SIGNAL(triggered()), this, SLOT(resetFont())); connect(ui->actionAlign_Left, SIGNAL(triggered()), this, SLOT(alignLeft())); connect(ui->actionAlign_Center, SIGNAL(triggered()), this, SLOT(alignCenter())); connect(ui->actionAlign_Right, SIGNAL(triggered()), this, SLOT(alignRight())); connect(ui->actionAlign_Justify, SIGNAL(triggered()), this, SLOT(alignJustify())); // connect View menu slots connect(ui->actionHide_Window, SIGNAL(triggered()), this, SLOT(hide())); connect(ui->actionPrevious_Category, SIGNAL(triggered()), this, SLOT(previousCategory())); connect(ui->actionNext_Category, SIGNAL(triggered()), this, SLOT(nextCategory())); connect(ui->actionPrevious_Note, SIGNAL(triggered()), this, SLOT(previousNote())); connect(ui->actionNext_Note, SIGNAL(triggered()), this, SLOT(nextNote())); // connect Help menu slots connect(ui->actionAbout_Brainstorm, SIGNAL(triggered()), this, SLOT(aboutBrainstorm())); connect(ui->actionAbout_Qt, SIGNAL(triggered()), this, SLOT(aboutQt())); // connect application slots connect(ui->textNote, SIGNAL(cursorPositionChanged()), this, SLOT(updateMenus())); connect(ui->textNote, SIGNAL(currentCharFormatChanged(QTextCharFormat)), this, SLOT(updateMenus())); connect(ui->comboFonts, SIGNAL(activated(QString)), this, SLOT(setFont(QString))); connect(ui->comboFontSizes, SIGNAL(activated(QString)), this, SLOT(setFontSize(QString))); connect(ui->comboColors, SIGNAL(activated(int)), this, SLOT(setFontColor(int))); // connect category list slots connect(ui->listCategories->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(updateNoteList(QModelIndex))); // connect note list slots connect(ui->listNotes->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(updateNoteText(QModelIndex))); // connect text slots ui->textNote->installEventFilter((this)); // connect system tray icon connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); // initialize default data ui->listCategories->selectionModel()->setCurrentIndex(categoriesModel->index(0, 1), QItemSelectionModel::SelectCurrent); }