From 0b7f30930be1318030b9749f352a8dec3b9c6f39 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Tue, 20 Jan 2015 16:22:03 -0500 Subject: Completely revamp the notepad desktop plugin so that it is now file-based instead of saving everything into the plugin settings directly. This allows it to manage generic text files as well as just the *.note files in ~/Notes. --- .../desktop-plugins/notepad/NotepadPlugin.cpp | 268 +++++++++++++++++---- .../desktop-plugins/notepad/NotepadPlugin.h | 20 +- 2 files changed, 233 insertions(+), 55 deletions(-) (limited to 'lumina-desktop') diff --git a/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp b/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp index 214de63c..17372202 100644 --- a/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp +++ b/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp @@ -2,7 +2,10 @@ #include #include "LSession.h" - +#include +#include +#include +#include NotePadPlugin::NotePadPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){ QVBoxLayout *vlay = new QVBoxLayout(); @@ -15,21 +18,32 @@ NotePadPlugin::NotePadPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID) this->layout()->addWidget(frame); frame->setLayout(vlay); + if(!QFile::exists(QDir::homePath()+"/Notes")){ + //Create the notes directory if non-existant + QDir dir; + dir.mkpath(QDir::homePath()+"/Notes"); + } + watcher = new QFileSystemWatcher(this); + //Always watch the notes directory for new files/changes + watcher->addPath(QDir::homePath()+"/Notes"); + + typeTimer = new QTimer(this); + typeTimer->setInterval(1000); // 1 second before it saves + typeTimer->setSingleShot(true); //compress lots of signals into a single save + + updating = false; //Setup the title bar header buttons QHBoxLayout *hlay = new QHBoxLayout(); - next = new QToolButton(this); - next->setAutoRaise(true); - prev = new QToolButton(this); - prev->setAutoRaise(true); + open = new QToolButton(this); + open->setAutoRaise(true); add = new QToolButton(this); add->setAutoRaise(true); rem = new QToolButton(this); rem->setAutoRaise(true); - label = new QLabel(this); - label->setAlignment(Qt::AlignCenter); - hlay->addWidget(prev); - hlay->addWidget(next); - hlay->addWidget(label); + cnote = new QComboBox(this); + + hlay->addWidget(cnote); + hlay->addWidget(open); hlay->addWidget(add); hlay->addWidget(rem); vlay->addLayout(hlay); @@ -37,20 +51,47 @@ NotePadPlugin::NotePadPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID) //Setup the main text widget edit = new QPlainTextEdit(this); edit->setReadOnly(false); + edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); vlay->addWidget(edit); - //Now setup the initial values - cnote = this->settings->value("currentNote", 1).toInt(); - maxnote = this->settings->value("availableNotes",1).toInt(); + //Special detection of the old notes format and conversion to the new files format + if( this->settings->value("availableNotes",-1).toInt() > 0){ + qDebug() << "Converting all old desktop notes into the new file-based format (located at ~/Notes/.note)"; + int notes = this->settings->value("availableNotes",1).toInt(); + int current = settings->value("currentNote",1).toInt(); + for(int i=0; i<(notes+1); i++){ + QString note = settings->value("Note-"+QString::number(i),"").toString(); + settings->remove("Note-"+QString::number(i)); + if(!note.isEmpty()){ + //Save this note in the new file format + LUtils::writeFile(QDir::homePath()+"/Notes/Note-"+QString::number(i)+".note", note.split("\n"), true); + } + if(i==current){ + //Convert the current note value to the new format + settings->setValue("currentFile", QDir::homePath()+"/Notes/Note-"+QString::number(i)+".note"); + } + } + //Clear the old settings-based values + settings->remove("availableNotes"); + settings->remove("currentNote"); + } + //Now load the new file-based system for saving notes + settings->setValue("customFile",""); //always clear this when the plugin is initialized (only maintained per-session) + notesDirChanged(); + + //Now setup the initial values for the plugin this->setInitialSize(200,300); + //Setup the button connections - connect(next, SIGNAL(clicked()), this, SLOT(nextNote()) ); - connect(prev, SIGNAL(clicked()), this, SLOT(prevNote()) ); + connect(open, SIGNAL(clicked()), this, SLOT(openNote()) ); connect(add, SIGNAL(clicked()), this, SLOT(newNote()) ); connect(rem, SIGNAL(clicked()), this, SLOT(remNote()) ); - connect(edit, SIGNAL(textChanged()), this, SLOT(noteChanged()) ); + connect(edit, SIGNAL(textChanged()), this, SLOT(newTextAvailable()) ); + connect(cnote, SIGNAL(currentIndexChanged(QString)), this, SLOT(noteChanged()) ); + connect(typeTimer, SIGNAL(timeout()), this, SLOT(updateContents()) ); + connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(notesDirChanged()) ); //re-load the available notes + connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(noteChanged()) ); //re-load the current file QTimer::singleShot(0,this, SLOT(loadIcons()) ); - QTimer::singleShot(0,this, SLOT(updateContents()) ); } @@ -58,54 +99,187 @@ NotePadPlugin::~NotePadPlugin(){ } -void NotePadPlugin::nextNote(){ - cnote++; - if(cnote>maxnote){ cnote = 1; } //go to the first - updateContents(); -} -void NotePadPlugin::prevNote(){ - cnote--; - if(cnote<1){ cnote = maxnote; } //go to the last - updateContents(); +void NotePadPlugin::openNote(){ + //qDebug() << "Open New Note:"; + //Prompt for a name for the new note + QFileDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint ); + dlg.setFileMode(QFileDialog::ExistingFile); + dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setNameFilters( QStringList() << tr("Note Files (*.note)") << tr("Text Files (*)")); + dlg.setWindowTitle(tr("Open a note file")); + dlg.setWindowIcon( LXDG::findIcon("document-open","") ); + dlg.setDirectory(QDir::homePath()); //start in the home directory + //ensure it is centered on the current screen + QPoint center = QApplication::desktop()->screenGeometry(this).center(); + dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) ); + dlg.show(); + while( dlg.isVisible() ){ + QApplication::processEvents(); + } + QStringList sel = dlg.selectedFiles(); + if(sel.isEmpty()){ return; } //cancelled + QString fullpath = sel.first(); + QString name = fullpath.section("/",-1); + //qDebug() << " - Found Note:" << name << fullpath; + int index = cnote->findText(name, Qt::MatchExactly | Qt::MatchCaseSensitive); + if(QFile::exists(fullpath) && index <0){ + //Alternate option of searching for the file in the list + index = cnote->findText(fullpath, Qt::MatchExactly | Qt::MatchCaseSensitive); + } + if(index>=0){ + //This note already exists: just load it + cnote->setCurrentIndex(index); + }else{ + //New note - add it to the end of the list and then load it + cnote->addItem(name, fullpath); + settings->setValue("customFile", fullpath); //save this as a custom file + cnote->setCurrentIndex( cnote->count()-1 ); + QTimer::singleShot(1000, this, SLOT(notesDirChanged())); //Make sure to refresh the list (only one custom file at a time) + } } void NotePadPlugin::newNote(){ - maxnote++; - cnote = maxnote; - updateContents(); + //Prompt for a name for the new note + //qDebug() << "Create new note"; + QInputDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint ); + dlg.setInputMode(QInputDialog::TextInput); + dlg.setLabelText(tr("New Note Name:")); + dlg.setTextEchoMode(QLineEdit::Normal); + dlg.setWindowTitle(tr("Create a new note")); + dlg.setWindowIcon( LXDG::findIcon("document-new","") ); + //ensure it is centered on the current screen + QPoint center = QApplication::desktop()->screenGeometry(this).center(); + dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) ); + dlg.show(); + while( dlg.isVisible() ){ + QApplication::processEvents(); + } + QString name = dlg.textValue(); + if(name.isEmpty()){ return; } //cancelled + QString fullpath = QDir::homePath()+"/Notes/"+name; + if(!fullpath.endsWith(".note")){ fullpath.append(".note"); } + //qDebug() << " - New Note:" << name << fullpath; + int index = cnote->findText(name, Qt::MatchExactly | Qt::MatchCaseSensitive); + if(QFile::exists(fullpath) && index <0){ + //Alternate option of searching for the file in the list + index = cnote->findText(fullpath, Qt::MatchExactly | Qt::MatchCaseSensitive); + } + if(index>=0){ + //This note already exists: just load it + cnote->setCurrentIndex(index); + }else{ + //New note - add it to the end of the list and then load it + cnote->addItem(name, fullpath); + cnote->setCurrentIndex( cnote->count()-1 ); + } } void NotePadPlugin::remNote(){ - //Clear the current note - settings->remove("Note-"+QString::number(cnote)); - //If the last note, also decrease the max number - if(cnote==maxnote && maxnote>1){ maxnote--; } - //Now go to the previous note - cnote--; - if(cnote<1){ cnote = maxnote; } - updateContents(); + QString note = cnote->currentData().toString(); + if(note.isEmpty()){ return; } + watcher->removePath(note); //remove this file from the watcher + settings->setValue("currentFile",""); //reset the internal value + QFile::remove(note); //remove the file + //if(!note.startsWith(QDir::homePath()+"/Notes/") ){ + //If the file was not in the notes directory, need to manually prompt for a re-load + // otherwise, the directory watcher will catch it and trigger a re-load (no need to double-load) + notesDirChanged(); + //} +} + +void NotePadPlugin::newTextAvailable(){ + if(updating){ return; } //programmatic change of the widget + if(typeTimer->isActive()){ typeTimer->stop(); } + typeTimer->start(); } void NotePadPlugin::updateContents(){ - next->setEnabled(cnotesetEnabled(cnote>1); - label->setText( QString(tr("Note #%1")).arg(QString::number(cnote)) ); - settings->setValue("currentNote", cnote); - settings->setValue("availableNotes", maxnote); - edit->setPlainText( settings->value("Note-"+QString::number(cnote), "").toString() ); + if(updating){ return; } //this was a programmatic change to the widget + //The text was changed in the plugin - save it in the file + QString note = cnote->currentData().toString(); + updating = true; + LUtils::writeFile(note, edit->toPlainText().split("\n"), true); + updating = false; } +void NotePadPlugin::notesDirChanged(){ + QString cfile = settings->value("currentFile","").toString(); + QStringList notes; + QDir dir(QDir::homePath()+"/Notes"); + QStringList files = dir.entryList(QStringList() << "*.note", QDir::Files | QDir::NoDotAndDotDot, QDir::Name); + for(int i=0; ivalue("customFile","").toString(); + if(!custom.isEmpty() && QFile::exists(custom) ){ notes << custom; } + //qDebug() << "Available Notes:" << notes << cfile; + //Now update the UI list + updating = true; //don't refresh the UI until done changing lists + cnote->clear(); + bool found = false; + for(int i=0; iaddItem(name, notes[i]); + if(notes[i]==cfile){ cnote->setCurrentIndex(i); found = true;} + } + if(!found && !cfile.isEmpty()){ + //Current note is a manually-loaded text file + cnote->addItem(cfile.section("/",-1), cfile); + cnote->setCurrentIndex( cnote->count()-1 ); //last item + found = true; + } + if(!found && cnote->count()>0){ cnote->setCurrentIndex(0); } + updating =false; + noteChanged(); +} void NotePadPlugin::noteChanged(){ - //Save the current text - settings->setValue("Note-"+QString::number(cnote), edit->toPlainText()); + if(updating){ return; } + updating =true; + QString note; + if(cnote->currentIndex()>=0){ + note = cnote->currentData().toString(); + } + if(note.isEmpty() && cnote->count()>0){ + updating=false; + cnote->setCurrentIndex(0); + return; + } + QString oldnote = settings->value("currentFile","").toString(); + //qDebug() << "Note Changed:" << note << oldnote; + if( oldnote!=note ){ + //Clear the old note file/setting + if(!oldnote.isEmpty()){ + watcher->removePath(oldnote); + settings->setValue("currentFile",""); + } + if(!note.isEmpty()){ + settings->setValue("currentFile",note); + watcher->addPath(note); + } + } + + if(!note.isEmpty()){ + QString text = LUtils::readFile(note).join("\n"); + if(text!=edit->toPlainText()){ + edit->setPlainText( text ); + } + }else{ + edit->clear(); + } + //If no notes available - disable the editor until a new one is created + edit->setEnabled(!note.isEmpty()); + rem->setEnabled(!note.isEmpty()); + cnote->setEnabled(!note.isEmpty()); + //leave the new/open buttons enabled all the time + updating = false; } void NotePadPlugin::loadIcons(){ - next->setIcon( LXDG::findIcon("go-next-view","") ); - prev->setIcon( LXDG::findIcon("go-previous-view","") ); + open->setIcon( LXDG::findIcon("document-open","") ); add->setIcon( LXDG::findIcon("document-new","") ); rem->setIcon( LXDG::findIcon("document-close","") ); } diff --git a/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h b/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h index 0a4311ed..a1d9bf8f 100644 --- a/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h +++ b/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h @@ -11,9 +11,10 @@ #include #include -#include +#include #include #include +#include #include "../LDPlugin.h" class NotePadPlugin : public LDPlugin{ @@ -24,25 +25,28 @@ public: private: QPlainTextEdit *edit; - QToolButton *next, *prev, *add, *rem; - QLabel *label; + QToolButton *open, *add, *rem; + QComboBox *cnote; QFrame *frame; - int cnote, maxnote; //current/max note - + QFileSystemWatcher *watcher; + bool updating; + QTimer *typeTimer; + private slots: - void nextNote(); - void prevNote(); + void openNote(); void newNote(); void remNote(); + void newTextAvailable(); void updateContents(); + void notesDirChanged(); void noteChanged(); void loadIcons(); public slots: void LocaleChange(){ - QTimer::singleShot(0,this, SLOT(updateContents())); + QTimer::singleShot(0,this, SLOT(noteChanged())); } void ThemeChange(){ QTimer::singleShot(0,this, SLOT(loadIcons())); -- cgit