Code Monkey home page Code Monkey logo

libquentier's People

Contributors

d1vanov avatar michaelkn avatar robert7 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

libquentier's Issues

Sort the tags being sent to Evernote by parent-child relations and update the parent guid for child tags as their parents get synced

Page 57 of Nixnote's User Documentation states:

The tricky part about sending changes to Evernote are tags. Before a new child tag can be created, its parent tag needs to exist at Evernote.

For instance, if I were to create TAG1 and TAG2 and set TAG2 as a child to TAG1, neither tag has a valid Evernote GUID so, when I synchronize, I need to be sure to synchronize TAG1 first, get the new GUID, update the parent GUID for TAG2, then finally synchronize TAG2. If there is an error with TAG1 and it can't be synchronized, then TAG2 will not be synchronized either. Most of this is accomplished with lists to keep track of what tags are ready to be synchronized.

Need to deal with this problem:

  1. Sort the dirty tags need to be sent to Evernote by parent-child relations
  2. Each time the parent tag is sent i.e. receives guid, update its child tags, set parent tag guid to them

Factor the autnehtication stuff out of SynchronizationManager class

Currently all the authentication stuff lives inside SynchronizationManager class' internals. It should be factored out to a separate class - preferably using some IAuthenticationManager interface that would actually be used by SynchronizationManager. The rationale is to avoid the hard dependency on QEverCloud's desktop OAuth - if there's no such dependency, porting the library to mobile platforms (which might happen some day, who knows) would be much simpler.

Implement CMake-time check for presence of new libhunspell API and use it if possible

As I mentioned in hunspell/hunspell#549, although libhunspell itself doesn't offer compile-time check for availability of the new API, I could test for its availability using CMake's try_compile command: should add some tiny code piece using the new libhunspell API first appeared in 1.4.1 version. Then right after finding libhunspell and its development headers (in the end of cmake/modules/LibquentierFindHunspell.cmake) should try to compile this fragment of code and in case of success do something like add_definition(-DHUNSPELL_NEW_API_AVAILABLE). Then within the source code actually using libhunspell API (SpellChecker_p.cpp) split the code fragments using new and old libhunspell APIs using #ifdef HUNSPELL_NEW_API_AVAILABLE.

Testing: should build with both recent enough libhunspell and with some old one (1.3.x, for example) and ensure the correct branch of code works in each case - either with the help of debugger or via adding some trace-level log entry and watching for it.

Add build info to version info

Ideally should have a string composed at CMake step containing git branch and last commit hash. If that information is not available (git not installed or build is not done from a git repo), can just default this information to "unknown".

Implement the possibility to request note count per all tags simultaneously

TagModel in Quentier requests note count for each tag individually during the initial load of tag items from the local storage + on some events like note update. With many tags within the account it leads to many slot invokations which makes the UI thread unresponsive for a couple of seconds.

The suggestion is to implement the method to request note counts for all tags at once so that there's the only one slot invokation which is then just parsed by the TagModel in Quentier.

Improvements for logging

  • Should remove as much logics of log entry composing as possible from the public header. If that means file name and line number should become separate arguments to QuentierLogger::addLogEntry, so be it.
  • Should write the log to file within a separate thread, otherwise it's too damn slow

Unify word's highlighting methods

There are (at least) two places where the words' highlighting is used: Find and replace and Spell checker. Perhaps, the newly added findAndReplaceDOMText script could help in both places.

findAndReplaceDOMText(node, {
 find: 'something',
 wrap: 'span',
 wrapClass: 'hilitorHelper'
});

Evaluate Boost stacktrace library for stack trace functionality

Currently libquentier includes API for providing stack traces: SysInfo::stackTrace (in headers/quentier/utility/SysInfo.h). Currently no Windows backend is actually implemented for it so the method just returns the following string: Stack trace obtaining is not implemented on Windows, patches are welcome.

Boost stracktrace library is available since boost 1.63 and includes more or less cross-platform support for getting stack traces. Would be nice to introduce optional use of this boost library by libquentier and see how it goes. By optional I mean either use this library or use the "old way" i.e. the current implementation doing nothing on Windows. Probably will also need to expose the use of this library in VersionInfo.h (auto-configured file by CMake from template at `headers/quentier/utility/VersionInfo.h.in).

Support translations i.e. running lupdate/lrelease as CMake build targets

Need to figure out how to generate .ts files and how to update .qm files as necessary using CMake. Also need to verify that lupdate runs successfully and generates something meaningful/workable.

Also need to find out where the translations for the library are to be installed to be visible for the application.

Get rid of "failure" signal in LocalStorageManagerAsync

For each request there should be one corresponding signal indicating the failure of the request - the generic one is difficult to use properly as it's unclear in response to what it's being sent and what should one do upon receiving it.

Integrate AppVeyor CI

Need to write .appveyor.yml file describing the build process along with installing all available pre-built dependencies and building those not available.

Bullet-proof conflict resolution during sync

Per Evernote's spec notebooks, tags and saved searches need to have unique names in case-insensitive manner. Need to have a smart conflict resolution logic when syncing the changes from the remote storage to the local one.

Example of a non-trivial situation:

  1. In an Evernote client, do the following: suppose there was a tag called "bash"; rename it to "bash2" and then create a new tag called "bash3" but don't sync yet.
  2. Go to Evernote web, rename "bash" tag to "bash3" there.
  3. Return back to Evernote client and run the sync. What would happen?

Mac's official Evernote client renames "bash2" tag to "bash3" (i.e. the remote changes wins over the local one) and renames the local "bash3" tag to "bash3 1" i.e. changes the name of the different tag conflicting with the downloaded one by name in order to avoid the conflict.

Need to use this logic, only maybe to add some meaningful prefix to the name, like " - conflicted" or " - conflicted (n)" where would be the name of the conflicting local item and n would be some number >= 2 purely for the resolution of potential multiple conflicting items.

Add the possibility to format text as a code block

For now without syntax highlighting but as simple as the following:

#!xml

</div>This is a second command I used on Linux:<br clear="none" /></div><div><pre style="font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 0.9em; border-radius: 4px; letter-spacing: 0.015em; padding: 1em; border: 1px solid #cccccc; background-color: #f8f8f8; overflow-x: auto;">$ sudo second command</pre></div><div><br /></div>

Bug on the second sync attempt after having modified the same note between two syncs

The error text says: "Internal error: empty note store url for the linked notebook's note store".

Some surrounding content from the log:

libquentier/src/synchronization/RemoteToLocalSynchronizationManager.cpp @ 4636 [Debug]: "Got authentication tokens for all linked notebooks, can proceed with their synchronization"
libquentier/src/synchronization/RemoteToLocalSynchronizationManager.cpp @ 4811 [Debug]: "RemoteToLocalSynchronizationManager::downloadLinkedNotebooksSyncChunks"
libquentier/src/synchronization/RemoteToLocalSynchronizationManager.cpp @ 4727 [Debug]: "RemoteToLocalSynchronizationManager::getLinkedNotebookSyncState"
libquentier/src/synchronization/SynchronizationManager_p.cpp @ 1680 [Debug]: "SynchronizationManagerPrivate::noteStoreForLinkedNotebookGuid: guid = ""a93f6851-5107-4575-adab-cf43aa54fd0d"
libquentier/src/synchronization/SynchronizationManager_p.cpp @ 1693 [Debug]: "Found no existing note store corresponding to linked notebook guid ""a93f6851-5107-4575-adab-cf43aa54fd0d"
libquentier/src/synchronization/SynchronizationManager_p.cpp @ 569 [Debug]: "SynchronizationManagerPrivate::onRemoteToLocalSyncFailure: ""Internal error: empty note store url for the linked notebook's note store"

Remove parent tag guids leading to inaccessible tags from tags downloaded from linked notebooks

Linked notebooks are a funny feature of Evernote. When a linked notebook is added to your account, you get a notebook, its notes and all the tags associated with those notes. But no other tags from the linked notebook owner's account. As it was revealed empirically, that means that sometimes you get tags with parent tag guids which are inaccessible. The official Evernote client just shows such tags as if they had no parent and it appears I need to do the same thing.

But this logic needs to be implemented on sync algorithm side, not on local storage side because the check for parent tag's accessibility within local storage is useful as it prevents mistakes in code from messing up the database.

As a first step, need to finally migrate from using QList of qevercloud::Tag to some indexable data structure - indexable by guid, by name, by parent tag guid and by linked notebook guid. Lookup complexity is important because tags can easily hit the number of a thousand (at least during the full sync).

Implement special processing for pasting the html mime data into the note

Right now there is no special processing i.e. the HTML just gets pasted as is. It doesn't hurt the conversion of the note to ENML since all forbidden/unsupported tags and attributes are eliminated but

  1. They are only eliminated at the point of conversion to ENML so would be visible only after the next conversion from ENML back into HTML
  2. The pasted HTML might contain img tags pointing to some external images. These need to be downloaded (or at least attempted to be downloaded) and attached to the note as new resources.

Hopefully it should be possible to convert the HTML about to be pasted into valid XML via libtidy5 and then parse it via QXmlStreamReader

Implement API for access/addition/removal of dictionary files used by SpellChecker

Currently SpellChecker class (from headers/quentier/note_editor/SpellChecker.h) provides quite a limited support for dealing with dictionaries it is using:

  1. The dictionary files (.dic and .aff files used by hunspell backend) are detected automatically, without any user's intervention, their locations are persisted with the help of QSettings. That's mostly good only this way doesn't provide much flexibility for cases when new dictionaries are installed, some existing ones are uninstalled, their location changes etc.
  2. Currently it is only possible to list the language codes of dictionaries used by SpellChecker + methods to enable/disable the certain dictionary.

Although it sort of leaks the implementation detail, I believe it'd be worth it to add new methods allowing to associate language codes with particular .dic and .aff files and thus provide the management of these, for example:

class QUENTIER_EXPORT SpellChecker: public QObject
{
    Q_OBJECT
public:
<...>
    class QUENTIER_EXPORT Dictionary: public Printable
    {
    public:
        Dictionary();
        Dictionary(const QString & languageCode, const QString & dicFileLocation,
                         const QString & affFileLocation, const bool enabled);

        const QString & languageCode() const;
        void setLanguageCode(const QString & languageCode);
 
        const QString & dicFileLocation() const;
        void setDicFileLocation(const QString & dicFileLocation);

        const QString & affFileLocation() const;
        void setAffFileLocation(const QString & affFileLocation);
        
        bool isEnabled() const;
        void setEnabled(const bool enabled);
        
        /**
         * @return True if dictionary object is valid i.e. its language code is valid and its paths to dic and aff files are valid i.e. they are path to existing readable files which base names correspond to the language code and which extensions correspond to dic and aff correspondingly, false otherwise
         */
        bool isValid() const;
        
        virtual QTextStream & print(QTextStream & strm) const Q_DECL_OVERRIDE;
        
    private:
        QString     m_languageCode;
        QString     m_dicFileLocation;
        QString     m_affFileLocation;
        bool          m_enabled;
    };

    QVector<Dictionary> listAvailableDictionaries() const;

    /**
     * @return existing valid dictionary for the provided language code, invalid dictionary otherwise
     */
    Dictionary findDictionary(const QString & languageCode) const;

    /**
     * @return True if dictionary corresponding to the language code was successfully enabled, false otherwise
     */
    bool enableDictionary(const QString & languageCode);

    /**
     * @return True if dictionary corresponding to the language code was successfully disabled, false otherwise
     */
    bool disableDictionary(const QString & languageCode);
    
    /**
     * @return True if valid dictionary was successfully added to or updated within the list of available dictionaries, false if the dictionary is invalid
     */
    bool addOrUpdateDictionary(const Dictionary & dictionary);
    
    /**
     * @return True if the dictionary corresponding to the language code was successfully removed from the list of available dictionaries, false if no dictionary corresponding to the language code was found
     */
    bool removeDictionary(const QString & languageCode);
};

There's likely a bug in findReplaceManager.js, function clearHighlightTags

    // TODO: should replace this with some more proper way                                                              
    this.clearHighlightTags = function(html) {                                                                          
        var highlightOpenTagStart = 0;                                                                                  
        while(true) {                                                                                                   
            highlightOpenTagStart = html.indexOf("<span", highlightOpenTagStart);                                       
            if (highlightOpenTagStart < 0) {                                                                            
                break;                                                                                                  
            }                                                                                                           
                                                                                                                        
            var highlightOpenTagEnd = html.indexOf(">", highlightOpenTagStart);                                         
            if (highlightOpenTagEnd < 0) {                                                                              
                break;                                                                                                  
            }                                                                                                           
                                                                                                                        
            var highlightCloseTagStart = html.indexOf("</span>", highlightOpenTagEnd);                                  
            if (highlightCloseTagStart < 0) {                                                                           
                break;                                                                                                  
            }                                                                                                           
                                                                                                                        
            var classAttributeValueStart = html.indexOf("hilitorHelper");                                               
            if ((classAttributeValueStart <= highlightOpenTagStart) && (classAttributeValueStart >= highlightOpenTagEnd)) {
                continue;                                                                                               
            }                                                                                                           
                                                                                                                        
            var highlightedText = html.substring(highlightOpenTagEnd + 1, highlightCloseTagStart);                      
            html = html.substring(0, highlightOpenTagStart) + highlightedText + html.substring(highlightCloseTagStart + 5, html.length);
        }                                                                                                               
                                                                                                                        
        return html;                                                                                                    
    }

highlightOpenTagStart should be less than highlightOpenTagEnd, therefore the condition (classAttributeValueStart <= highlightOpenTagStart) && (classAttributeValueStart >= highlightOpenTagEnd) doesn't seem to make much sense, it should be || instead of && it seems.

Infinite loop in Replace all

Easily reproduces by input a same word into the find and replace fields. Then press Replace all button - Note editor hangs and app crashes on exit.
Actually, the words might be not same but similar, like 'wake' and 'awake'.

minidump.tar.gz

Implement infrastructure for testing of synchronization logic

Synchronization logic is quite complex and definitely needs some regression tests. However, before we can have the tests, we need the infrastructure for them i.e. we need some way to fake the Evernote servers communicating with the local app. I see several possible solutions:

  1. Add INoteStore interface which would be implemented by NoteStore (for production synchronization) and FakeNoteStore (for tests). The injection of a particular note store would then need to happen in runtime. It means some switch would be needed to tell libquentier it needs to inject the fake note store instead of the real one for tests. It can be a dedicated API method or it can be something better hidden, for example, examining some environment variable like LIBQUENTIER_USE_FAKE_NOTE_STORE_FOR_SYNCHRONIZATION_TESTING. Or it might examine the value within some settings file instead of the environment variable.
  2. Use some trick with preloading some shared library "catching" the calls to QEverCloud's methods. On Linux it could work with the help of LD_PRELOAD but not sure if there are equivalents on Windows and Mac.
  3. Implement fake server on the local host with which QEverCloud would communicate. Most complex of all variants as it would require decoding and encoding of data from/to Thrift binary format. QEverCloud currently doesn't export the stuff related to that.

Note editor: table inserter doesn't work

It inserts a broken HTML:

<div>
<table collapse;="" margin-left:="" 0px;="" table-layout:="" fixed;="" width:="" 400px;\x22=""><tbody>
<tr><td 1px="" solid="" rgb(219,="" 219,="" 219);="" padding:="" 10="" px;="" margin:="" 0px;="" width:="" 400px;\x22=""><div><br></div></td></tr>
</tbody></table>
</div>

Rename QNCRITICAL logging macro to QNERROR and get rid of Fatal log level

Fatal log level in several logging frameworks terminates the application in addition to printing the "fatal" log entry. Currently libquentier's fatal log level doesn't terminate the application and thus can be the source of confusion. On the other hand, I don't really want to encourage anyone to terminate the application in this way as well. So it's better to just get rid of this log level and replace its occurrences within the source code by Error log entries or even Warning log entries.

Also need to change QNCRITICAL macro to QNERROR since that would actually correspond to Error log level.

Integrate Travis CI

Need to write .travis.yml file describing the build process along with installing all available pre-built dependencies and building those not available.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.