From a0e0fc98ae35398952314b5adb571cab90c7d3f3 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 23 Dec 2017 22:19:17 +0100 Subject: [PATCH 01/63] XML mode for the cell editor The new editor mode shares the same Scintilla widget as the JSON mode. The JsonTextEdit class has been generalised. Future modes supported by Scintilla could be added with the current pattern. As a consequence, the EditMode is not always equal to the current stacked widget. Some code in EditDialog has been refactored, so it is easier to understand and modified with so many modes. textNullSet has been replaced by the use of dataType as Null. SVG is promoted to a new recognised data type, so it can be edited in the XML mode. The XML data is formatted and validated following the pattern established by the JSON mode. New modules are needed by the XML mode: the Qt XML module and some new Scintilla files required by the HTML/XML lexer. The indent_compact was incorrectly named in Setting::getDefaultValue. See issue #1253. --- CMakeLists.txt | 7 +- libs/qscintilla/Qt4Qt5/CMakeLists.txt | 11 + libs/qscintilla/Qt4Qt5/Qsci/qscilexercpp.h | 398 +++ libs/qscintilla/Qt4Qt5/Qsci/qscilexerhtml.h | 532 ++++ .../Qt4Qt5/Qsci/qscilexerjavascript.h | 81 + libs/qscintilla/Qt4Qt5/Qsci/qscilexerpython.h | 321 +++ libs/qscintilla/Qt4Qt5/Qsci/qscilexerxml.h | 106 + libs/qscintilla/Qt4Qt5/qscilexercpp.cpp | 801 ++++++ libs/qscintilla/Qt4Qt5/qscilexerhtml.cpp | 1181 +++++++++ .../qscintilla/Qt4Qt5/qscilexerjavascript.cpp | 120 + libs/qscintilla/Qt4Qt5/qscilexerpython.cpp | 489 ++++ libs/qscintilla/Qt4Qt5/qscilexerxml.cpp | 252 ++ libs/qscintilla/lexers/LexHTML.cpp | 2203 +++++++++++++++++ libs/qscintilla/src/Catalogue.cpp | 2 + src/EditDialog.cpp | 478 ++-- src/EditDialog.h | 21 +- src/EditDialog.ui | 37 +- src/ExtendedScintilla.cpp | 27 +- src/ExtendedScintilla.h | 3 +- src/Settings.cpp | 2 +- src/docktextedit.cpp | 79 + src/docktextedit.h | 40 + src/jsontextedit.cpp | 54 - src/jsontextedit.h | 25 - src/sqltextedit.cpp | 31 +- src/src.pro | 6 +- 26 files changed, 6979 insertions(+), 328 deletions(-) create mode 100644 libs/qscintilla/Qt4Qt5/Qsci/qscilexercpp.h create mode 100644 libs/qscintilla/Qt4Qt5/Qsci/qscilexerhtml.h create mode 100644 libs/qscintilla/Qt4Qt5/Qsci/qscilexerjavascript.h create mode 100644 libs/qscintilla/Qt4Qt5/Qsci/qscilexerpython.h create mode 100644 libs/qscintilla/Qt4Qt5/Qsci/qscilexerxml.h create mode 100644 libs/qscintilla/Qt4Qt5/qscilexercpp.cpp create mode 100644 libs/qscintilla/Qt4Qt5/qscilexerhtml.cpp create mode 100644 libs/qscintilla/Qt4Qt5/qscilexerjavascript.cpp create mode 100644 libs/qscintilla/Qt4Qt5/qscilexerpython.cpp create mode 100644 libs/qscintilla/Qt4Qt5/qscilexerxml.cpp create mode 100644 libs/qscintilla/lexers/LexHTML.cpp create mode 100644 src/docktextedit.cpp create mode 100644 src/docktextedit.h delete mode 100644 src/jsontextedit.cpp delete mode 100644 src/jsontextedit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b85e12a..6b919e89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ find_package(Qt5Widgets REQUIRED) find_package(Qt5LinguistTools REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5Concurrent REQUIRED) +find_package(Qt5Xml REQUIRED) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -105,7 +106,7 @@ set(SQLB_MOC_HDR src/VacuumDialog.h src/sqlitetablemodel.h src/sqltextedit.h - src/jsontextedit.h + src/docktextedit.h src/DbStructureModel.h src/Application.h src/CipherDialog.h @@ -142,7 +143,7 @@ set(SQLB_SRC src/sqlitetablemodel.cpp src/sqlitetypes.cpp src/sqltextedit.cpp - src/jsontextedit.cpp + src/docktextedit.cpp src/csvparser.cpp src/DbStructureModel.cpp src/grammar/Sqlite3Lexer.cpp @@ -329,7 +330,7 @@ add_executable(${PROJECT_NAME} ${SQLB_RESOURCES_RCC} ${SQLB_MISC}) -qt5_use_modules(${PROJECT_NAME} Gui Widgets Network Test PrintSupport Concurrent) +qt5_use_modules(${PROJECT_NAME} Gui Widgets Network Test PrintSupport Concurrent Xml) set(QT_LIBRARIES "") add_dependencies(${PROJECT_NAME} qhexedit qcustomplot) diff --git a/libs/qscintilla/Qt4Qt5/CMakeLists.txt b/libs/qscintilla/Qt4Qt5/CMakeLists.txt index a90f00b8..b3d70aef 100644 --- a/libs/qscintilla/Qt4Qt5/CMakeLists.txt +++ b/libs/qscintilla/Qt4Qt5/CMakeLists.txt @@ -23,6 +23,11 @@ set(QSCINTILLA_SRC qscilexercustom.cpp qscilexersql.cpp qscilexerjson.cpp + qscilexerhtml.cpp + qscilexerxml.cpp + qscilexerjavascript.cpp + qscilexercpp.cpp + qscilexerpython.cpp qscimacro.cpp qsciprinter.cpp qscistyle.cpp @@ -35,6 +40,7 @@ set(QSCINTILLA_SRC ScintillaQt.cpp ../lexers/LexSQL.cpp ../lexers/LexJSON.cpp + ../lexers/LexHTML.cpp ../lexlib/Accessor.cpp ../lexlib/CharacterCategory.cpp ../lexlib/CharacterSet.cpp @@ -146,6 +152,11 @@ set(QSCINTILLA_MOC_HDR ./Qsci/qscilexercustom.h ./Qsci/qscilexersql.h ./Qsci/qscilexerjson.h + ./Qsci/qscilexerhtml.h + ./Qsci/qscilexerxml.h + ./Qsci/qscilexerjavascript.h + ./Qsci/qscilexercpp.h + ./Qsci/qscilexerpython.h ./Qsci/qscimacro.h SciClasses.h ScintillaQt.h diff --git a/libs/qscintilla/Qt4Qt5/Qsci/qscilexercpp.h b/libs/qscintilla/Qt4Qt5/Qsci/qscilexercpp.h new file mode 100644 index 00000000..e823d072 --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/Qsci/qscilexercpp.h @@ -0,0 +1,398 @@ +// This defines the interface to the QsciLexerCPP class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXERCPP_H +#define QSCILEXERCPP_H + +#include + +#include +#include + + +//! \brief The QsciLexerCPP class encapsulates the Scintilla C++ +//! lexer. +class QSCINTILLA_EXPORT QsciLexerCPP : public QsciLexer +{ + Q_OBJECT + +public: + //! This enum defines the meanings of the different styles used by the + //! C++ lexer. + enum { + //! The default. + Default = 0, + InactiveDefault = Default + 64, + + //! A C comment. + Comment = 1, + InactiveComment = Comment + 64, + + //! A C++ comment line. + CommentLine = 2, + InactiveCommentLine = CommentLine + 64, + + //! A JavaDoc/Doxygen style C comment. + CommentDoc = 3, + InactiveCommentDoc = CommentDoc + 64, + + //! A number. + Number = 4, + InactiveNumber = Number + 64, + + //! A keyword. + Keyword = 5, + InactiveKeyword = Keyword + 64, + + //! A double-quoted string. + DoubleQuotedString = 6, + InactiveDoubleQuotedString = DoubleQuotedString + 64, + + //! A single-quoted string. + SingleQuotedString = 7, + InactiveSingleQuotedString = SingleQuotedString + 64, + + //! An IDL UUID. + UUID = 8, + InactiveUUID = UUID + 64, + + //! A pre-processor block. + PreProcessor = 9, + InactivePreProcessor = PreProcessor + 64, + + //! An operator. + Operator = 10, + InactiveOperator = Operator + 64, + + //! An identifier + Identifier = 11, + InactiveIdentifier = Identifier + 64, + + //! The end of a line where a string is not closed. + UnclosedString = 12, + InactiveUnclosedString = UnclosedString + 64, + + //! A C# verbatim string. + VerbatimString = 13, + InactiveVerbatimString = VerbatimString + 64, + + //! A JavaScript regular expression. + Regex = 14, + InactiveRegex = Regex + 64, + + //! A JavaDoc/Doxygen style C++ comment line. + CommentLineDoc = 15, + InactiveCommentLineDoc = CommentLineDoc + 64, + + //! A keyword defined in keyword set number 2. The class must be + //! sub-classed and re-implement keywords() to make use of this style. + KeywordSet2 = 16, + InactiveKeywordSet2 = KeywordSet2 + 64, + + //! A JavaDoc/Doxygen keyword. + CommentDocKeyword = 17, + InactiveCommentDocKeyword = CommentDocKeyword + 64, + + //! A JavaDoc/Doxygen keyword error. + CommentDocKeywordError = 18, + InactiveCommentDocKeywordError = CommentDocKeywordError + 64, + + //! A global class or typedef defined in keyword set number 5. The + //! class must be sub-classed and re-implement keywords() to make use + //! of this style. + GlobalClass = 19, + InactiveGlobalClass = GlobalClass + 64, + + //! A C++ raw string. + RawString = 20, + InactiveRawString = RawString + 64, + + //! A Vala triple-quoted verbatim string. + TripleQuotedVerbatimString = 21, + InactiveTripleQuotedVerbatimString = TripleQuotedVerbatimString + 64, + + //! A Pike hash-quoted string. + HashQuotedString = 22, + InactiveHashQuotedString = HashQuotedString + 64, + + //! A pre-processor stream comment. + PreProcessorComment = 23, + InactivePreProcessorComment = PreProcessorComment + 64, + + //! A JavaDoc/Doxygen style pre-processor comment. + PreProcessorCommentLineDoc = 24, + InactivePreProcessorCommentLineDoc = PreProcessorCommentLineDoc + 64, + + //! A user-defined literal. + UserLiteral = 25, + InactiveUserLiteral = UserLiteral + 64, + + //! A task marker. + TaskMarker = 26, + InactiveTaskMarker = TaskMarker + 64, + + //! An escape sequence. + EscapeSequence = 27, + InactiveEscapeSequence = EscapeSequence + 64, + }; + + //! Construct a QsciLexerCPP with parent \a parent. \a parent is typically + //! the QsciScintilla instance. \a caseInsensitiveKeywords is true if the + //! lexer ignores the case of keywords. + QsciLexerCPP(QObject *parent = 0, bool caseInsensitiveKeywords = false); + + //! Destroys the QsciLexerCPP instance. + virtual ~QsciLexerCPP(); + + //! Returns the name of the language. + const char *language() const; + + //! Returns the name of the lexer. Some lexers support a number of + //! languages. + const char *lexer() const; + + //! \internal Returns the character sequences that can separate + //! auto-completion words. + QStringList autoCompletionWordSeparators() const; + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the end of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockEnd(int *style = 0) const; + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the start of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockStart(int *style = 0) const; + + //! \internal Returns a space separated list of keywords in a + //! particular style that define the start of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockStartKeyword(int *style = 0) const; + + //! \internal Returns the style used for braces for brace matching. + int braceStyle() const; + + //! Returns the string of characters that comprise a word. + const char *wordCharacters() const; + + //! Returns the foreground colour of the text for style number \a style. + //! + //! \sa defaultPaper() + QColor defaultColor(int style) const; + + //! Returns the end-of-line fill for style number \a style. + bool defaultEolFill(int style) const; + + //! Returns the font for style number \a style. + QFont defaultFont(int style) const; + + //! Returns the background colour of the text for style number \a style. + //! + //! \sa defaultColor() + QColor defaultPaper(int style) const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. Set 1 is normally used for + //! primary keywords and identifiers. Set 2 is normally used for secondary + //! keywords and identifiers. Set 3 is normally used for documentation + //! comment keywords. Set 4 is normally used for global classes and + //! typedefs. + const char *keywords(int set) const; + + //! Returns the descriptive name for style number \a style. If the + //! style is invalid for this language then an empty QString is returned. + //! This is intended to be used in user preference dialogs. + QString description(int style) const; + + //! Causes all properties to be refreshed by emitting the + //! propertyChanged() signal as required. + void refreshProperties(); + + //! Returns true if "} else {" lines can be folded. + //! + //! \sa setFoldAtElse() + bool foldAtElse() const {return fold_atelse;} + + //! Returns true if multi-line comment blocks can be folded. + //! + //! \sa setFoldComments() + bool foldComments() const {return fold_comments;} + + //! Returns true if trailing blank lines are included in a fold block. + //! + //! \sa setFoldCompact() + bool foldCompact() const {return fold_compact;} + + //! Returns true if preprocessor blocks can be folded. + //! + //! \sa setFoldPreprocessor() + bool foldPreprocessor() const {return fold_preproc;} + + //! Returns true if preprocessor lines (after the preprocessor + //! directive) are styled. + //! + //! \sa setStylePreprocessor() + bool stylePreprocessor() const {return style_preproc;} + + //! If \a allowed is true then '$' characters are allowed in identifier + //! names. The default is true. + //! + //! \sa dollarsAllowed() + void setDollarsAllowed(bool allowed); + + //! Returns true if '$' characters are allowed in identifier names. + //! + //! \sa setDollarsAllowed() + bool dollarsAllowed() const {return dollars;} + + //! If \a enabled is true then triple quoted strings are highlighted. The + //! default is false. + //! + //! \sa highlightTripleQuotedStrings() + void setHighlightTripleQuotedStrings(bool enabled); + + //! Returns true if triple quoted strings should be highlighted. + //! + //! \sa setHighlightTripleQuotedStrings() + bool highlightTripleQuotedStrings() const {return highlight_triple;} + + //! If \a enabled is true then hash quoted strings are highlighted. The + //! default is false. + //! + //! \sa highlightHashQuotedStrings() + void setHighlightHashQuotedStrings(bool enabled); + + //! Returns true if hash quoted strings should be highlighted. + //! + //! \sa setHighlightHashQuotedStrings() + bool highlightHashQuotedStrings() const {return highlight_hash;} + + //! If \a enabled is true then back-quoted raw strings are highlighted. + //! The default is false. + //! + //! \sa highlightBackQuotedStrings() + void setHighlightBackQuotedStrings(bool enabled); + + //! Returns true if back-quoted raw strings should be highlighted. + //! + //! \sa setHighlightBackQuotedStrings() + bool highlightBackQuotedStrings() const {return highlight_back;} + + //! If \a enabled is true then escape sequences in strings are highlighted. + //! The default is false. + //! + //! \sa highlightEscapeSequences() + void setHighlightEscapeSequences(bool enabled); + + //! Returns true if escape sequences in strings should be highlighted. + //! + //! \sa setHighlightEscapeSequences() + bool highlightEscapeSequences() const {return highlight_escape;} + + //! If \a allowed is true then escape sequences are allowed in verbatim + //! strings. The default is false. + //! + //! \sa verbatimStringEscapeSequencesAllowed() + void setVerbatimStringEscapeSequencesAllowed(bool allowed); + + //! Returns true if hash quoted strings should be highlighted. + //! + //! \sa setVerbatimStringEscapeSequencesAllowed() + bool verbatimStringEscapeSequencesAllowed() const {return vs_escape;} + +public slots: + //! If \a fold is true then "} else {" lines can be folded. The + //! default is false. + //! + //! \sa foldAtElse() + virtual void setFoldAtElse(bool fold); + + //! If \a fold is true then multi-line comment blocks can be folded. + //! The default is false. + //! + //! \sa foldComments() + virtual void setFoldComments(bool fold); + + //! If \a fold is true then trailing blank lines are included in a fold + //! block. The default is true. + //! + //! \sa foldCompact() + virtual void setFoldCompact(bool fold); + + //! If \a fold is true then preprocessor blocks can be folded. The + //! default is true. + //! + //! \sa foldPreprocessor() + virtual void setFoldPreprocessor(bool fold); + + //! If \a style is true then preprocessor lines (after the preprocessor + //! directive) are styled. The default is false. + //! + //! \sa stylePreprocessor() + virtual void setStylePreprocessor(bool style); + +protected: + //! The lexer's properties are read from the settings \a qs. \a prefix + //! (which has a trailing '/') should be used as a prefix to the key of + //! each setting. true is returned if there is no error. + //! + //! \sa writeProperties() + bool readProperties(QSettings &qs,const QString &prefix); + + //! The lexer's properties are written to the settings \a qs. + //! \a prefix (which has a trailing '/') should be used as a prefix to + //! the key of each setting. true is returned if there is no error. + //! + //! \sa readProperties() + bool writeProperties(QSettings &qs,const QString &prefix) const; + +private: + void setAtElseProp(); + void setCommentProp(); + void setCompactProp(); + void setPreprocProp(); + void setStylePreprocProp(); + void setDollarsProp(); + void setHighlightTripleProp(); + void setHighlightHashProp(); + void setHighlightBackProp(); + void setHighlightEscapeProp(); + void setVerbatimStringEscapeProp(); + + bool fold_atelse; + bool fold_comments; + bool fold_compact; + bool fold_preproc; + bool style_preproc; + bool dollars; + bool highlight_triple; + bool highlight_hash; + bool highlight_back; + bool highlight_escape; + bool vs_escape; + + bool nocase; + + QsciLexerCPP(const QsciLexerCPP &); + QsciLexerCPP &operator=(const QsciLexerCPP &); +}; + +#endif diff --git a/libs/qscintilla/Qt4Qt5/Qsci/qscilexerhtml.h b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerhtml.h new file mode 100644 index 00000000..33d24fa9 --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerhtml.h @@ -0,0 +1,532 @@ +// This defines the interface to the QsciLexerHTML class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXERHTML_H +#define QSCILEXERHTML_H + +#include + +#include +#include + + +//! \brief The QsciLexerHTML class encapsulates the Scintilla HTML lexer. +class QSCINTILLA_EXPORT QsciLexerHTML : public QsciLexer +{ + Q_OBJECT + +public: + //! This enum defines the meanings of the different styles used by the + //! HTML lexer. + enum { + //! The default. + Default = 0, + + //! A tag. + Tag = 1, + + //! An unknown tag. + UnknownTag = 2, + + //! An attribute. + Attribute = 3, + + //! An unknown attribute. + UnknownAttribute = 4, + + //! An HTML number. + HTMLNumber = 5, + + //! An HTML double-quoted string. + HTMLDoubleQuotedString = 6, + + //! An HTML single-quoted string. + HTMLSingleQuotedString = 7, + + //! Other text within a tag. + OtherInTag = 8, + + //! An HTML comment. + HTMLComment = 9, + + //! An entity. + Entity = 10, + + //! The end of an XML style tag. + XMLTagEnd = 11, + + //! The start of an XML fragment. + XMLStart = 12, + + //! The end of an XML fragment. + XMLEnd = 13, + + //! A script tag. + Script = 14, + + //! The start of an ASP fragment with @. + ASPAtStart = 15, + + //! The start of an ASP fragment. + ASPStart = 16, + + //! CDATA. + CDATA = 17, + + //! The start of a PHP fragment. + PHPStart = 18, + + //! An unquoted HTML value. + HTMLValue = 19, + + //! An ASP X-Code comment. + ASPXCComment = 20, + + //! The default for SGML. + SGMLDefault = 21, + + //! An SGML command. + SGMLCommand = 22, + + //! The first parameter of an SGML command. + SGMLParameter = 23, + + //! An SGML double-quoted string. + SGMLDoubleQuotedString = 24, + + //! An SGML single-quoted string. + SGMLSingleQuotedString = 25, + + //! An SGML error. + SGMLError = 26, + + //! An SGML special entity. + SGMLSpecial = 27, + + //! An SGML entity. + SGMLEntity = 28, + + //! An SGML comment. + SGMLComment = 29, + + //! A comment with the first parameter of an SGML command. + SGMLParameterComment = 30, + + //! The default for an SGML block. + SGMLBlockDefault = 31, + + //! The start of a JavaScript fragment. + JavaScriptStart = 40, + + //! The default for JavaScript. + JavaScriptDefault = 41, + + //! A JavaScript comment. + JavaScriptComment = 42, + + //! A JavaScript line comment. + JavaScriptCommentLine = 43, + + //! A JavaDoc style JavaScript comment. + JavaScriptCommentDoc = 44, + + //! A JavaScript number. + JavaScriptNumber = 45, + + //! A JavaScript word. + JavaScriptWord = 46, + + //! A JavaScript keyword. + JavaScriptKeyword = 47, + + //! A JavaScript double-quoted string. + JavaScriptDoubleQuotedString = 48, + + //! A JavaScript single-quoted string. + JavaScriptSingleQuotedString = 49, + + //! A JavaScript symbol. + JavaScriptSymbol = 50, + + //! The end of a JavaScript line where a string is not closed. + JavaScriptUnclosedString = 51, + + //! A JavaScript regular expression. + JavaScriptRegex = 52, + + //! The start of an ASP JavaScript fragment. + ASPJavaScriptStart = 55, + + //! The default for ASP JavaScript. + ASPJavaScriptDefault = 56, + + //! An ASP JavaScript comment. + ASPJavaScriptComment = 57, + + //! An ASP JavaScript line comment. + ASPJavaScriptCommentLine = 58, + + //! An ASP JavaDoc style JavaScript comment. + ASPJavaScriptCommentDoc = 59, + + //! An ASP JavaScript number. + ASPJavaScriptNumber = 60, + + //! An ASP JavaScript word. + ASPJavaScriptWord = 61, + + //! An ASP JavaScript keyword. + ASPJavaScriptKeyword = 62, + + //! An ASP JavaScript double-quoted string. + ASPJavaScriptDoubleQuotedString = 63, + + //! An ASP JavaScript single-quoted string. + ASPJavaScriptSingleQuotedString = 64, + + //! An ASP JavaScript symbol. + ASPJavaScriptSymbol = 65, + + //! The end of an ASP JavaScript line where a string is not + //! closed. + ASPJavaScriptUnclosedString = 66, + + //! An ASP JavaScript regular expression. + ASPJavaScriptRegex = 67, + + //! The start of a VBScript fragment. + VBScriptStart = 70, + + //! The default for VBScript. + VBScriptDefault = 71, + + //! A VBScript comment. + VBScriptComment = 72, + + //! A VBScript number. + VBScriptNumber = 73, + + //! A VBScript keyword. + VBScriptKeyword = 74, + + //! A VBScript string. + VBScriptString = 75, + + //! A VBScript identifier. + VBScriptIdentifier = 76, + + //! The end of a VBScript line where a string is not closed. + VBScriptUnclosedString = 77, + + //! The start of an ASP VBScript fragment. + ASPVBScriptStart = 80, + + //! The default for ASP VBScript. + ASPVBScriptDefault = 81, + + //! An ASP VBScript comment. + ASPVBScriptComment = 82, + + //! An ASP VBScript number. + ASPVBScriptNumber = 83, + + //! An ASP VBScript keyword. + ASPVBScriptKeyword = 84, + + //! An ASP VBScript string. + ASPVBScriptString = 85, + + //! An ASP VBScript identifier. + ASPVBScriptIdentifier = 86, + + //! The end of an ASP VBScript line where a string is not + //! closed. + ASPVBScriptUnclosedString = 87, + + //! The start of a Python fragment. + PythonStart = 90, + + //! The default for Python. + PythonDefault = 91, + + //! A Python comment. + PythonComment = 92, + + //! A Python number. + PythonNumber = 93, + + //! A Python double-quoted string. + PythonDoubleQuotedString = 94, + + //! A Python single-quoted string. + PythonSingleQuotedString = 95, + + //! A Python keyword. + PythonKeyword = 96, + + //! A Python triple single-quoted string. + PythonTripleSingleQuotedString = 97, + + //! A Python triple double-quoted string. + PythonTripleDoubleQuotedString = 98, + + //! The name of a Python class. + PythonClassName = 99, + + //! The name of a Python function or method. + PythonFunctionMethodName = 100, + + //! A Python operator. + PythonOperator = 101, + + //! A Python identifier. + PythonIdentifier = 102, + + //! The start of an ASP Python fragment. + ASPPythonStart = 105, + + //! The default for ASP Python. + ASPPythonDefault = 106, + + //! An ASP Python comment. + ASPPythonComment = 107, + + //! An ASP Python number. + ASPPythonNumber = 108, + + //! An ASP Python double-quoted string. + ASPPythonDoubleQuotedString = 109, + + //! An ASP Python single-quoted string. + ASPPythonSingleQuotedString = 110, + + //! An ASP Python keyword. + ASPPythonKeyword = 111, + + //! An ASP Python triple single-quoted string. + ASPPythonTripleSingleQuotedString = 112, + + //! An ASP Python triple double-quoted string. + ASPPythonTripleDoubleQuotedString = 113, + + //! The name of an ASP Python class. + ASPPythonClassName = 114, + + //! The name of an ASP Python function or method. + ASPPythonFunctionMethodName = 115, + + //! An ASP Python operator. + ASPPythonOperator = 116, + + //! An ASP Python identifier + ASPPythonIdentifier = 117, + + //! The default for PHP. + PHPDefault = 118, + + //! A PHP double-quoted string. + PHPDoubleQuotedString = 119, + + //! A PHP single-quoted string. + PHPSingleQuotedString = 120, + + //! A PHP keyword. + PHPKeyword = 121, + + //! A PHP number. + PHPNumber = 122, + + //! A PHP variable. + PHPVariable = 123, + + //! A PHP comment. + PHPComment = 124, + + //! A PHP line comment. + PHPCommentLine = 125, + + //! A PHP double-quoted variable. + PHPDoubleQuotedVariable = 126, + + //! A PHP operator. + PHPOperator = 127 + }; + + //! Construct a QsciLexerHTML with parent \a parent. \a parent is + //! typically the QsciScintilla instance. + QsciLexerHTML(QObject *parent = 0); + + //! Destroys the QsciLexerHTML instance. + virtual ~QsciLexerHTML(); + + //! Returns the name of the language. + const char *language() const; + + //! Returns the name of the lexer. Some lexers support a number of + //! languages. + const char *lexer() const; + + //! \internal Returns the auto-completion fillup characters. + const char *autoCompletionFillups() const; + + //! Returns the string of characters that comprise a word. + const char *wordCharacters() const; + + //! Returns the foreground colour of the text for style number \a style. + //! + //! \sa defaultPaper() + QColor defaultColor(int style) const; + + //! Returns the end-of-line fill for style number \a style. + bool defaultEolFill(int style) const; + + //! Returns the font for style number \a style. + QFont defaultFont(int style) const; + + //! Returns the background colour of the text for style number \a style. + //! + //! \sa defaultColor() + QColor defaultPaper(int style) const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. + const char *keywords(int set) const; + + //! Returns the descriptive name for style number \a style. If the + //! style is invalid for this language then an empty QString is returned. + //! This is intended to be used in user preference dialogs. + QString description(int style) const; + + //! Causes all properties to be refreshed by emitting the + //! propertyChanged() signal as required. + void refreshProperties(); + + //! Returns true if tags are case sensitive. + //! + //! \sa setCaseSensitiveTags() + bool caseSensitiveTags() const {return case_sens_tags;} + + //! If \a enabled is true then Django templates are enabled. The default + //! is false. + //! + //! \sa djangoTemplates() + void setDjangoTemplates(bool enabled); + + //! Returns true if support for Django templates is enabled. + //! + //! \sa setDjangoTemplates() + bool djangoTemplates() const {return django_templates;} + + //! Returns true if trailing blank lines are included in a fold block. + //! + //! \sa setFoldCompact() + bool foldCompact() const {return fold_compact;} + + //! Returns true if preprocessor blocks can be folded. + //! + //! \sa setFoldPreprocessor() + bool foldPreprocessor() const {return fold_preproc;} + + //! If \a fold is true then script comments can be folded. The default is + //! false. + //! + //! \sa foldScriptComments() + void setFoldScriptComments(bool fold); + + //! Returns true if script comments can be folded. + //! + //! \sa setFoldScriptComments() + bool foldScriptComments() const {return fold_script_comments;} + + //! If \a fold is true then script heredocs can be folded. The default is + //! false. + //! + //! \sa foldScriptHeredocs() + void setFoldScriptHeredocs(bool fold); + + //! Returns true if script heredocs can be folded. + //! + //! \sa setFoldScriptHeredocs() + bool foldScriptHeredocs() const {return fold_script_heredocs;} + + //! If \a enabled is true then Mako templates are enabled. The default is + //! false. + //! + //! \sa makoTemplates() + void setMakoTemplates(bool enabled); + + //! Returns true if support for Mako templates is enabled. + //! + //! \sa setMakoTemplates() + bool makoTemplates() const {return mako_templates;} + +public slots: + //! If \a fold is true then trailing blank lines are included in a fold + //! block. The default is true. + //! + //! \sa foldCompact() + virtual void setFoldCompact(bool fold); + + //! If \a fold is true then preprocessor blocks can be folded. The + //! default is false. + //! + //! \sa foldPreprocessor() + virtual void setFoldPreprocessor(bool fold); + + //! If \a sens is true then tags are case sensitive. The default is false. + //! + //! \sa caseSensitiveTags() + virtual void setCaseSensitiveTags(bool sens); + +protected: + //! The lexer's properties are read from the settings \a qs. \a prefix + //! (which has a trailing '/') should be used as a prefix to the key of + //! each setting. true is returned if there is no error. + //! + bool readProperties(QSettings &qs,const QString &prefix); + + //! The lexer's properties are written to the settings \a qs. + //! \a prefix (which has a trailing '/') should be used as a prefix to + //! the key of each setting. true is returned if there is no error. + //! + bool writeProperties(QSettings &qs,const QString &prefix) const; + +private: + void setCompactProp(); + void setPreprocProp(); + void setCaseSensTagsProp(); + void setScriptCommentsProp(); + void setScriptHeredocsProp(); + void setDjangoProp(); + void setMakoProp(); + + bool fold_compact; + bool fold_preproc; + bool case_sens_tags; + bool fold_script_comments; + bool fold_script_heredocs; + bool django_templates; + bool mako_templates; + + QsciLexerHTML(const QsciLexerHTML &); + QsciLexerHTML &operator=(const QsciLexerHTML &); +}; + +#endif diff --git a/libs/qscintilla/Qt4Qt5/Qsci/qscilexerjavascript.h b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerjavascript.h new file mode 100644 index 00000000..081030a5 --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerjavascript.h @@ -0,0 +1,81 @@ +// This defines the interface to the QsciLexerJavaScript class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXERJSCRIPT_H +#define QSCILEXERJSCRIPT_H + +#include + +#include +#include + + +//! \brief The QsciLexerJavaScript class encapsulates the Scintilla JavaScript +//! lexer. +class QSCINTILLA_EXPORT QsciLexerJavaScript : public QsciLexerCPP +{ + Q_OBJECT + +public: + //! Construct a QsciLexerJavaScript with parent \a parent. \a parent is + //! typically the QsciScintilla instance. + QsciLexerJavaScript(QObject *parent = 0); + + //! Destroys the QsciLexerJavaScript instance. + virtual ~QsciLexerJavaScript(); + + //! Returns the name of the language. + const char *language() const; + + //! Returns the foreground colour of the text for style number \a style. + //! + //! \sa defaultPaper() + QColor defaultColor(int style) const; + + //! Returns the end-of-line fill for style number \a style. + bool defaultEolFill(int style) const; + + //! Returns the font for style number \a style. + QFont defaultFont(int style) const; + + //! Returns the background colour of the text for style number \a style. + //! + //! \sa defaultColor() + QColor defaultPaper(int style) const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. + const char *keywords(int set) const; + + //! Returns the descriptive name for style number \a style. If the + //! style is invalid for this language then an empty QString is returned. + //! This is intended to be used in user preference dialogs. + QString description(int style) const; + +private: + friend class QsciLexerHTML; + + static const char *keywordClass; + + QsciLexerJavaScript(const QsciLexerJavaScript &); + QsciLexerJavaScript &operator=(const QsciLexerJavaScript &); +}; + +#endif diff --git a/libs/qscintilla/Qt4Qt5/Qsci/qscilexerpython.h b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerpython.h new file mode 100644 index 00000000..350785ca --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerpython.h @@ -0,0 +1,321 @@ +// This defines the interface to the QsciLexerPython class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXERPYTHON_H +#define QSCILEXERPYTHON_H + +#include + +#include +#include +#include "Qsci/qsciscintillabase.h" + + +//! \brief The QsciLexerPython class encapsulates the Scintilla Python lexer. +class QSCINTILLA_EXPORT QsciLexerPython : public QsciLexer +{ + Q_OBJECT + +public: + //! This enum defines the meanings of the different styles used by the + //! Python lexer. + enum { + //! The default. + Default = 0, + + //! A comment. + Comment = 1, + + //! A number. + Number = 2, + + //! A double-quoted string. + DoubleQuotedString = 3, + + //! A single-quoted string. + SingleQuotedString = 4, + + //! A keyword. + Keyword = 5, + + //! A triple single-quoted string. + TripleSingleQuotedString = 6, + + //! A triple double-quoted string. + TripleDoubleQuotedString = 7, + + //! The name of a class. + ClassName = 8, + + //! The name of a function or method. + FunctionMethodName = 9, + + //! An operator. + Operator = 10, + + //! An identifier + Identifier = 11, + + //! A comment block. + CommentBlock = 12, + + //! The end of a line where a string is not closed. + UnclosedString = 13, + + //! A highlighted identifier. These are defined by keyword set + //! 2. Reimplement keywords() to define keyword set 2. + HighlightedIdentifier = 14, + + //! A decorator. + Decorator = 15 + }; + + //! This enum defines the different conditions that can cause + //! indentations to be displayed as being bad. + enum IndentationWarning { + //! Bad indentation is not displayed differently. + NoWarning = 0, + + //! The indentation is inconsistent when compared to the + //! previous line, ie. it is made up of a different combination + //! of tabs and/or spaces. + Inconsistent = 1, + + //! The indentation is made up of spaces followed by tabs. + TabsAfterSpaces = 2, + + //! The indentation contains spaces. + Spaces = 3, + + //! The indentation contains tabs. + Tabs = 4 + }; + + //! Construct a QsciLexerPython with parent \a parent. \a parent is + //! typically the QsciScintilla instance. + QsciLexerPython(QObject *parent = 0); + + //! Destroys the QsciLexerPython instance. + virtual ~QsciLexerPython(); + + //! Returns the name of the language. + const char *language() const; + + //! Returns the name of the lexer. Some lexers support a number of + //! languages. + const char *lexer() const; + + //! \internal Returns the character sequences that can separate + //! auto-completion words. + QStringList autoCompletionWordSeparators() const; + + //! \internal Returns the number of lines prior to the current one when + //! determining the scope of a block when auto-indenting. + int blockLookback() const; + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the start of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockStart(int *style = 0) const; + + //! \internal Returns the style used for braces for brace matching. + int braceStyle() const; + + //! Returns the foreground colour of the text for style number \a style. + //! + //! \sa defaultPaper() + QColor defaultColor(int style) const; + + //! Returns the end-of-line fill for style number \a style. + bool defaultEolFill(int style) const; + + //! Returns the font for style number \a style. + QFont defaultFont(int style) const; + + //! Returns the background colour of the text for style number \a style. + //! + //! \sa defaultColor() + QColor defaultPaper(int style) const; + + //! \internal Returns the view used for indentation guides. + virtual int indentationGuideView() const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. + const char *keywords(int set) const; + + //! Returns the descriptive name for style number \a style. If the + //! style is invalid for this language then an empty QString is returned. + //! This is intended to be used in user preference dialogs. + QString description(int style) const; + + //! Causes all properties to be refreshed by emitting the + //! propertyChanged() signal as required. + void refreshProperties(); + + //! Returns true if indented comment blocks can be folded. + //! + //! \sa setFoldComments() + bool foldComments() const {return fold_comments;} + + //! If \a fold is true then trailing blank lines are included in a fold + //! block. The default is true. + //! + //! \sa foldCompact() + void setFoldCompact(bool fold); + + //! Returns true if trailing blank lines are included in a fold block. + //! + //! \sa setFoldCompact() + bool foldCompact() const {return fold_compact;} + + //! Returns true if triple quoted strings can be folded. + //! + //! \sa setFoldQuotes() + bool foldQuotes() const {return fold_quotes;} + + //! Returns the condition that will cause bad indentations to be + //! displayed. + //! + //! \sa setIndentationWarning() + QsciLexerPython::IndentationWarning indentationWarning() const {return indent_warn;} + + //! If \a enabled is true then sub-identifiers defined in keyword set 2 + //! will be highlighted. For example, if it is false and "open" is defined + //! in keyword set 2 then "foo.open" will not be highlighted. The default + //! is true. + //! + //! \sa highlightSubidentifiers() + void setHighlightSubidentifiers(bool enabled); + + //! Returns true if string literals are allowed to span newline characters. + //! + //! \sa setHighlightSubidentifiers() + bool highlightSubidentifiers() const {return highlight_subids;} + + //! If \a allowed is true then string literals are allowed to span newline + //! characters. The default is false. + //! + //! \sa stringsOverNewlineAllowed() + void setStringsOverNewlineAllowed(bool allowed); + + //! Returns true if string literals are allowed to span newline characters. + //! + //! \sa setStringsOverNewlineAllowed() + bool stringsOverNewlineAllowed() const {return strings_over_newline;} + + //! If \a allowed is true then Python v2 unicode string literals (e.g. + //! u"utf8") are allowed. The default is true. + //! + //! \sa v2UnicodeAllowed() + void setV2UnicodeAllowed(bool allowed); + + //! Returns true if Python v2 unicode string literals (e.g. u"utf8") are + //! allowed. + //! + //! \sa setV2UnicodeAllowed() + bool v2UnicodeAllowed() const {return v2_unicode;} + + //! If \a allowed is true then Python v3 binary and octal literals (e.g. + //! 0b1011, 0o712) are allowed. The default is true. + //! + //! \sa v3BinaryOctalAllowed() + void setV3BinaryOctalAllowed(bool allowed); + + //! Returns true if Python v3 binary and octal literals (e.g. 0b1011, + //! 0o712) are allowed. + //! + //! \sa setV3BinaryOctalAllowed() + bool v3BinaryOctalAllowed() const {return v3_binary_octal;} + + //! If \a allowed is true then Python v3 bytes string literals (e.g. + //! b"bytes") are allowed. The default is true. + //! + //! \sa v3BytesAllowed() + void setV3BytesAllowed(bool allowed); + + //! Returns true if Python v3 bytes string literals (e.g. b"bytes") are + //! allowed. + //! + //! \sa setV3BytesAllowed() + bool v3BytesAllowed() const {return v3_bytes;} + +public slots: + //! If \a fold is true then indented comment blocks can be folded. The + //! default is false. + //! + //! \sa foldComments() + virtual void setFoldComments(bool fold); + + //! If \a fold is true then triple quoted strings can be folded. The + //! default is false. + //! + //! \sa foldQuotes() + virtual void setFoldQuotes(bool fold); + + //! Sets the condition that will cause bad indentations to be + //! displayed. + //! + //! \sa indentationWarning() + virtual void setIndentationWarning(QsciLexerPython::IndentationWarning warn); + +protected: + //! The lexer's properties are read from the settings \a qs. \a prefix + //! (which has a trailing '/') should be used as a prefix to the key of + //! each setting. true is returned if there is no error. + //! + bool readProperties(QSettings &qs,const QString &prefix); + + //! The lexer's properties are written to the settings \a qs. + //! \a prefix (which has a trailing '/') should be used as a prefix to + //! the key of each setting. true is returned if there is no error. + //! + bool writeProperties(QSettings &qs,const QString &prefix) const; + +private: + void setCommentProp(); + void setCompactProp(); + void setQuotesProp(); + void setTabWhingeProp(); + void setStringsOverNewlineProp(); + void setV2UnicodeProp(); + void setV3BinaryOctalProp(); + void setV3BytesProp(); + void setHighlightSubidsProp(); + + bool fold_comments; + bool fold_compact; + bool fold_quotes; + IndentationWarning indent_warn; + bool strings_over_newline; + bool v2_unicode; + bool v3_binary_octal; + bool v3_bytes; + bool highlight_subids; + + friend class QsciLexerHTML; + + static const char *keywordClass; + + QsciLexerPython(const QsciLexerPython &); + QsciLexerPython &operator=(const QsciLexerPython &); +}; + +#endif diff --git a/libs/qscintilla/Qt4Qt5/Qsci/qscilexerxml.h b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerxml.h new file mode 100644 index 00000000..2fc7f209 --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/Qsci/qscilexerxml.h @@ -0,0 +1,106 @@ +// This defines the interface to the QsciLexerXML class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXERXML_H +#define QSCILEXERXML_H + +#include + +#include +#include + + +//! \brief The QsciLexerXML class encapsulates the Scintilla XML lexer. +class QSCINTILLA_EXPORT QsciLexerXML : public QsciLexerHTML +{ + Q_OBJECT + +public: + //! Construct a QsciLexerXML with parent \a parent. \a parent is typically + //! the QsciScintilla instance. + QsciLexerXML(QObject *parent = 0); + + //! Destroys the QsciLexerXML instance. + virtual ~QsciLexerXML(); + + //! Returns the name of the language. + const char *language() const; + + //! Returns the name of the lexer. Some lexers support a number of + //! languages. + const char *lexer() const; + + //! Returns the foreground colour of the text for style number \a style. + //! + //! \sa defaultPaper() + QColor defaultColor(int style) const; + + //! Returns the end-of-line fill for style number \a style. + bool defaultEolFill(int style) const; + + //! Returns the font for style number \a style. + QFont defaultFont(int style) const; + + //! Returns the background colour of the text for style number \a style. + //! + //! \sa defaultColor() + QColor defaultPaper(int style) const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. + const char *keywords(int set) const; + + //! Causes all properties to be refreshed by emitting the + //! propertyChanged() signal as required. + void refreshProperties(); + + //! If \a allowed is true then scripts are styled. The default is true. + //! + //! \sa scriptsStyled() + void setScriptsStyled(bool styled); + + //! Returns true if scripts are styled. + //! + //! \sa setScriptsStyled() + bool scriptsStyled() const; + +protected: + //! The lexer's properties are read from the settings \a qs. \a prefix + //! (which has a trailing '/') should be used as a prefix to the key of + //! each setting. true is returned if there is no error. + //! + bool readProperties(QSettings &qs, const QString &prefix); + + //! The lexer's properties are written to the settings \a qs. + //! \a prefix (which has a trailing '/') should be used as a prefix to + //! the key of each setting. true is returned if there is no error. + //! + bool writeProperties(QSettings &qs, const QString &prefix) const; + +private: + void setScriptsProp(); + + bool scripts; + + QsciLexerXML(const QsciLexerXML &); + QsciLexerXML &operator=(const QsciLexerXML &); +}; + +#endif diff --git a/libs/qscintilla/Qt4Qt5/qscilexercpp.cpp b/libs/qscintilla/Qt4Qt5/qscilexercpp.cpp new file mode 100644 index 00000000..6316018e --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/qscilexercpp.cpp @@ -0,0 +1,801 @@ +// This module implements the QsciLexerCPP class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "Qsci/qscilexercpp.h" + +#include +#include +#include + + +// The ctor. +QsciLexerCPP::QsciLexerCPP(QObject *parent, bool caseInsensitiveKeywords) + : QsciLexer(parent), + fold_atelse(false), fold_comments(false), fold_compact(true), + fold_preproc(true), style_preproc(false), dollars(true), + highlight_triple(false), highlight_hash(false), highlight_back(false), + highlight_escape(false), vs_escape(false), + nocase(caseInsensitiveKeywords) +{ +} + + +// The dtor. +QsciLexerCPP::~QsciLexerCPP() +{ +} + + +// Returns the language name. +const char *QsciLexerCPP::language() const +{ + return "C++"; +} + + +// Returns the lexer name. +const char *QsciLexerCPP::lexer() const +{ + return (nocase ? "cppnocase" : "cpp"); +} + + +// Return the set of character sequences that can separate auto-completion +// words. +QStringList QsciLexerCPP::autoCompletionWordSeparators() const +{ + QStringList wl; + + wl << "::" << "->" << "."; + + return wl; +} + + +// Return the list of keywords that can start a block. +const char *QsciLexerCPP::blockStartKeyword(int *style) const +{ + if (style) + *style = Keyword; + + return "case catch class default do else finally for if private " + "protected public struct try union while"; +} + + +// Return the list of characters that can start a block. +const char *QsciLexerCPP::blockStart(int *style) const +{ + if (style) + *style = Operator; + + return "{"; +} + + +// Return the list of characters that can end a block. +const char *QsciLexerCPP::blockEnd(int *style) const +{ + if (style) + *style = Operator; + + return "}"; +} + + +// Return the style used for braces. +int QsciLexerCPP::braceStyle() const +{ + return Operator; +} + + +// Return the string of characters that comprise a word. +const char *QsciLexerCPP::wordCharacters() const +{ + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_#"; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexerCPP::defaultColor(int style) const +{ + switch (style) + { + case Default: + return QColor(0x80, 0x80, 0x80); + + case Comment: + case CommentLine: + return QColor(0x00, 0x7f, 0x00); + + case CommentDoc: + case CommentLineDoc: + case PreProcessorCommentLineDoc: + return QColor(0x3f, 0x70, 0x3f); + + case Number: + return QColor(0x00, 0x7f, 0x7f); + + case Keyword: + return QColor(0x00, 0x00, 0x7f); + + case DoubleQuotedString: + case SingleQuotedString: + case RawString: + return QColor(0x7f, 0x00, 0x7f); + + case PreProcessor: + return QColor(0x7f, 0x7f, 0x00); + + case Operator: + case UnclosedString: + return QColor(0x00, 0x00, 0x00); + + case VerbatimString: + case TripleQuotedVerbatimString: + case HashQuotedString: + return QColor(0x00, 0x7f, 0x00); + + case Regex: + return QColor(0x3f, 0x7f, 0x3f); + + case CommentDocKeyword: + return QColor(0x30, 0x60, 0xa0); + + case CommentDocKeywordError: + return QColor(0x80, 0x40, 0x20); + + case PreProcessorComment: + return QColor(0x65, 0x99, 0x00); + + case InactiveDefault: + case InactiveUUID: + case InactiveCommentLineDoc: + case InactiveKeywordSet2: + case InactiveCommentDocKeyword: + case InactiveCommentDocKeywordError: + case InactivePreProcessorCommentLineDoc: + return QColor(0xc0, 0xc0, 0xc0); + + case InactiveComment: + case InactiveCommentLine: + case InactiveNumber: + case InactiveVerbatimString: + case InactiveTripleQuotedVerbatimString: + case InactiveHashQuotedString: + return QColor(0x90, 0xb0, 0x90); + + case InactiveCommentDoc: + return QColor(0xd0, 0xd0, 0xd0); + + case InactiveKeyword: + return QColor(0x90, 0x90, 0xb0); + + case InactiveDoubleQuotedString: + case InactiveSingleQuotedString: + case InactiveRawString: + return QColor(0xb0, 0x90, 0xb0); + + case InactivePreProcessor: + return QColor(0xb0, 0xb0, 0x90); + + case InactiveOperator: + case InactiveIdentifier: + case InactiveGlobalClass: + return QColor(0xb0, 0xb0, 0xb0); + + case InactiveUnclosedString: + return QColor(0x00, 0x00, 0x00); + + case InactiveRegex: + return QColor(0x7f, 0xaf, 0x7f); + + case InactivePreProcessorComment: + return QColor(0xa0, 0xc0, 0x90); + + case UserLiteral: + return QColor(0xc0, 0x60, 0x00); + + case InactiveUserLiteral: + return QColor(0xd7, 0xa0, 0x90); + + case TaskMarker: + return QColor(0xbe, 0x07, 0xff); + + case InactiveTaskMarker: + return QColor(0xc3, 0xa1, 0xcf); + } + + return QsciLexer::defaultColor(style); +} + + +// Returns the end-of-line fill for a style. +bool QsciLexerCPP::defaultEolFill(int style) const +{ + switch (style) + { + case UnclosedString: + case InactiveUnclosedString: + case VerbatimString: + case InactiveVerbatimString: + case Regex: + case InactiveRegex: + case TripleQuotedVerbatimString: + case InactiveTripleQuotedVerbatimString: + case HashQuotedString: + case InactiveHashQuotedString: + return true; + } + + return QsciLexer::defaultEolFill(style); +} + + +// Returns the font of the text for a style. +QFont QsciLexerCPP::defaultFont(int style) const +{ + QFont f; + + switch (style) + { + case Comment: + case InactiveComment: + case CommentLine: + case InactiveCommentLine: + case CommentDoc: + case InactiveCommentDoc: + case CommentLineDoc: + case InactiveCommentLineDoc: + case CommentDocKeyword: + case InactiveCommentDocKeyword: + case CommentDocKeywordError: + case InactiveCommentDocKeywordError: + case TaskMarker: + case InactiveTaskMarker: +#if defined(Q_OS_WIN) + f = QFont("Comic Sans MS",9); +#elif defined(Q_OS_MAC) + f = QFont("Comic Sans MS", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + break; + + case Keyword: + case InactiveKeyword: + case Operator: + case InactiveOperator: + f = QsciLexer::defaultFont(style); + f.setBold(true); + break; + + case DoubleQuotedString: + case InactiveDoubleQuotedString: + case SingleQuotedString: + case InactiveSingleQuotedString: + case UnclosedString: + case InactiveUnclosedString: + case VerbatimString: + case InactiveVerbatimString: + case Regex: + case InactiveRegex: + case TripleQuotedVerbatimString: + case InactiveTripleQuotedVerbatimString: + case HashQuotedString: + case InactiveHashQuotedString: +#if defined(Q_OS_WIN) + f = QFont("Courier New",10); +#elif defined(Q_OS_MAC) + f = QFont("Courier", 12); +#else + f = QFont("Bitstream Vera Sans Mono",9); +#endif + break; + + default: + f = QsciLexer::defaultFont(style); + } + + return f; +} + + +// Returns the set of keywords. +const char *QsciLexerCPP::keywords(int set) const +{ + if (set == 1) + return + "and and_eq asm auto bitand bitor bool break case " + "catch char class compl const const_cast continue " + "default delete do double dynamic_cast else enum " + "explicit export extern false float for friend goto if " + "inline int long mutable namespace new not not_eq " + "operator or or_eq private protected public register " + "reinterpret_cast return short signed sizeof static " + "static_cast struct switch template this throw true " + "try typedef typeid typename union unsigned using " + "virtual void volatile wchar_t while xor xor_eq"; + + if (set == 3) + return + "a addindex addtogroup anchor arg attention author b " + "brief bug c class code date def defgroup deprecated " + "dontinclude e em endcode endhtmlonly endif " + "endlatexonly endlink endverbatim enum example " + "exception f$ f[ f] file fn hideinitializer " + "htmlinclude htmlonly if image include ingroup " + "internal invariant interface latexonly li line link " + "mainpage name namespace nosubgrouping note overload " + "p page par param post pre ref relates remarks return " + "retval sa section see showinitializer since skip " + "skipline struct subsection test throw todo typedef " + "union until var verbatim verbinclude version warning " + "weakgroup $ @ \\ & < > # { }"; + + return 0; +} + + +// Returns the user name of a style. +QString QsciLexerCPP::description(int style) const +{ + switch (style) + { + case Default: + return tr("Default"); + + case InactiveDefault: + return tr("Inactive default"); + + case Comment: + return tr("C comment"); + + case InactiveComment: + return tr("Inactive C comment"); + + case CommentLine: + return tr("C++ comment"); + + case InactiveCommentLine: + return tr("Inactive C++ comment"); + + case CommentDoc: + return tr("JavaDoc style C comment"); + + case InactiveCommentDoc: + return tr("Inactive JavaDoc style C comment"); + + case Number: + return tr("Number"); + + case InactiveNumber: + return tr("Inactive number"); + + case Keyword: + return tr("Keyword"); + + case InactiveKeyword: + return tr("Inactive keyword"); + + case DoubleQuotedString: + return tr("Double-quoted string"); + + case InactiveDoubleQuotedString: + return tr("Inactive double-quoted string"); + + case SingleQuotedString: + return tr("Single-quoted string"); + + case InactiveSingleQuotedString: + return tr("Inactive single-quoted string"); + + case UUID: + return tr("IDL UUID"); + + case InactiveUUID: + return tr("Inactive IDL UUID"); + + case PreProcessor: + return tr("Pre-processor block"); + + case InactivePreProcessor: + return tr("Inactive pre-processor block"); + + case Operator: + return tr("Operator"); + + case InactiveOperator: + return tr("Inactive operator"); + + case Identifier: + return tr("Identifier"); + + case InactiveIdentifier: + return tr("Inactive identifier"); + + case UnclosedString: + return tr("Unclosed string"); + + case InactiveUnclosedString: + return tr("Inactive unclosed string"); + + case VerbatimString: + return tr("C# verbatim string"); + + case InactiveVerbatimString: + return tr("Inactive C# verbatim string"); + + case Regex: + return tr("JavaScript regular expression"); + + case InactiveRegex: + return tr("Inactive JavaScript regular expression"); + + case CommentLineDoc: + return tr("JavaDoc style C++ comment"); + + case InactiveCommentLineDoc: + return tr("Inactive JavaDoc style C++ comment"); + + case KeywordSet2: + return tr("Secondary keywords and identifiers"); + + case InactiveKeywordSet2: + return tr("Inactive secondary keywords and identifiers"); + + case CommentDocKeyword: + return tr("JavaDoc keyword"); + + case InactiveCommentDocKeyword: + return tr("Inactive JavaDoc keyword"); + + case CommentDocKeywordError: + return tr("JavaDoc keyword error"); + + case InactiveCommentDocKeywordError: + return tr("Inactive JavaDoc keyword error"); + + case GlobalClass: + return tr("Global classes and typedefs"); + + case InactiveGlobalClass: + return tr("Inactive global classes and typedefs"); + + case RawString: + return tr("C++ raw string"); + + case InactiveRawString: + return tr("Inactive C++ raw string"); + + case TripleQuotedVerbatimString: + return tr("Vala triple-quoted verbatim string"); + + case InactiveTripleQuotedVerbatimString: + return tr("Inactive Vala triple-quoted verbatim string"); + + case HashQuotedString: + return tr("Pike hash-quoted string"); + + case InactiveHashQuotedString: + return tr("Inactive Pike hash-quoted string"); + + case PreProcessorComment: + return tr("Pre-processor C comment"); + + case InactivePreProcessorComment: + return tr("Inactive pre-processor C comment"); + + case PreProcessorCommentLineDoc: + return tr("JavaDoc style pre-processor comment"); + + case InactivePreProcessorCommentLineDoc: + return tr("Inactive JavaDoc style pre-processor comment"); + + case UserLiteral: + return tr("User-defined literal"); + + case InactiveUserLiteral: + return tr("Inactive user-defined literal"); + + case TaskMarker: + return tr("Task marker"); + + case InactiveTaskMarker: + return tr("Inactive task marker"); + + case EscapeSequence: + return tr("Escape sequence"); + + case InactiveEscapeSequence: + return tr("Inactive escape sequence"); + } + + return QString(); +} + + +// Returns the background colour of the text for a style. +QColor QsciLexerCPP::defaultPaper(int style) const +{ + switch (style) + { + case UnclosedString: + case InactiveUnclosedString: + return QColor(0xe0,0xc0,0xe0); + + case VerbatimString: + case InactiveVerbatimString: + case TripleQuotedVerbatimString: + case InactiveTripleQuotedVerbatimString: + return QColor(0xe0,0xff,0xe0); + + case Regex: + case InactiveRegex: + return QColor(0xe0,0xf0,0xe0); + + case RawString: + case InactiveRawString: + return QColor(0xff,0xf3,0xff); + + case HashQuotedString: + case InactiveHashQuotedString: + return QColor(0xe7,0xff,0xd7); + } + + return QsciLexer::defaultPaper(style); +} + + +// Refresh all properties. +void QsciLexerCPP::refreshProperties() +{ + setAtElseProp(); + setCommentProp(); + setCompactProp(); + setPreprocProp(); + setStylePreprocProp(); + setDollarsProp(); + setHighlightTripleProp(); + setHighlightHashProp(); + setHighlightBackProp(); + setHighlightEscapeProp(); + setVerbatimStringEscapeProp(); +} + + +// Read properties from the settings. +bool QsciLexerCPP::readProperties(QSettings &qs,const QString &prefix) +{ + fold_atelse = qs.value(prefix + "foldatelse", false).toBool(); + fold_comments = qs.value(prefix + "foldcomments", false).toBool(); + fold_compact = qs.value(prefix + "foldcompact", true).toBool(); + fold_preproc = qs.value(prefix + "foldpreprocessor", true).toBool(); + style_preproc = qs.value(prefix + "stylepreprocessor", false).toBool(); + dollars = qs.value(prefix + "dollars", true).toBool(); + highlight_triple = qs.value(prefix + "highlighttriple", false).toBool(); + highlight_hash = qs.value(prefix + "highlighthash", false).toBool(); + highlight_back = qs.value(prefix + "highlightback", false).toBool(); + highlight_escape = qs.value(prefix + "highlightescape", false).toBool(); + vs_escape = qs.value(prefix + "verbatimstringescape", false).toBool(); + + return true; +} + + +// Write properties to the settings. +bool QsciLexerCPP::writeProperties(QSettings &qs,const QString &prefix) const +{ + qs.setValue(prefix + "foldatelse", fold_atelse); + qs.setValue(prefix + "foldcomments", fold_comments); + qs.setValue(prefix + "foldcompact", fold_compact); + qs.setValue(prefix + "foldpreprocessor", fold_preproc); + qs.setValue(prefix + "stylepreprocessor", style_preproc); + qs.setValue(prefix + "dollars", dollars); + qs.setValue(prefix + "highlighttriple", highlight_triple); + qs.setValue(prefix + "highlighthash", highlight_hash); + qs.setValue(prefix + "highlightback", highlight_back); + qs.setValue(prefix + "highlightescape", highlight_escape); + qs.setValue(prefix + "verbatimstringescape", vs_escape); + + return true; +} + + +// Set if else can be folded. +void QsciLexerCPP::setFoldAtElse(bool fold) +{ + fold_atelse = fold; + + setAtElseProp(); +} + + +// Set the "fold.at.else" property. +void QsciLexerCPP::setAtElseProp() +{ + emit propertyChanged("fold.at.else",(fold_atelse ? "1" : "0")); +} + + +// Set if comments can be folded. +void QsciLexerCPP::setFoldComments(bool fold) +{ + fold_comments = fold; + + setCommentProp(); +} + + +// Set the "fold.comment" property. +void QsciLexerCPP::setCommentProp() +{ + emit propertyChanged("fold.comment",(fold_comments ? "1" : "0")); +} + + +// Set if folds are compact +void QsciLexerCPP::setFoldCompact(bool fold) +{ + fold_compact = fold; + + setCompactProp(); +} + + +// Set the "fold.compact" property. +void QsciLexerCPP::setCompactProp() +{ + emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); +} + + +// Set if preprocessor blocks can be folded. +void QsciLexerCPP::setFoldPreprocessor(bool fold) +{ + fold_preproc = fold; + + setPreprocProp(); +} + + +// Set the "fold.preprocessor" property. +void QsciLexerCPP::setPreprocProp() +{ + emit propertyChanged("fold.preprocessor",(fold_preproc ? "1" : "0")); +} + + +// Set if preprocessor lines are styled. +void QsciLexerCPP::setStylePreprocessor(bool style) +{ + style_preproc = style; + + setStylePreprocProp(); +} + + +// Set the "styling.within.preprocessor" property. +void QsciLexerCPP::setStylePreprocProp() +{ + emit propertyChanged("styling.within.preprocessor",(style_preproc ? "1" : "0")); +} + + +// Set if '$' characters are allowed. +void QsciLexerCPP::setDollarsAllowed(bool allowed) +{ + dollars = allowed; + + setDollarsProp(); +} + + +// Set the "lexer.cpp.allow.dollars" property. +void QsciLexerCPP::setDollarsProp() +{ + emit propertyChanged("lexer.cpp.allow.dollars",(dollars ? "1" : "0")); +} + + +// Set if triple quoted strings are highlighted. +void QsciLexerCPP::setHighlightTripleQuotedStrings(bool enabled) +{ + highlight_triple = enabled; + + setHighlightTripleProp(); +} + + +// Set the "lexer.cpp.triplequoted.strings" property. +void QsciLexerCPP::setHighlightTripleProp() +{ + emit propertyChanged("lexer.cpp.triplequoted.strings", + (highlight_triple ? "1" : "0")); +} + + +// Set if hash quoted strings are highlighted. +void QsciLexerCPP::setHighlightHashQuotedStrings(bool enabled) +{ + highlight_hash = enabled; + + setHighlightHashProp(); +} + + +// Set the "lexer.cpp.hashquoted.strings" property. +void QsciLexerCPP::setHighlightHashProp() +{ + emit propertyChanged("lexer.cpp.hashquoted.strings", + (highlight_hash ? "1" : "0")); +} + + +// Set if back-quoted strings are highlighted. +void QsciLexerCPP::setHighlightBackQuotedStrings(bool enabled) +{ + highlight_back = enabled; + + setHighlightBackProp(); +} + + +// Set the "lexer.cpp.backquoted.strings" property. +void QsciLexerCPP::setHighlightBackProp() +{ + emit propertyChanged("lexer.cpp.backquoted.strings", + (highlight_back ? "1" : "0")); +} + + +// Set if escape sequences in strings are highlighted. +void QsciLexerCPP::setHighlightEscapeSequences(bool enabled) +{ + highlight_escape = enabled; + + setHighlightEscapeProp(); +} + + +// Set the "lexer.cpp.escape.sequence" property. +void QsciLexerCPP::setHighlightEscapeProp() +{ + emit propertyChanged("lexer.cpp.escape.sequence", + (highlight_escape ? "1" : "0")); +} + + +// Set if escape sequences in verbatim strings are allowed. +void QsciLexerCPP::setVerbatimStringEscapeSequencesAllowed(bool allowed) +{ + vs_escape = allowed; + + setVerbatimStringEscapeProp(); +} + + +// Set the "lexer.cpp.verbatim.strings.allow.escapes" property. +void QsciLexerCPP::setVerbatimStringEscapeProp() +{ + emit propertyChanged("lexer.cpp.verbatim.strings.allow.escapes", + (vs_escape ? "1" : "0")); +} diff --git a/libs/qscintilla/Qt4Qt5/qscilexerhtml.cpp b/libs/qscintilla/Qt4Qt5/qscilexerhtml.cpp new file mode 100644 index 00000000..0df3a6c8 --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/qscilexerhtml.cpp @@ -0,0 +1,1181 @@ +// This module implements the QsciLexerHTML class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "Qsci/qscilexerhtml.h" + +#include +#include +#include + +#include "Qsci/qscilexerjavascript.h" +#include "Qsci/qscilexerpython.h" + + +// The ctor. +QsciLexerHTML::QsciLexerHTML(QObject *parent) + : QsciLexer(parent), + fold_compact(true), fold_preproc(true), case_sens_tags(false), + fold_script_comments(false), fold_script_heredocs(false), + django_templates(false), mako_templates(false) +{ +} + + +// The dtor. +QsciLexerHTML::~QsciLexerHTML() +{ +} + + +// Returns the language name. +const char *QsciLexerHTML::language() const +{ + return "HTML"; +} + + +// Returns the lexer name. +const char *QsciLexerHTML::lexer() const +{ + return "hypertext"; +} + + +// Return the auto-completion fillup characters. +const char *QsciLexerHTML::autoCompletionFillups() const +{ + return "/>"; +} + + +// Return the string of characters that comprise a word. +const char *QsciLexerHTML::wordCharacters() const +{ + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexerHTML::defaultColor(int style) const +{ + switch (style) + { + case Default: + case JavaScriptDefault: + case JavaScriptWord: + case JavaScriptSymbol: + case ASPJavaScriptDefault: + case ASPJavaScriptWord: + case ASPJavaScriptSymbol: + case VBScriptDefault: + case ASPVBScriptDefault: + case PHPOperator: + return QColor(0x00,0x00,0x00); + + case Tag: + case XMLTagEnd: + case Script: + case SGMLDefault: + case SGMLCommand: + case VBScriptKeyword: + case VBScriptIdentifier: + case VBScriptUnclosedString: + case ASPVBScriptKeyword: + case ASPVBScriptIdentifier: + case ASPVBScriptUnclosedString: + return QColor(0x00,0x00,0x80); + + case UnknownTag: + case UnknownAttribute: + return QColor(0xff,0x00,0x00); + + case Attribute: + case VBScriptNumber: + case ASPVBScriptNumber: + return QColor(0x00,0x80,0x80); + + case HTMLNumber: + case JavaScriptNumber: + case ASPJavaScriptNumber: + case PythonNumber: + case PythonFunctionMethodName: + case ASPPythonNumber: + case ASPPythonFunctionMethodName: + return QColor(0x00,0x7f,0x7f); + + case HTMLDoubleQuotedString: + case HTMLSingleQuotedString: + case JavaScriptDoubleQuotedString: + case JavaScriptSingleQuotedString: + case ASPJavaScriptDoubleQuotedString: + case ASPJavaScriptSingleQuotedString: + case PythonDoubleQuotedString: + case PythonSingleQuotedString: + case ASPPythonDoubleQuotedString: + case ASPPythonSingleQuotedString: + case PHPKeyword: + return QColor(0x7f,0x00,0x7f); + + case OtherInTag: + case Entity: + case VBScriptString: + case ASPVBScriptString: + return QColor(0x80,0x00,0x80); + + case HTMLComment: + case SGMLComment: + return QColor(0x80,0x80,0x00); + + case XMLStart: + case XMLEnd: + case PHPStart: + case PythonClassName: + case ASPPythonClassName: + return QColor(0x00,0x00,0xff); + + case HTMLValue: + return QColor(0xff,0x00,0xff); + + case SGMLParameter: + return QColor(0x00,0x66,0x00); + + case SGMLDoubleQuotedString: + case SGMLError: + return QColor(0x80,0x00,0x00); + + case SGMLSingleQuotedString: + return QColor(0x99,0x33,0x00); + + case SGMLSpecial: + return QColor(0x33,0x66,0xff); + + case SGMLEntity: + return QColor(0x33,0x33,0x33); + + case SGMLBlockDefault: + return QColor(0x00,0x00,0x66); + + case JavaScriptStart: + case ASPJavaScriptStart: + return QColor(0x7f,0x7f,0x00); + + case JavaScriptComment: + case JavaScriptCommentLine: + case ASPJavaScriptComment: + case ASPJavaScriptCommentLine: + case PythonComment: + case ASPPythonComment: + case PHPDoubleQuotedString: + return QColor(0x00,0x7f,0x00); + + case JavaScriptCommentDoc: + return QColor(0x3f,0x70,0x3f); + + case JavaScriptKeyword: + case ASPJavaScriptKeyword: + case PythonKeyword: + case ASPPythonKeyword: + case PHPVariable: + case PHPDoubleQuotedVariable: + return QColor(0x00,0x00,0x7f); + + case ASPJavaScriptCommentDoc: + return QColor(0x7f,0x7f,0x7f); + + case VBScriptComment: + case ASPVBScriptComment: + return QColor(0x00,0x80,0x00); + + case PythonStart: + case PythonDefault: + case ASPPythonStart: + case ASPPythonDefault: + return QColor(0x80,0x80,0x80); + + case PythonTripleSingleQuotedString: + case PythonTripleDoubleQuotedString: + case ASPPythonTripleSingleQuotedString: + case ASPPythonTripleDoubleQuotedString: + return QColor(0x7f,0x00,0x00); + + case PHPDefault: + return QColor(0x00,0x00,0x33); + + case PHPSingleQuotedString: + return QColor(0x00,0x9f,0x00); + + case PHPNumber: + return QColor(0xcc,0x99,0x00); + + case PHPComment: + return QColor(0x99,0x99,0x99); + + case PHPCommentLine: + return QColor(0x66,0x66,0x66); + } + + return QsciLexer::defaultColor(style); +} + + +// Returns the end-of-line fill for a style. +bool QsciLexerHTML::defaultEolFill(int style) const +{ + switch (style) + { + case JavaScriptDefault: + case JavaScriptComment: + case JavaScriptCommentDoc: + case JavaScriptUnclosedString: + case ASPJavaScriptDefault: + case ASPJavaScriptComment: + case ASPJavaScriptCommentDoc: + case ASPJavaScriptUnclosedString: + case VBScriptDefault: + case VBScriptComment: + case VBScriptNumber: + case VBScriptKeyword: + case VBScriptString: + case VBScriptIdentifier: + case VBScriptUnclosedString: + case ASPVBScriptDefault: + case ASPVBScriptComment: + case ASPVBScriptNumber: + case ASPVBScriptKeyword: + case ASPVBScriptString: + case ASPVBScriptIdentifier: + case ASPVBScriptUnclosedString: + case PythonDefault: + case PythonComment: + case PythonNumber: + case PythonDoubleQuotedString: + case PythonSingleQuotedString: + case PythonKeyword: + case PythonTripleSingleQuotedString: + case PythonTripleDoubleQuotedString: + case PythonClassName: + case PythonFunctionMethodName: + case PythonOperator: + case PythonIdentifier: + case ASPPythonDefault: + case ASPPythonComment: + case ASPPythonNumber: + case ASPPythonDoubleQuotedString: + case ASPPythonSingleQuotedString: + case ASPPythonKeyword: + case ASPPythonTripleSingleQuotedString: + case ASPPythonTripleDoubleQuotedString: + case ASPPythonClassName: + case ASPPythonFunctionMethodName: + case ASPPythonOperator: + case ASPPythonIdentifier: + case PHPDefault: + return true; + } + + return QsciLexer::defaultEolFill(style); +} + + +// Returns the font of the text for a style. +QFont QsciLexerHTML::defaultFont(int style) const +{ + QFont f; + + switch (style) + { + case Default: + case Entity: +#if defined(Q_OS_WIN) + f = QFont("Times New Roman",11); +#elif defined(Q_OS_MAC) + f = QFont("Times New Roman", 12); +#else + f = QFont("Bitstream Charter",10); +#endif + break; + + case HTMLComment: +#if defined(Q_OS_WIN) + f = QFont("Verdana",9); +#elif defined(Q_OS_MAC) + f = QFont("Verdana", 12); +#else + f = QFont("Bitstream Vera Sans",8); +#endif + break; + + case SGMLCommand: + case PythonKeyword: + case PythonClassName: + case PythonFunctionMethodName: + case PythonOperator: + case ASPPythonKeyword: + case ASPPythonClassName: + case ASPPythonFunctionMethodName: + case ASPPythonOperator: + f = QsciLexer::defaultFont(style); + f.setBold(true); + break; + + case JavaScriptDefault: + case JavaScriptCommentDoc: + case JavaScriptKeyword: + case JavaScriptSymbol: + case ASPJavaScriptDefault: + case ASPJavaScriptCommentDoc: + case ASPJavaScriptKeyword: + case ASPJavaScriptSymbol: +#if defined(Q_OS_WIN) + f = QFont("Comic Sans MS",9); +#elif defined(Q_OS_MAC) + f = QFont("Comic Sans MS", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + f.setBold(true); + break; + + case JavaScriptComment: + case JavaScriptCommentLine: + case JavaScriptNumber: + case JavaScriptWord: + case JavaScriptDoubleQuotedString: + case JavaScriptSingleQuotedString: + case ASPJavaScriptComment: + case ASPJavaScriptCommentLine: + case ASPJavaScriptNumber: + case ASPJavaScriptWord: + case ASPJavaScriptDoubleQuotedString: + case ASPJavaScriptSingleQuotedString: + case VBScriptComment: + case ASPVBScriptComment: + case PythonComment: + case ASPPythonComment: + case PHPComment: +#if defined(Q_OS_WIN) + f = QFont("Comic Sans MS",9); +#elif defined(Q_OS_MAC) + f = QFont("Comic Sans MS", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + break; + + case VBScriptDefault: + case VBScriptNumber: + case VBScriptString: + case VBScriptIdentifier: + case VBScriptUnclosedString: + case ASPVBScriptDefault: + case ASPVBScriptNumber: + case ASPVBScriptString: + case ASPVBScriptIdentifier: + case ASPVBScriptUnclosedString: +#if defined(Q_OS_WIN) + f = QFont("Lucida Sans Unicode",9); +#elif defined(Q_OS_MAC) + f = QFont("Lucida Grande", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + break; + + case VBScriptKeyword: + case ASPVBScriptKeyword: +#if defined(Q_OS_WIN) + f = QFont("Lucida Sans Unicode",9); +#elif defined(Q_OS_MAC) + f = QFont("Lucida Grande", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + f.setBold(true); + break; + + case PythonDoubleQuotedString: + case PythonSingleQuotedString: + case ASPPythonDoubleQuotedString: + case ASPPythonSingleQuotedString: +#if defined(Q_OS_WIN) + f = QFont("Courier New",10); +#elif defined(Q_OS_MAC) + f = QFont("Courier New", 12); +#else + f = QFont("Bitstream Vera Sans Mono",9); +#endif + break; + + case PHPKeyword: + case PHPVariable: + case PHPDoubleQuotedVariable: + f = QsciLexer::defaultFont(style); + f.setItalic(true); + break; + + case PHPCommentLine: +#if defined(Q_OS_WIN) + f = QFont("Comic Sans MS",9); +#elif defined(Q_OS_MAC) + f = QFont("Comic Sans MS", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + f.setItalic(true); + break; + + default: + f = QsciLexer::defaultFont(style); + } + + return f; +} + + +// Returns the set of keywords. +const char *QsciLexerHTML::keywords(int set) const +{ + if (set == 1) + return + "a abbr acronym address applet area " + "b base basefont bdo big blockquote body br button " + "caption center cite code col colgroup " + "dd del dfn dir div dl dt " + "em " + "fieldset font form frame frameset " + "h1 h2 h3 h4 h5 h6 head hr html " + "i iframe img input ins isindex " + "kbd " + "label legend li link " + "map menu meta " + "noframes noscript " + "object ol optgroup option " + "p param pre " + "q " + "s samp script select small span strike strong style " + "sub sup " + "table tbody td textarea tfoot th thead title tr tt " + "u ul " + "var " + "xml xmlns " + "abbr accept-charset accept accesskey action align " + "alink alt archive axis " + "background bgcolor border " + "cellpadding cellspacing char charoff charset checked " + "cite class classid clear codebase codetype color " + "cols colspan compact content coords " + "data datafld dataformatas datapagesize datasrc " + "datetime declare defer dir disabled " + "enctype event " + "face for frame frameborder " + "headers height href hreflang hspace http-equiv " + "id ismap label lang language leftmargin link " + "longdesc " + "marginwidth marginheight maxlength media method " + "multiple " + "name nohref noresize noshade nowrap " + "object onblur onchange onclick ondblclick onfocus " + "onkeydown onkeypress onkeyup onload onmousedown " + "onmousemove onmouseover onmouseout onmouseup onreset " + "onselect onsubmit onunload " + "profile prompt " + "readonly rel rev rows rowspan rules " + "scheme scope selected shape size span src standby " + "start style summary " + "tabindex target text title topmargin type " + "usemap " + "valign value valuetype version vlink vspace " + "width " + "text password checkbox radio submit reset file " + "hidden image " + "public !doctype"; + + if (set == 2) + return QsciLexerJavaScript::keywordClass; + + if (set == 3) + return + // Move these to QsciLexerVisualBasic when we + // get round to implementing it. + "and begin case call continue do each else elseif end " + "erase error event exit false for function get gosub " + "goto if implement in load loop lset me mid new next " + "not nothing on or property raiseevent rem resume " + "return rset select set stop sub then to true unload " + "until wend while with withevents attribute alias as " + "boolean byref byte byval const compare currency date " + "declare dim double enum explicit friend global " + "integer let lib long module object option optional " + "preserve private property public redim single static " + "string type variant"; + + if (set == 4) + return QsciLexerPython::keywordClass; + + if (set == 5) + return + "and argv as argc break case cfunction class continue " + "declare default do die " + "echo else elseif empty enddeclare endfor endforeach " + "endif endswitch endwhile e_all e_parse e_error " + "e_warning eval exit extends " + "false for foreach function global " + "http_cookie_vars http_get_vars http_post_vars " + "http_post_files http_env_vars http_server_vars " + "if include include_once list new not null " + "old_function or " + "parent php_os php_self php_version print " + "require require_once return " + "static switch stdclass this true var xor virtual " + "while " + "__file__ __line__ __sleep __wakeup"; + + if (set == 6) + return "ELEMENT DOCTYPE ATTLIST ENTITY NOTATION"; + + return 0; +} + + +// Returns the user name of a style. +QString QsciLexerHTML::description(int style) const +{ + switch (style) + { + case Default: + return tr("HTML default"); + + case Tag: + return tr("Tag"); + + case UnknownTag: + return tr("Unknown tag"); + + case Attribute: + return tr("Attribute"); + + case UnknownAttribute: + return tr("Unknown attribute"); + + case HTMLNumber: + return tr("HTML number"); + + case HTMLDoubleQuotedString: + return tr("HTML double-quoted string"); + + case HTMLSingleQuotedString: + return tr("HTML single-quoted string"); + + case OtherInTag: + return tr("Other text in a tag"); + + case HTMLComment: + return tr("HTML comment"); + + case Entity: + return tr("Entity"); + + case XMLTagEnd: + return tr("End of a tag"); + + case XMLStart: + return tr("Start of an XML fragment"); + + case XMLEnd: + return tr("End of an XML fragment"); + + case Script: + return tr("Script tag"); + + case ASPAtStart: + return tr("Start of an ASP fragment with @"); + + case ASPStart: + return tr("Start of an ASP fragment"); + + case CDATA: + return tr("CDATA"); + + case PHPStart: + return tr("Start of a PHP fragment"); + + case HTMLValue: + return tr("Unquoted HTML value"); + + case ASPXCComment: + return tr("ASP X-Code comment"); + + case SGMLDefault: + return tr("SGML default"); + + case SGMLCommand: + return tr("SGML command"); + + case SGMLParameter: + return tr("First parameter of an SGML command"); + + case SGMLDoubleQuotedString: + return tr("SGML double-quoted string"); + + case SGMLSingleQuotedString: + return tr("SGML single-quoted string"); + + case SGMLError: + return tr("SGML error"); + + case SGMLSpecial: + return tr("SGML special entity"); + + case SGMLComment: + return tr("SGML comment"); + + case SGMLParameterComment: + return tr("First parameter comment of an SGML command"); + + case SGMLBlockDefault: + return tr("SGML block default"); + + case JavaScriptStart: + return tr("Start of a JavaScript fragment"); + + case JavaScriptDefault: + return tr("JavaScript default"); + + case JavaScriptComment: + return tr("JavaScript comment"); + + case JavaScriptCommentLine: + return tr("JavaScript line comment"); + + case JavaScriptCommentDoc: + return tr("JavaDoc style JavaScript comment"); + + case JavaScriptNumber: + return tr("JavaScript number"); + + case JavaScriptWord: + return tr("JavaScript word"); + + case JavaScriptKeyword: + return tr("JavaScript keyword"); + + case JavaScriptDoubleQuotedString: + return tr("JavaScript double-quoted string"); + + case JavaScriptSingleQuotedString: + return tr("JavaScript single-quoted string"); + + case JavaScriptSymbol: + return tr("JavaScript symbol"); + + case JavaScriptUnclosedString: + return tr("JavaScript unclosed string"); + + case JavaScriptRegex: + return tr("JavaScript regular expression"); + + case ASPJavaScriptStart: + return tr("Start of an ASP JavaScript fragment"); + + case ASPJavaScriptDefault: + return tr("ASP JavaScript default"); + + case ASPJavaScriptComment: + return tr("ASP JavaScript comment"); + + case ASPJavaScriptCommentLine: + return tr("ASP JavaScript line comment"); + + case ASPJavaScriptCommentDoc: + return tr("JavaDoc style ASP JavaScript comment"); + + case ASPJavaScriptNumber: + return tr("ASP JavaScript number"); + + case ASPJavaScriptWord: + return tr("ASP JavaScript word"); + + case ASPJavaScriptKeyword: + return tr("ASP JavaScript keyword"); + + case ASPJavaScriptDoubleQuotedString: + return tr("ASP JavaScript double-quoted string"); + + case ASPJavaScriptSingleQuotedString: + return tr("ASP JavaScript single-quoted string"); + + case ASPJavaScriptSymbol: + return tr("ASP JavaScript symbol"); + + case ASPJavaScriptUnclosedString: + return tr("ASP JavaScript unclosed string"); + + case ASPJavaScriptRegex: + return tr("ASP JavaScript regular expression"); + + case VBScriptStart: + return tr("Start of a VBScript fragment"); + + case VBScriptDefault: + return tr("VBScript default"); + + case VBScriptComment: + return tr("VBScript comment"); + + case VBScriptNumber: + return tr("VBScript number"); + + case VBScriptKeyword: + return tr("VBScript keyword"); + + case VBScriptString: + return tr("VBScript string"); + + case VBScriptIdentifier: + return tr("VBScript identifier"); + + case VBScriptUnclosedString: + return tr("VBScript unclosed string"); + + case ASPVBScriptStart: + return tr("Start of an ASP VBScript fragment"); + + case ASPVBScriptDefault: + return tr("ASP VBScript default"); + + case ASPVBScriptComment: + return tr("ASP VBScript comment"); + + case ASPVBScriptNumber: + return tr("ASP VBScript number"); + + case ASPVBScriptKeyword: + return tr("ASP VBScript keyword"); + + case ASPVBScriptString: + return tr("ASP VBScript string"); + + case ASPVBScriptIdentifier: + return tr("ASP VBScript identifier"); + + case ASPVBScriptUnclosedString: + return tr("ASP VBScript unclosed string"); + + case PythonStart: + return tr("Start of a Python fragment"); + + case PythonDefault: + return tr("Python default"); + + case PythonComment: + return tr("Python comment"); + + case PythonNumber: + return tr("Python number"); + + case PythonDoubleQuotedString: + return tr("Python double-quoted string"); + + case PythonSingleQuotedString: + return tr("Python single-quoted string"); + + case PythonKeyword: + return tr("Python keyword"); + + case PythonTripleDoubleQuotedString: + return tr("Python triple double-quoted string"); + + case PythonTripleSingleQuotedString: + return tr("Python triple single-quoted string"); + + case PythonClassName: + return tr("Python class name"); + + case PythonFunctionMethodName: + return tr("Python function or method name"); + + case PythonOperator: + return tr("Python operator"); + + case PythonIdentifier: + return tr("Python identifier"); + + case ASPPythonStart: + return tr("Start of an ASP Python fragment"); + + case ASPPythonDefault: + return tr("ASP Python default"); + + case ASPPythonComment: + return tr("ASP Python comment"); + + case ASPPythonNumber: + return tr("ASP Python number"); + + case ASPPythonDoubleQuotedString: + return tr("ASP Python double-quoted string"); + + case ASPPythonSingleQuotedString: + return tr("ASP Python single-quoted string"); + + case ASPPythonKeyword: + return tr("ASP Python keyword"); + + case ASPPythonTripleDoubleQuotedString: + return tr("ASP Python triple double-quoted string"); + + case ASPPythonTripleSingleQuotedString: + return tr("ASP Python triple single-quoted string"); + + case ASPPythonClassName: + return tr("ASP Python class name"); + + case ASPPythonFunctionMethodName: + return tr("ASP Python function or method name"); + + case ASPPythonOperator: + return tr("ASP Python operator"); + + case ASPPythonIdentifier: + return tr("ASP Python identifier"); + + case PHPDefault: + return tr("PHP default"); + + case PHPDoubleQuotedString: + return tr("PHP double-quoted string"); + + case PHPSingleQuotedString: + return tr("PHP single-quoted string"); + + case PHPKeyword: + return tr("PHP keyword"); + + case PHPNumber: + return tr("PHP number"); + + case PHPVariable: + return tr("PHP variable"); + + case PHPComment: + return tr("PHP comment"); + + case PHPCommentLine: + return tr("PHP line comment"); + + case PHPDoubleQuotedVariable: + return tr("PHP double-quoted variable"); + + case PHPOperator: + return tr("PHP operator"); + } + + return QString(); +} + + +// Returns the background colour of the text for a style. +QColor QsciLexerHTML::defaultPaper(int style) const +{ + switch (style) + { + case ASPAtStart: + return QColor(0xff,0xff,0x00); + + case ASPStart: + case CDATA: + return QColor(0xff,0xdf,0x00); + + case PHPStart: + return QColor(0xff,0xef,0xbf); + + case HTMLValue: + return QColor(0xff,0xef,0xff); + + case SGMLDefault: + case SGMLCommand: + case SGMLParameter: + case SGMLDoubleQuotedString: + case SGMLSingleQuotedString: + case SGMLSpecial: + case SGMLEntity: + case SGMLComment: + return QColor(0xef,0xef,0xff); + + case SGMLError: + return QColor(0xff,0x66,0x66); + + case SGMLBlockDefault: + return QColor(0xcc,0xcc,0xe0); + + case JavaScriptDefault: + case JavaScriptComment: + case JavaScriptCommentLine: + case JavaScriptCommentDoc: + case JavaScriptNumber: + case JavaScriptWord: + case JavaScriptKeyword: + case JavaScriptDoubleQuotedString: + case JavaScriptSingleQuotedString: + case JavaScriptSymbol: + return QColor(0xf0,0xf0,0xff); + + case JavaScriptUnclosedString: + case ASPJavaScriptUnclosedString: + return QColor(0xbf,0xbb,0xb0); + + case JavaScriptRegex: + case ASPJavaScriptRegex: + return QColor(0xff,0xbb,0xb0); + + case ASPJavaScriptDefault: + case ASPJavaScriptComment: + case ASPJavaScriptCommentLine: + case ASPJavaScriptCommentDoc: + case ASPJavaScriptNumber: + case ASPJavaScriptWord: + case ASPJavaScriptKeyword: + case ASPJavaScriptDoubleQuotedString: + case ASPJavaScriptSingleQuotedString: + case ASPJavaScriptSymbol: + return QColor(0xdf,0xdf,0x7f); + + case VBScriptDefault: + case VBScriptComment: + case VBScriptNumber: + case VBScriptKeyword: + case VBScriptString: + case VBScriptIdentifier: + return QColor(0xef,0xef,0xff); + + case VBScriptUnclosedString: + case ASPVBScriptUnclosedString: + return QColor(0x7f,0x7f,0xff); + + case ASPVBScriptDefault: + case ASPVBScriptComment: + case ASPVBScriptNumber: + case ASPVBScriptKeyword: + case ASPVBScriptString: + case ASPVBScriptIdentifier: + return QColor(0xcf,0xcf,0xef); + + case PythonDefault: + case PythonComment: + case PythonNumber: + case PythonDoubleQuotedString: + case PythonSingleQuotedString: + case PythonKeyword: + case PythonTripleSingleQuotedString: + case PythonTripleDoubleQuotedString: + case PythonClassName: + case PythonFunctionMethodName: + case PythonOperator: + case PythonIdentifier: + return QColor(0xef,0xff,0xef); + + case ASPPythonDefault: + case ASPPythonComment: + case ASPPythonNumber: + case ASPPythonDoubleQuotedString: + case ASPPythonSingleQuotedString: + case ASPPythonKeyword: + case ASPPythonTripleSingleQuotedString: + case ASPPythonTripleDoubleQuotedString: + case ASPPythonClassName: + case ASPPythonFunctionMethodName: + case ASPPythonOperator: + case ASPPythonIdentifier: + return QColor(0xcf,0xef,0xcf); + + case PHPDefault: + case PHPDoubleQuotedString: + case PHPSingleQuotedString: + case PHPKeyword: + case PHPNumber: + case PHPVariable: + case PHPComment: + case PHPCommentLine: + case PHPDoubleQuotedVariable: + case PHPOperator: + return QColor(0xff,0xf8,0xf8); + } + + return QsciLexer::defaultPaper(style); +} + + +// Refresh all properties. +void QsciLexerHTML::refreshProperties() +{ + setCompactProp(); + setPreprocProp(); + setCaseSensTagsProp(); + setScriptCommentsProp(); + setScriptHeredocsProp(); + setDjangoProp(); + setMakoProp(); +} + + +// Read properties from the settings. +bool QsciLexerHTML::readProperties(QSettings &qs,const QString &prefix) +{ + int rc = true; + + fold_compact = qs.value(prefix + "foldcompact", true).toBool(); + fold_preproc = qs.value(prefix + "foldpreprocessor", false).toBool(); + case_sens_tags = qs.value(prefix + "casesensitivetags", false).toBool(); + fold_script_comments = qs.value(prefix + "foldscriptcomments", false).toBool(); + fold_script_heredocs = qs.value(prefix + "foldscriptheredocs", false).toBool(); + django_templates = qs.value(prefix + "djangotemplates", false).toBool(); + mako_templates = qs.value(prefix + "makotemplates", false).toBool(); + + return rc; +} + + +// Write properties to the settings. +bool QsciLexerHTML::writeProperties(QSettings &qs,const QString &prefix) const +{ + int rc = true; + + qs.setValue(prefix + "foldcompact", fold_compact); + qs.setValue(prefix + "foldpreprocessor", fold_preproc); + qs.setValue(prefix + "casesensitivetags", case_sens_tags); + qs.setValue(prefix + "foldscriptcomments", fold_script_comments); + qs.setValue(prefix + "foldscriptheredocs", fold_script_heredocs); + qs.setValue(prefix + "djangotemplates", django_templates); + qs.setValue(prefix + "makotemplates", mako_templates); + + return rc; +} + + +// Set if tags are case sensitive. +void QsciLexerHTML::setCaseSensitiveTags(bool sens) +{ + case_sens_tags = sens; + + setCaseSensTagsProp(); +} + + +// Set the "html.tags.case.sensitive" property. +void QsciLexerHTML::setCaseSensTagsProp() +{ + emit propertyChanged("html.tags.case.sensitive",(case_sens_tags ? "1" : "0")); +} + + +// Set if folds are compact +void QsciLexerHTML::setFoldCompact(bool fold) +{ + fold_compact = fold; + + setCompactProp(); +} + + +// Set the "fold.compact" property. +void QsciLexerHTML::setCompactProp() +{ + emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); +} + + +// Set if preprocessor blocks can be folded. +void QsciLexerHTML::setFoldPreprocessor(bool fold) +{ + fold_preproc = fold; + + setPreprocProp(); +} + + +// Set the "fold.html.preprocessor" property. +void QsciLexerHTML::setPreprocProp() +{ + emit propertyChanged("fold.html.preprocessor",(fold_preproc ? "1" : "0")); +} + + +// Set if script comments can be folded. +void QsciLexerHTML::setFoldScriptComments(bool fold) +{ + fold_script_comments = fold; + + setScriptCommentsProp(); +} + + +// Set the "fold.hypertext.comment" property. +void QsciLexerHTML::setScriptCommentsProp() +{ + emit propertyChanged("fold.hypertext.comment",(fold_script_comments ? "1" : "0")); +} + + +// Set if script heredocs can be folded. +void QsciLexerHTML::setFoldScriptHeredocs(bool fold) +{ + fold_script_heredocs = fold; + + setScriptHeredocsProp(); +} + + +// Set the "fold.hypertext.heredoc" property. +void QsciLexerHTML::setScriptHeredocsProp() +{ + emit propertyChanged("fold.hypertext.heredoc",(fold_script_heredocs ? "1" : "0")); +} + + +// Set if Django templates are supported. +void QsciLexerHTML::setDjangoTemplates(bool enable) +{ + django_templates = enable; + + setDjangoProp(); +} + + +// Set the "lexer.html.django" property. +void QsciLexerHTML::setDjangoProp() +{ + emit propertyChanged("lexer.html.django", (django_templates ? "1" : "0")); +} + + +// Set if Mako templates are supported. +void QsciLexerHTML::setMakoTemplates(bool enable) +{ + mako_templates = enable; + + setMakoProp(); +} + + +// Set the "lexer.html.mako" property. +void QsciLexerHTML::setMakoProp() +{ + emit propertyChanged("lexer.html.mako", (mako_templates ? "1" : "0")); +} diff --git a/libs/qscintilla/Qt4Qt5/qscilexerjavascript.cpp b/libs/qscintilla/Qt4Qt5/qscilexerjavascript.cpp new file mode 100644 index 00000000..afa9c9bd --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/qscilexerjavascript.cpp @@ -0,0 +1,120 @@ +// This module implements the QsciLexerJavaScript class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "Qsci/qscilexerjavascript.h" + +#include +#include + + +// The list of JavaScript keywords that can be used by other friendly lexers. +const char *QsciLexerJavaScript::keywordClass = + "abstract boolean break byte case catch char class const continue " + "debugger default delete do double else enum export extends final " + "finally float for function goto if implements import in instanceof " + "int interface long native new package private protected public " + "return short static super switch synchronized this throw throws " + "transient try typeof var void volatile while with"; + + +// The ctor. +QsciLexerJavaScript::QsciLexerJavaScript(QObject *parent) + : QsciLexerCPP(parent) +{ +} + + +// The dtor. +QsciLexerJavaScript::~QsciLexerJavaScript() +{ +} + + +// Returns the language name. +const char *QsciLexerJavaScript::language() const +{ + return "JavaScript"; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexerJavaScript::defaultColor(int style) const +{ + if (style == Regex) + return QColor(0x3f,0x7f,0x3f); + + return QsciLexerCPP::defaultColor(style); +} + + +// Returns the end-of-line fill for a style. +bool QsciLexerJavaScript::defaultEolFill(int style) const +{ + if (style == Regex) + return true; + + return QsciLexerCPP::defaultEolFill(style); +} + + +// Returns the font of the text for a style. +QFont QsciLexerJavaScript::defaultFont(int style) const +{ + if (style == Regex) +#if defined(Q_OS_WIN) + return QFont("Courier New",10); +#elif defined(Q_OS_MAC) + return QFont("Courier", 12); +#else + return QFont("Bitstream Vera Sans Mono",9); +#endif + + return QsciLexerCPP::defaultFont(style); +} + + +// Returns the set of keywords. +const char *QsciLexerJavaScript::keywords(int set) const +{ + if (set != 1) + return 0; + + return keywordClass; +} + + +// Returns the user name of a style. +QString QsciLexerJavaScript::description(int style) const +{ + if (style == Regex) + return tr("Regular expression"); + + return QsciLexerCPP::description(style); +} + + +// Returns the background colour of the text for a style. +QColor QsciLexerJavaScript::defaultPaper(int style) const +{ + if (style == Regex) + return QColor(0xe0,0xf0,0xff); + + return QsciLexer::defaultPaper(style); +} diff --git a/libs/qscintilla/Qt4Qt5/qscilexerpython.cpp b/libs/qscintilla/Qt4Qt5/qscilexerpython.cpp new file mode 100644 index 00000000..817d75fd --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/qscilexerpython.cpp @@ -0,0 +1,489 @@ +// This module implements the QsciLexerPython class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "Qsci/qscilexerpython.h" + +#include +#include +#include + + +// The list of Python keywords that can be used by other friendly lexers. +const char *QsciLexerPython::keywordClass = + "and as assert break class continue def del elif else except exec " + "finally for from global if import in is lambda None not or pass " + "print raise return try while with yield"; + + +// The ctor. +QsciLexerPython::QsciLexerPython(QObject *parent) + : QsciLexer(parent), + fold_comments(false), fold_compact(true), fold_quotes(false), + indent_warn(NoWarning), strings_over_newline(false), v2_unicode(true), + v3_binary_octal(true), v3_bytes(true), highlight_subids(true) +{ +} + + +// The dtor. +QsciLexerPython::~QsciLexerPython() +{ +} + + +// Returns the language name. +const char *QsciLexerPython::language() const +{ + return "Python"; +} + + +// Returns the lexer name. +const char *QsciLexerPython::lexer() const +{ + return "python"; +} + + +// Return the view used for indentation guides. +int QsciLexerPython::indentationGuideView() const +{ + return QsciScintillaBase::SC_IV_LOOKFORWARD; +} + + +// Return the set of character sequences that can separate auto-completion +// words. +QStringList QsciLexerPython::autoCompletionWordSeparators() const +{ + QStringList wl; + + wl << "."; + + return wl; +} + +// Return the list of characters that can start a block. +const char *QsciLexerPython::blockStart(int *style) const +{ + if (style) + *style = Operator; + + return ":"; +} + + +// Return the number of lines to look back when auto-indenting. +int QsciLexerPython::blockLookback() const +{ + // This must be 0 otherwise de-indenting a Python block gets very + // difficult. + return 0; +} + + +// Return the style used for braces. +int QsciLexerPython::braceStyle() const +{ + return Operator; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexerPython::defaultColor(int style) const +{ + switch (style) + { + case Default: + return QColor(0x80,0x80,0x80); + + case Comment: + return QColor(0x00,0x7f,0x00); + + case Number: + return QColor(0x00,0x7f,0x7f); + + case DoubleQuotedString: + case SingleQuotedString: + return QColor(0x7f,0x00,0x7f); + + case Keyword: + return QColor(0x00,0x00,0x7f); + + case TripleSingleQuotedString: + case TripleDoubleQuotedString: + return QColor(0x7f,0x00,0x00); + + case ClassName: + return QColor(0x00,0x00,0xff); + + case FunctionMethodName: + return QColor(0x00,0x7f,0x7f); + + case Operator: + case Identifier: + break; + + case CommentBlock: + return QColor(0x7f,0x7f,0x7f); + + case UnclosedString: + return QColor(0x00,0x00,0x00); + + case HighlightedIdentifier: + return QColor(0x40,0x70,0x90); + + case Decorator: + return QColor(0x80,0x50,0x00); + } + + return QsciLexer::defaultColor(style); +} + + +// Returns the end-of-line fill for a style. +bool QsciLexerPython::defaultEolFill(int style) const +{ + if (style == UnclosedString) + return true; + + return QsciLexer::defaultEolFill(style); +} + + +// Returns the font of the text for a style. +QFont QsciLexerPython::defaultFont(int style) const +{ + QFont f; + + switch (style) + { + case Comment: +#if defined(Q_OS_WIN) + f = QFont("Comic Sans MS",9); +#elif defined(Q_OS_MAC) + f = QFont("Comic Sans MS", 12); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + break; + + case DoubleQuotedString: + case SingleQuotedString: + case UnclosedString: +#if defined(Q_OS_WIN) + f = QFont("Courier New",10); +#elif defined(Q_OS_MAC) + f = QFont("Courier", 12); +#else + f = QFont("Bitstream Vera Sans Mono",9); +#endif + break; + + case Keyword: + case ClassName: + case FunctionMethodName: + case Operator: + f = QsciLexer::defaultFont(style); + f.setBold(true); + break; + + default: + f = QsciLexer::defaultFont(style); + } + + return f; +} + + +// Returns the set of keywords. +const char *QsciLexerPython::keywords(int set) const +{ + if (set != 1) + return 0; + + return keywordClass; +} + + +// Returns the user name of a style. +QString QsciLexerPython::description(int style) const +{ + switch (style) + { + case Default: + return tr("Default"); + + case Comment: + return tr("Comment"); + + case Number: + return tr("Number"); + + case DoubleQuotedString: + return tr("Double-quoted string"); + + case SingleQuotedString: + return tr("Single-quoted string"); + + case Keyword: + return tr("Keyword"); + + case TripleSingleQuotedString: + return tr("Triple single-quoted string"); + + case TripleDoubleQuotedString: + return tr("Triple double-quoted string"); + + case ClassName: + return tr("Class name"); + + case FunctionMethodName: + return tr("Function or method name"); + + case Operator: + return tr("Operator"); + + case Identifier: + return tr("Identifier"); + + case CommentBlock: + return tr("Comment block"); + + case UnclosedString: + return tr("Unclosed string"); + + case HighlightedIdentifier: + return tr("Highlighted identifier"); + + case Decorator: + return tr("Decorator"); + } + + return QString(); +} + + +// Returns the background colour of the text for a style. +QColor QsciLexerPython::defaultPaper(int style) const +{ + if (style == UnclosedString) + return QColor(0xe0,0xc0,0xe0); + + return QsciLexer::defaultPaper(style); +} + + +// Refresh all properties. +void QsciLexerPython::refreshProperties() +{ + setCommentProp(); + setCompactProp(); + setQuotesProp(); + setTabWhingeProp(); + setStringsOverNewlineProp(); + setV2UnicodeProp(); + setV3BinaryOctalProp(); + setV3BytesProp(); + setHighlightSubidsProp(); +} + + +// Read properties from the settings. +bool QsciLexerPython::readProperties(QSettings &qs,const QString &prefix) +{ + int rc = true, num; + + fold_comments = qs.value(prefix + "foldcomments", false).toBool(); + fold_compact = qs.value(prefix + "foldcompact", true).toBool(); + fold_quotes = qs.value(prefix + "foldquotes", false).toBool(); + indent_warn = (IndentationWarning)qs.value(prefix + "indentwarning", (int)NoWarning).toInt(); + strings_over_newline = qs.value(prefix + "stringsovernewline", false).toBool(); + v2_unicode = qs.value(prefix + "v2unicode", true).toBool(); + v3_binary_octal = qs.value(prefix + "v3binaryoctal", true).toBool(); + v3_bytes = qs.value(prefix + "v3bytes", true).toBool(); + highlight_subids = qs.value(prefix + "highlightsubids", true).toBool(); + + return rc; +} + + +// Write properties to the settings. +bool QsciLexerPython::writeProperties(QSettings &qs,const QString &prefix) const +{ + int rc = true; + + qs.setValue(prefix + "foldcomments", fold_comments); + qs.setValue(prefix + "foldcompact", fold_compact); + qs.setValue(prefix + "foldquotes", fold_quotes); + qs.setValue(prefix + "indentwarning", (int)indent_warn); + qs.setValue(prefix + "stringsovernewline", strings_over_newline); + qs.setValue(prefix + "v2unicode", v2_unicode); + qs.setValue(prefix + "v3binaryoctal", v3_binary_octal); + qs.setValue(prefix + "v3bytes", v3_bytes); + qs.setValue(prefix + "highlightsubids", highlight_subids); + + return rc; +} + + +// Set if comments can be folded. +void QsciLexerPython::setFoldComments(bool fold) +{ + fold_comments = fold; + + setCommentProp(); +} + + +// Set the "fold.comment.python" property. +void QsciLexerPython::setCommentProp() +{ + emit propertyChanged("fold.comment.python",(fold_comments ? "1" : "0")); +} + + +// Set if folds are compact. +void QsciLexerPython::setFoldCompact(bool fold) +{ + fold_compact = fold; + + setCompactProp(); +} + + +// Set the "fold.compact" property. +void QsciLexerPython::setCompactProp() +{ + emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); +} + + +// Set if quotes can be folded. +void QsciLexerPython::setFoldQuotes(bool fold) +{ + fold_quotes = fold; + + setQuotesProp(); +} + + +// Set the "fold.quotes.python" property. +void QsciLexerPython::setQuotesProp() +{ + emit propertyChanged("fold.quotes.python",(fold_quotes ? "1" : "0")); +} + + +// Set the indentation warning. +void QsciLexerPython::setIndentationWarning(QsciLexerPython::IndentationWarning warn) +{ + indent_warn = warn; + + setTabWhingeProp(); +} + + +// Set the "tab.timmy.whinge.level" property. +void QsciLexerPython::setTabWhingeProp() +{ + emit propertyChanged("tab.timmy.whinge.level", QByteArray::number(indent_warn)); +} + + +// Set if string literals can span newlines. +void QsciLexerPython::setStringsOverNewlineAllowed(bool allowed) +{ + strings_over_newline = allowed; + + setStringsOverNewlineProp(); +} + + +// Set the "lexer.python.strings.u" property. +void QsciLexerPython::setStringsOverNewlineProp() +{ + emit propertyChanged("lexer.python.strings.over.newline", (strings_over_newline ? "1" : "0")); +} + + +// Set if v2 unicode string literals are allowed. +void QsciLexerPython::setV2UnicodeAllowed(bool allowed) +{ + v2_unicode = allowed; + + setV2UnicodeProp(); +} + + +// Set the "lexer.python.strings.u" property. +void QsciLexerPython::setV2UnicodeProp() +{ + emit propertyChanged("lexer.python.strings.u", (v2_unicode ? "1" : "0")); +} + + +// Set if v3 binary and octal literals are allowed. +void QsciLexerPython::setV3BinaryOctalAllowed(bool allowed) +{ + v3_binary_octal = allowed; + + setV3BinaryOctalProp(); +} + + +// Set the "lexer.python.literals.binary" property. +void QsciLexerPython::setV3BinaryOctalProp() +{ + emit propertyChanged("lexer.python.literals.binary", (v3_binary_octal ? "1" : "0")); +} + + +// Set if v3 bytes string literals are allowed. +void QsciLexerPython::setV3BytesAllowed(bool allowed) +{ + v3_bytes = allowed; + + setV3BytesProp(); +} + + +// Set the "lexer.python.strings.b" property. +void QsciLexerPython::setV3BytesProp() +{ + emit propertyChanged("lexer.python.strings.b",(v3_bytes ? "1" : "0")); +} + + +// Set if sub-identifiers are highlighted. +void QsciLexerPython::setHighlightSubidentifiers(bool enabled) +{ + highlight_subids = enabled; + + setHighlightSubidsProp(); +} + + +// Set the "lexer.python.keywords2.no.sub.identifiers" property. +void QsciLexerPython::setHighlightSubidsProp() +{ + emit propertyChanged("lexer.python.keywords2.no.sub.identifiers", + (highlight_subids ? "0" : "1")); +} diff --git a/libs/qscintilla/Qt4Qt5/qscilexerxml.cpp b/libs/qscintilla/Qt4Qt5/qscilexerxml.cpp new file mode 100644 index 00000000..4394ef3d --- /dev/null +++ b/libs/qscintilla/Qt4Qt5/qscilexerxml.cpp @@ -0,0 +1,252 @@ +// This module implements the QsciLexerXML class. +// +// Copyright (c) 2017 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public License +// version 3.0 as published by the Free Software Foundation and appearing in +// the file LICENSE included in the packaging of this file. Please review the +// following information to ensure the GNU General Public License version 3.0 +// requirements will be met: http://www.gnu.org/copyleft/gpl.html. +// +// If you do not wish to use this file under the terms of the GPL version 3.0 +// then you may purchase a commercial license. For more information contact +// info@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "Qsci/qscilexerxml.h" + +#include +#include +#include + + +// The ctor. +QsciLexerXML::QsciLexerXML(QObject *parent) + : QsciLexerHTML(parent), scripts(true) +{ +} + + +// The dtor. +QsciLexerXML::~QsciLexerXML() +{ +} + + +// Returns the language name. +const char *QsciLexerXML::language() const +{ + return "XML"; +} + + +// Returns the lexer name. +const char *QsciLexerXML::lexer() const +{ + return "xml"; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexerXML::defaultColor(int style) const +{ + switch (style) + { + case Default: + return QColor(0x00,0x00,0x00); + + case Tag: + case UnknownTag: + case XMLTagEnd: + case SGMLDefault: + case SGMLCommand: + return QColor(0x00,0x00,0x80); + + case Attribute: + case UnknownAttribute: + return QColor(0x00,0x80,0x80); + + case HTMLNumber: + return QColor(0x00,0x7f,0x7f); + + case HTMLDoubleQuotedString: + case HTMLSingleQuotedString: + return QColor(0x7f,0x00,0x7f); + + case OtherInTag: + case Entity: + case XMLStart: + case XMLEnd: + return QColor(0x80,0x00,0x80); + + case HTMLComment: + case SGMLComment: + return QColor(0x80,0x80,0x00); + + case CDATA: + case PHPStart: + case SGMLDoubleQuotedString: + case SGMLError: + return QColor(0x80,0x00,0x00); + + case HTMLValue: + return QColor(0x60,0x80,0x60); + + case SGMLParameter: + return QColor(0x00,0x66,0x00); + + case SGMLSingleQuotedString: + return QColor(0x99,0x33,0x00); + + case SGMLSpecial: + return QColor(0x33,0x66,0xff); + + case SGMLEntity: + return QColor(0x33,0x33,0x33); + + case SGMLBlockDefault: + return QColor(0x00,0x00,0x66); + } + + return QsciLexerHTML::defaultColor(style); +} + + +// Returns the end-of-line fill for a style. +bool QsciLexerXML::defaultEolFill(int style) const +{ + if (style == CDATA) + return true; + + return QsciLexerHTML::defaultEolFill(style); +} + + +// Returns the font of the text for a style. +QFont QsciLexerXML::defaultFont(int style) const +{ + QFont f; + + switch (style) + { + case Default: + case Entity: + case CDATA: +#if defined(Q_OS_WIN) + f = QFont("Times New Roman",11); +#elif defined(Q_OS_MAC) + f = QFont("Times New Roman", 12); +#else + f = QFont("Bitstream Charter",10); +#endif + break; + + case XMLStart: + case XMLEnd: + case SGMLCommand: + f = QsciLexer::defaultFont(style); + f.setBold(true); + break; + + default: + f = QsciLexerHTML::defaultFont(style); + } + + return f; +} + + +// Returns the set of keywords. +const char *QsciLexerXML::keywords(int set) const +{ + if (set == 6) + return QsciLexerHTML::keywords(set); + + return 0; +} + + +// Returns the background colour of the text for a style. +QColor QsciLexerXML::defaultPaper(int style) const +{ + switch (style) + { + case CDATA: + return QColor(0xff,0xf0,0xf0); + + case SGMLDefault: + case SGMLCommand: + case SGMLParameter: + case SGMLDoubleQuotedString: + case SGMLSingleQuotedString: + case SGMLSpecial: + case SGMLEntity: + case SGMLComment: + return QColor(0xef,0xef,0xff); + + case SGMLError: + return QColor(0xff,0x66,0x66); + + case SGMLBlockDefault: + return QColor(0xcc,0xcc,0xe0); + } + + return QsciLexerHTML::defaultPaper(style); +} + + +// Refresh all properties. +void QsciLexerXML::refreshProperties() +{ + setScriptsProp(); +} + + +// Read properties from the settings. +bool QsciLexerXML::readProperties(QSettings &qs, const QString &prefix) +{ + int rc = QsciLexerHTML::readProperties(qs, prefix), num; + + scripts = qs.value(prefix + "scriptsstyled", true).toBool(); + + return rc; +} + + +// Write properties to the settings. +bool QsciLexerXML::writeProperties(QSettings &qs, const QString &prefix) const +{ + int rc = QsciLexerHTML::writeProperties(qs, prefix); + + qs.setValue(prefix + "scriptsstyled", scripts); + + return rc; +} + + +// Return true if scripts are styled. +bool QsciLexerXML::scriptsStyled() const +{ + return scripts; +} + + +// Set if scripts are styled. +void QsciLexerXML::setScriptsStyled(bool styled) +{ + scripts = styled; + + setScriptsProp(); +} + + +// Set the "lexer.xml.allow.scripts" property. +void QsciLexerXML::setScriptsProp() +{ + emit propertyChanged("lexer.xml.allow.scripts",(scripts ? "1" : "0")); +} diff --git a/libs/qscintilla/lexers/LexHTML.cpp b/libs/qscintilla/lexers/LexHTML.cpp new file mode 100644 index 00000000..bd14534d --- /dev/null +++ b/libs/qscintilla/lexers/LexHTML.cpp @@ -0,0 +1,2203 @@ +// Scintilla source code edit control +/** @file LexHTML.cxx + ** Lexer for HTML. + **/ +// Copyright 1998-2005 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include +#include + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "StringCopy.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +#define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START) +#define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START) +#define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START) + +enum script_type { eScriptNone = 0, eScriptJS, eScriptVBS, eScriptPython, eScriptPHP, eScriptXML, eScriptSGML, eScriptSGMLblock, eScriptComment }; +enum script_mode { eHtml = 0, eNonHtmlScript, eNonHtmlPreProc, eNonHtmlScriptPreProc }; + +static inline bool IsAWordChar(const int ch) { + return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); +} + +static inline bool IsAWordStart(const int ch) { + return (ch < 0x80) && (isalnum(ch) || ch == '_'); +} + +inline bool IsOperator(int ch) { + if (IsASCII(ch) && isalnum(ch)) + return false; + // '.' left out as it is used to make up numbers + if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || + ch == '(' || ch == ')' || ch == '-' || ch == '+' || + ch == '=' || ch == '|' || ch == '{' || ch == '}' || + ch == '[' || ch == ']' || ch == ':' || ch == ';' || + ch == '<' || ch == '>' || ch == ',' || ch == '/' || + ch == '?' || ch == '!' || ch == '.' || ch == '~') + return true; + return false; +} + +static void GetTextSegment(Accessor &styler, Sci_PositionU start, Sci_PositionU end, char *s, size_t len) { + Sci_PositionU i = 0; + for (; (i < end - start + 1) && (i < len-1); i++) { + s[i] = static_cast(MakeLowerCase(styler[start + i])); + } + s[i] = '\0'; +} + +static const char *GetNextWord(Accessor &styler, Sci_PositionU start, char *s, size_t sLen) { + + Sci_PositionU i = 0; + for (; i < sLen-1; i++) { + char ch = static_cast(styler.SafeGetCharAt(start + i)); + if ((i == 0) && !IsAWordStart(ch)) + break; + if ((i > 0) && !IsAWordChar(ch)) + break; + s[i] = ch; + } + s[i] = '\0'; + + return s; +} + +static script_type segIsScriptingIndicator(Accessor &styler, Sci_PositionU start, Sci_PositionU end, script_type prevValue) { + char s[100]; + GetTextSegment(styler, start, end, s, sizeof(s)); + //Platform::DebugPrintf("Scripting indicator [%s]\n", s); + if (strstr(s, "src")) // External script + return eScriptNone; + if (strstr(s, "vbs")) + return eScriptVBS; + if (strstr(s, "pyth")) + return eScriptPython; + if (strstr(s, "javas")) + return eScriptJS; + if (strstr(s, "jscr")) + return eScriptJS; + if (strstr(s, "php")) + return eScriptPHP; + if (strstr(s, "xml")) { + const char *xml = strstr(s, "xml"); + for (const char *t=s; t= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) { + return eScriptPython; + } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) { + return eScriptVBS; + } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) { + return eScriptJS; + } else if ((state >= SCE_HPHP_DEFAULT) && (state <= SCE_HPHP_COMMENTLINE)) { + return eScriptPHP; + } else if ((state >= SCE_H_SGML_DEFAULT) && (state < SCE_H_SGML_BLOCK_DEFAULT)) { + return eScriptSGML; + } else if (state == SCE_H_SGML_BLOCK_DEFAULT) { + return eScriptSGMLblock; + } else { + return eScriptNone; + } +} + +static int statePrintForState(int state, script_mode inScriptType) { + int StateToPrint = state; + + if (state >= SCE_HJ_START) { + if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) { + StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_PYTHON); + } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) { + StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_VBS); + } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) { + StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_JS); + } + } + + return StateToPrint; +} + +static int stateForPrintState(int StateToPrint) { + int state; + + if ((StateToPrint >= SCE_HPA_START) && (StateToPrint <= SCE_HPA_IDENTIFIER)) { + state = StateToPrint - SCE_HA_PYTHON; + } else if ((StateToPrint >= SCE_HBA_START) && (StateToPrint <= SCE_HBA_STRINGEOL)) { + state = StateToPrint - SCE_HA_VBS; + } else if ((StateToPrint >= SCE_HJA_START) && (StateToPrint <= SCE_HJA_REGEX)) { + state = StateToPrint - SCE_HA_JS; + } else { + state = StateToPrint; + } + + return state; +} + +static inline bool IsNumber(Sci_PositionU start, Accessor &styler) { + return IsADigit(styler[start]) || (styler[start] == '.') || + (styler[start] == '-') || (styler[start] == '#'); +} + +static inline bool isStringState(int state) { + bool bResult; + + switch (state) { + case SCE_HJ_DOUBLESTRING: + case SCE_HJ_SINGLESTRING: + case SCE_HJA_DOUBLESTRING: + case SCE_HJA_SINGLESTRING: + case SCE_HB_STRING: + case SCE_HBA_STRING: + case SCE_HP_STRING: + case SCE_HP_CHARACTER: + case SCE_HP_TRIPLE: + case SCE_HP_TRIPLEDOUBLE: + case SCE_HPA_STRING: + case SCE_HPA_CHARACTER: + case SCE_HPA_TRIPLE: + case SCE_HPA_TRIPLEDOUBLE: + case SCE_HPHP_HSTRING: + case SCE_HPHP_SIMPLESTRING: + case SCE_HPHP_HSTRING_VARIABLE: + case SCE_HPHP_COMPLEX_VARIABLE: + bResult = true; + break; + default : + bResult = false; + break; + } + return bResult; +} + +static inline bool stateAllowsTermination(int state) { + bool allowTermination = !isStringState(state); + if (allowTermination) { + switch (state) { + case SCE_HB_COMMENTLINE: + case SCE_HPHP_COMMENT: + case SCE_HP_COMMENTLINE: + case SCE_HPA_COMMENTLINE: + allowTermination = false; + } + } + return allowTermination; +} + +// not really well done, since it's only comments that should lex the %> and <% +static inline bool isCommentASPState(int state) { + bool bResult; + + switch (state) { + case SCE_HJ_COMMENT: + case SCE_HJ_COMMENTLINE: + case SCE_HJ_COMMENTDOC: + case SCE_HB_COMMENTLINE: + case SCE_HP_COMMENTLINE: + case SCE_HPHP_COMMENT: + case SCE_HPHP_COMMENTLINE: + bResult = true; + break; + default : + bResult = false; + break; + } + return bResult; +} + +static void classifyAttribHTML(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler) { + bool wordIsNumber = IsNumber(start, styler); + char chAttr = SCE_H_ATTRIBUTEUNKNOWN; + if (wordIsNumber) { + chAttr = SCE_H_NUMBER; + } else { + char s[100]; + GetTextSegment(styler, start, end, s, sizeof(s)); + if (keywords.InList(s)) + chAttr = SCE_H_ATTRIBUTE; + } + if ((chAttr == SCE_H_ATTRIBUTEUNKNOWN) && !keywords) + // No keywords -> all are known + chAttr = SCE_H_ATTRIBUTE; + styler.ColourTo(end, chAttr); +} + +static int classifyTagHTML(Sci_PositionU start, Sci_PositionU end, + WordList &keywords, Accessor &styler, bool &tagDontFold, + bool caseSensitive, bool isXml, bool allowScripts) { + char withSpace[30 + 2] = " "; + const char *s = withSpace + 1; + // Copy after the '<' + Sci_PositionU i = 1; + for (Sci_PositionU cPos = start; cPos <= end && i < 30; cPos++) { + char ch = styler[cPos]; + if ((ch != '<') && (ch != '/')) { + withSpace[i++] = caseSensitive ? ch : static_cast(MakeLowerCase(ch)); + } + } + + //The following is only a quick hack, to see if this whole thing would work + //we first need the tagname with a trailing space... + withSpace[i] = ' '; + withSpace[i+1] = '\0'; + + // if the current language is XML, I can fold any tag + // if the current language is HTML, I don't want to fold certain tags (input, meta, etc.) + //...to find it in the list of no-container-tags + tagDontFold = (!isXml) && (NULL != strstr(" area base basefont br col command embed frame hr img input isindex keygen link meta param source track wbr ", withSpace)); + + //now we can remove the trailing space + withSpace[i] = '\0'; + + // No keywords -> all are known + char chAttr = SCE_H_TAGUNKNOWN; + if (s[0] == '!') { + chAttr = SCE_H_SGML_DEFAULT; + } else if (!keywords || keywords.InList(s)) { + chAttr = SCE_H_TAG; + } + styler.ColourTo(end, chAttr); + if (chAttr == SCE_H_TAG) { + if (allowScripts && 0 == strcmp(s, "script")) { + // check to see if this is a self-closing tag by sniffing ahead + bool isSelfClose = false; + for (Sci_PositionU cPos = end; cPos <= end + 200; cPos++) { + char ch = styler.SafeGetCharAt(cPos, '\0'); + if (ch == '\0' || ch == '>') + break; + else if (ch == '/' && styler.SafeGetCharAt(cPos + 1, '\0') == '>') { + isSelfClose = true; + break; + } + } + + // do not enter a script state if the tag self-closed + if (!isSelfClose) + chAttr = SCE_H_SCRIPT; + } else if (!isXml && 0 == strcmp(s, "comment")) { + chAttr = SCE_H_COMMENT; + } + } + return chAttr; +} + +static void classifyWordHTJS(Sci_PositionU start, Sci_PositionU end, + WordList &keywords, Accessor &styler, script_mode inScriptType) { + char s[30 + 1]; + Sci_PositionU i = 0; + for (; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + } + s[i] = '\0'; + + char chAttr = SCE_HJ_WORD; + bool wordIsNumber = IsADigit(s[0]) || ((s[0] == '.') && IsADigit(s[1])); + if (wordIsNumber) { + chAttr = SCE_HJ_NUMBER; + } else if (keywords.InList(s)) { + chAttr = SCE_HJ_KEYWORD; + } + styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); +} + +static int classifyWordHTVB(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler, script_mode inScriptType) { + char chAttr = SCE_HB_IDENTIFIER; + bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.'); + if (wordIsNumber) { + chAttr = SCE_HB_NUMBER; + } else { + char s[100]; + GetTextSegment(styler, start, end, s, sizeof(s)); + if (keywords.InList(s)) { + chAttr = SCE_HB_WORD; + if (strcmp(s, "rem") == 0) + chAttr = SCE_HB_COMMENTLINE; + } + } + styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); + if (chAttr == SCE_HB_COMMENTLINE) + return SCE_HB_COMMENTLINE; + else + return SCE_HB_DEFAULT; +} + +static void classifyWordHTPy(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler, char *prevWord, script_mode inScriptType, bool isMako) { + bool wordIsNumber = IsADigit(styler[start]); + char s[30 + 1]; + Sci_PositionU i = 0; + for (; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + } + s[i] = '\0'; + char chAttr = SCE_HP_IDENTIFIER; + if (0 == strcmp(prevWord, "class")) + chAttr = SCE_HP_CLASSNAME; + else if (0 == strcmp(prevWord, "def")) + chAttr = SCE_HP_DEFNAME; + else if (wordIsNumber) + chAttr = SCE_HP_NUMBER; + else if (keywords.InList(s)) + chAttr = SCE_HP_WORD; + else if (isMako && 0 == strcmp(s, "block")) + chAttr = SCE_HP_WORD; + styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); + strcpy(prevWord, s); +} + +// Update the word colour to default or keyword +// Called when in a PHP word +static void classifyWordHTPHP(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler) { + char chAttr = SCE_HPHP_DEFAULT; + bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.' && start+1 <= end && IsADigit(styler[start+1])); + if (wordIsNumber) { + chAttr = SCE_HPHP_NUMBER; + } else { + char s[100]; + GetTextSegment(styler, start, end, s, sizeof(s)); + if (keywords.InList(s)) + chAttr = SCE_HPHP_WORD; + } + styler.ColourTo(end, chAttr); +} + +static bool isWordHSGML(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler) { + char s[30 + 1]; + Sci_PositionU i = 0; + for (; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + } + s[i] = '\0'; + return keywords.InList(s); +} + +static bool isWordCdata(Sci_PositionU start, Sci_PositionU end, Accessor &styler) { + char s[30 + 1]; + Sci_PositionU i = 0; + for (; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + } + s[i] = '\0'; + return (0 == strcmp(s, "[CDATA[")); +} + +// Return the first state to reach when entering a scripting language +static int StateForScript(script_type scriptLanguage) { + int Result; + switch (scriptLanguage) { + case eScriptVBS: + Result = SCE_HB_START; + break; + case eScriptPython: + Result = SCE_HP_START; + break; + case eScriptPHP: + Result = SCE_HPHP_DEFAULT; + break; + case eScriptXML: + Result = SCE_H_TAGUNKNOWN; + break; + case eScriptSGML: + Result = SCE_H_SGML_DEFAULT; + break; + case eScriptComment: + Result = SCE_H_COMMENT; + break; + default : + Result = SCE_HJ_START; + break; + } + return Result; +} + +static inline bool issgmlwordchar(int ch) { + return !IsASCII(ch) || + (isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '['); +} + +static inline bool IsPhpWordStart(int ch) { + return (IsASCII(ch) && (isalpha(ch) || (ch == '_'))) || (ch >= 0x7f); +} + +static inline bool IsPhpWordChar(int ch) { + return IsADigit(ch) || IsPhpWordStart(ch); +} + +static bool InTagState(int state) { + return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN || + state == SCE_H_SCRIPT || + state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN || + state == SCE_H_NUMBER || state == SCE_H_OTHER || + state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING; +} + +static bool IsCommentState(const int state) { + return state == SCE_H_COMMENT || state == SCE_H_SGML_COMMENT; +} + +static bool IsScriptCommentState(const int state) { + return state == SCE_HJ_COMMENT || state == SCE_HJ_COMMENTLINE || state == SCE_HJA_COMMENT || + state == SCE_HJA_COMMENTLINE || state == SCE_HB_COMMENTLINE || state == SCE_HBA_COMMENTLINE; +} + +static bool isLineEnd(int ch) { + return ch == '\r' || ch == '\n'; +} + +static bool isMakoBlockEnd(const int ch, const int chNext, const char *blockType) { + if (strlen(blockType) == 0) { + return ((ch == '%') && (chNext == '>')); + } else if ((0 == strcmp(blockType, "inherit")) || + (0 == strcmp(blockType, "namespace")) || + (0 == strcmp(blockType, "include")) || + (0 == strcmp(blockType, "page"))) { + return ((ch == '/') && (chNext == '>')); + } else if (0 == strcmp(blockType, "%")) { + if (ch == '/' && isLineEnd(chNext)) + return 1; + else + return isLineEnd(ch); + } else if (0 == strcmp(blockType, "{")) { + return ch == '}'; + } else { + return (ch == '>'); + } +} + +static bool isDjangoBlockEnd(const int ch, const int chNext, const char *blockType) { + if (strlen(blockType) == 0) { + return 0; + } else if (0 == strcmp(blockType, "%")) { + return ((ch == '%') && (chNext == '}')); + } else if (0 == strcmp(blockType, "{")) { + return ((ch == '}') && (chNext == '}')); + } else { + return 0; + } +} + +static bool isPHPStringState(int state) { + return + (state == SCE_HPHP_HSTRING) || + (state == SCE_HPHP_SIMPLESTRING) || + (state == SCE_HPHP_HSTRING_VARIABLE) || + (state == SCE_HPHP_COMPLEX_VARIABLE); +} + +static Sci_Position FindPhpStringDelimiter(char *phpStringDelimiter, const int phpStringDelimiterSize, Sci_Position i, const Sci_Position lengthDoc, Accessor &styler, bool &isSimpleString) { + Sci_Position j; + const Sci_Position beginning = i - 1; + bool isValidSimpleString = false; + + while (i < lengthDoc && (styler[i] == ' ' || styler[i] == '\t')) + i++; + + char ch = styler.SafeGetCharAt(i); + const char chNext = styler.SafeGetCharAt(i + 1); + if (!IsPhpWordStart(ch)) { + if (ch == '\'' && IsPhpWordStart(chNext)) { + i++; + ch = chNext; + isSimpleString = true; + } else { + phpStringDelimiter[0] = '\0'; + return beginning; + } + } + phpStringDelimiter[0] = ch; + i++; + + for (j = i; j < lengthDoc && !isLineEnd(styler[j]); j++) { + if (!IsPhpWordChar(styler[j])) { + if (isSimpleString && (styler[j] == '\'') && isLineEnd(styler.SafeGetCharAt(j + 1))) { + isValidSimpleString = true; + j++; + break; + } else { + phpStringDelimiter[0] = '\0'; + return beginning; + } + } + if (j - i < phpStringDelimiterSize - 2) + phpStringDelimiter[j-i+1] = styler[j]; + else + i++; + } + if (isSimpleString && !isValidSimpleString) { + phpStringDelimiter[0] = '\0'; + return beginning; + } + phpStringDelimiter[j-i+1 - (isSimpleString ? 1 : 0)] = '\0'; + return j - 1; +} + +static void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], + Accessor &styler, bool isXml) { + WordList &keywords = *keywordlists[0]; + WordList &keywords2 = *keywordlists[1]; + WordList &keywords3 = *keywordlists[2]; + WordList &keywords4 = *keywordlists[3]; + WordList &keywords5 = *keywordlists[4]; + WordList &keywords6 = *keywordlists[5]; // SGML (DTD) keywords + + styler.StartAt(startPos); + char prevWord[200]; + prevWord[0] = '\0'; + char phpStringDelimiter[200]; // PHP is not limited in length, we are + phpStringDelimiter[0] = '\0'; + int StateToPrint = initStyle; + int state = stateForPrintState(StateToPrint); + char makoBlockType[200]; + makoBlockType[0] = '\0'; + int makoComment = 0; + char djangoBlockType[2]; + djangoBlockType[0] = '\0'; + + // If inside a tag, it may be a script tag, so reread from the start of line starting tag to ensure any language tags are seen + if (InTagState(state)) { + while ((startPos > 0) && (InTagState(styler.StyleAt(startPos - 1)))) { + Sci_Position backLineStart = styler.LineStart(styler.GetLine(startPos-1)); + length += startPos - backLineStart; + startPos = backLineStart; + } + state = SCE_H_DEFAULT; + } + // String can be heredoc, must find a delimiter first. Reread from beginning of line containing the string, to get the correct lineState + if (isPHPStringState(state)) { + while (startPos > 0 && (isPHPStringState(state) || !isLineEnd(styler[startPos - 1]))) { + startPos--; + length++; + state = styler.StyleAt(startPos); + } + if (startPos == 0) + state = SCE_H_DEFAULT; + } + styler.StartAt(startPos); + + /* Nothing handles getting out of these, so we need not start in any of them. + * As we're at line start and they can't span lines, we'll re-detect them anyway */ + switch (state) { + case SCE_H_QUESTION: + case SCE_H_XMLSTART: + case SCE_H_XMLEND: + case SCE_H_ASP: + state = SCE_H_DEFAULT; + break; + } + + Sci_Position lineCurrent = styler.GetLine(startPos); + int lineState; + if (lineCurrent > 0) { + lineState = styler.GetLineState(lineCurrent-1); + } else { + // Default client and ASP scripting language is JavaScript + lineState = eScriptJS << 8; + + // property asp.default.language + // Script in ASP code is initially assumed to be in JavaScript. + // To change this to VBScript set asp.default.language to 2. Python is 3. + lineState |= styler.GetPropertyInt("asp.default.language", eScriptJS) << 4; + } + script_mode inScriptType = script_mode((lineState >> 0) & 0x03); // 2 bits of scripting mode + bool tagOpened = (lineState >> 2) & 0x01; // 1 bit to know if we are in an opened tag + bool tagClosing = (lineState >> 3) & 0x01; // 1 bit to know if we are in a closing tag + bool tagDontFold = false; //some HTML tags should not be folded + script_type aspScript = script_type((lineState >> 4) & 0x0F); // 4 bits of script name + script_type clientScript = script_type((lineState >> 8) & 0x0F); // 4 bits of script name + int beforePreProc = (lineState >> 12) & 0xFF; // 8 bits of state + + script_type scriptLanguage = ScriptOfState(state); + // If eNonHtmlScript coincides with SCE_H_COMMENT, assume eScriptComment + if (inScriptType == eNonHtmlScript && state == SCE_H_COMMENT) { + scriptLanguage = eScriptComment; + } + script_type beforeLanguage = ScriptOfState(beforePreProc); + + // property fold.html + // Folding is turned on or off for HTML and XML files with this option. + // The fold option must also be on for folding to occur. + const bool foldHTML = styler.GetPropertyInt("fold.html", 0) != 0; + + const bool fold = foldHTML && styler.GetPropertyInt("fold", 0); + + // property fold.html.preprocessor + // Folding is turned on or off for scripts embedded in HTML files with this option. + // The default is on. + const bool foldHTMLPreprocessor = foldHTML && styler.GetPropertyInt("fold.html.preprocessor", 1); + + const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + + // property fold.hypertext.comment + // Allow folding for comments in scripts embedded in HTML. + // The default is off. + const bool foldComment = fold && styler.GetPropertyInt("fold.hypertext.comment", 0) != 0; + + // property fold.hypertext.heredoc + // Allow folding for heredocs in scripts embedded in HTML. + // The default is off. + const bool foldHeredoc = fold && styler.GetPropertyInt("fold.hypertext.heredoc", 0) != 0; + + // property html.tags.case.sensitive + // For XML and HTML, setting this property to 1 will make tags match in a case + // sensitive way which is the expected behaviour for XML and XHTML. + const bool caseSensitive = styler.GetPropertyInt("html.tags.case.sensitive", 0) != 0; + + // property lexer.xml.allow.scripts + // Set to 0 to disable scripts in XML. + const bool allowScripts = styler.GetPropertyInt("lexer.xml.allow.scripts", 1) != 0; + + // property lexer.html.mako + // Set to 1 to enable the mako template language. + const bool isMako = styler.GetPropertyInt("lexer.html.mako", 0) != 0; + + // property lexer.html.django + // Set to 1 to enable the django template language. + const bool isDjango = styler.GetPropertyInt("lexer.html.django", 0) != 0; + + const CharacterSet setHTMLWord(CharacterSet::setAlphaNum, ".-_:!#", 0x80, true); + const CharacterSet setTagContinue(CharacterSet::setAlphaNum, ".-_:!#[", 0x80, true); + const CharacterSet setAttributeContinue(CharacterSet::setAlphaNum, ".-_:!#/", 0x80, true); + // TODO: also handle + and - (except if they're part of ++ or --) and return keywords + const CharacterSet setOKBeforeJSRE(CharacterSet::setNone, "([{=,:;!%^&*|?~"); + + int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; + int levelCurrent = levelPrev; + int visibleChars = 0; + int lineStartVisibleChars = 0; + + int chPrev = ' '; + int ch = ' '; + int chPrevNonWhite = ' '; + // look back to set chPrevNonWhite properly for better regex colouring + if (scriptLanguage == eScriptJS && startPos > 0) { + Sci_Position back = startPos; + int style = 0; + while (--back) { + style = styler.StyleAt(back); + if (style < SCE_HJ_DEFAULT || style > SCE_HJ_COMMENTDOC) + // includes SCE_HJ_COMMENT & SCE_HJ_COMMENTLINE + break; + } + if (style == SCE_HJ_SYMBOLS) { + chPrevNonWhite = static_cast(styler.SafeGetCharAt(back)); + } + } + + styler.StartSegment(startPos); + const Sci_Position lengthDoc = startPos + length; + for (Sci_Position i = startPos; i < lengthDoc; i++) { + const int chPrev2 = chPrev; + chPrev = ch; + if (!IsASpace(ch) && state != SCE_HJ_COMMENT && + state != SCE_HJ_COMMENTLINE && state != SCE_HJ_COMMENTDOC) + chPrevNonWhite = ch; + ch = static_cast(styler[i]); + int chNext = static_cast(styler.SafeGetCharAt(i + 1)); + const int chNext2 = static_cast(styler.SafeGetCharAt(i + 2)); + + // Handle DBCS codepages + if (styler.IsLeadByte(static_cast(ch))) { + chPrev = ' '; + i += 1; + continue; + } + + if ((!IsASpace(ch) || !foldCompact) && fold) + visibleChars++; + if (!IsASpace(ch)) + lineStartVisibleChars++; + + // decide what is the current state to print (depending of the script tag) + StateToPrint = statePrintForState(state, inScriptType); + + // handle script folding + if (fold) { + switch (scriptLanguage) { + case eScriptJS: + case eScriptPHP: + //not currently supported case eScriptVBS: + + if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC) && (!isStringState(state))) { + //Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle); + //if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) { + if (ch == '#') { + Sci_Position j = i + 1; + while ((j < lengthDoc) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { + j++; + } + if (styler.Match(j, "region") || styler.Match(j, "if")) { + levelCurrent++; + } else if (styler.Match(j, "end")) { + levelCurrent--; + } + } else if ((ch == '{') || (ch == '}') || (foldComment && (ch == '/') && (chNext == '*'))) { + levelCurrent += (((ch == '{') || (ch == '/')) ? 1 : -1); + } + } else if (((state == SCE_HPHP_COMMENT) || (state == SCE_HJ_COMMENT)) && foldComment && (ch == '*') && (chNext == '/')) { + levelCurrent--; + } + break; + case eScriptPython: + if (state != SCE_HP_COMMENTLINE && !isMako) { + if ((ch == ':') && ((chNext == '\n') || (chNext == '\r' && chNext2 == '\n'))) { + levelCurrent++; + } else if ((ch == '\n') && !((chNext == '\r') && (chNext2 == '\n')) && (chNext != '\n')) { + // check if the number of tabs is lower than the level + int Findlevel = (levelCurrent & ~SC_FOLDLEVELBASE) * 8; + for (Sci_Position j = 0; Findlevel > 0; j++) { + char chTmp = styler.SafeGetCharAt(i + j + 1); + if (chTmp == '\t') { + Findlevel -= 8; + } else if (chTmp == ' ') { + Findlevel--; + } else { + break; + } + } + + if (Findlevel > 0) { + levelCurrent -= Findlevel / 8; + if (Findlevel % 8) + levelCurrent--; + } + } + } + break; + default: + break; + } + } + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) + // Avoid triggering two times on Dos/Win + // New line -> record any line state onto /next/ line + if (fold) { + int lev = levelPrev; + if (visibleChars == 0) + lev |= SC_FOLDLEVELWHITEFLAG; + if ((levelCurrent > levelPrev) && (visibleChars > 0)) + lev |= SC_FOLDLEVELHEADERFLAG; + + styler.SetLevel(lineCurrent, lev); + visibleChars = 0; + levelPrev = levelCurrent; + } + styler.SetLineState(lineCurrent, + ((inScriptType & 0x03) << 0) | + ((tagOpened ? 1 : 0) << 2) | + ((tagClosing ? 1 : 0) << 3) | + ((aspScript & 0x0F) << 4) | + ((clientScript & 0x0F) << 8) | + ((beforePreProc & 0xFF) << 12)); + lineCurrent++; + lineStartVisibleChars = 0; + } + + // handle start of Mako comment line + if (isMako && ch == '#' && chNext == '#') { + makoComment = 1; + state = SCE_HP_COMMENTLINE; + } + + // handle end of Mako comment line + else if (isMako && makoComment && (ch == '\r' || ch == '\n')) { + makoComment = 0; + styler.ColourTo(i - 1, StateToPrint); + if (scriptLanguage == eScriptPython) { + state = SCE_HP_DEFAULT; + } else { + state = SCE_H_DEFAULT; + } + } + + // Allow falling through to mako handling code if newline is going to end a block + if (((ch == '\r' && chNext != '\n') || (ch == '\n')) && + (!isMako || (0 != strcmp(makoBlockType, "%")))) { + } + // Ignore everything in mako comment until the line ends + else if (isMako && makoComment) { + } + + // generic end of script processing + else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) { + // Check if it's the end of the script tag (or any other HTML tag) + switch (state) { + // in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!) + case SCE_H_DOUBLESTRING: + case SCE_H_SINGLESTRING: + case SCE_HJ_COMMENT: + case SCE_HJ_COMMENTDOC: + //case SCE_HJ_COMMENTLINE: // removed as this is a common thing done to hide + // the end of script marker from some JS interpreters. + case SCE_HB_COMMENTLINE: + case SCE_HBA_COMMENTLINE: + case SCE_HJ_DOUBLESTRING: + case SCE_HJ_SINGLESTRING: + case SCE_HJ_REGEX: + case SCE_HB_STRING: + case SCE_HBA_STRING: + case SCE_HP_STRING: + case SCE_HP_TRIPLE: + case SCE_HP_TRIPLEDOUBLE: + case SCE_HPHP_HSTRING: + case SCE_HPHP_SIMPLESTRING: + case SCE_HPHP_COMMENT: + case SCE_HPHP_COMMENTLINE: + break; + default : + // check if the closing tag is a script tag + if (const char *tag = + state == SCE_HJ_COMMENTLINE || isXml ? "script" : + state == SCE_H_COMMENT ? "comment" : 0) { + Sci_Position j = i + 2; + int chr; + do { + chr = static_cast(*tag++); + } while (chr != 0 && chr == MakeLowerCase(styler.SafeGetCharAt(j++))); + if (chr != 0) break; + } + // closing tag of the script (it's a closing HTML tag anyway) + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_TAGUNKNOWN; + inScriptType = eHtml; + scriptLanguage = eScriptNone; + clientScript = eScriptJS; + i += 2; + visibleChars += 2; + tagClosing = true; + continue; + } + } + + ///////////////////////////////////// + // handle the start of PHP pre-processor = Non-HTML + else if ((state != SCE_H_ASPAT) && + !isStringState(state) && + (state != SCE_HPHP_COMMENT) && + (state != SCE_HPHP_COMMENTLINE) && + (ch == '<') && + (chNext == '?') && + !IsScriptCommentState(state)) { + beforeLanguage = scriptLanguage; + scriptLanguage = segIsScriptingIndicator(styler, i + 2, i + 6, isXml ? eScriptXML : eScriptPHP); + if ((scriptLanguage != eScriptPHP) && (isStringState(state) || (state==SCE_H_COMMENT))) continue; + styler.ColourTo(i - 1, StateToPrint); + beforePreProc = state; + i++; + visibleChars++; + i += PrintScriptingIndicatorOffset(styler, styler.GetStartSegment() + 2, i + 6); + if (scriptLanguage == eScriptXML) + styler.ColourTo(i, SCE_H_XMLSTART); + else + styler.ColourTo(i, SCE_H_QUESTION); + state = StateForScript(scriptLanguage); + if (inScriptType == eNonHtmlScript) + inScriptType = eNonHtmlScriptPreProc; + else + inScriptType = eNonHtmlPreProc; + // Fold whole script, but not if the XML first tag (all XML-like tags in this case) + if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) { + levelCurrent++; + } + // should be better + ch = static_cast(styler.SafeGetCharAt(i)); + continue; + } + + // handle the start Mako template Python code + else if (isMako && scriptLanguage == eScriptNone && ((ch == '<' && chNext == '%') || + (lineStartVisibleChars == 1 && ch == '%') || + (lineStartVisibleChars == 1 && ch == '/' && chNext == '%') || + (ch == '$' && chNext == '{') || + (ch == '<' && chNext == '/' && chNext2 == '%'))) { + if (ch == '%' || ch == '/') + StringCopy(makoBlockType, "%"); + else if (ch == '$') + StringCopy(makoBlockType, "{"); + else if (chNext == '/') + GetNextWord(styler, i+3, makoBlockType, sizeof(makoBlockType)); + else + GetNextWord(styler, i+2, makoBlockType, sizeof(makoBlockType)); + styler.ColourTo(i - 1, StateToPrint); + beforePreProc = state; + if (inScriptType == eNonHtmlScript) + inScriptType = eNonHtmlScriptPreProc; + else + inScriptType = eNonHtmlPreProc; + + if (chNext == '/') { + i += 2; + visibleChars += 2; + } else if (ch != '%') { + i++; + visibleChars++; + } + state = SCE_HP_START; + scriptLanguage = eScriptPython; + styler.ColourTo(i, SCE_H_ASP); + + if (ch != '%' && ch != '$' && ch != '/') { + i += static_cast(strlen(makoBlockType)); + visibleChars += static_cast(strlen(makoBlockType)); + if (keywords4.InList(makoBlockType)) + styler.ColourTo(i, SCE_HP_WORD); + else + styler.ColourTo(i, SCE_H_TAGUNKNOWN); + } + + ch = static_cast(styler.SafeGetCharAt(i)); + continue; + } + + // handle the start/end of Django comment + else if (isDjango && state != SCE_H_COMMENT && (ch == '{' && chNext == '#')) { + styler.ColourTo(i - 1, StateToPrint); + beforePreProc = state; + beforeLanguage = scriptLanguage; + if (inScriptType == eNonHtmlScript) + inScriptType = eNonHtmlScriptPreProc; + else + inScriptType = eNonHtmlPreProc; + i += 1; + visibleChars += 1; + scriptLanguage = eScriptComment; + state = SCE_H_COMMENT; + styler.ColourTo(i, SCE_H_ASP); + ch = static_cast(styler.SafeGetCharAt(i)); + continue; + } else if (isDjango && state == SCE_H_COMMENT && (ch == '#' && chNext == '}')) { + styler.ColourTo(i - 1, StateToPrint); + i += 1; + visibleChars += 1; + styler.ColourTo(i, SCE_H_ASP); + state = beforePreProc; + if (inScriptType == eNonHtmlScriptPreProc) + inScriptType = eNonHtmlScript; + else + inScriptType = eHtml; + scriptLanguage = beforeLanguage; + continue; + } + + // handle the start Django template code + else if (isDjango && scriptLanguage != eScriptPython && (ch == '{' && (chNext == '%' || chNext == '{'))) { + if (chNext == '%') + StringCopy(djangoBlockType, "%"); + else + StringCopy(djangoBlockType, "{"); + styler.ColourTo(i - 1, StateToPrint); + beforePreProc = state; + if (inScriptType == eNonHtmlScript) + inScriptType = eNonHtmlScriptPreProc; + else + inScriptType = eNonHtmlPreProc; + + i += 1; + visibleChars += 1; + state = SCE_HP_START; + beforeLanguage = scriptLanguage; + scriptLanguage = eScriptPython; + styler.ColourTo(i, SCE_H_ASP); + + ch = static_cast(styler.SafeGetCharAt(i)); + continue; + } + + // handle the start of ASP pre-processor = Non-HTML + else if (!isMako && !isDjango && !isCommentASPState(state) && (ch == '<') && (chNext == '%') && !isPHPStringState(state)) { + styler.ColourTo(i - 1, StateToPrint); + beforePreProc = state; + if (inScriptType == eNonHtmlScript) + inScriptType = eNonHtmlScriptPreProc; + else + inScriptType = eNonHtmlPreProc; + + if (chNext2 == '@') { + i += 2; // place as if it was the second next char treated + visibleChars += 2; + state = SCE_H_ASPAT; + } else if ((chNext2 == '-') && (styler.SafeGetCharAt(i + 3) == '-')) { + styler.ColourTo(i + 3, SCE_H_ASP); + state = SCE_H_XCCOMMENT; + scriptLanguage = eScriptVBS; + continue; + } else { + if (chNext2 == '=') { + i += 2; // place as if it was the second next char treated + visibleChars += 2; + } else { + i++; // place as if it was the next char treated + visibleChars++; + } + + state = StateForScript(aspScript); + } + scriptLanguage = eScriptVBS; + styler.ColourTo(i, SCE_H_ASP); + // fold whole script + if (foldHTMLPreprocessor) + levelCurrent++; + // should be better + ch = static_cast(styler.SafeGetCharAt(i)); + continue; + } + + ///////////////////////////////////// + // handle the start of SGML language (DTD) + else if (((scriptLanguage == eScriptNone) || (scriptLanguage == eScriptXML)) && + (chPrev == '<') && + (ch == '!') && + (StateToPrint != SCE_H_CDATA) && + (!IsCommentState(StateToPrint)) && + (!IsScriptCommentState(StateToPrint))) { + beforePreProc = state; + styler.ColourTo(i - 2, StateToPrint); + if ((chNext == '-') && (chNext2 == '-')) { + state = SCE_H_COMMENT; // wait for a pending command + styler.ColourTo(i + 2, SCE_H_COMMENT); + i += 2; // follow styling after the -- + } else if (isWordCdata(i + 1, i + 7, styler)) { + state = SCE_H_CDATA; + } else { + styler.ColourTo(i, SCE_H_SGML_DEFAULT); // ') { + i++; + visibleChars++; + } + else if (0 == strcmp(makoBlockType, "%") && ch == '/') { + i++; + visibleChars++; + } + if (0 != strcmp(makoBlockType, "%") || ch == '/') { + styler.ColourTo(i, SCE_H_ASP); + } + state = beforePreProc; + if (inScriptType == eNonHtmlScriptPreProc) + inScriptType = eNonHtmlScript; + else + inScriptType = eHtml; + scriptLanguage = eScriptNone; + continue; + } + + // handle the end of Django template code + else if (isDjango && + ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) && + (scriptLanguage != eScriptNone) && stateAllowsTermination(state) && + isDjangoBlockEnd(ch, chNext, djangoBlockType)) { + if (state == SCE_H_ASPAT) { + aspScript = segIsScriptingIndicator(styler, + styler.GetStartSegment(), i - 1, aspScript); + } + if (state == SCE_HP_WORD) { + classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); + } else { + styler.ColourTo(i - 1, StateToPrint); + } + i += 1; + visibleChars += 1; + styler.ColourTo(i, SCE_H_ASP); + state = beforePreProc; + if (inScriptType == eNonHtmlScriptPreProc) + inScriptType = eNonHtmlScript; + else + inScriptType = eHtml; + scriptLanguage = beforeLanguage; + continue; + } + + // handle the end of a pre-processor = Non-HTML + else if ((!isMako && !isDjango && ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) && + (((scriptLanguage != eScriptNone) && stateAllowsTermination(state))) && + (((ch == '%') || (ch == '?')) && (chNext == '>'))) || + ((scriptLanguage == eScriptSGML) && (ch == '>') && (state != SCE_H_SGML_COMMENT))) { + if (state == SCE_H_ASPAT) { + aspScript = segIsScriptingIndicator(styler, + styler.GetStartSegment(), i - 1, aspScript); + } + // Bounce out of any ASP mode + switch (state) { + case SCE_HJ_WORD: + classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType); + break; + case SCE_HB_WORD: + classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType); + break; + case SCE_HP_WORD: + classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); + break; + case SCE_HPHP_WORD: + classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); + break; + case SCE_H_XCCOMMENT: + styler.ColourTo(i - 1, state); + break; + default : + styler.ColourTo(i - 1, StateToPrint); + break; + } + if (scriptLanguage != eScriptSGML) { + i++; + visibleChars++; + } + if (ch == '%') + styler.ColourTo(i, SCE_H_ASP); + else if (scriptLanguage == eScriptXML) + styler.ColourTo(i, SCE_H_XMLEND); + else if (scriptLanguage == eScriptSGML) + styler.ColourTo(i, SCE_H_SGML_DEFAULT); + else + styler.ColourTo(i, SCE_H_QUESTION); + state = beforePreProc; + if (inScriptType == eNonHtmlScriptPreProc) + inScriptType = eNonHtmlScript; + else + inScriptType = eHtml; + // Unfold all scripting languages, except for XML tag + if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) { + levelCurrent--; + } + scriptLanguage = beforeLanguage; + continue; + } + ///////////////////////////////////// + + switch (state) { + case SCE_H_DEFAULT: + if (ch == '<') { + // in HTML, fold on tag open and unfold on tag close + tagOpened = true; + tagClosing = (chNext == '/'); + styler.ColourTo(i - 1, StateToPrint); + if (chNext != '!') + state = SCE_H_TAGUNKNOWN; + } else if (ch == '&') { + styler.ColourTo(i - 1, SCE_H_DEFAULT); + state = SCE_H_ENTITY; + } + break; + case SCE_H_SGML_DEFAULT: + case SCE_H_SGML_BLOCK_DEFAULT: +// if (scriptLanguage == eScriptSGMLblock) +// StateToPrint = SCE_H_SGML_BLOCK_DEFAULT; + + if (ch == '\"') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_SGML_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_SGML_SIMPLESTRING; + } else if ((ch == '-') && (chPrev == '-')) { + if (static_cast(styler.GetStartSegment()) <= (i - 2)) { + styler.ColourTo(i - 2, StateToPrint); + } + state = SCE_H_SGML_COMMENT; + } else if (IsASCII(ch) && isalpha(ch) && (chPrev == '%')) { + styler.ColourTo(i - 2, StateToPrint); + state = SCE_H_SGML_ENTITY; + } else if (ch == '#') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_SGML_SPECIAL; + } else if (ch == '[') { + styler.ColourTo(i - 1, StateToPrint); + scriptLanguage = eScriptSGMLblock; + state = SCE_H_SGML_BLOCK_DEFAULT; + } else if (ch == ']') { + if (scriptLanguage == eScriptSGMLblock) { + styler.ColourTo(i, StateToPrint); + scriptLanguage = eScriptSGML; + } else { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i, SCE_H_SGML_ERROR); + } + state = SCE_H_SGML_DEFAULT; + } else if (scriptLanguage == eScriptSGMLblock) { + if ((ch == '!') && (chPrev == '<')) { + styler.ColourTo(i - 2, StateToPrint); + styler.ColourTo(i, SCE_H_SGML_DEFAULT); + state = SCE_H_SGML_COMMAND; + } else if (ch == '>') { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i, SCE_H_SGML_DEFAULT); + } + } + break; + case SCE_H_SGML_COMMAND: + if ((ch == '-') && (chPrev == '-')) { + styler.ColourTo(i - 2, StateToPrint); + state = SCE_H_SGML_COMMENT; + } else if (!issgmlwordchar(ch)) { + if (isWordHSGML(styler.GetStartSegment(), i - 1, keywords6, styler)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_SGML_1ST_PARAM; + } else { + state = SCE_H_SGML_ERROR; + } + } + break; + case SCE_H_SGML_1ST_PARAM: + // wait for the beginning of the word + if ((ch == '-') && (chPrev == '-')) { + if (scriptLanguage == eScriptSGMLblock) { + styler.ColourTo(i - 2, SCE_H_SGML_BLOCK_DEFAULT); + } else { + styler.ColourTo(i - 2, SCE_H_SGML_DEFAULT); + } + state = SCE_H_SGML_1ST_PARAM_COMMENT; + } else if (issgmlwordchar(ch)) { + if (scriptLanguage == eScriptSGMLblock) { + styler.ColourTo(i - 1, SCE_H_SGML_BLOCK_DEFAULT); + } else { + styler.ColourTo(i - 1, SCE_H_SGML_DEFAULT); + } + // find the length of the word + int size = 1; + while (setHTMLWord.Contains(static_cast(styler.SafeGetCharAt(i + size)))) + size++; + styler.ColourTo(i + size - 1, StateToPrint); + i += size - 1; + visibleChars += size - 1; + ch = static_cast(styler.SafeGetCharAt(i)); + if (scriptLanguage == eScriptSGMLblock) { + state = SCE_H_SGML_BLOCK_DEFAULT; + } else { + state = SCE_H_SGML_DEFAULT; + } + continue; + } + break; + case SCE_H_SGML_ERROR: + if ((ch == '-') && (chPrev == '-')) { + styler.ColourTo(i - 2, StateToPrint); + state = SCE_H_SGML_COMMENT; + } + break; + case SCE_H_SGML_DOUBLESTRING: + if (ch == '\"') { + styler.ColourTo(i, StateToPrint); + state = SCE_H_SGML_DEFAULT; + } + break; + case SCE_H_SGML_SIMPLESTRING: + if (ch == '\'') { + styler.ColourTo(i, StateToPrint); + state = SCE_H_SGML_DEFAULT; + } + break; + case SCE_H_SGML_COMMENT: + if ((ch == '-') && (chPrev == '-')) { + styler.ColourTo(i, StateToPrint); + state = SCE_H_SGML_DEFAULT; + } + break; + case SCE_H_CDATA: + if ((chPrev2 == ']') && (chPrev == ']') && (ch == '>')) { + styler.ColourTo(i, StateToPrint); + state = SCE_H_DEFAULT; + levelCurrent--; + } + break; + case SCE_H_COMMENT: + if ((scriptLanguage != eScriptComment) && (chPrev2 == '-') && (chPrev == '-') && (ch == '>')) { + styler.ColourTo(i, StateToPrint); + state = SCE_H_DEFAULT; + levelCurrent--; + } + break; + case SCE_H_SGML_1ST_PARAM_COMMENT: + if ((ch == '-') && (chPrev == '-')) { + styler.ColourTo(i, SCE_H_SGML_COMMENT); + state = SCE_H_SGML_1ST_PARAM; + } + break; + case SCE_H_SGML_SPECIAL: + if (!(IsASCII(ch) && isupper(ch))) { + styler.ColourTo(i - 1, StateToPrint); + if (isalnum(ch)) { + state = SCE_H_SGML_ERROR; + } else { + state = SCE_H_SGML_DEFAULT; + } + } + break; + case SCE_H_SGML_ENTITY: + if (ch == ';') { + styler.ColourTo(i, StateToPrint); + state = SCE_H_SGML_DEFAULT; + } else if (!(IsASCII(ch) && isalnum(ch)) && ch != '-' && ch != '.') { + styler.ColourTo(i, SCE_H_SGML_ERROR); + state = SCE_H_SGML_DEFAULT; + } + break; + case SCE_H_ENTITY: + if (ch == ';') { + styler.ColourTo(i, StateToPrint); + state = SCE_H_DEFAULT; + } + if (ch != '#' && !(IsASCII(ch) && isalnum(ch)) // Should check that '#' follows '&', but it is unlikely anyway... + && ch != '.' && ch != '-' && ch != '_' && ch != ':') { // valid in XML + if (!IsASCII(ch)) // Possibly start of a multibyte character so don't allow this byte to be in entity style + styler.ColourTo(i-1, SCE_H_TAGUNKNOWN); + else + styler.ColourTo(i, SCE_H_TAGUNKNOWN); + state = SCE_H_DEFAULT; + } + break; + case SCE_H_TAGUNKNOWN: + if (!setTagContinue.Contains(ch) && !((ch == '/') && (chPrev == '<'))) { + int eClass = classifyTagHTML(styler.GetStartSegment(), + i - 1, keywords, styler, tagDontFold, caseSensitive, isXml, allowScripts); + if (eClass == SCE_H_SCRIPT || eClass == SCE_H_COMMENT) { + if (!tagClosing) { + inScriptType = eNonHtmlScript; + scriptLanguage = eClass == SCE_H_SCRIPT ? clientScript : eScriptComment; + } else { + scriptLanguage = eScriptNone; + } + eClass = SCE_H_TAG; + } + if (ch == '>') { + styler.ColourTo(i, eClass); + if (inScriptType == eNonHtmlScript) { + state = StateForScript(scriptLanguage); + } else { + state = SCE_H_DEFAULT; + } + tagOpened = false; + if (!tagDontFold) { + if (tagClosing) { + levelCurrent--; + } else { + levelCurrent++; + } + } + tagClosing = false; + } else if (ch == '/' && chNext == '>') { + if (eClass == SCE_H_TAGUNKNOWN) { + styler.ColourTo(i + 1, SCE_H_TAGUNKNOWN); + } else { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i + 1, SCE_H_TAGEND); + } + i++; + ch = chNext; + state = SCE_H_DEFAULT; + tagOpened = false; + } else { + if (eClass != SCE_H_TAGUNKNOWN) { + if (eClass == SCE_H_SGML_DEFAULT) { + state = SCE_H_SGML_DEFAULT; + } else { + state = SCE_H_OTHER; + } + } + } + } + break; + case SCE_H_ATTRIBUTE: + if (!setAttributeContinue.Contains(ch)) { + if (inScriptType == eNonHtmlScript) { + int scriptLanguagePrev = scriptLanguage; + clientScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, scriptLanguage); + scriptLanguage = clientScript; + if ((scriptLanguagePrev != scriptLanguage) && (scriptLanguage == eScriptNone)) + inScriptType = eHtml; + } + classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler); + if (ch == '>') { + styler.ColourTo(i, SCE_H_TAG); + if (inScriptType == eNonHtmlScript) { + state = StateForScript(scriptLanguage); + } else { + state = SCE_H_DEFAULT; + } + tagOpened = false; + if (!tagDontFold) { + if (tagClosing) { + levelCurrent--; + } else { + levelCurrent++; + } + } + tagClosing = false; + } else if (ch == '=') { + styler.ColourTo(i, SCE_H_OTHER); + state = SCE_H_VALUE; + } else { + state = SCE_H_OTHER; + } + } + break; + case SCE_H_OTHER: + if (ch == '>') { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i, SCE_H_TAG); + if (inScriptType == eNonHtmlScript) { + state = StateForScript(scriptLanguage); + } else { + state = SCE_H_DEFAULT; + } + tagOpened = false; + if (!tagDontFold) { + if (tagClosing) { + levelCurrent--; + } else { + levelCurrent++; + } + } + tagClosing = false; + } else if (ch == '\"') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_SINGLESTRING; + } else if (ch == '=') { + styler.ColourTo(i, StateToPrint); + state = SCE_H_VALUE; + } else if (ch == '/' && chNext == '>') { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + tagOpened = false; + } else if (ch == '?' && chNext == '>') { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i + 1, SCE_H_XMLEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } else if (setHTMLWord.Contains(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_H_ATTRIBUTE; + } + break; + case SCE_H_DOUBLESTRING: + if (ch == '\"') { + if (inScriptType == eNonHtmlScript) { + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); + } + styler.ColourTo(i, SCE_H_DOUBLESTRING); + state = SCE_H_OTHER; + } + break; + case SCE_H_SINGLESTRING: + if (ch == '\'') { + if (inScriptType == eNonHtmlScript) { + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); + } + styler.ColourTo(i, SCE_H_SINGLESTRING); + state = SCE_H_OTHER; + } + break; + case SCE_H_VALUE: + if (!setHTMLWord.Contains(ch)) { + if (ch == '\"' && chPrev == '=') { + // Should really test for being first character + state = SCE_H_DOUBLESTRING; + } else if (ch == '\'' && chPrev == '=') { + state = SCE_H_SINGLESTRING; + } else { + if (IsNumber(styler.GetStartSegment(), styler)) { + styler.ColourTo(i - 1, SCE_H_NUMBER); + } else { + styler.ColourTo(i - 1, StateToPrint); + } + if (ch == '>') { + styler.ColourTo(i, SCE_H_TAG); + if (inScriptType == eNonHtmlScript) { + state = StateForScript(scriptLanguage); + } else { + state = SCE_H_DEFAULT; + } + tagOpened = false; + if (!tagDontFold) { + if (tagClosing) { + levelCurrent--; + } else { + levelCurrent++; + } + } + tagClosing = false; + } else { + state = SCE_H_OTHER; + } + } + } + break; + case SCE_HJ_DEFAULT: + case SCE_HJ_START: + case SCE_HJ_SYMBOLS: + if (IsAWordStart(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_WORD; + } else if (ch == '/' && chNext == '*') { + styler.ColourTo(i - 1, StateToPrint); + if (chNext2 == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + if (chNext2 == '/') { + // Eat the * so it isn't used for the end of the comment + i++; + } + } else if (ch == '/' && chNext == '/') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_COMMENTLINE; + } else if (ch == '/' && setOKBeforeJSRE.Contains(chPrevNonWhite)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_REGEX; + } else if (ch == '\"') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_SINGLESTRING; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_COMMENTLINE; + } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_COMMENTLINE; + i += 2; + } else if (IsOperator(ch)) { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); + state = SCE_HJ_DEFAULT; + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HJ_START) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_DEFAULT; + } + } + break; + case SCE_HJ_WORD: + if (!IsAWordChar(ch)) { + classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType); + //styler.ColourTo(i - 1, eHTJSKeyword); + state = SCE_HJ_DEFAULT; + if (ch == '/' && chNext == '*') { + if (chNext2 == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + state = SCE_HJ_SINGLESTRING; + } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_COMMENTLINE; + i += 2; + } else if (IsOperator(ch)) { + styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); + state = SCE_HJ_DEFAULT; + } + } + break; + case SCE_HJ_COMMENT: + case SCE_HJ_COMMENTDOC: + if (ch == '/' && chPrev == '*') { + styler.ColourTo(i, StateToPrint); + state = SCE_HJ_DEFAULT; + ch = ' '; + } + break; + case SCE_HJ_COMMENTLINE: + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, statePrintForState(SCE_HJ_COMMENTLINE, inScriptType)); + state = SCE_HJ_DEFAULT; + ch = ' '; + } + break; + case SCE_HJ_DOUBLESTRING: + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + } + } else if (ch == '\"') { + styler.ColourTo(i, statePrintForState(SCE_HJ_DOUBLESTRING, inScriptType)); + state = SCE_HJ_DEFAULT; + } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_COMMENTLINE; + i += 2; + } else if (isLineEnd(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_STRINGEOL; + } + break; + case SCE_HJ_SINGLESTRING: + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + } + } else if (ch == '\'') { + styler.ColourTo(i, statePrintForState(SCE_HJ_SINGLESTRING, inScriptType)); + state = SCE_HJ_DEFAULT; + } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_COMMENTLINE; + i += 2; + } else if (isLineEnd(ch)) { + styler.ColourTo(i - 1, StateToPrint); + if (chPrev != '\\' && (chPrev2 != '\\' || chPrev != '\r' || ch != '\n')) { + state = SCE_HJ_STRINGEOL; + } + } + break; + case SCE_HJ_STRINGEOL: + if (!isLineEnd(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HJ_DEFAULT; + } else if (!isLineEnd(chNext)) { + styler.ColourTo(i, StateToPrint); + state = SCE_HJ_DEFAULT; + } + break; + case SCE_HJ_REGEX: + if (ch == '\r' || ch == '\n' || ch == '/') { + if (ch == '/') { + while (IsASCII(chNext) && islower(chNext)) { // gobble regex flags + i++; + ch = chNext; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } + } + styler.ColourTo(i, StateToPrint); + state = SCE_HJ_DEFAULT; + } else if (ch == '\\') { + // Gobble up the quoted character + if (chNext == '\\' || chNext == '/') { + i++; + ch = chNext; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } + } + break; + case SCE_HB_DEFAULT: + case SCE_HB_START: + if (IsAWordStart(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_WORD; + } else if (ch == '\'') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_STRING; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_COMMENTLINE; + } else if (IsOperator(ch)) { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType)); + state = SCE_HB_DEFAULT; + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HB_START) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_DEFAULT; + } + } + break; + case SCE_HB_WORD: + if (!IsAWordChar(ch)) { + state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType); + if (state == SCE_HB_DEFAULT) { + if (ch == '\"') { + state = SCE_HB_STRING; + } else if (ch == '\'') { + state = SCE_HB_COMMENTLINE; + } else if (IsOperator(ch)) { + styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType)); + state = SCE_HB_DEFAULT; + } + } + } + break; + case SCE_HB_STRING: + if (ch == '\"') { + styler.ColourTo(i, StateToPrint); + state = SCE_HB_DEFAULT; + } else if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_STRINGEOL; + } + break; + case SCE_HB_COMMENTLINE: + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_DEFAULT; + } + break; + case SCE_HB_STRINGEOL: + if (!isLineEnd(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HB_DEFAULT; + } else if (!isLineEnd(chNext)) { + styler.ColourTo(i, StateToPrint); + state = SCE_HB_DEFAULT; + } + break; + case SCE_HP_DEFAULT: + case SCE_HP_START: + if (IsAWordStart(ch)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HP_WORD; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HP_COMMENTLINE; + } else if (ch == '#') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HP_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, StateToPrint); + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_HP_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } else { + // state = statePrintForState(SCE_HP_STRING,inScriptType); + state = SCE_HP_STRING; + } + } else if (ch == '\'') { + styler.ColourTo(i - 1, StateToPrint); + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_HP_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } else { + state = SCE_HP_CHARACTER; + } + } else if (IsOperator(ch)) { + styler.ColourTo(i - 1, StateToPrint); + styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType)); + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HP_START) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HP_DEFAULT; + } + } + break; + case SCE_HP_WORD: + if (!IsAWordChar(ch)) { + classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); + state = SCE_HP_DEFAULT; + if (ch == '#') { + state = SCE_HP_COMMENTLINE; + } else if (ch == '\"') { + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_HP_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } else { + state = SCE_HP_STRING; + } + } else if (ch == '\'') { + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_HP_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } else { + state = SCE_HP_CHARACTER; + } + } else if (IsOperator(ch)) { + styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType)); + } + } + break; + case SCE_HP_COMMENTLINE: + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HP_DEFAULT; + } + break; + case SCE_HP_STRING: + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } + } else if (ch == '\"') { + styler.ColourTo(i, StateToPrint); + state = SCE_HP_DEFAULT; + } + break; + case SCE_HP_CHARACTER: + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = static_cast(styler.SafeGetCharAt(i + 1)); + } + } else if (ch == '\'') { + styler.ColourTo(i, StateToPrint); + state = SCE_HP_DEFAULT; + } + break; + case SCE_HP_TRIPLE: + if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { + styler.ColourTo(i, StateToPrint); + state = SCE_HP_DEFAULT; + } + break; + case SCE_HP_TRIPLEDOUBLE: + if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { + styler.ColourTo(i, StateToPrint); + state = SCE_HP_DEFAULT; + } + break; + ///////////// start - PHP state handling + case SCE_HPHP_WORD: + if (!IsAWordChar(ch)) { + classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); + if (ch == '/' && chNext == '*') { + i++; + state = SCE_HPHP_COMMENT; + } else if (ch == '/' && chNext == '/') { + i++; + state = SCE_HPHP_COMMENTLINE; + } else if (ch == '#') { + state = SCE_HPHP_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HPHP_HSTRING; + StringCopy(phpStringDelimiter, "\""); + } else if (styler.Match(i, "<<<")) { + bool isSimpleString = false; + i = FindPhpStringDelimiter(phpStringDelimiter, sizeof(phpStringDelimiter), i + 3, lengthDoc, styler, isSimpleString); + if (strlen(phpStringDelimiter)) { + state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING); + if (foldHeredoc) levelCurrent++; + } + } else if (ch == '\'') { + state = SCE_HPHP_SIMPLESTRING; + StringCopy(phpStringDelimiter, "\'"); + } else if (ch == '$' && IsPhpWordStart(chNext)) { + state = SCE_HPHP_VARIABLE; + } else if (IsOperator(ch)) { + state = SCE_HPHP_OPERATOR; + } else { + state = SCE_HPHP_DEFAULT; + } + } + break; + case SCE_HPHP_NUMBER: + // recognize bases 8,10 or 16 integers OR floating-point numbers + if (!IsADigit(ch) + && strchr(".xXabcdefABCDEF", ch) == NULL + && ((ch != '-' && ch != '+') || (chPrev != 'e' && chPrev != 'E'))) { + styler.ColourTo(i - 1, SCE_HPHP_NUMBER); + if (IsOperator(ch)) + state = SCE_HPHP_OPERATOR; + else + state = SCE_HPHP_DEFAULT; + } + break; + case SCE_HPHP_VARIABLE: + if (!IsPhpWordChar(chNext)) { + styler.ColourTo(i, SCE_HPHP_VARIABLE); + state = SCE_HPHP_DEFAULT; + } + break; + case SCE_HPHP_COMMENT: + if (ch == '/' && chPrev == '*') { + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_DEFAULT; + } + break; + case SCE_HPHP_COMMENTLINE: + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HPHP_DEFAULT; + } + break; + case SCE_HPHP_HSTRING: + if (ch == '\\' && (phpStringDelimiter[0] == '\"' || chNext == '$' || chNext == '{')) { + // skip the next char + i++; + } else if (((ch == '{' && chNext == '$') || (ch == '$' && chNext == '{')) + && IsPhpWordStart(chNext2)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HPHP_COMPLEX_VARIABLE; + } else if (ch == '$' && IsPhpWordStart(chNext)) { + styler.ColourTo(i - 1, StateToPrint); + state = SCE_HPHP_HSTRING_VARIABLE; + } else if (styler.Match(i, phpStringDelimiter)) { + if (phpStringDelimiter[0] == '\"') { + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_DEFAULT; + } else if (isLineEnd(chPrev)) { + const int psdLength = static_cast(strlen(phpStringDelimiter)); + const char chAfterPsd = styler.SafeGetCharAt(i + psdLength); + const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1); + if (isLineEnd(chAfterPsd) || + (chAfterPsd == ';' && isLineEnd(chAfterPsd2))) { + i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1; + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_DEFAULT; + if (foldHeredoc) levelCurrent--; + } + } + } + break; + case SCE_HPHP_SIMPLESTRING: + if (phpStringDelimiter[0] == '\'') { + if (ch == '\\') { + // skip the next char + i++; + } else if (ch == '\'') { + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_DEFAULT; + } + } else if (isLineEnd(chPrev) && styler.Match(i, phpStringDelimiter)) { + const int psdLength = static_cast(strlen(phpStringDelimiter)); + const char chAfterPsd = styler.SafeGetCharAt(i + psdLength); + const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1); + if (isLineEnd(chAfterPsd) || + (chAfterPsd == ';' && isLineEnd(chAfterPsd2))) { + i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1; + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_DEFAULT; + if (foldHeredoc) levelCurrent--; + } + } + break; + case SCE_HPHP_HSTRING_VARIABLE: + if (!IsPhpWordChar(chNext)) { + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_HSTRING; + } + break; + case SCE_HPHP_COMPLEX_VARIABLE: + if (ch == '}') { + styler.ColourTo(i, StateToPrint); + state = SCE_HPHP_HSTRING; + } + break; + case SCE_HPHP_OPERATOR: + case SCE_HPHP_DEFAULT: + styler.ColourTo(i - 1, StateToPrint); + if (IsADigit(ch) || (ch == '.' && IsADigit(chNext))) { + state = SCE_HPHP_NUMBER; + } else if (IsAWordStart(ch)) { + state = SCE_HPHP_WORD; + } else if (ch == '/' && chNext == '*') { + i++; + state = SCE_HPHP_COMMENT; + } else if (ch == '/' && chNext == '/') { + i++; + state = SCE_HPHP_COMMENTLINE; + } else if (ch == '#') { + state = SCE_HPHP_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HPHP_HSTRING; + StringCopy(phpStringDelimiter, "\""); + } else if (styler.Match(i, "<<<")) { + bool isSimpleString = false; + i = FindPhpStringDelimiter(phpStringDelimiter, sizeof(phpStringDelimiter), i + 3, lengthDoc, styler, isSimpleString); + if (strlen(phpStringDelimiter)) { + state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING); + if (foldHeredoc) levelCurrent++; + } + } else if (ch == '\'') { + state = SCE_HPHP_SIMPLESTRING; + StringCopy(phpStringDelimiter, "\'"); + } else if (ch == '$' && IsPhpWordStart(chNext)) { + state = SCE_HPHP_VARIABLE; + } else if (IsOperator(ch)) { + state = SCE_HPHP_OPERATOR; + } else if ((state == SCE_HPHP_OPERATOR) && (IsASpace(ch))) { + state = SCE_HPHP_DEFAULT; + } + break; + ///////////// end - PHP state handling + } + + // Some of the above terminated their lexeme but since the same character starts + // the same class again, only reenter if non empty segment. + + bool nonEmptySegment = i >= static_cast(styler.GetStartSegment()); + if (state == SCE_HB_DEFAULT) { // One of the above succeeded + if ((ch == '\"') && (nonEmptySegment)) { + state = SCE_HB_STRING; + } else if (ch == '\'') { + state = SCE_HB_COMMENTLINE; + } else if (IsAWordStart(ch)) { + state = SCE_HB_WORD; + } else if (IsOperator(ch)) { + styler.ColourTo(i, SCE_HB_DEFAULT); + } + } else if (state == SCE_HBA_DEFAULT) { // One of the above succeeded + if ((ch == '\"') && (nonEmptySegment)) { + state = SCE_HBA_STRING; + } else if (ch == '\'') { + state = SCE_HBA_COMMENTLINE; + } else if (IsAWordStart(ch)) { + state = SCE_HBA_WORD; + } else if (IsOperator(ch)) { + styler.ColourTo(i, SCE_HBA_DEFAULT); + } + } else if (state == SCE_HJ_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_HJ_COMMENTLINE; + } else if ((ch == '\"') && (nonEmptySegment)) { + state = SCE_HJ_DOUBLESTRING; + } else if ((ch == '\'') && (nonEmptySegment)) { + state = SCE_HJ_SINGLESTRING; + } else if (IsAWordStart(ch)) { + state = SCE_HJ_WORD; + } else if (IsOperator(ch)) { + styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); + } + } + } + + switch (state) { + case SCE_HJ_WORD: + classifyWordHTJS(styler.GetStartSegment(), lengthDoc - 1, keywords2, styler, inScriptType); + break; + case SCE_HB_WORD: + classifyWordHTVB(styler.GetStartSegment(), lengthDoc - 1, keywords3, styler, inScriptType); + break; + case SCE_HP_WORD: + classifyWordHTPy(styler.GetStartSegment(), lengthDoc - 1, keywords4, styler, prevWord, inScriptType, isMako); + break; + case SCE_HPHP_WORD: + classifyWordHTPHP(styler.GetStartSegment(), lengthDoc - 1, keywords5, styler); + break; + default: + StateToPrint = statePrintForState(state, inScriptType); + if (static_cast(styler.GetStartSegment()) < lengthDoc) + styler.ColourTo(lengthDoc - 1, StateToPrint); + break; + } + + // Fill in the real level of the next line, keeping the current flags as they will be filled in later + if (fold) { + int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; + styler.SetLevel(lineCurrent, levelPrev | flagsNext); + } +} + +static void ColouriseXMLDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + // Passing in true because we're lexing XML + ColouriseHyperTextDoc(startPos, length, initStyle, keywordlists, styler, true); +} + +static void ColouriseHTMLDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + // Passing in false because we're notlexing XML + ColouriseHyperTextDoc(startPos, length, initStyle, keywordlists, styler, false); +} + +static void ColourisePHPScriptDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + if (startPos == 0) + initStyle = SCE_HPHP_DEFAULT; + ColouriseHTMLDoc(startPos, length, initStyle, keywordlists, styler); +} + +static const char * const htmlWordListDesc[] = { + "HTML elements and attributes", + "JavaScript keywords", + "VBScript keywords", + "Python keywords", + "PHP keywords", + "SGML and DTD keywords", + 0, +}; + +static const char * const phpscriptWordListDesc[] = { + "", //Unused + "", //Unused + "", //Unused + "", //Unused + "PHP keywords", + "", //Unused + 0, +}; + +LexerModule lmHTML(SCLEX_HTML, ColouriseHTMLDoc, "hypertext", 0, htmlWordListDesc); +LexerModule lmXML(SCLEX_XML, ColouriseXMLDoc, "xml", 0, htmlWordListDesc); +LexerModule lmPHPSCRIPT(SCLEX_PHPSCRIPT, ColourisePHPScriptDoc, "phpscript", 0, phpscriptWordListDesc); diff --git a/libs/qscintilla/src/Catalogue.cpp b/libs/qscintilla/src/Catalogue.cpp index 375781d9..6dd4db2c 100644 --- a/libs/qscintilla/src/Catalogue.cpp +++ b/libs/qscintilla/src/Catalogue.cpp @@ -79,6 +79,8 @@ int Scintilla_LinkLexers() { //**\(\tLINK_LEXER(\*);\n\) LINK_LEXER(lmSQL); LINK_LEXER(lmJSON); + LINK_LEXER(lmHTML); + LINK_LEXER(lmXML); //--Autogenerated -- end of automatically generated section diff --git a/src/EditDialog.cpp b/src/EditDialog.cpp index 8fd73e30..7a5fbf68 100644 --- a/src/EditDialog.cpp +++ b/src/EditDialog.cpp @@ -3,6 +3,7 @@ #include "sqlitedb.h" #include "Settings.h" #include "src/qhexedit.h" +#include "docktextedit.h" #include "FileDialog.h" #include @@ -12,6 +13,7 @@ #include #include #include +#include #include EditDialog::EditDialog(QWidget* parent) @@ -20,7 +22,6 @@ EditDialog::EditDialog(QWidget* parent) currentIndex(QModelIndex()), dataSource(TextBuffer), dataType(Null), - textNullSet(false), isReadOnly(true) { ui->setupUi(this); @@ -33,17 +34,18 @@ EditDialog::EditDialog(QWidget* parent) hexLayout->addWidget(hexEdit); hexEdit->setOverwriteMode(false); - QHBoxLayout* jsonLayout = new QHBoxLayout(ui->editorJSON); - jsonEdit = new JsonTextEdit(this); - jsonLayout->addWidget(jsonEdit); + QHBoxLayout* sciLayout = new QHBoxLayout(ui->editorSci); + sciEdit = new DockTextEdit(this); + sciLayout->addWidget(sciEdit); QShortcut* ins = new QShortcut(QKeySequence(Qt::Key_Insert), this); connect(ins, SIGNAL(activated()), this, SLOT(toggleOverwriteMode())); connect(ui->editorText, SIGNAL(textChanged()), this, SLOT(updateApplyButton())); connect(hexEdit, SIGNAL(dataChanged()), this, SLOT(updateApplyButton())); - connect(jsonEdit, SIGNAL(textChanged()), this, SLOT(updateApplyButton())); - connect(jsonEdit, SIGNAL(textChanged()), this, SLOT(editTextChanged())); + + connect(sciEdit, SIGNAL(textChanged()), this, SLOT(updateApplyButton())); + connect(sciEdit, SIGNAL(textChanged()), this, SLOT(editTextChanged())); mustIndentAndCompact = Settings::getValue("databrowser", "indent_compact").toBool(); ui->buttonIndent->setChecked(mustIndentAndCompact); @@ -95,15 +97,15 @@ void EditDialog::loadData(const QByteArray& data) // Determine the data type, saving that info in the class variable dataType = checkDataType(data); - // Get the current editor mode (eg text, hex, or image mode) - int editMode = ui->editorStack->currentIndex(); + // Get the current editor mode (eg text, hex, image, json or xml mode) + int editMode = ui->comboMode->currentIndex(); // Data type specific handling switch (dataType) { case Null: // Set enabled any of the text widgets ui->editorText->setEnabled(true); - jsonEdit->setEnabled(true); + sciEdit->setEnabled(true); switch (editMode) { case TextEditor: // The text widget buffer is now the main data source @@ -115,15 +117,16 @@ void EditDialog::loadData(const QByteArray& data) break; case JsonEditor: + case XmlEditor: + // The JSON widget buffer is now the main data source - dataSource = JsonBuffer; + dataSource = SciBuffer; // Empty the text editor contents, then enable text editing - jsonEdit->clear(); + sciEdit->clear(); break; - case HexEditor: // The hex widget buffer is now the main data source dataSource = HexBuffer; @@ -150,74 +153,32 @@ void EditDialog::loadData(const QByteArray& data) case Text: case JSON: - // Set enabled any of the text widgets - ui->editorText->setEnabled(true); - jsonEdit->setEnabled(true); + // Can be stored in any widget, except the ImageViewer switch (editMode) { case TextEditor: - // The text widget buffer is now the main data source - dataSource = TextBuffer; - - // Load the text into the text editor - textData = QString::fromUtf8(data.constData(), data.size()); - ui->editorText->setPlainText(textData); - - // Select all of the text by default - ui->editorText->selectAll(); - + setDataInBuffer(data, TextBuffer); break; case JsonEditor: - // The JSON widget buffer is now the main data source - dataSource = JsonBuffer; - { - QJsonParseError parseError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(QByteArray(data.constData(), data.size()), &parseError); - - if (mustIndentAndCompact && !jsonDoc.isNull()) { - // Load indented JSON into the JSON editor - textData = QString(jsonDoc.toJson(QJsonDocument::Indented)); - jsonEdit->setText(textData); - } else { - // Fallback case. The data is not yet valid JSON. - textData = QString::fromUtf8(data.constData(), data.size()); - jsonEdit->setText(textData); - } - - jsonEdit->clearErrorIndicators(); - if (parseError.error != QJsonParseError::NoError) - jsonEdit->setErrorIndicator(parseError.offset-1); - - } + case XmlEditor: + setDataInBuffer(data, SciBuffer); break; case HexEditor: - // The hex widget buffer is now the main data source - dataSource = HexBuffer; - - // Load the text into the hex editor - hexEdit->setData(data); + setDataInBuffer(data, HexBuffer); break; case ImageViewer: - // The text widget buffer is now the main data source - dataSource = TextBuffer; + // The image viewer cannot hold data nor display text. // Clear any image from the image viewing widget ui->editorImage->setPixmap(QPixmap(0,0)); // Load the text into the text editor - textData = QString::fromUtf8(data.constData(), data.size()); - ui->editorText->setPlainText(textData); - - // Enable text editing - ui->editorText->setEnabled(true); - - // Select all of the text by default - ui->editorText->selectAll(); + setDataInBuffer(data, TextBuffer); break; } @@ -228,10 +189,7 @@ void EditDialog::loadData(const QByteArray& data) // stored it in the editorImage widget instead, it would be a pixmap // and there's no good way to restore that back to the original // (pristine) image data. eg image metadata would be lost - hexEdit->setData(data); - - // The hex widget buffer is now the main data source - dataSource = HexBuffer; + setDataInBuffer(data, HexBuffer); // Update the display if in text edit or image viewer mode switch (editMode) { @@ -243,10 +201,12 @@ void EditDialog::loadData(const QByteArray& data) ui->editorText->setEnabled(false); break; + case XmlEditor: case JsonEditor: // Disable text editing, and use a warning message as the contents - jsonEdit->setText(tr("Image data can't be viewed with the JSON editor")); - jsonEdit->setEnabled(false); + sciEdit->setText(tr("Image data can't be viewed with this editor")); + sciEdit->setEnabled(false); + break; case ImageViewer: @@ -257,16 +217,44 @@ void EditDialog::loadData(const QByteArray& data) break; } break; + case SVG: + // Set the XML data in any buffer or update image in image viewer mode + switch (editMode) { + case TextEditor: + setDataInBuffer(data, TextBuffer); + break; + + case JsonEditor: + case XmlEditor: + + setDataInBuffer(data, SciBuffer); + break; + + case HexEditor: + + setDataInBuffer(data, HexBuffer); + break; + + case ImageViewer: + // Set data in the XML (Sci) Buffer and load the SVG Image + setDataInBuffer(data, SciBuffer); + sciEdit->setLanguage(DockTextEdit::XML); + + // Load the image into the image viewing widget + if (img.loadFromData(data)) { + ui->editorImage->setPixmap(QPixmap::fromImage(img)); + } + break; + } + break; default: - // The hex widget buffer is now the main data source - dataSource = HexBuffer; // The data seems to be general binary data, which is always loaded // into the hex widget (the only safe place for it) - // Load the data into the hex editor - hexEdit->setData(data); + // Load the data into the hex buffer + setDataInBuffer(data, HexBuffer); switch (editMode) { case TextEditor: @@ -278,9 +266,10 @@ void EditDialog::loadData(const QByteArray& data) break; case JsonEditor: + case XmlEditor: // Disable text editing, and use a warning message as the contents - jsonEdit->setText(QString(tr("Binary data can't be viewed with the JSON editor"))); - jsonEdit->setEnabled(false); + sciEdit->setText(QString(tr("Binary data can't be viewed with this editor"))); + sciEdit->setEnabled(false); break; case ImageViewer: @@ -303,7 +292,7 @@ void EditDialog::importData() this, tr("Choose a file to import") #ifndef Q_OS_MAC // Filters on OS X are buggy - , tr("Text files(*.txt);;Image files(%1);;JSON files(*.json);;All files(*)").arg(image_formats) + , tr("Text files (*.txt);;Image files (%1);;JSON files (*.json);;XML files (*.xml);;All files (*)").arg(image_formats) #endif ); if(QFile::exists(fileName)) @@ -354,11 +343,10 @@ void EditDialog::exportData() // Data source is the text buffer file.write(ui->editorText->toPlainText().toUtf8()); break; - case JsonBuffer: + case SciBuffer: // Data source is the JSON buffer - file.write(jsonEdit->text().toUtf8()); + file.write(sciEdit->text().toUtf8()); break; - } file.close(); } @@ -370,24 +358,15 @@ void EditDialog::setNull() ui->editorText->clear(); ui->editorImage->clear(); hexEdit->setData(QByteArray()); - jsonEdit->clear(); + sciEdit->clear(); + + // The text editors don't know the difference between an empty string + // and a NULL, so we need to record NULL outside of that dataType = Null; - // Check if in text editor mode - int editMode = ui->editorStack->currentIndex(); - if (editMode == TextEditor || editMode == JsonEditor) { - // Setting NULL in the text editor switches the data source to it - dataSource = TextBuffer; - - // Ensure the text editor is enabled - ui->editorText->setEnabled(true); - // Ensure the JSON editor is enabled - jsonEdit->setEnabled(true); - - // The text editor doesn't know the difference between an empty string - // and a NULL, so we need to record NULL outside of that - textNullSet = true; - } + // Ensure the text (plain and Scintilla) editors are enabled + ui->editorText->setEnabled(true); + sciEdit->setEnabled(true); // Update the cell data info in the bottom left of the Edit Cell updateCellInfo(hexEdit->data()); @@ -416,47 +395,46 @@ void EditDialog::accept() if(!currentIndex.isValid()) return; + if (dataType == Null) { + emit recordTextUpdated(currentIndex, hexEdit->data(), true); + return; + } + switch (dataSource) { case TextBuffer: - // Check if a NULL is set in the text editor - if (textNullSet) { - emit recordTextUpdated(currentIndex, hexEdit->data(), true); - } else { - // It's not NULL, so proceed with normal text string checking - QString oldData = currentIndex.data(Qt::EditRole).toString(); - QString newData = ui->editorText->toPlainText(); - if (oldData != newData) - // The data is different, so commit it back to the database - emit recordTextUpdated(currentIndex, newData.toUtf8(), false); - } + { + QString oldData = currentIndex.data(Qt::EditRole).toString(); + QString newData = ui->editorText->toPlainText(); + if (oldData != newData) + // The data is different, so commit it back to the database + emit recordTextUpdated(currentIndex, newData.toUtf8(), false); break; - case JsonBuffer: - // Check if a NULL is set in the text editor - if (textNullSet) { - emit recordTextUpdated(currentIndex, hexEdit->data(), true); - } else { - // It's not NULL, so proceed with normal text string checking + } + case SciBuffer: + switch (sciEdit->language()) { + case DockTextEdit::JSON: + { QString oldData = currentIndex.data(Qt::EditRole).toString(); QString newData; QJsonParseError parseError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonEdit->text().toUtf8(), &parseError); + QJsonDocument jsonDoc = QJsonDocument::fromJson(sciEdit->text().toUtf8(), &parseError); bool proceed; - jsonEdit->clearErrorIndicators(); + sciEdit->clearErrorIndicators(); if (parseError.error != QJsonParseError::NoError) - jsonEdit->setErrorIndicator(parseError.offset-1); + sciEdit->setErrorIndicator(parseError.offset-1); if (!jsonDoc.isNull()) { if (mustIndentAndCompact) // Compact the JSON data before storing newData = QString(jsonDoc.toJson(QJsonDocument::Compact)); else - newData = jsonEdit->text(); + newData = sciEdit->text(); proceed = (oldData != newData); } else { - newData = jsonEdit->text(); + newData = sciEdit->text(); proceed = (oldData != newData && promptInvalidData("JSON", parseError.errorString())); } if (proceed) @@ -464,7 +442,37 @@ void EditDialog::accept() emit recordTextUpdated(currentIndex, newData.toUtf8(), false); } break; + case DockTextEdit::XML: + { + QString oldData = currentIndex.data(Qt::EditRole).toString(); + QString newData; + QDomDocument xmlDoc; + QString errorMsg; + int errorLine, errorColumn; + + bool isValid = xmlDoc.setContent(sciEdit->text().toUtf8(), true, &errorMsg, &errorLine, &errorColumn); + bool proceed; + + sciEdit->clearErrorIndicators(); + if (!isValid) { + sciEdit->setErrorIndicator(errorLine-1, errorColumn-1, errorLine, 0); + newData = sciEdit->text(); + proceed = (oldData != newData && promptInvalidData("XML", errorMsg)); + } else { + if (mustIndentAndCompact) + // Compact the XML data before storing. If indent is -1, no whitespace at all is added. + newData = xmlDoc.toString(-1); + else + newData = sciEdit->text(); + proceed = (oldData != newData); + } + if (proceed) + // The data is different, so commit it back to the database + emit recordTextUpdated(currentIndex, newData.toUtf8(), false); + } + break; + } case HexBuffer: // The data source is the hex widget buffer, thus binary data QByteArray oldData = currentIndex.data(Qt::EditRole).toByteArray(); @@ -475,10 +483,90 @@ void EditDialog::accept() } } +void EditDialog::setDataInBuffer(const QByteArray& data, DataSources source) +{ + dataSource = source; + QString textData; + + // 1) Perform validation and text formatting (if applicable). + // 2) Set the text in the corresponding editor widget (the text widget for the Image case). + // 3) Enable the widget. + switch (dataSource) { + case TextBuffer: + + textData = QString::fromUtf8(data.constData(), data.size()); + ui->editorText->setPlainText(QString::fromUtf8(data.constData(), data.size())); + + // Select all of the text by default (this is useful for simple text data that we usually edit as a whole) + ui->editorText->selectAll(); + ui->editorText->setEnabled(true); + + break; + + case SciBuffer: + switch (sciEdit->language()) { + case DockTextEdit::JSON: + { + QJsonParseError parseError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(QByteArray(data.constData(), data.size()), &parseError); + + if (mustIndentAndCompact && !jsonDoc.isNull()) { + // Load indented JSON into the JSON editor + textData = QString(jsonDoc.toJson(QJsonDocument::Indented)); + } else { + // Fallback case. The data is not yet valid JSON or no auto-formatting applied. + textData = QString::fromUtf8(data.constData(), data.size()); + } + sciEdit->setText(textData); + + sciEdit->clearErrorIndicators(); + if (parseError.error != QJsonParseError::NoError) + sciEdit->setErrorIndicator(parseError.offset-1); + sciEdit->setEnabled(true); + + } + + break; + + case DockTextEdit::XML: + { + QString errorMsg; + int errorLine, errorColumn; + QDomDocument xmlDoc; + bool isValid = xmlDoc.setContent(data, true, &errorMsg, &errorLine, &errorColumn); + + if (mustIndentAndCompact && isValid) { + // Load indented XML into the XML editor + textData = xmlDoc.toString(Settings::getValue("editor", "tabsize").toInt()); + } else { + // Fallback case. The data is not yet valid JSON or no auto-formatting applied. + textData = QString::fromUtf8(data.constData(), data.size()); + } + sciEdit->setText(textData); + + sciEdit->clearErrorIndicators(); + if (!isValid) + // Adjust line and column by one (Scintilla starts at 1 and QDomDocument at 0) + sciEdit->setErrorIndicator(errorLine-1, errorColumn-1, errorLine, 0); + sciEdit->setEnabled(true); + + } + break; + } + case HexBuffer: + hexEdit->setData(data); + hexEdit->setEnabled(true); + + break; + } + +} + // Called when the user manually changes the "Mode" drop down combobox void EditDialog::editModeChanged(int newMode) { - ui->buttonIndent->setEnabled(newMode == JsonEditor); + ui->buttonIndent->setEnabled(newMode == JsonEditor || newMode == XmlEditor); + setStackCurrentIndex(newMode); // * If the dataSource is the text buffer, the data is always text * switch (dataSource) { @@ -488,30 +576,16 @@ void EditDialog::editModeChanged(int newMode) // Nothing to do, as the text is already in the text buffer break; - case JsonEditor: // Switching to the JSON editor + case JsonEditor: // Switching to one of the Scintilla editor modes + case XmlEditor: - // Convert the text widget buffer for the JSON widget - // * If the dataSource is the TextBuffer, the contents could - // be still compacted so we just pass it to our loadData() - // function to handle, for indenting if necessary * - // Switch to the selected editor first, as loadData() relies - // on it being current - ui->editorStack->setCurrentIndex(newMode); - - // Load the data into the appropriate widget, as done by loadData() - loadData(ui->editorText->toPlainText().toUtf8()); - // jsonEdit->setText(ui->editorText->toPlainText().toUtf8()); - - // The JSON widget buffer is now the main data source - dataSource = JsonBuffer; + setDataInBuffer(ui->editorText->toPlainText().toUtf8(), SciBuffer); break; case HexEditor: // Switching to the hex editor // Convert the text widget buffer for the hex widget - hexEdit->setData(ui->editorText->toPlainText().toUtf8()); - // The hex widget buffer is now the main data source - dataSource = HexBuffer; + setDataInBuffer(ui->editorText->toPlainText().toUtf8(), HexBuffer); break; case ImageViewer: @@ -519,72 +593,75 @@ void EditDialog::editModeChanged(int newMode) ui->editorImage->setPixmap(QPixmap(0,0)); break; } - - // Switch to the selected editor - ui->editorStack->setCurrentIndex(newMode); - return; break; case HexBuffer: // * If the dataSource is the hex buffer, the contents could be anything // so we just pass it to our loadData() function to handle * - // Switch to the selected editor first, as loadData() relies on it + // Note that we have already set the editor, as loadData() relies on it // being current - ui->editorStack->setCurrentIndex(newMode); // Load the data into the appropriate widget, as done by loadData() loadData(hexEdit->data()); break; - case JsonBuffer: + case SciBuffer: switch (newMode) { case TextEditor: // Switching to the text editor // Convert the text widget buffer for the JSON widget - ui->editorText->setText(jsonEdit->text()); - - // The Text widget buffer is now the main data source - dataSource = TextBuffer; + setDataInBuffer(sciEdit->text().toUtf8(), TextBuffer); break; - case JsonEditor: // Switching to the JSON editor - // Nothing to do, as the text is already in the JSON buffer - break; - - case HexEditor: // Switching to the hex editor // Convert the text widget buffer for the hex widget - hexEdit->setData(jsonEdit->text().toUtf8()); - - // The hex widget buffer is now the main data source - dataSource = HexBuffer; + setDataInBuffer(sciEdit->text().toUtf8(), HexBuffer); break; - case ImageViewer: - // Clear any image from the image viewing widget - ui->editorImage->setPixmap(QPixmap(0,0)); + { + // When SVG format, load the image, else clear it. + QByteArray data = sciEdit->text().toUtf8(); + dataType = checkDataType(data); + if (dataType == SVG) { + QImage img; + + if (img.loadFromData(data)) + ui->editorImage->setPixmap(QPixmap::fromImage(img)); + else + // Clear any image from the image viewing widget + ui->editorImage->setPixmap(QPixmap(0,0)); + } + } + break; + + case JsonEditor: // Switching to the JSON editor + case XmlEditor: // Switching to the XML editor + // The text is already in the Sci buffer but we need to perform the necessary formatting. + setDataInBuffer(sciEdit->text().toUtf8(), SciBuffer); + break; } - - // Switch to the selected editor - ui->editorStack->setCurrentIndex(newMode); - } + } } // Called for every keystroke in the text editor (only) void EditDialog::editTextChanged() { - if (dataSource == TextBuffer || dataSource == JsonBuffer) { + if (dataSource == TextBuffer || dataSource == SciBuffer) { // Data has been changed in the text editor, so it can't be a NULL - // any more - textNullSet = false; + // any more. It hasn't been validated yet, so it cannot be JSON nor XML. + dataType = Text; // Update the cell info in the bottom left manually. This is because // updateCellInfo() only works with QByteArray's (for now) int dataLength; - if (dataSource == TextBuffer) + switch (dataSource) { + case TextBuffer: dataLength = ui->editorText->toPlainText().length(); - else - dataLength = jsonEdit->text().length(); - ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); + break; + case SciBuffer: + dataLength = sciEdit->text().length(); + break; + } + // ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); ui->labelSize->setText(tr("%n char(s)", "", dataLength)); } } @@ -593,12 +670,11 @@ void EditDialog::setMustIndentAndCompact(bool enable) { mustIndentAndCompact = enable; - // Indent or compact if necessary. If data has changed, reload from the widget, else from the table. - if (ui->buttonApply->isEnabled()) - loadData(jsonEdit->text().toUtf8()); - else + // Indent or compact if necessary. If data has changed (button Apply indicates so), reload from the widget, else from the table. + if (ui->buttonApply->isEnabled()) { + setDataInBuffer(sciEdit->text().toUtf8(), SciBuffer); + } else setCurrentIndex(currentIndex); - } // Determine the type of data in the cell @@ -615,8 +691,9 @@ int EditDialog::checkDataType(const QByteArray& data) // that returned true, do a more sophisticated test of the data. This way we get both, good performance and proper data checking. QBuffer imageBuffer(&cellData); QImageReader readerBuffer(&imageBuffer); + QString imageFormat = readerBuffer.format(); if(readerBuffer.canRead() && !readerBuffer.read().isNull()) - return Image; + return imageFormat == "svg" ? SVG : Image; // Check if it's text only if (QString(cellData).toUtf8() == cellData) { // Is there a better way to check this? @@ -639,7 +716,7 @@ void EditDialog::toggleOverwriteMode() hexEdit->setOverwriteMode(currentMode); ui->editorText->setOverwriteMode(currentMode); - jsonEdit->setOverwriteMode(currentMode); + sciEdit->setOverwriteMode(currentMode); } void EditDialog::setFocus() @@ -650,9 +727,25 @@ void EditDialog::setFocus() // to the dock itself doesn't make much sense as it's just a frame; you'd // have to tab to the editor which is what you most likely want to use. So // in order to save the user from doing this we explicitly set the focus - // to the editor. - ui->editorText->setFocus(); - ui->editorText->selectAll(); + // to the current editor. + int editMode = ui->editorStack->currentIndex(); + + switch (editMode) { + case TextEditor: + ui->editorText->setFocus(); + ui->editorText->selectAll(); + break; + case HexEditor: + hexEdit->setFocus(); + break; + case SciEditor: + sciEdit->setFocus(); + break; + case ImageViewer: + // Nothing to do + break; + } + } // Enables or disables the Apply, Null, & Import buttons in the Edit Cell dock @@ -669,7 +762,7 @@ void EditDialog::setReadOnly(bool ro) ui->editorText->setTextInteractionFlags(textFlags); ui->editorBinary->setEnabled(!ro); // We disable the entire hex editor here instead of setting it to read only because it doesn't have a setReadOnly() method - jsonEdit->setReadOnly(ro); + sciEdit->setReadOnly(ro); } // Update the information labels in the bottom left corner of the dialog @@ -678,7 +771,7 @@ void EditDialog::updateCellInfo(const QByteArray& data) QByteArray cellData = data; // Image data needs special treatment - if (dataType == Image) { + if (dataType == Image || dataType == SVG) { QBuffer imageBuffer(&cellData); QImageReader imageReader(&imageBuffer); @@ -768,6 +861,27 @@ void EditDialog::reloadSettings() hexFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); hexEdit->setFont(hexFont); - jsonEdit->reloadSettings(); - + sciEdit->reloadSettings(); +} + +void EditDialog::setStackCurrentIndex(int editMode) +{ + switch (editMode) { + case TextEditor: + case HexEditor: + case ImageViewer: + // General case: switch to the selected editor + ui->editorStack->setCurrentIndex(editMode); + break; + case JsonEditor: + // Scintilla case: switch to the single Scintilla editor and set language + ui->editorStack->setCurrentIndex(SciEditor); + sciEdit->setLanguage(DockTextEdit::JSON); + break; + case XmlEditor: + // Scintilla case: switch to the single Scintilla editor and set language + ui->editorStack->setCurrentIndex(SciEditor); + sciEdit->setLanguage(DockTextEdit::XML); + break; + } } diff --git a/src/EditDialog.h b/src/EditDialog.h index 56981abb..cf91c8e9 100644 --- a/src/EditDialog.h +++ b/src/EditDialog.h @@ -4,9 +4,8 @@ #include #include -#include "jsontextedit.h" - class QHexEdit; +class DockTextEdit; namespace Ui { class EditDialog; @@ -50,38 +49,44 @@ signals: private: Ui::EditDialog* ui; QHexEdit* hexEdit; - JsonTextEdit* jsonEdit; + DockTextEdit* sciEdit; QPersistentModelIndex currentIndex; int dataSource; int dataType; - bool textNullSet; bool isReadOnly; bool mustIndentAndCompact; enum DataSources { TextBuffer, HexBuffer, - JsonBuffer + SciBuffer }; + // SVG is both an Image and an XML document so it is treated separately enum DataTypes { Binary, Image, Null, Text, - JSON + JSON, + SVG }; + // Edit modes and editor stack (this must be aligned with the UI) + // Note that JSON and XML share the Scintilla widget. enum EditModes { TextEditor = 0, HexEditor = 1, - JsonEditor = 2, - ImageViewer = 3 + ImageViewer = 2, + JsonEditor, SciEditor = 3, + XmlEditor = 4 }; int checkDataType(const QByteArray& data); QString humanReadableSize(double byteCount) const; bool promptInvalidData(const QString& dataType, const QString& errorString); + void setDataInBuffer(const QByteArray& data, DataSources source); + void setStackCurrentIndex(int editMode); }; #endif diff --git a/src/EditDialog.ui b/src/EditDialog.ui index 05656913..ed9b2eb8 100644 --- a/src/EditDialog.ui +++ b/src/EditDialog.ui @@ -47,6 +47,11 @@ Binary + + + Image + + JSON @@ -54,7 +59,7 @@ - Image + XML @@ -182,13 +187,6 @@ - - - This editor mode lets you edit JSON data with syntax highlighting, automatic formatting and validation before saving. - -Errors are indicated with a red squiggle underline. - - true @@ -213,6 +211,13 @@ Errors are indicated with a red squiggle underline. + + + This editor mode lets you edit JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + @@ -305,22 +310,6 @@ Errors are indicated with a red squiggle underline. - - editorStack - currentChanged(int) - comboMode - setCurrentIndex(int) - - - 185 - 169 - - - 149 - 39 - - - buttonApply clicked() diff --git a/src/ExtendedScintilla.cpp b/src/ExtendedScintilla.cpp index 5e9e3aa1..4ca3de4b 100644 --- a/src/ExtendedScintilla.cpp +++ b/src/ExtendedScintilla.cpp @@ -87,16 +87,16 @@ void ExtendedScintilla::dropEvent(QDropEvent* e) f.close(); } -void ExtendedScintilla::setupSyntaxHighlightingFormat(const QString& settings_name, int style) +void ExtendedScintilla::setupSyntaxHighlightingFormat(QsciLexer *lexer, const QString& settings_name, int style) { - lexer()->setColor(QColor(Settings::getValue("syntaxhighlighter", settings_name + "_colour").toString()), style); + lexer->setColor(QColor(Settings::getValue("syntaxhighlighter", settings_name + "_colour").toString()), style); QFont font(Settings::getValue("editor", "font").toString()); font.setPointSize(Settings::getValue("editor", "fontsize").toInt()); font.setBold(Settings::getValue("syntaxhighlighter", settings_name + "_bold").toBool()); font.setItalic(Settings::getValue("syntaxhighlighter", settings_name + "_italic").toBool()); font.setUnderline(Settings::getValue("syntaxhighlighter", settings_name + "_underline").toBool()); - lexer()->setFont(font, style); + lexer->setFont(font, style); } void ExtendedScintilla::reloadKeywords() @@ -107,23 +107,16 @@ void ExtendedScintilla::reloadKeywords() void ExtendedScintilla::reloadSettings() { - // Enable auto completion if it hasn't been disabled - if(Settings::getValue("editor", "auto_completion").toBool()) - { - setAutoCompletionThreshold(3); - setAutoCompletionCaseSensitivity(true); - setAutoCompletionShowSingle(true); - setAutoCompletionSource(QsciScintilla::AcsAPIs); - } else { - setAutoCompletionThreshold(0); - } - + reloadLexerSettings(lexer()); +} +void ExtendedScintilla::reloadLexerSettings(QsciLexer *lexer) +{ // Set syntax highlighting settings QFont defaultfont(Settings::getValue("editor", "font").toString()); defaultfont.setStyleHint(QFont::TypeWriter); defaultfont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); - lexer()->setDefaultColor(Qt::black); - lexer()->setFont(defaultfont); + lexer->setDefaultColor(Qt::black); + lexer->setFont(defaultfont); // Set font QFont font(Settings::getValue("editor", "font").toString()); @@ -145,7 +138,7 @@ void ExtendedScintilla::reloadSettings() // Set tab width setTabWidth(Settings::getValue("editor", "tabsize").toInt()); - lexer()->refreshProperties(); + lexer->refreshProperties(); // Check if error indicators are enabled and clear them if they just got disabled showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool(); diff --git a/src/ExtendedScintilla.h b/src/ExtendedScintilla.h index 68f56b5d..9a7a1b37 100644 --- a/src/ExtendedScintilla.h +++ b/src/ExtendedScintilla.h @@ -32,7 +32,8 @@ public slots: protected: void dropEvent(QDropEvent* e); - void setupSyntaxHighlightingFormat(const QString& settings_name, int style); + void setupSyntaxHighlightingFormat(QsciLexer *lexer, const QString& settings_name, int style); + void reloadLexerSettings(QsciLexer *lexer); int errorIndicatorNumber; bool showErrorIndicators; diff --git a/src/Settings.cpp b/src/Settings.cpp index 6d6efbaa..0079a17a 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -172,7 +172,7 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) return 10; if(name == "symbol_limit") return 5000; - if(name == "compact_indent") + if(name == "indent_compact") return false; if(name == "null_text") return "NULL"; diff --git a/src/docktextedit.cpp b/src/docktextedit.cpp new file mode 100644 index 00000000..ae913134 --- /dev/null +++ b/src/docktextedit.cpp @@ -0,0 +1,79 @@ +#include "docktextedit.h" +#include "Settings.h" + +QsciLexerJSON* DockTextEdit::jsonLexer = nullptr; +QsciLexerXML* DockTextEdit::xmlLexer = nullptr; + +DockTextEdit::DockTextEdit(QWidget* parent) : + ExtendedScintilla(parent) +{ + // Create lexer objects if not done yet + if(jsonLexer == nullptr) + jsonLexer = new QsciLexerJSON(this); + if(xmlLexer == nullptr) + xmlLexer = new QsciLexerXML(this); + + // Set the JSON lexer as default + setLexer(jsonLexer); + + jsonLexer->setFoldCompact(false); + jsonLexer->setHighlightComments(true); + + // Do rest of initialisation + reloadSettings(); +} + +DockTextEdit::~DockTextEdit() +{ +} + +void DockTextEdit::reloadSettings() +{ + // Set the parent settings for both lexers + reloadLexerSettings(jsonLexer); + reloadLexerSettings(xmlLexer); + + setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentLine); + setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentBlock); + setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::Keyword); + setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::KeywordLD); + setupSyntaxHighlightingFormat(jsonLexer, "string", QsciLexerJSON::String); + setupSyntaxHighlightingFormat(jsonLexer, "table", QsciLexerJSON::Number); + setupSyntaxHighlightingFormat(jsonLexer, "identifier", QsciLexerJSON::Property); + + // The default style for invalid JSON or unclosed strings uses red + // background and white foreground, but the current line has + // precedence, so it is by default white over gray. We change the + // default to something more readable for the current line at + // invalid JSON. + QColor stringColor = QColor(Settings::getValue("syntaxhighlighter", "string_colour").toString()); + jsonLexer->setColor(stringColor, QsciLexerJSON::Error); + jsonLexer->setColor(stringColor, QsciLexerJSON::UnclosedString); + QFont errorFont(Settings::getValue("editor", "font").toString()); + errorFont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); + errorFont.setItalic(true); + jsonLexer->setFont(errorFont, QsciLexerJSON::Error); + jsonLexer->setFont(errorFont, QsciLexerJSON::UnclosedString); + jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::Error); + jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::UnclosedString); + + setupSyntaxHighlightingFormat(xmlLexer, "comment", QsciLexerHTML::HTMLComment); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::Tag); + setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLDoubleQuotedString); + setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLSingleQuotedString); + setupSyntaxHighlightingFormat(xmlLexer, "table", QsciLexerHTML::HTMLNumber); + setupSyntaxHighlightingFormat(xmlLexer, "identifier", QsciLexerHTML::Attribute); +} + +void DockTextEdit::setLanguage(Language lang) +{ + m_language = lang; + switch (lang) { + case JSON: + setLexer(jsonLexer); + break; + case XML: + setLexer(xmlLexer); + break; + } +} diff --git a/src/docktextedit.h b/src/docktextedit.h new file mode 100644 index 00000000..75f66b3e --- /dev/null +++ b/src/docktextedit.h @@ -0,0 +1,40 @@ +#ifndef DOCKTEXTEDIT_H +#define DOCKTEXTEDIT_H + +#include "ExtendedScintilla.h" +#include +#include + +/** + * @brief The DockTextEdit class + * This class is based on our Extended QScintilla widget + */ +class DockTextEdit : public ExtendedScintilla +{ + Q_OBJECT + +public: + explicit DockTextEdit(QWidget *parent = nullptr); + virtual ~DockTextEdit(); + + // Enumeration of supported languages + enum Language + { + JSON, + XML + }; + + void setLanguage(Language lang); + Language language() { return m_language; }; + +public slots: + void reloadSettings(); + +protected: + static QsciLexerJSON* jsonLexer; + static QsciLexerXML* xmlLexer; +private: + Language m_language; +}; + +#endif diff --git a/src/jsontextedit.cpp b/src/jsontextedit.cpp deleted file mode 100644 index 4d0bb1da..00000000 --- a/src/jsontextedit.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "jsontextedit.h" -#include "Settings.h" - -QsciLexerJSON* JsonTextEdit::jsonLexer = nullptr; - -JsonTextEdit::JsonTextEdit(QWidget* parent) : - ExtendedScintilla(parent) -{ - // Create lexer object if not done yet - if(jsonLexer == nullptr) - jsonLexer = new QsciLexerJSON(this); - - // Set the JSON lexer - setLexer(jsonLexer); - - jsonLexer->setFoldCompact(false); - - // Do rest of initialisation - reloadSettings(); -} - -JsonTextEdit::~JsonTextEdit() -{ -} - -void JsonTextEdit::reloadSettings() -{ - ExtendedScintilla::reloadSettings(); - - setupSyntaxHighlightingFormat("comment", QsciLexerJSON::CommentLine); - setupSyntaxHighlightingFormat("comment", QsciLexerJSON::CommentBlock); - setupSyntaxHighlightingFormat("keyword", QsciLexerJSON::Keyword); - setupSyntaxHighlightingFormat("keyword", QsciLexerJSON::KeywordLD); - setupSyntaxHighlightingFormat("string", QsciLexerJSON::String); - setupSyntaxHighlightingFormat("table", QsciLexerJSON::Number); - setupSyntaxHighlightingFormat("identifier", QsciLexerJSON::Property); - jsonLexer->setHighlightComments(true); - - // The default style for invalid JSON or unclosed strings uses red - // background and white foreground, but the current line has - // precedence, so it is by default white over gray. We change the - // default to something more readable for the current line at - // invalid JSON. - QColor stringColor = QColor(Settings::getValue("syntaxhighlighter", "string_colour").toString()); - jsonLexer->setColor(stringColor, QsciLexerJSON::Error); - jsonLexer->setColor(stringColor, QsciLexerJSON::UnclosedString); - QFont errorFont(Settings::getValue("editor", "font").toString()); - errorFont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); - errorFont.setItalic(true); - jsonLexer->setFont(errorFont, QsciLexerJSON::Error); - jsonLexer->setFont(errorFont, QsciLexerJSON::UnclosedString); - jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::Error); - jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::UnclosedString); -} diff --git a/src/jsontextedit.h b/src/jsontextedit.h deleted file mode 100644 index 4c81ebd2..00000000 --- a/src/jsontextedit.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef JSONTEXTEDIT_H -#define JSONTEXTEDIT_H - -#include "ExtendedScintilla.h" -#include - -/** - * @brief The JsonTextEdit class - * This class is based on our Extended QScintilla widget - */ -class JsonTextEdit : public ExtendedScintilla -{ - Q_OBJECT - -public: - explicit JsonTextEdit(QWidget *parent = nullptr); - virtual ~JsonTextEdit(); - - static QsciLexerJSON* jsonLexer; - -public slots: - void reloadSettings(); -}; - -#endif diff --git a/src/sqltextedit.cpp b/src/sqltextedit.cpp index 3f21e0ff..a8302d2a 100644 --- a/src/sqltextedit.cpp +++ b/src/sqltextedit.cpp @@ -30,16 +30,27 @@ SqlTextEdit::~SqlTextEdit() void SqlTextEdit::reloadSettings() { + // Enable auto completion if it hasn't been disabled + if(Settings::getValue("editor", "auto_completion").toBool()) + { + setAutoCompletionThreshold(3); + setAutoCompletionCaseSensitivity(true); + setAutoCompletionShowSingle(true); + setAutoCompletionSource(QsciScintilla::AcsAPIs); + } else { + setAutoCompletionThreshold(0); + } + ExtendedScintilla::reloadSettings(); - setupSyntaxHighlightingFormat("comment", QsciLexerSQL::Comment); - setupSyntaxHighlightingFormat("comment", QsciLexerSQL::CommentLine); - setupSyntaxHighlightingFormat("comment", QsciLexerSQL::CommentDoc); - setupSyntaxHighlightingFormat("keyword", QsciLexerSQL::Keyword); - setupSyntaxHighlightingFormat("table", QsciLexerSQL::KeywordSet6); - setupSyntaxHighlightingFormat("function", QsciLexerSQL::KeywordSet7); - setupSyntaxHighlightingFormat("string", QsciLexerSQL::DoubleQuotedString); - setupSyntaxHighlightingFormat("string", QsciLexerSQL::SingleQuotedString); - setupSyntaxHighlightingFormat("identifier", QsciLexerSQL::Identifier); - setupSyntaxHighlightingFormat("identifier", QsciLexerSQL::QuotedIdentifier); + setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::Comment); + setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::CommentLine); + setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::CommentDoc); + setupSyntaxHighlightingFormat(sqlLexer, "keyword", QsciLexerSQL::Keyword); + setupSyntaxHighlightingFormat(sqlLexer, "table", QsciLexerSQL::KeywordSet6); + setupSyntaxHighlightingFormat(sqlLexer, "function", QsciLexerSQL::KeywordSet7); + setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::DoubleQuotedString); + setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::SingleQuotedString); + setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::Identifier); + setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::QuotedIdentifier); } diff --git a/src/src.pro b/src/src.pro index 70c08e01..0165b78a 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,6 +1,6 @@ TEMPLATE = app -QT += core gui network widgets printsupport concurrent +QT += core gui network widgets printsupport concurrent xml macx: QT += opengl TARGET = sqlitebrowser @@ -59,7 +59,7 @@ HEADERS += \ RemoteDock.h \ RemoteModel.h \ RemotePushDialog.h \ - jsontextedit.h \ + docktextedit.h \ FindReplaceDialog.h \ ExtendedScintilla.h @@ -98,7 +98,7 @@ SOURCES += \ RemoteDock.cpp \ RemoteModel.cpp \ RemotePushDialog.cpp \ - jsontextedit.cpp \ + docktextedit.cpp \ FindReplaceDialog.cpp \ ExtendedScintilla.cpp From 5a4d8fdd36891901f75b9184ec65cf10daa3c3e9 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 23 Dec 2017 22:24:00 +0100 Subject: [PATCH 02/63] Restore line that was commented out in previous commit That change was unwanted. --- src/EditDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditDialog.cpp b/src/EditDialog.cpp index 7a5fbf68..507b70ff 100644 --- a/src/EditDialog.cpp +++ b/src/EditDialog.cpp @@ -661,7 +661,7 @@ void EditDialog::editTextChanged() dataLength = sciEdit->text().length(); break; } - // ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); + ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); ui->labelSize->setText(tr("%n char(s)", "", dataLength)); } } From aa680622c0364df36a20ddbbd801102a6b5003b9 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 20 Jan 2018 18:08:31 +0100 Subject: [PATCH 03/63] Bar charts and Axis Type column in Plot Dock String type columns are now selectable as X axis. In that case a bar chart is plotted where the column values are used as bar labels. A new Axis Type column is added to the axis selection table, so the user knows before-hand how the plot will be drawn. Line type and point shape combo-boxes are not enabled for bar charts, since they don't make sense. Columns that make no sense for the Y axis as strings and date/times are not selectable for that axis. --- src/PlotDock.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++---- src/PlotDock.h | 1 + src/PlotDock.ui | 7 +++++- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/PlotDock.cpp b/src/PlotDock.cpp index d1e2daf2..5cd3c9ec 100644 --- a/src/PlotDock.cpp +++ b/src/PlotDock.cpp @@ -119,9 +119,27 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett for(int i=0;icolumnCount();++i) { QVariant::Type columntype = guessDataType(model, i); - if(columntype != QVariant::String && columntype != QVariant::Invalid) + if(columntype != QVariant::Invalid) { QTreeWidgetItem* columnitem = new QTreeWidgetItem(ui->treePlotColumns); + + switch (columntype) { + case QVariant::DateTime: + columnitem->setText(PlotColumnType, "Date/Time"); + break; + case QVariant::Date: + columnitem->setText(PlotColumnType, "Date"); + break; + case QVariant::Time: + columnitem->setText(PlotColumnType, "Time"); + break; + case QVariant::Double: + columnitem->setText(PlotColumnType, "Numeric"); + break; + case QVariant::String: + columnitem->setText(PlotColumnType, "Label"); + break; + } // maybe i make this more complicated than i should // but store the model column index in the first 16 bit and the type // in the other 16 bits @@ -137,7 +155,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett columnitem->setCheckState(PlotColumnY, mapItemsY[columnitem->text(PlotColumnField)].active ? Qt::Checked : Qt::Unchecked); columnitem->setBackgroundColor(PlotColumnY, mapItemsY[columnitem->text(PlotColumnField)].colour); } else { - columnitem->setCheckState(PlotColumnY, Qt::Unchecked); + if (columntype == QVariant::Double) + columnitem->setCheckState(PlotColumnY, Qt::Unchecked); } if(sItemX == columnitem->text(PlotColumnField)) @@ -146,6 +165,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett columnitem->setCheckState(PlotColumnX, Qt::Unchecked); } } + ui->treePlotColumns->resizeColumnToContents(PlotColumnField); // Add a row number column at the beginning of the column list, but only when there were (other) columns added @@ -157,6 +177,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett uint itemdata = -1; columnitem->setData(PlotColumnField, Qt::UserRole, itemdata); columnitem->setText(PlotColumnField, tr("Row #")); + columnitem->setText(PlotColumnType, "Numeric"); // restore previous check state if(mapItemsY.contains(columnitem->text(PlotColumnField))) @@ -229,6 +250,9 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett ui->plotWidget->xAxis->setTicker(ticker); break; } + case QVariant::String: { + break; + } default: { QSharedPointer ticker(new QCPAxisTickerFixed); ticker->setTickStepStrategy(QCPAxisTicker::tssReadability); @@ -254,6 +278,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett // possible improvement might be a QVector subclass that directly // access the model data, to save memory, we are copying here QVector xdata(model->rowCount()), ydata(model->rowCount()), tdata(model->rowCount()); + QVector labels; for(int i = 0; i < model->rowCount(); ++i) { tdata[i] = i; @@ -272,6 +297,11 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett xdata[i] = t.msecsSinceStartOfDay() / 1000.0; break; } + case QVariant::String: { + xdata[i] = i+1; + labels << model->data(model->index(i, x)).toString(); + break; + } default: { // Get the x value for this point. If the selected column is -1, i.e. the row number, just use the current row number from the loop // instead of retrieving some value from the model. @@ -299,6 +329,11 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett else ydata[i] = pointdata.toDouble(); } + + // Line type and point shape are not supported by the String X type (Bars) + ui->comboLineType->setEnabled(xtype != QVariant::String); + ui->comboPointShape->setEnabled(xtype != QVariant::String); + // WARN: ssDot is removed int shapeIdx = ui->comboPointShape->currentIndex(); if (shapeIdx > 0) shapeIdx += 1; @@ -309,13 +344,23 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett // When it is not sorted by x, we draw a curve, so the order selected by the user in the table or in the query is // respected. In this case the line will have loops and only None and Line is supported as line style. // TODO: how to make the user aware of this without disturbing. - if (isSorted) { + if (xtype == QVariant::String) { + QCPBars* bars = new QCPBars(ui->plotWidget->xAxis, ui->plotWidget->yAxis); + plottable = bars; + bars->setData(xdata, ydata); + bars->setBrush(item->backgroundColor(PlotColumnY)); + QSharedPointer ticker(new QCPAxisTickerText); + ticker->addTicks(xdata, labels); + ui->plotWidget->xAxis->setTicker(ticker); + ui->plotWidget->xAxis->setTickLabelRotation(60); + } else if (isSorted) { QCPGraph* graph = ui->plotWidget->addGraph(); plottable = graph; graph->setData(xdata, ydata, /*alreadySorted*/ true); // set some graph styles not supported by the abstract plottable graph->setLineStyle((QCPGraph::LineStyle) ui->comboLineType->currentIndex()); graph->setScatterStyle(scatterStyle); + ui->plotWidget->xAxis->setTickLabelRotation(0); } else { QCPCurve* curve = new QCPCurve(ui->plotWidget->xAxis, ui->plotWidget->yAxis); @@ -327,6 +372,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett else curve->setLineStyle(QCPCurve::lsLine); curve->setScatterStyle(scatterStyle); + ui->plotWidget->xAxis->setTickLabelRotation(0); } plottable->setPen(QPen(item->backgroundColor(PlotColumnY))); @@ -483,7 +529,10 @@ void PlotDock::on_treePlotColumns_itemDoubleClicked(QTreeWidgetItem* item, int c // disable change updates, or we get unwanted redrawing and weird behavior ui->treePlotColumns->blockSignals(true); - if(column == PlotColumnY) + uint itemdata = item->data(PlotColumnField, Qt::UserRole).toUInt(); + int type = itemdata & (uint)0xFF; + + if(column == PlotColumnY && type == QVariant::Double) { // On double click open the colordialog QColorDialog colordialog(this); diff --git a/src/PlotDock.h b/src/PlotDock.h index 5b296012..6acc02dd 100644 --- a/src/PlotDock.h +++ b/src/PlotDock.h @@ -77,6 +77,7 @@ private: PlotColumnField = 0, PlotColumnX = 1, PlotColumnY = 2, + PlotColumnType = 3, }; Ui::PlotDock* ui; diff --git a/src/PlotDock.ui b/src/PlotDock.ui index b001546c..b9a7e553 100644 --- a/src/PlotDock.ui +++ b/src/PlotDock.ui @@ -30,7 +30,7 @@ true - 3 + 4 100 @@ -53,6 +53,11 @@ Y + + + Axis Type + + From 175407645be3e5acf30a4e5b95fc33410ef1de42 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 20 Jan 2018 18:28:03 +0100 Subject: [PATCH 04/63] Simplify the axis type storing, translucent additional bars and What's This Now that we have a proper type column in the plot selection widget, the internal type storing can be simplified. If the plot has more than one Y selections for one X of label type (bar charts) the first bar is opaque, but the additional are translucent in order to be seen, since they will overlap. What's This information added to explain all the possible selections for plotting. --- src/PlotDock.cpp | 46 +++++++++++++++++++++------------------------- src/PlotDock.ui | 3 +++ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/PlotDock.cpp b/src/PlotDock.cpp index 5cd3c9ec..7e37c1cc 100644 --- a/src/PlotDock.cpp +++ b/src/PlotDock.cpp @@ -72,8 +72,8 @@ PlotDock::~PlotDock() void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* settings, bool update, bool keepOrResetSelection) { // Each column has an id that we use internally, starting from 0. However, at the beginning of the columns list we want to add - // the virtual 'Row #' column which needs a separate unique id for internal use. This id is defined here as -1 in a 16bit integer. - const unsigned int RowNumId = 0xFFFF; + // the virtual 'Row #' column which needs a separate unique id for internal use. This id is defined here as -1. + const int RowNumId = -1; // add columns to x/y selection tree widget if(update) @@ -140,13 +140,11 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett columnitem->setText(PlotColumnType, "Label"); break; } - // maybe i make this more complicated than i should - // but store the model column index in the first 16 bit and the type - // in the other 16 bits - uint itemdata = 0; - itemdata = i << 16; - itemdata |= columntype; - columnitem->setData(PlotColumnField, Qt::UserRole, itemdata); + + // Store the model column index in the PlotColumnField and the type + // in the PlotColumnType, both using the User Role. + columnitem->setData(PlotColumnField, Qt::UserRole, i); + columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(columntype)); columnitem->setText(PlotColumnField, model->headerData(i, Qt::Horizontal).toString()); // restore previous check state @@ -173,10 +171,10 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett { QTreeWidgetItem* columnitem = new QTreeWidgetItem(ui->treePlotColumns); - // Just set all bits in the user role information field here to somehow indicate what column this is - uint itemdata = -1; - columnitem->setData(PlotColumnField, Qt::UserRole, itemdata); + // Just set RowNumId in the user role information field here to somehow indicate what column this is + columnitem->setData(PlotColumnField, Qt::UserRole, RowNumId); columnitem->setText(PlotColumnField, tr("Row #")); + columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(QVariant::Double)); columnitem->setText(PlotColumnType, "Numeric"); // restore previous check state @@ -223,11 +221,9 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett if(xitem) { // regain the model column index and the datatype - // leading 16 bit are column index, the other 16 bit are the datatype - // right now datatype is only important for X axis (date, non date) - uint xitemdata = xitem->data(PlotColumnField, Qt::UserRole).toUInt(); - int x = xitemdata >> 16; - int xtype = xitemdata & (uint)0xFF; + // right now datatype is only important for X axis (Y is always numeric) + int x = xitem->data(PlotColumnField, Qt::UserRole).toInt(); + int xtype = xitem->data(PlotColumnType, Qt::UserRole).toInt(); // check if we have a x axis with datetime data switch (xtype) { @@ -267,10 +263,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); if(item->checkState((PlotColumnY)) == Qt::Checked) { - // regain the model column index and the datatype - // leading 16 bit are column index - uint itemdata = item->data(0, Qt::UserRole).toUInt(); - int column = itemdata >> 16; + // regain the model column index + int column = item->data(PlotColumnField, Qt::UserRole).toInt(); bool isSorted = true; @@ -348,7 +342,10 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett QCPBars* bars = new QCPBars(ui->plotWidget->xAxis, ui->plotWidget->yAxis); plottable = bars; bars->setData(xdata, ydata); - bars->setBrush(item->backgroundColor(PlotColumnY)); + QColor brush = item->backgroundColor(PlotColumnY); + if (ui->plotWidget->plottableCount() > 1) + brush.setAlpha(124); + bars->setBrush(brush); QSharedPointer ticker(new QCPAxisTickerText); ticker->addTicks(xdata, labels); ui->plotWidget->xAxis->setTicker(ticker); @@ -376,7 +373,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett } plottable->setPen(QPen(item->backgroundColor(PlotColumnY))); - plottable->setSelectable (QCP::stDataRange); + plottable->setSelectable(QCP::stDataRange); // gather Y label column names if(column == RowNumId) @@ -529,8 +526,7 @@ void PlotDock::on_treePlotColumns_itemDoubleClicked(QTreeWidgetItem* item, int c // disable change updates, or we get unwanted redrawing and weird behavior ui->treePlotColumns->blockSignals(true); - uint itemdata = item->data(PlotColumnField, Qt::UserRole).toUInt(); - int type = itemdata & (uint)0xFF; + int type = item->data(PlotColumnType, Qt::UserRole).toInt(); if(column == PlotColumnY && type == QVariant::Double) { diff --git a/src/PlotDock.ui b/src/PlotDock.ui index b9a7e553..d37703af 100644 --- a/src/PlotDock.ui +++ b/src/PlotDock.ui @@ -26,6 +26,9 @@ 2 + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + true From c5ec23e92e352af5a6220328bda5f28069a26a60 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sun, 21 Jan 2018 17:00:45 +0100 Subject: [PATCH 05/63] Stacked or grouped bars and plot legend Two new options added to the context menu of the plot: - Stacked bars: switches between stacked bars or grouped bars. The former overlapped layout is avoided since it doesn't make much sense. - Show legend: toggles the display of a plot legend with a translucent background. Possible future improvement is dragging the legend with the mouse. --- src/PlotDock.cpp | 127 ++++++++++++++++++++++++++++++++++++----------- src/PlotDock.h | 6 ++- 2 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/PlotDock.cpp b/src/PlotDock.cpp index 7e37c1cc..cf9c33d7 100644 --- a/src/PlotDock.cpp +++ b/src/PlotDock.cpp @@ -9,7 +9,9 @@ PlotDock::PlotDock(QWidget* parent) : QDialog(parent), ui(new Ui::PlotDock), m_currentPlotModel(nullptr), - m_currentTableSettings(nullptr) + m_currentTableSettings(nullptr), + m_showLegend(false), + m_stackedBars(false) { ui->setupUi(this); @@ -50,6 +52,18 @@ PlotDock::PlotDock(QWidget* parent) copy(); }); + QAction* showLegendAction = new QAction(tr("Show legend"), m_contextMenu); + showLegendAction->setCheckable(true); + m_contextMenu->addAction(showLegendAction); + + connect(showLegendAction, SIGNAL(toggled(bool)), this, SLOT(toggleLegendVisible(bool))); + + QAction* stackedBarsAction = new QAction(tr("Stacked bars"), m_contextMenu); + stackedBarsAction->setCheckable(true); + m_contextMenu->addAction(stackedBarsAction); + + connect(stackedBarsAction, SIGNAL(toggled(bool)), this, SLOT(toggleStackedBars(bool))); + connect(ui->plotWidget, &QTableView::customContextMenuRequested, [=](const QPoint& pos) { // Show menu @@ -225,6 +239,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett int x = xitem->data(PlotColumnField, Qt::UserRole).toInt(); int xtype = xitem->data(PlotColumnType, Qt::UserRole).toInt(); + ui->plotWidget->xAxis->setTickLabelRotation(0); + // check if we have a x axis with datetime data switch (xtype) { case QVariant::Date: { @@ -247,6 +263,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett break; } case QVariant::String: { + // Ticker is set when we have got the labels + ui->plotWidget->xAxis->setTickLabelRotation(60); break; } default: { @@ -334,6 +352,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett QCPScatterStyle scatterStyle = QCPScatterStyle(static_cast(shapeIdx), 5); QCPAbstractPlottable* plottable; + // When the X type is String, we draw a bar chart. // When it is already sorted by x, we draw a graph. // When it is not sorted by x, we draw a curve, so the order selected by the user in the table or in the query is // respected. In this case the line will have loops and only None and Line is supported as line style. @@ -342,38 +361,39 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett QCPBars* bars = new QCPBars(ui->plotWidget->xAxis, ui->plotWidget->yAxis); plottable = bars; bars->setData(xdata, ydata); - QColor brush = item->backgroundColor(PlotColumnY); - if (ui->plotWidget->plottableCount() > 1) - brush.setAlpha(124); - bars->setBrush(brush); - QSharedPointer ticker(new QCPAxisTickerText); - ticker->addTicks(xdata, labels); - ui->plotWidget->xAxis->setTicker(ticker); - ui->plotWidget->xAxis->setTickLabelRotation(60); - } else if (isSorted) { - QCPGraph* graph = ui->plotWidget->addGraph(); - plottable = graph; - graph->setData(xdata, ydata, /*alreadySorted*/ true); - // set some graph styles not supported by the abstract plottable - graph->setLineStyle((QCPGraph::LineStyle) ui->comboLineType->currentIndex()); - graph->setScatterStyle(scatterStyle); - ui->plotWidget->xAxis->setTickLabelRotation(0); - + // Set ticker once + if (ui->plotWidget->plottableCount() == 1) { + QSharedPointer ticker(new QCPAxisTickerText); + ticker->addTicks(xdata, labels); + ui->plotWidget->xAxis->setTicker(ticker); + } + QColor color = item->backgroundColor(PlotColumnY); + bars->setBrush(color); + plottable->setPen(QPen(color.darker(150))); } else { - QCPCurve* curve = new QCPCurve(ui->plotWidget->xAxis, ui->plotWidget->yAxis); - plottable = curve; - curve->setData(tdata, xdata, ydata, /*alreadySorted*/ true); - // set some curve styles not supported by the abstract plottable - if (ui->comboLineType->currentIndex() == QCPCurve::lsNone) - curve->setLineStyle(QCPCurve::lsNone); - else - curve->setLineStyle(QCPCurve::lsLine); - curve->setScatterStyle(scatterStyle); - ui->plotWidget->xAxis->setTickLabelRotation(0); + if (isSorted) { + QCPGraph* graph = ui->plotWidget->addGraph(); + plottable = graph; + graph->setData(xdata, ydata, /*alreadySorted*/ true); + // set some graph styles not supported by the abstract plottable + graph->setLineStyle((QCPGraph::LineStyle) ui->comboLineType->currentIndex()); + graph->setScatterStyle(scatterStyle); + } else { + QCPCurve* curve = new QCPCurve(ui->plotWidget->xAxis, ui->plotWidget->yAxis); + plottable = curve; + curve->setData(tdata, xdata, ydata, /*alreadySorted*/ true); + // set some curve styles not supported by the abstract plottable + if (ui->comboLineType->currentIndex() == QCPCurve::lsNone) + curve->setLineStyle(QCPCurve::lsNone); + else + curve->setLineStyle(QCPCurve::lsLine); + curve->setScatterStyle(scatterStyle); + } + plottable->setPen(QPen(item->backgroundColor(PlotColumnY))); } - plottable->setPen(QPen(item->backgroundColor(PlotColumnY))); plottable->setSelectable(QCP::stDataRange); + plottable->setName(item->text(PlotColumnField)); // gather Y label column names if(column == RowNumId) @@ -384,6 +404,9 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett } ui->plotWidget->rescaleAxes(true); + ui->plotWidget->legend->setVisible(m_showLegend); + // Legend with slightly transparent background brush: + ui->plotWidget->legend->setBrush(QColor(255, 255, 255, 150)); // set axis labels if(x == RowNumId) @@ -392,6 +415,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett ui->plotWidget->xAxis->setLabel(model->headerData(x, Qt::Horizontal).toString()); ui->plotWidget->yAxis->setLabel(yAxisLabels.join("|")); } + + adjustBars(); ui->plotWidget->replot(); // Warn user if not all data has been fetched and hint about the button for loading all the data @@ -789,3 +814,47 @@ void PlotDock::copy() { QApplication::clipboard()->setPixmap(ui->plotWidget->toPixmap()); } + +void PlotDock::toggleLegendVisible(bool visible) +{ + m_showLegend = visible; + ui->plotWidget->legend->setVisible(m_showLegend); + ui->plotWidget->replot(); +} + +// Stack or group bars and set the appropiate bar width (since it is not automatically done by QCustomPlot). +void PlotDock::adjustBars() +{ + const double padding = 0.15; + const double groupedWidth = ui->plotWidget->plottableCount()? 1.0 / ui->plotWidget->plottableCount() : 0.0; + QCPBars* previousBar = nullptr; + QCPBarsGroup* barsGroup = m_stackedBars? nullptr : new QCPBarsGroup(ui->plotWidget); + for (int i = 0, ie = ui->plotWidget->plottableCount(); i < ie; ++i) + { + QCPBars* bar = qobject_cast(ui->plotWidget->plottable(i)); + if (bar) { + if (m_stackedBars) { + // Ungroup if grouped + bar->setBarsGroup(nullptr); + if (previousBar) + bar->moveAbove(previousBar); + // Set width to ocuppy the full coordinate space, less padding + bar->setWidth(1.0 - padding); + } else { + // Unstack if stacked + bar->moveAbove(nullptr); + bar->setBarsGroup(barsGroup); + // Set width to a plot coordinate width, less padding + bar->setWidth(groupedWidth - padding); + } + previousBar = bar; + } + } +} + +void PlotDock::toggleStackedBars(bool stacked) +{ + m_stackedBars = stacked; + adjustBars(); + ui->plotWidget->replot(); +} diff --git a/src/PlotDock.h b/src/PlotDock.h index 6acc02dd..11631582 100644 --- a/src/PlotDock.h +++ b/src/PlotDock.h @@ -85,6 +85,8 @@ private: SqliteTableModel* m_currentPlotModel; BrowseDataTableSettings* m_currentTableSettings; QMenu* m_contextMenu; + bool m_showLegend; + bool m_stackedBars; /*! * \brief guessdatatype try to parse the first 10 rows and decide the datatype @@ -93,6 +95,7 @@ private: * \return the guessed datatype */ QVariant::Type guessDataType(SqliteTableModel* model, int column); + void adjustBars(); private slots: void on_treePlotColumns_itemChanged(QTreeWidgetItem* item, int column); @@ -104,7 +107,8 @@ private slots: void mousePress(); void mouseWheel(); void copy(); - + void toggleLegendVisible(bool visible); + void toggleStackedBars(bool stacked); }; #endif From 1110b87d95108f3f01430f7e05aec4c9e7ebc628 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Fri, 26 Jan 2018 14:44:13 +0100 Subject: [PATCH 06/63] Fix structure view after changing settings This is fixing a follow-up issue of 012ad9217a9bb71264bb6c5ad3a1da847610effc. See issue #1288. --- src/MainWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 5d9c0483..fcf46479 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1933,6 +1933,7 @@ void MainWindow::reloadSettings() // Refresh view dbStructureModel->reloadData(); + populateStructure(); populateTable(); // Hide or show the remote dock as needed From 74f19d7bc86bd125fa3f6a27671a355dde391a57 Mon Sep 17 00:00:00 2001 From: phydroxide <31145228+phydroxide@users.noreply.github.com> Date: Fri, 26 Jan 2018 06:29:38 -0800 Subject: [PATCH 07/63] Update BUILDING.md (#1307) * Update BUILDING.md Package list for Yum incomplete * Update BUILDING.md My first git clone or contribution ever so bear with me --- BUILDING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BUILDING.md b/BUILDING.md index 9df79344..0fb6283a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -87,6 +87,11 @@ $ sudo make install This should complete without errors, and `sqlitebrowser` should now be launch-able from the command line. +**Note 3** +On CentOS if cmake complains about missing Qt5 Libraries or sqllite: +``` sudo yum install ant-antlr antlr-C++ cmake gcc-c++ git qt-dev qwt-qt5-devel sqllite-devel qt qt5widgets qt5-qtbase-devel qt5-linguist sqlite-devel``` + + ### MacOS X The application can be compiled to a single executable binary file, similar to From 42bb1c0d65dec158c0c83ba32764b85031598f5c Mon Sep 17 00:00:00 2001 From: mgrojo Date: Fri, 26 Jan 2018 18:13:20 +0100 Subject: [PATCH 08/63] Translatable strings and default case branch This addresses review comments by @MKleusberg in PR #1302. --- src/PlotDock.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/PlotDock.cpp b/src/PlotDock.cpp index cf9c33d7..3f382fa7 100644 --- a/src/PlotDock.cpp +++ b/src/PlotDock.cpp @@ -139,20 +139,23 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett switch (columntype) { case QVariant::DateTime: - columnitem->setText(PlotColumnType, "Date/Time"); + columnitem->setText(PlotColumnType, tr("Date/Time")); break; case QVariant::Date: - columnitem->setText(PlotColumnType, "Date"); + columnitem->setText(PlotColumnType, tr("Date")); break; case QVariant::Time: - columnitem->setText(PlotColumnType, "Time"); + columnitem->setText(PlotColumnType, tr("Time")); break; case QVariant::Double: - columnitem->setText(PlotColumnType, "Numeric"); + columnitem->setText(PlotColumnType, tr("Numeric")); break; case QVariant::String: - columnitem->setText(PlotColumnType, "Label"); + columnitem->setText(PlotColumnType, tr("Label")); break; + default: + // This is not actually expected + columnitem->setText(PlotColumnType, tr("Invalid")); } // Store the model column index in the PlotColumnField and the type @@ -189,7 +192,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett columnitem->setData(PlotColumnField, Qt::UserRole, RowNumId); columnitem->setText(PlotColumnField, tr("Row #")); columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(QVariant::Double)); - columnitem->setText(PlotColumnType, "Numeric"); + columnitem->setText(PlotColumnType, tr("Numeric")); // restore previous check state if(mapItemsY.contains(columnitem->text(PlotColumnField))) From b5af5653fcfa5a27a0e9e54629dfc97c1e3e8111 Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Fri, 26 Jan 2018 17:36:38 +0000 Subject: [PATCH 09/63] Tweak the CentOS 7 build instructions They should now avoid giving a warning about a missing `qwt-qt5-devel` package. --- BUILDING.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 0fb6283a..2b356cb4 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -71,9 +71,10 @@ Done. :) ### CentOS / Fedora Linux -**Note** - On CentOS or an older version of Fedora, you may need to use `yum` instead of `dnf` +**Note** - On CentOS or an older version of Fedora, you may need to use `yum` instead of `dnf`. -**Note 2** - On CentOS 7.x, you need to add `qt5-qtbase-devel` to the `dnf install` line below +**Note 2** - On CentOS 7.x, you need to replace the `qwt-qt5-devel` package name with +`qt5-qtbase-devel` in the `dnf install` line below. ``` $ sudo dnf install ant-antlr antlr-C++ cmake gcc-c++ git qt-devel qt5-linguist qwt-qt5-devel \ @@ -87,11 +88,6 @@ $ sudo make install This should complete without errors, and `sqlitebrowser` should now be launch-able from the command line. -**Note 3** -On CentOS if cmake complains about missing Qt5 Libraries or sqllite: -``` sudo yum install ant-antlr antlr-C++ cmake gcc-c++ git qt-dev qwt-qt5-devel sqllite-devel qt qt5widgets qt5-qtbase-devel qt5-linguist sqlite-devel``` - - ### MacOS X The application can be compiled to a single executable binary file, similar to From 0c99f32ce7aa4a0e5481722934c9b6495fcd6589 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 27 Jan 2018 18:30:24 +0100 Subject: [PATCH 10/63] Address comments in PR XML mode for the cell editor #1275 Set breaks in nested switch where missing. Fix editModeChanged since it was overwriting the dataType for JSON and SVG. Additionally, removed unnecessary conversion in fromJson. --- src/EditDialog.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/EditDialog.cpp b/src/EditDialog.cpp index 507b70ff..cad770fe 100644 --- a/src/EditDialog.cpp +++ b/src/EditDialog.cpp @@ -473,6 +473,7 @@ void EditDialog::accept() } break; } + break; case HexBuffer: // The data source is the hex widget buffer, thus binary data QByteArray oldData = currentIndex.data(Qt::EditRole).toByteArray(); @@ -553,6 +554,7 @@ void EditDialog::setDataInBuffer(const QByteArray& data, DataSources source) } break; } + break; case HexBuffer: hexEdit->setData(data); hexEdit->setEnabled(true); @@ -648,8 +650,10 @@ void EditDialog::editTextChanged() if (dataSource == TextBuffer || dataSource == SciBuffer) { // Data has been changed in the text editor, so it can't be a NULL // any more. It hasn't been validated yet, so it cannot be JSON nor XML. - dataType = Text; - + if (dataType == Null) { + dataType = Text; + ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); + } // Update the cell info in the bottom left manually. This is because // updateCellInfo() only works with QByteArray's (for now) int dataLength; @@ -661,7 +665,6 @@ void EditDialog::editTextChanged() dataLength = sciEdit->text().length(); break; } - ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); ui->labelSize->setText(tr("%n char(s)", "", dataLength)); } } @@ -698,7 +701,7 @@ int EditDialog::checkDataType(const QByteArray& data) // Check if it's text only if (QString(cellData).toUtf8() == cellData) { // Is there a better way to check this? - QJsonDocument jsonDoc = QJsonDocument::fromJson(QString(cellData).toUtf8()); + QJsonDocument jsonDoc = QJsonDocument::fromJson(cellData); if (!jsonDoc.isNull()) return JSON; else From 5dbb7ff6457c40e23b853c49c5fec1295af746ef Mon Sep 17 00:00:00 2001 From: mgrojo Date: Tue, 30 Jan 2018 20:33:15 +0100 Subject: [PATCH 11/63] Ensure the Escape key doesn't make Plot and Remote docks go away Override reject() as done in other dock dialogs. Fixes #1310 --- src/PlotDock.cpp | 7 +++++++ src/PlotDock.h | 1 + src/RemoteDock.cpp | 7 +++++++ src/RemoteDock.h | 3 +++ 4 files changed, 18 insertions(+) diff --git a/src/PlotDock.cpp b/src/PlotDock.cpp index 3f382fa7..0be88aa2 100644 --- a/src/PlotDock.cpp +++ b/src/PlotDock.cpp @@ -861,3 +861,10 @@ void PlotDock::toggleStackedBars(bool stacked) adjustBars(); ui->plotWidget->replot(); } + +void PlotDock::reject() +{ + // We override this, to ensure the Escape key doesn't make this dialog + // dock go away + return; +} diff --git a/src/PlotDock.h b/src/PlotDock.h index 11631582..fb609f9a 100644 --- a/src/PlotDock.h +++ b/src/PlotDock.h @@ -67,6 +67,7 @@ public slots: void updatePlot(SqliteTableModel* model, BrowseDataTableSettings* settings = nullptr, bool update = true, bool keepOrResetSelection = true); void fetchAllData(); void resetPlot(); + virtual void reject(); signals: void pointsSelected(int firstIndex, int count); diff --git a/src/RemoteDock.cpp b/src/RemoteDock.cpp index f53c9be8..b64f2125 100644 --- a/src/RemoteDock.cpp +++ b/src/RemoteDock.cpp @@ -132,3 +132,10 @@ void RemoteDock::newDirectoryNode(const QModelIndex& parent) } } } + +void RemoteDock::reject() +{ + // We override this, to ensure the Escape key doesn't make this dialog + // dock go away + return; +} diff --git a/src/RemoteDock.h b/src/RemoteDock.h index ac8649d7..070237de 100644 --- a/src/RemoteDock.h +++ b/src/RemoteDock.h @@ -22,6 +22,9 @@ public: void reloadSettings(); void enableButtons(); +public slots: + virtual void reject(); + private slots: void setNewIdentity(); void fetchDatabase(const QModelIndex& idx); From 290461778dd26e8d76d7bf59870bd943263dc3b8 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Tue, 30 Jan 2018 21:01:44 +0100 Subject: [PATCH 12/63] Fix qmake compilation for XML mode PR #1275 Also, some spaces have been replaced by tabs for uniformity. See issue #1309 --- libs/qscintilla/Qt4Qt5/qscintilla.pro | 35 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/libs/qscintilla/Qt4Qt5/qscintilla.pro b/libs/qscintilla/Qt4Qt5/qscintilla.pro index 127f249a..1901b09b 100644 --- a/libs/qscintilla/Qt4Qt5/qscintilla.pro +++ b/libs/qscintilla/Qt4Qt5/qscintilla.pro @@ -87,6 +87,11 @@ HEADERS = \ ./Qsci/qscilexercustom.h \ ./Qsci/qscilexersql.h \ ./Qsci/qscilexerjson.h \ + ./Qsci/qscilexerhtml.h \ + ./Qsci/qscilexerxml.h \ + ./Qsci/qscilexerjavascript.h \ + ./Qsci/qscilexercpp.h \ + ./Qsci/qscilexerpython.h \ ./Qsci/qscimacro.h \ ./Qsci/qsciprinter.h \ ./Qsci/qscistyle.h \ @@ -157,21 +162,27 @@ SOURCES = \ qscicommandset.cpp \ qscidocument.cpp \ qscilexer.cpp \ - qscilexercustom.cpp \ - qscilexersql.cpp \ - qscilexerjson.cpp \ + qscilexercustom.cpp \ + qscilexersql.cpp \ + qscilexerjson.cpp \ + qscilexerhtml.cpp \ + qscilexerxml.cpp \ + qscilexerjavascript.cpp \ + qscilexercpp.cpp \ + qscilexerpython.cpp \ qscimacro.cpp \ qsciprinter.cpp \ qscistyle.cpp \ qscistyledtext.cpp \ - MacPasteboardMime.cpp \ - InputMethod.cpp \ + MacPasteboardMime.cpp \ + InputMethod.cpp \ SciClasses.cpp \ ListBoxQt.cpp \ PlatQt.cpp \ - ScintillaQt.cpp \ - ../lexers/LexSQL.cpp \ - ../lexers/LexJSON.cpp \ + ScintillaQt.cpp \ + ../lexers/LexSQL.cpp \ + ../lexers/LexJSON.cpp \ + ../lexers/LexHTML.cpp \ ../lexlib/Accessor.cpp \ ../lexlib/CharacterCategory.cpp \ ../lexlib/CharacterSet.cpp \ @@ -197,15 +208,15 @@ SOURCES = \ ../src/EditView.cpp \ ../src/ExternalLexer.cpp \ ../src/Indicator.cpp \ - ../src/KeyMap.cpp \ + ../src/KeyMap.cpp \ ../src/LineMarker.cpp \ ../src/MarginView.cpp \ ../src/PerLine.cpp \ ../src/PositionCache.cpp \ - ../src/RESearch.cpp \ + ../src/RESearch.cpp \ ../src/RunStyles.cpp \ - ../src/ScintillaBase.cpp \ - ../src/Selection.cpp \ + ../src/ScintillaBase.cpp \ + ../src/Selection.cpp \ ../src/Style.cpp \ ../src/UniConversion.cpp \ ../src/ViewStyle.cpp \ From e43ed1716251b2f50e7b1d7c231acdc27449c1c8 Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Tue, 30 Jan 2018 20:02:35 +0000 Subject: [PATCH 13/63] Include the Qt XML dll in our installation package --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b790b95f..a306ad95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -447,6 +447,16 @@ if(WIN32 AND MSVC) DESTINATION platforms) install(PROGRAMS "${VSREDIST_DIR}/${VSREDIST}" DESTINATION redist) + # The XML dll + install(FILES + "${QT5_PATH}/bin/Qt5Xmld.dll" + DESTINATION "/" + CONFIGURATIONS Debug) + install(FILES + "${QT5_PATH}/bin/Qt5Xml.dll" + DESTINATION "/" + CONFIGURATIONS Release) + # The image format plugins install(FILES ${WIN_IMG_PLUGINS_DEBUG} From 52ae85dd28ac8a21e5db67db02e551e059917821 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Fri, 2 Feb 2018 21:27:28 +0100 Subject: [PATCH 14/63] Added some "What's This" information Added some texts to the "What's This" information of some buttons or other widgets that lacked them. This will help the user to discover the provided features. Specifically, help is added for the filter fields and the remote dock. See discussions in issues #1311 and #1312. --- src/EditDialog.ui | 6 +++++ src/FilterLineEdit.cpp | 12 ++++++++++ src/MainWindow.ui | 50 +++++++++++++++++++++++++++++++++++++++++- src/RemoteDock.ui | 6 ++++- 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/EditDialog.ui b/src/EditDialog.ui index ed9b2eb8..f920188c 100644 --- a/src/EditDialog.ui +++ b/src/EditDialog.ui @@ -37,6 +37,9 @@ 0 + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Text @@ -258,6 +261,9 @@ Errors are indicated with a red squiggle underline. Apply data to cell [Ctrl+Return] + + This button saves the changes performed in the cell editor to the database cell. + Apply diff --git a/src/FilterLineEdit.cpp b/src/FilterLineEdit.cpp index d00ad628..7c9d0a99 100644 --- a/src/FilterLineEdit.cpp +++ b/src/FilterLineEdit.cpp @@ -20,6 +20,18 @@ FilterLineEdit::FilterLineEdit(QWidget* parent, QList* filters, connect(this, SIGNAL(textChanged(QString)), delaySignalTimer, SLOT(start())); connect(delaySignalTimer, SIGNAL(timeout()), this, SLOT(delayedSignalTimerTriggered())); + setWhatsThis(tr("These input fields allow you to perform quick filters in the currently selected table.\n" + "By default, the rows containing the input text are filtered out.\n" + "The following operators are also supported:\n" + "%\tWildcard\n" + ">\tGreater than\n" + "<\tLess than\n" + ">=\tEqual to or greater\n" + "<=\tEqual to or less\n" + "=\tEqual to: exact match\n" + "<>\tUnequal: exact inverse match\n" + "x~y\tRange: values between x and y")); + // Immediately emit the delayed filter value changed signal if the user presses the enter or the return key or // the line edit widget loses focus connect(this, SIGNAL(editingFinished()), this, SLOT(delayedSignalTimerTriggered())); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 6211e390..fc8c9c1f 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -154,6 +154,9 @@ You can drag SQL sentences from an object row and drop them into other applicati Clear all filters + + This button clears all the filters set in the header input fields for the currently browsed table. + @@ -168,6 +171,9 @@ You can drag SQL sentences from an object row and drop them into other applicati Save the current filter, sort column and display formats as a view + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + ... @@ -209,7 +215,7 @@ You can drag SQL sentences from an object row and drop them into other applicati Delete the current record - This button deletes the record currently selected in the database + This button deletes the record or records currently selected in the table Delete Record @@ -1060,6 +1066,9 @@ You can drag SQL sentences from an object row and drop them into other applicati 30 + + This button clears the contents of the SQL logs + &Clear @@ -1069,6 +1078,9 @@ You can drag SQL sentences from an object row and drop them into other applicati + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + 0 @@ -1268,6 +1280,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Close the current database file + + This button closes the connection to the currently open database file + Ctrl+W @@ -1563,6 +1578,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Open &tab + + This button opens a new tab for the SQL editor + Ctrl+T @@ -1578,6 +1596,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Execute SQL [F5, Ctrl+Return, Ctrl+R] + + This button executes all the SQL statements of the current editor tab + @@ -1587,6 +1608,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Open SQL file + + This button opens a file containing SQL statements and loads it in a new editor tab + @@ -1623,6 +1647,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Execute current line [Shift+F5] + + This button executes the SQL statement present in the current editor line + Shift+F5 @@ -1688,6 +1715,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Save the current session to a file + + This button lets you save all the settings associated to the open DB to a DB4S project file + QAction::NoRole @@ -1706,6 +1736,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Load a working session from a file + + This button lets you open a DB4S project file + QAction::NoRole @@ -1727,6 +1760,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Add another database file to the current database connection + + This button lets you add another database file to the current database connection + QAction::NoRole @@ -1766,6 +1802,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Save SQL file + + This button opens a saves the content of the current SQL editor tab to a file + @@ -1897,6 +1936,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Save the results view + + This button lets you save the results of the last executed query + @@ -1912,6 +1954,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Find text in SQL editor [Ctrl+F] + + This button opens the search bar of the editor + Ctrl+F @@ -1930,6 +1975,9 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi Find or replace text in SQL editor [Ctrl+H] + + This button opens the find/replace dialog for the current editor tab + diff --git a/src/RemoteDock.ui b/src/RemoteDock.ui index 70489237..c1b5690c 100644 --- a/src/RemoteDock.ui +++ b/src/RemoteDock.ui @@ -74,7 +74,11 @@ - + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB4S. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to create a DB4S certificate (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB4S Preferences. Click the button to add a new certificate to DB4S and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + From b8e96379a749ef9369ab739feceb2d5f54ca9cf4 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 3 Feb 2018 16:14:30 +0100 Subject: [PATCH 15/63] Set disabled palette for the cell text editor when read-only In this way the user gets a hint about the text being read-only while still being able to select text with keyboard and mouse. See issue #1123 --- src/EditDialog.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/EditDialog.cpp b/src/EditDialog.cpp index 2def845d..75d004f7 100644 --- a/src/EditDialog.cpp +++ b/src/EditDialog.cpp @@ -754,21 +754,40 @@ void EditDialog::setFocus() } -// Enables or disables the Apply, Null, & Import buttons in the Edit Cell dock +// Enables or disables the Apply, Null, & Import buttons in the Edit Cell dock. +// Sets or unsets read-only properties for the editors. void EditDialog::setReadOnly(bool ro) { isReadOnly = ro; + QPalette textEditPalette = ui->editorText->palette(); ui->buttonApply->setEnabled(!ro); ui->buttonNull->setEnabled(!ro); ui->buttonImport->setEnabled(!ro); ui->editorText->setReadOnly(ro); + sciEdit->setReadOnly(ro); + // We disable the entire hex editor here instead of setting it to read only because it doesn't have a setReadOnly() method + ui->editorBinary->setEnabled(!ro); + + // This makes the caret being visible for selection, although the editor is read-only. Qt::TextInteractionFlags textFlags = ro? Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard : Qt::TextEditorInteraction; ui->editorText->setTextInteractionFlags(textFlags); - ui->editorBinary->setEnabled(!ro); // We disable the entire hex editor here instead of setting it to read only because it doesn't have a setReadOnly() method - sciEdit->setReadOnly(ro); + // If read-only, set the Disabled palette settings for the (in)active groups, so the user gets a hint about the text being read-only. + // This should be set also for the Scintilla widget, but it isn't working for that. + if (ro) { + textEditPalette.setColor(QPalette::Active, QPalette::Base, textEditPalette.color(QPalette::Disabled, QPalette::Base)); + textEditPalette.setColor(QPalette::Inactive, QPalette::Base, textEditPalette.color(QPalette::Disabled, QPalette::Base)); + textEditPalette.setColor(QPalette::Active, QPalette::Highlight, textEditPalette.color(QPalette::Disabled, QPalette::Highlight)); + textEditPalette.setColor(QPalette::Inactive, QPalette::Highlight, textEditPalette.color(QPalette::Disabled, QPalette::Highlight)); + textEditPalette.setColor(QPalette::Active, QPalette::HighlightedText, textEditPalette.color(QPalette::Disabled, QPalette::HighlightedText)); + textEditPalette.setColor(QPalette::Inactive, QPalette::HighlightedText, textEditPalette.color(QPalette::Disabled, QPalette::HighlightedText)); + ui->editorText->setPalette(textEditPalette); + } else { + // Restore default palette + ui->editorText->setPalette(QPalette()); + } } // Update the information labels in the bottom left corner of the dialog From 65c670acc017b9f3ef14bd69409c234f7f1ff8c3 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Wed, 14 Feb 2018 23:19:53 +0100 Subject: [PATCH 16/63] Do not escape single cell data in clipboard copy For single cell without-headers copy it is better to not escape the text since there isn't any gain in trying to escape quotes, end-of-lines or tabs. Escaping should only be done for table like data for compatibility to spreadsheets applications. See issue #1244. --- src/ExtendedTableWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ExtendedTableWidget.cpp b/src/ExtendedTableWidget.cpp index 1ed5663b..9ed7e11b 100644 --- a/src/ExtendedTableWidget.cpp +++ b/src/ExtendedTableWidget.cpp @@ -265,8 +265,8 @@ void ExtendedTableWidget::copy(const bool withHeaders) return; } - // The field isn't empty. Quote data as needed and copy it to the clipboard - qApp->clipboard()->setText(escapeCopiedData(data.toByteArray())); + // The field isn't empty. Copy the text to the clipboard without quoting (for general plain text clipboard) + qApp->clipboard()->setText(data.toByteArray()); return; } } From 379bbb81a2fd3849980788bcf8aaa63141f87a15 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sun, 25 Feb 2018 19:13:28 +0100 Subject: [PATCH 17/63] Support for dark themes in default settings and restore defaults button All the colour configurations have been reviewed under an operating-system theme dark theme. Some hard-coded colours in QScintilla editors and Data Browser have been replaced by queries of the system palette or reuse of our settings. New settings for foreground and background colours for QScintilla editors defaulting to system colours. This is mainly needed because if the user saves colour settings for a dark theme and then he changes the system theme back to a light theme, then the foreground colours are preserved while the background would fall back to the system theme leading to an incompatible combination. This also gives more freedom to the user in defining his own colour combinations. Since only the default colour settings adapt to the system theme, and once settings are saved this can no longer happen, a 'Restore Defaults' button is added so the default adapted colour settings can be restored. This is also useful for restoring default behaviour when wanted. Other fixes and improvements: waiting cursor while saving; check boxes in SQL tab for bold, italic and underline when applicable; avoid translation of hidden colour setting names used in code. See related issue #1324. --- src/ExtendedScintilla.cpp | 19 ++++++++-- src/ExtendedScintilla.h | 2 ++ src/PreferencesDialog.cpp | 23 ++++++++++-- src/PreferencesDialog.h | 2 ++ src/PreferencesDialog.ui | 70 ++++++++++++++++++------------------ src/Settings.cpp | 74 +++++++++++++++++++++++++++++---------- src/Settings.h | 1 + src/docktextedit.cpp | 5 +++ 8 files changed, 139 insertions(+), 57 deletions(-) diff --git a/src/ExtendedScintilla.cpp b/src/ExtendedScintilla.cpp index 4ca3de4b..b86048e6 100644 --- a/src/ExtendedScintilla.cpp +++ b/src/ExtendedScintilla.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -99,6 +100,17 @@ void ExtendedScintilla::setupSyntaxHighlightingFormat(QsciLexer *lexer, const QS lexer->setFont(font, style); } +void ExtendedScintilla::setLexer(QsciLexer *lexer) +{ + QsciScintilla::setLexer(lexer); + + // Set margins to system window theme. setLexer seems to reset these colours. + setMarginsBackgroundColor(QPalette().color(QPalette::Active, QPalette::Window)); + setMarginsForegroundColor(QPalette().color(QPalette::Active, QPalette::WindowText)); + setIndentationGuidesBackgroundColor(QPalette().color(QPalette::Active, QPalette::Window)); + setIndentationGuidesForegroundColor(QPalette().color(QPalette::Active, QPalette::WindowText)); +} + void ExtendedScintilla::reloadKeywords() { // Set lexer again to reload the updated keywords list @@ -115,9 +127,11 @@ void ExtendedScintilla::reloadLexerSettings(QsciLexer *lexer) QFont defaultfont(Settings::getValue("editor", "font").toString()); defaultfont.setStyleHint(QFont::TypeWriter); defaultfont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); - lexer->setDefaultColor(Qt::black); lexer->setFont(defaultfont); + lexer->setDefaultColor(QColor(Settings::getValue("syntaxhighlighter", "foreground_colour").toString())); + lexer->setPaper(QColor(Settings::getValue("syntaxhighlighter", "background_colour").toString())); + // Set font QFont font(Settings::getValue("editor", "font").toString()); font.setStyleHint(QFont::TypeWriter); @@ -129,12 +143,13 @@ void ExtendedScintilla::reloadLexerSettings(QsciLexer *lexer) marginsfont.setPointSize(font.pointSize()); setMarginsFont(marginsfont); setMarginLineNumbers(0, true); - setMarginsBackgroundColor(Qt::lightGray); + updateLineNumberAreaWidth(); // Highlight current line setCaretLineVisible(true); setCaretLineBackgroundColor(QColor(Settings::getValue("syntaxhighlighter", "currentline_colour").toString())); + setCaretForegroundColor(QColor(Settings::getValue("syntaxhighlighter", "foreground_colour").toString())); // Set tab width setTabWidth(Settings::getValue("editor", "tabsize").toInt()); diff --git a/src/ExtendedScintilla.h b/src/ExtendedScintilla.h index 9a7a1b37..99260450 100644 --- a/src/ExtendedScintilla.h +++ b/src/ExtendedScintilla.h @@ -19,6 +19,8 @@ public: bool findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward); void clearSelection(); + // Override parent setLexer + void setLexer(QsciLexer *lexer); public slots: void reloadKeywords(); diff --git a/src/PreferencesDialog.cpp b/src/PreferencesDialog.cpp index 41b9c59d..cddb6fe4 100644 --- a/src/PreferencesDialog.cpp +++ b/src/PreferencesDialog.cpp @@ -110,7 +110,7 @@ void PreferencesDialog::loadSettings() ui->treeSyntaxHighlighting->topLevelItem(i)->setTextColor(2, color); ui->treeSyntaxHighlighting->topLevelItem(i)->setBackgroundColor(2, color); ui->treeSyntaxHighlighting->topLevelItem(i)->setText(2, colorname); - if (name != "null") { + if (name != "null" && name != "currentline" && name != "background" && name != "foreground") { ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(3, Settings::getValue("syntaxhighlighter", name + "_bold").toBool() ? Qt::Checked : Qt::Unchecked); ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(4, Settings::getValue("syntaxhighlighter", name + "_italic").toBool() ? Qt::Checked : Qt::Unchecked); ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(5, Settings::getValue("syntaxhighlighter", name + "_underline").toBool() ? Qt::Checked : Qt::Unchecked); @@ -181,6 +181,8 @@ void PreferencesDialog::loadSettings() void PreferencesDialog::saveSettings() { + QApplication::setOverrideCursor(Qt::WaitCursor); + Settings::setValue("db", "defaultencoding", ui->encodingComboBox->currentText()); Settings::setValue("db", "defaultlocation", ui->locationEdit->text()); Settings::setValue("db", "savedefaultlocation", ui->comboDefaultLocation->currentIndex()); @@ -281,10 +283,11 @@ void PreferencesDialog::saveSettings() Settings::setValue("General", "language", newLanguage); Settings::setValue("General", "toolbarStyle", ui->toolbarStyleComboBox->currentIndex()); - Settings::setValue("General", "DBFileExtensions", m_dbFileExtensions.join(";;") ); accept(); + + QApplication::restoreOverrideCursor(); } void PreferencesDialog::showColourDialog(QTreeWidgetItem* item, int column) @@ -578,3 +581,19 @@ void PreferencesDialog::on_buttonManageFileExtension_clicked() m_dbFileExtensions = manager->getDBFileExtensions(); } } + +void PreferencesDialog::on_buttonBox_clicked(QAbstractButton* button) +{ + if (button == ui->buttonBox->button(QDialogButtonBox::Cancel)) + reject(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Save)) + saveSettings(); + else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) { + if (QMessageBox::warning(this, QApplication::applicationName(), tr("Are you sure you want to clear all the saved settings?\nAll your preferences will be lost and default values will be used."), + QMessageBox::RestoreDefaults | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::RestoreDefaults) + { + Settings::restoreDefaults(); + accept(); + } + } +} diff --git a/src/PreferencesDialog.h b/src/PreferencesDialog.h index eba8cbc3..e7cfd87f 100644 --- a/src/PreferencesDialog.h +++ b/src/PreferencesDialog.h @@ -9,6 +9,7 @@ class QTreeWidgetItem; class QFrame; class QTableWidget; class QSslCertificate; +class QAbstractButton; namespace Ui { class PreferencesDialog; @@ -37,6 +38,7 @@ private slots: void updatePreviewFont(); void on_buttonManageFileExtension_clicked(); + void on_buttonBox_clicked(QAbstractButton* button); private: Ui::PreferencesDialog *ui; diff --git a/src/PreferencesDialog.ui b/src/PreferencesDialog.ui index 1029df6f..e5030d15 100644 --- a/src/PreferencesDialog.ui +++ b/src/PreferencesDialog.ui @@ -806,7 +806,7 @@ - function + function Function @@ -894,12 +894,28 @@ - currentline + currentline Current line + + + background + + + Background + + + + + foreground + + + Foreground + + @@ -1349,7 +1365,7 @@ Qt::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Save + QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save @@ -1415,38 +1431,6 @@ - - buttonBox - accepted() - PreferencesDialog - saveSettings() - - - 287 - 607 - - - 155 - 143 - - - - - buttonBox - rejected() - PreferencesDialog - reject() - - - 355 - 607 - - - 286 - 144 - - - buttonAddExtension clicked() @@ -1623,6 +1607,22 @@ + + buttonBox + clicked(QAbstractButton*) + PreferencesDialog + on_buttonBox_clicked(QAbstractButton*) + + + 385 + 591 + + + 385 + 306 + + + saveSettings() diff --git a/src/Settings.cpp b/src/Settings.cpp index 6aaeb35d..28da7c17 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -6,6 +6,7 @@ #include #include #include +#include QHash Settings::m_hCache; @@ -188,15 +189,15 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) if(name == "null_fg_colour") return QColor(Qt::lightGray).name(); if(name == "null_bg_colour") - return QColor(Qt::white).name(); + return QPalette().color(QPalette::Active, QPalette::Base).name(); if(name == "reg_fg_colour") - return QColor(Qt::black).name(); + return QPalette().color(QPalette::Active, QPalette::Text).name(); if(name == "reg_bg_colour") - return QColor(Qt::white).name(); + return QPalette().color(QPalette::Active, QPalette::Base).name(); if(name == "bin_fg_colour") return QColor(Qt::lightGray).name(); if(name == "bin_bg_colour") - return QColor(Qt::white).name(); + return QPalette().color(QPalette::Active, QPalette::Base).name(); } // syntaxhighlighter? @@ -217,20 +218,50 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) // Colour? if(name.right(6) == "colour") { - if(name == "keyword_colour") - return QColor(Qt::darkBlue).name(); - else if(name == "function_colour") - return QColor(Qt::blue).name(); - else if(name == "table_colour") - return QColor(Qt::darkCyan).name(); - else if(name == "comment_colour") - return QColor(Qt::darkGreen).name(); - else if(name == "identifier_colour") - return QColor(Qt::darkMagenta).name(); - else if(name == "string_colour") - return QColor(Qt::red).name(); - else if(name == "currentline_colour") - return QColor(236, 236, 245).name(); + QColor backgroundColour = QPalette().color(QPalette::Active, QPalette::Base); + QColor foregroundColour = QPalette().color(QPalette::Active, QPalette::Text); + + if(name == "foreground_colour") + return foregroundColour.name(); + else if(name == "background_colour") + return backgroundColour.name(); + + // Detect and provide sensible defaults for dark themes + if (backgroundColour.value() < foregroundColour.value()) { + if(name == "keyword_colour") + return QColor(82, 148, 226).name(); + else if(name == "function_colour") + return QColor(Qt::yellow).name(); + else if(name == "table_colour") + return QColor(Qt::cyan).name(); + else if(name == "comment_colour") + return QColor(Qt::green).name(); + else if(name == "identifier_colour") + return QColor(Qt::magenta).name(); + else if(name == "string_colour") + return QColor(Qt::lightGray).name(); + else if(name == "currentline_colour") + return backgroundColour.lighter(150).name(); + else if(name == "background_colour") + return backgroundColour.name(); + } else { + if(name == "keyword_colour") + return QColor(Qt::darkBlue).name(); + else if(name == "function_colour") + return QColor(Qt::blue).name(); + else if(name == "table_colour") + return QColor(Qt::darkCyan).name(); + else if(name == "comment_colour") + return QColor(Qt::darkGreen).name(); + else if(name == "identifier_colour") + return QColor(Qt::darkMagenta).name(); + else if(name == "string_colour") + return QColor(Qt::red).name(); + else if(name == "currentline_colour") + return QColor(236, 236, 245).name(); + else if(name == "background_colour") + return backgroundColour.name(); + } } } @@ -310,3 +341,10 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) // Unknown combination of group and name? Return an invalid QVariant! return QVariant(); } + +void Settings::restoreDefaults () +{ + QSettings settings(QApplication::organizationName(), QApplication::organizationName()); + settings.clear(); + m_hCache.clear(); +} diff --git a/src/Settings.h b/src/Settings.h index 983a81f4..f80a1aed 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -12,6 +12,7 @@ class Settings public: static QVariant getValue(const QString& group, const QString& name); static void setValue(const QString& group, const QString& name, const QVariant& value, bool dont_save_to_disk = false); + static void restoreDefaults(); private: Settings() { } // class is fully static diff --git a/src/docktextedit.cpp b/src/docktextedit.cpp index ae913134..e5d99fb0 100644 --- a/src/docktextedit.cpp +++ b/src/docktextedit.cpp @@ -37,6 +37,7 @@ void DockTextEdit::reloadSettings() setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentBlock); setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::Keyword); setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::KeywordLD); + setupSyntaxHighlightingFormat(jsonLexer, "function", QsciLexerJSON::Operator); setupSyntaxHighlightingFormat(jsonLexer, "string", QsciLexerJSON::String); setupSyntaxHighlightingFormat(jsonLexer, "table", QsciLexerJSON::Number); setupSyntaxHighlightingFormat(jsonLexer, "identifier", QsciLexerJSON::Property); @@ -57,8 +58,12 @@ void DockTextEdit::reloadSettings() jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::Error); jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::UnclosedString); + xmlLexer->setColor(QColor(Settings::getValue("syntaxhighlighter", "foreground_colour").toString())); setupSyntaxHighlightingFormat(xmlLexer, "comment", QsciLexerHTML::HTMLComment); setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::Tag); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLTagEnd); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLStart); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLEnd); setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLDoubleQuotedString); setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLSingleQuotedString); setupSyntaxHighlightingFormat(xmlLexer, "table", QsciLexerHTML::HTMLNumber); From b1ba58fcc037f26e32eb296e1f5b44ae33346d3a Mon Sep 17 00:00:00 2001 From: mgrojo Date: Mon, 26 Feb 2018 21:52:16 +0100 Subject: [PATCH 18/63] 'Export -> Table(s) to JSON' takes into account the column type Use SQLite3 and Qt APIs to export the table data using appropriate JSON data types. See issue #1323: JSON table export converts integer and null values to string. --- src/ExportDataDialog.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/ExportDataDialog.cpp b/src/ExportDataDialog.cpp index 615dd14b..827a23ff 100644 --- a/src/ExportDataDialog.cpp +++ b/src/ExportDataDialog.cpp @@ -220,10 +220,32 @@ bool ExportDataDialog::exportQueryJson(const QString& sQuery, const QString& sFi QJsonObject json_row; for(int i=0;i Date: Wed, 28 Feb 2018 23:18:49 +0100 Subject: [PATCH 19/63] Problems with WITHOUT ROWID tables Quoted values in DELETE FROM and UPDATE SET take into account that value could have a single quote and they are now doubled. Detect tables without rowid in order to make invisible the "Show rowid column" See issue #1332 --- src/MainWindow.cpp | 3 ++- src/sqlitedb.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index fcf46479..838332d0 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -595,8 +595,9 @@ void MainWindow::populateTable() if(db.getObjectByName(currentlyBrowsedTableName())->type() == sqlb::Object::Table) { // Table + sqlb::TablePtr table = db.getObjectByName(currentlyBrowsedTableName()).dynamicCast(); ui->actionUnlockViewEditing->setVisible(false); - ui->actionShowRowidColumn->setVisible(true); + ui->actionShowRowidColumn->setVisible(!table->isWithoutRowidTable()); } else { // View ui->actionUnlockViewEditing->setVisible(true); diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 30d6d887..1864d2ad 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -980,8 +980,8 @@ bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const QStri if (!isOpen()) return false; QStringList quoted_rowids; - for(const QString& rowid : rowids) - quoted_rowids.append("'" + rowid + "'"); + for(QString rowid : rowids) + quoted_rowids.append("'" + rowid.replace("'", "''") + "'"); QString statement = QString("DELETE FROM %1 WHERE %2 IN (%3);") .arg(table.toString()) @@ -1022,7 +1022,7 @@ bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const QStrin .arg(table.toString()) .arg(sqlb::escapeIdentifier(column)) .arg(pk) - .arg(rowid); + .arg(QString(rowid).replace("'", "''")); logSQL(sql, kLogMsg_App); setSavepoint(); From 211f7341ff03063e9eb2ae7b681d5d7be7cb27f9 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 3 Mar 2018 20:06:49 +0100 Subject: [PATCH 20/63] New XML format for browse data table settings in project files Browse data table settings are now saved in the project files using a pure tagged XML format. This would make easier the generation of our project files by external tools or direct human edition of the project files. Compatibility with the older format is preserved in the loading. Previous software versions have been tested with the new format, and they are also able to load the new project files ignoring these new tags. See related issue #1306 --- src/MainWindow.cpp | 159 +++++++++++++++++++++++++++++++++++++++++---- src/MainWindow.h | 16 ----- 2 files changed, 145 insertions(+), 30 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 838332d0..9ad797a3 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -2046,6 +2046,65 @@ void MainWindow::updateBrowseDataColumnWidth(int section, int /*old_size*/, int } } +static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlStreamReader& xml) +{ + settings.sortOrderIndex = xml.attributes().value("sort_order_index").toInt(); + settings.sortOrderMode = static_cast(xml.attributes().value("sort_order_mode").toInt()); + settings.showRowid = xml.attributes().value("show_row_id").toInt(); + settings.encoding = xml.attributes().value("encoding").toString(); + settings.plotXAxis = xml.attributes().value("plot_x_axis").toString(); + settings.unlockViewPk = xml.attributes().value("unlock_view_pk").toString(); + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "table") { + if(xml.name() == "column_widths") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column_widths") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.columnWidths[index] = xml.attributes().value("value").toInt(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "filter_values") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "filter_values") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.filterValues[index] = xml.attributes().value("value").toString(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "display_formats") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "display_formats") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.displayFormats[index] = xml.attributes().value("value").toString(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "hidden_columns") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "hidden_columns") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.hiddenColumns[index] = xml.attributes().value("value").toInt(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "plot_y_axes") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "plot_y_axes") { + QString yAxisName; + PlotDock::PlotSettings yAxisSettings; + if (xml.name() == "y_axis") { + yAxisName = xml.attributes().value("name").toString(); + yAxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); + yAxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); + yAxisSettings.colour = QColor (xml.attributes().value("colour").toString()); + yAxisSettings.active = xml.attributes().value("active").toInt(); + xml.skipCurrentElement(); + } + settings.plotYAxes[yAxisName] = yAxisSettings; + } + } + } +} bool MainWindow::loadProject(QString filename, bool readOnly) { // Show the open file dialog when no filename was passed as parameter @@ -2137,17 +2196,33 @@ bool MainWindow::loadProject(QString filename, bool readOnly) QByteArray temp = QByteArray::fromBase64(attrData.toUtf8()); QDataStream stream(temp); stream >> browseTableSettings; - if(ui->mainTab->currentIndex() == BrowseTab) - { - populateTable(); // Refresh view - sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); - ui->dataTable->sortByColumn(browseTableSettings[current_table].sortOrderIndex, - browseTableSettings[current_table].sortOrderMode); - showRowidColumn(browseTableSettings[current_table].showRowid); - unlockViewEditing(!browseTableSettings[current_table].unlockViewPk.isEmpty(), browseTableSettings[current_table].unlockViewPk); + xml.skipCurrentElement(); + } else if(xml.name() == "browse_table_settings") { + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "browse_table_settings") { + if (xml.name() == "table") { + + sqlb::ObjectIdentifier tableIdentifier = + sqlb::ObjectIdentifier (xml.attributes().value("schema").toString(), + xml.attributes().value("name").toString()); + BrowseDataTableSettings settings; + loadBrowseDataTableSettings(settings, xml); + browseTableSettings[tableIdentifier] = settings; + } } xml.skipCurrentElement(); } + + if(ui->mainTab->currentIndex() == BrowseTab) + { + populateTable(); // Refresh view + sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); + ui->dataTable->sortByColumn(browseTableSettings[current_table].sortOrderIndex, + browseTableSettings[current_table].sortOrderMode); + showRowidColumn(browseTableSettings[current_table].showRowid); + unlockViewEditing(!browseTableSettings[current_table].unlockViewPk.isEmpty(), browseTableSettings[current_table].unlockViewPk); + } + } } else if(xml.name() == "tab_sql") { // Close all open tabs first @@ -2197,6 +2272,60 @@ static void saveDbTreeState(const QTreeView* tree, QXmlStreamWriter& xml, QModel } } +static void saveBrowseDataTableSettings(const BrowseDataTableSettings& object, QXmlStreamWriter& xml) +{ + xml.writeAttribute("sort_order_index", QString::number(object.sortOrderIndex)); + xml.writeAttribute("sort_order_mode", QString::number(object.sortOrderMode)); + xml.writeAttribute("show_row_id", QString::number(object.showRowid)); + xml.writeAttribute("encoding", object.encoding); + xml.writeAttribute("plot_x_axis", object.plotXAxis); + xml.writeAttribute("unlock_view_pk", object.unlockViewPk); + xml.writeStartElement("column_widths"); + for(auto iter=object.columnWidths.constBegin(); iter!=object.columnWidths.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", QString::number(iter.value())); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("filter_values"); + for(auto iter=object.filterValues.constBegin(); iter!=object.filterValues.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", iter.value()); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("display_formats"); + for(auto iter=object.displayFormats.constBegin(); iter!=object.displayFormats.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", iter.value()); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("hidden_columns"); + for(auto iter=object.hiddenColumns.constBegin(); iter!=object.hiddenColumns.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", QString::number(iter.value())); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("plot_y_axes"); + for(auto iter=object.plotYAxes.constBegin(); iter!=object.plotYAxes.constEnd(); ++iter) { + PlotDock::PlotSettings plotSettings = iter.value(); + xml.writeStartElement("y_axis"); + xml.writeAttribute("name", iter.key()); + xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); + xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); + xml.writeAttribute("colour", plotSettings.colour.name()); + xml.writeAttribute("active", QString::number(plotSettings.active)); + xml.writeEndElement(); + } + xml.writeEndElement(); +} + void MainWindow::saveProject() { QString filename = FileDialog::getSaveFileName(this, @@ -2248,12 +2377,14 @@ void MainWindow::saveProject() xml.writeStartElement("default_encoding"); // Default encoding for text stored in tables xml.writeAttribute("codec", defaultBrowseTableEncoding); xml.writeEndElement(); - { // Table browser information - QByteArray temp; - QDataStream stream(&temp, QIODevice::WriteOnly); - stream << browseTableSettings; - xml.writeStartElement("browsetable_info"); - xml.writeAttribute("data", temp.toBase64()); + + xml.writeStartElement("browse_table_settings"); + for(auto tableIt=browseTableSettings.constBegin(); tableIt!=browseTableSettings.constEnd(); ++tableIt) { + + xml.writeStartElement("table"); + xml.writeAttribute("schema", tableIt.key().schema()); + xml.writeAttribute("name", tableIt.key().name()); + saveBrowseDataTableSettings(tableIt.value(), xml); xml.writeEndElement(); } xml.writeEndElement(); diff --git a/src/MainWindow.h b/src/MainWindow.h index be6e567b..3341ffcc 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -45,22 +45,6 @@ struct BrowseDataTableSettings { } - friend QDataStream& operator<<(QDataStream& stream, const BrowseDataTableSettings& object) - { - stream << object.sortOrderIndex; - stream << static_cast(object.sortOrderMode); - stream << object.columnWidths; - stream << object.filterValues; - stream << object.displayFormats; - stream << object.showRowid; - stream << object.encoding; - stream << object.plotXAxis; - stream << object.plotYAxes; - stream << object.unlockViewPk; - stream << object.hiddenColumns; - - return stream; - } friend QDataStream& operator>>(QDataStream& stream, BrowseDataTableSettings& object) { stream >> object.sortOrderIndex; From b51cf69cbf97e79202cfdb357458e1c62b33d785 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Mon, 5 Mar 2018 21:13:08 +0100 Subject: [PATCH 21/63] Avoid removing multiple line breaks inside strings for simple cases In order to avoid removing multiple line breaks inside strings, the replacement is only done when removeCommentsFromQuery has performed some substitution. Otherwise the query is left as is. This will improve the problem described in issue #1334 for simple cases. There will be still problems when the query has comments and multiple line breaks inside strings. --- src/sqlitetablemodel.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index d413ef26..547c7aa1 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -654,7 +654,10 @@ void SqliteTableModel::buildQuery() setQuery(customQuery(true), true); } -void SqliteTableModel::removeCommentsFromQuery(QString& query) { +void SqliteTableModel::removeCommentsFromQuery(QString& query) +{ + int oldSize = query.size(); + // first remove block comments { QRegExp rxSQL("^((?:(?:[^'/]|/(?![*]))*|'[^']*')*)(/[*](?:[^*]|[*](?!/))*[*]/)(.*)$"); // set up regex to find block comment @@ -706,11 +709,13 @@ void SqliteTableModel::removeCommentsFromQuery(QString& query) { query = result.trimmed(); } - // Remove multiple line breaks that might have been created by deleting comments till the end of the line but not including the line break - query.replace(QRegExp("\\n+"), "\n"); + if (oldSize != query.size()) { + // Remove multiple line breaks that might have been created by deleting comments till the end of the line but not including the line break + query.replace(QRegExp("\\n+"), "\n"); - // Also remove any remaining whitespace at the end of each line - query.replace(QRegExp("[ \t]+\n"), "\n"); + // Also remove any remaining whitespace at the end of each line + query.replace(QRegExp("[ \t]+\n"), "\n"); + } } QStringList SqliteTableModel::getColumns(const QString& sQuery, QVector& fieldsTypes) From 2c9cf75419feea889d2a86f0b7549d8acacab0c2 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Fri, 9 Mar 2018 22:12:53 +0100 Subject: [PATCH 22/63] Tooltip and "What's This" text for 'Execute SQL' improved. README updated. Document the behaviour of the 'Execute SQL' button so users can discover the feature for executing the statements in the selection. See related issue #1336 "SQL sentences" to "SQL statements", as that is the standard term. Add plot feature to list of features in README file and DB4S abbreviation --- README.md | 3 ++- src/MainWindow.ui | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3fc1a0c5..4992258c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## What it is -DB Browser for SQLite is a high quality, visual, open source tool to +_DB Browser for SQLite_ (DB4S) is a high quality, visual, open source tool to create, design, and edit database files compatible with SQLite. It is for users and developers wanting to create databases, search, and edit @@ -29,6 +29,7 @@ Controls and wizards are available for users to: * Import and export databases from/to SQL dump files * Issue SQL queries and inspect the results * Examine a log of all SQL commands issued by the application +* Plot simple graphs based on table or query data ## What it is not diff --git a/src/MainWindow.ui b/src/MainWindow.ui index fc8c9c1f..0206c3cf 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -65,7 +65,7 @@ This is the structure of the opened database. -You can drag SQL sentences from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. @@ -1138,8 +1138,8 @@ You can drag SQL sentences from an object row and drop them into other applicati This is the structure of the opened database. -You can drag multiple object names from the Name column and drop them into the SQL editor . -You can drag SQL sentences from the Schema column and drop them into the SQL editor or into other applications. +You can drag multiple object names from the Name column and drop them into the SQL editor. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. @@ -1594,10 +1594,10 @@ You can drag SQL sentences from the Schema column and drop them into the SQL edi &Execute SQL - Execute SQL [F5, Ctrl+Return, Ctrl+R] + Execute all/selected SQL [F5, Ctrl+Return, Ctrl+R] - This button executes all the SQL statements of the current editor tab + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. From 9c409c85ad5c6f3cad755fe6fb678940e6bba6ae Mon Sep 17 00:00:00 2001 From: "C. Knoll" Date: Mon, 12 Mar 2018 20:02:36 +0100 Subject: [PATCH 23/63] Adding Debian subsection in README.md (see #1340) --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 4992258c..301c6cff 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,19 @@ For Fedora (i386 and x86_64) you can install by issuing: $ sudo dnf install sqlitebrowser +### Debian + +Note that Debian focuses more on stability rather than newest features. Therefore packages will typically contain some older (but well tested) version, compared to the latest release. + +Update the cache using: + + sudo apt-get update + +Install the package using: + + sudo apt-get install sqlitebrowser + + ### Ubuntu and Derivatives #### Stable release From 30fe096b851bb427a0e5930a5c8b21a5a1a8d948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E5=8D=9A=E4=BB=81=28Buo-Ren=20Lin=29?= Date: Tue, 13 Mar 2018 16:45:56 +0800 Subject: [PATCH 24/63] doc: BUILDING: Debian: Don't install the entire Git distribution just for cloning the repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The download and disk usage difference is apparent and should be avoided when possible ``` $ apt show git-core git 2>/dev/null | grep '^Installed-Size' Installed-Size: 8,192 B Installed-Size: 24.1 MB ``` Signed-off-by: æž—åšä» --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index 2b356cb4..4a6b3b23 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -54,7 +54,7 @@ The same process works for building the code in any platform supported by Qt ### Ubuntu Linux ```bash -$ sudo apt install build-essential git cmake libsqlite3-dev qt5-default qttools5-dev-tools \ +$ sudo apt install build-essential git-core cmake libsqlite3-dev qt5-default qttools5-dev-tools \ libsqlcipher-dev $ git clone https://github.com/sqlitebrowser/sqlitebrowser $ cd sqlitebrowser From 85dbe7b01686f31a22cf3ce141e258801da986e8 Mon Sep 17 00:00:00 2001 From: mgrojo Date: Wed, 28 Mar 2018 22:24:48 +0200 Subject: [PATCH 25/63] Setting for line wrap in Scintilla editors A new setting is added to the 'SQL' tab of the Preferences dialog. It enables the line wrapping in the editors with none/character/word/ whitespace boundaries. See comments in issue #1173. --- src/ExtendedScintilla.cpp | 6 +++++ src/PreferencesDialog.cpp | 2 ++ src/PreferencesDialog.ui | 50 ++++++++++++++++++++++++++++++++------- src/Settings.cpp | 4 ++++ 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/ExtendedScintilla.cpp b/src/ExtendedScintilla.cpp index b86048e6..eb8c8671 100644 --- a/src/ExtendedScintilla.cpp +++ b/src/ExtendedScintilla.cpp @@ -45,6 +45,9 @@ ExtendedScintilla::ExtendedScintilla(QWidget* parent) : // adjusts the scroll width to be narrower. setScrollWidthTracking(true); + // Visual flags for when wrap lines is enabled + setWrapVisualFlags(QsciScintilla::WrapFlagByBorder); + // Connect signals connect(this, SIGNAL(linesChanged()), this, SLOT(updateLineNumberAreaWidth())); @@ -155,6 +158,9 @@ void ExtendedScintilla::reloadLexerSettings(QsciLexer *lexer) setTabWidth(Settings::getValue("editor", "tabsize").toInt()); lexer->refreshProperties(); + // Set wrap lines + setWrapMode(static_cast(Settings::getValue("editor", "wrap_lines").toInt())); + // Check if error indicators are enabled and clear them if they just got disabled showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool(); if(!showErrorIndicators) diff --git a/src/PreferencesDialog.cpp b/src/PreferencesDialog.cpp index cddb6fe4..89289199 100644 --- a/src/PreferencesDialog.cpp +++ b/src/PreferencesDialog.cpp @@ -167,6 +167,7 @@ void PreferencesDialog::loadSettings() ui->spinEditorFontSize->setValue(Settings::getValue("editor", "fontsize").toInt()); ui->spinTabSize->setValue(Settings::getValue("editor", "tabsize").toInt()); ui->spinLogFontSize->setValue(Settings::getValue("log", "fontsize").toInt()); + ui->wrapComboBox->setCurrentIndex(Settings::getValue("editor", "wrap_lines").toInt()); ui->checkAutoCompletion->setChecked(Settings::getValue("editor", "auto_completion").toBool()); ui->checkCompleteUpper->setEnabled(Settings::getValue("editor", "auto_completion").toBool()); ui->checkCompleteUpper->setChecked(Settings::getValue("editor", "upper_keywords").toBool()); @@ -221,6 +222,7 @@ void PreferencesDialog::saveSettings() Settings::setValue("editor", "fontsize", ui->spinEditorFontSize->value()); Settings::setValue("editor", "tabsize", ui->spinTabSize->value()); Settings::setValue("log", "fontsize", ui->spinLogFontSize->value()); + Settings::setValue("editor", "wrap_lines", ui->wrapComboBox->currentIndex()); Settings::setValue("editor", "auto_completion", ui->checkAutoCompletion->isChecked()); Settings::setValue("editor", "upper_keywords", ui->checkCompleteUpper->isChecked()); Settings::setValue("editor", "error_indicators", ui->checkErrorIndicators->isChecked()); diff --git a/src/PreferencesDialog.ui b/src/PreferencesDialog.ui index e5030d15..20ab6828 100644 --- a/src/PreferencesDialog.ui +++ b/src/PreferencesDialog.ui @@ -990,7 +990,7 @@ - + Code co&mpletion @@ -1000,14 +1000,14 @@ - + enabled - + Keywords in &UPPER CASE @@ -1017,7 +1017,7 @@ - + When set, the SQL keywords are completed in UPPER CASE letters. @@ -1027,7 +1027,7 @@ - + Error indicators @@ -1037,7 +1037,7 @@ - + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background @@ -1047,7 +1047,7 @@ - + Hori&zontal tiling @@ -1057,7 +1057,7 @@ - + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. @@ -1067,6 +1067,40 @@ + + + + + Never + + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + + + + Wrap lines + + + wrapComboBox + + + diff --git a/src/Settings.cpp b/src/Settings.cpp index 28da7c17..763a3ca7 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -290,6 +290,10 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) } } + // editor/wrap_lines + if(group == "editor" && name == "wrap_lines") + return 0; // QsciScintilla::WrapNone + // editor/auto_completion? if(group == "editor" && name == "auto_completion") return true; From 86960a59527583061ca63c5baf26d28b149136b0 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Mon, 7 May 2018 17:42:29 +0200 Subject: [PATCH 26/63] Update project links to HTTPS --- README.md | 2 +- distri/sqlitebrowser.desktop.appdata.xml | 2 +- src/MainWindow.cpp | 2 +- src/translations/sqlb_ar_SA.ts | 4 ++-- src/translations/sqlb_cs.ts | 4 ++-- src/translations/sqlb_de.ts | 8 ++++---- src/translations/sqlb_en_GB.ts | 2 +- src/translations/sqlb_es_ES.ts | 4 ++-- src/translations/sqlb_fr.ts | 8 ++++---- src/translations/sqlb_ko_KR.ts | 4 ++-- src/translations/sqlb_pt_BR.ts | 4 ++-- src/translations/sqlb_ru.ts | 4 ++-- src/translations/sqlb_tr.ts | 4 ++-- src/translations/sqlb_uk_UA.ts | 4 ++-- src/translations/sqlb_zh.ts | 4 ++-- src/translations/sqlb_zh_TW.ts | 6 +++--- 16 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 301c6cff..668a9de5 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ Follow us on Twitter: https://twitter.com/sqlitebrowser ## Website -* http://sqlitebrowser.org +* https://sqlitebrowser.org ## Old project page diff --git a/distri/sqlitebrowser.desktop.appdata.xml b/distri/sqlitebrowser.desktop.appdata.xml index f95edb9c..3c9c07ea 100644 --- a/distri/sqlitebrowser.desktop.appdata.xml +++ b/distri/sqlitebrowser.desktop.appdata.xml @@ -40,6 +40,6 @@ DB Browser for SQLite, creating a table - http://sqlitebrowser.org/ + https://sqlitebrowser.org/ https://github.com/sqlitebrowser/sqlitebrowser/issues diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 9ad797a3..3acef0cd 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -2022,7 +2022,7 @@ void MainWindow::on_actionSqlCipherFaq_triggered() void MainWindow::on_actionWebsite_triggered() { - QDesktopServices::openUrl(QUrl("http://sqlitebrowser.org")); + QDesktopServices::openUrl(QUrl("https://sqlitebrowser.org")); } void MainWindow::updateBrowseDataColumnWidth(int section, int /*old_size*/, int new_size) diff --git a/src/translations/sqlb_ar_SA.ts b/src/translations/sqlb_ar_SA.ts index 707ee8fc..b1496084 100644 --- a/src/translations/sqlb_ar_SA.ts +++ b/src/translations/sqlb_ar_SA.ts @@ -15,9 +15,9 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html dir="rtl"><head/><body><p>«متصÙّح قواعد بيانات SQLite» أداة رسوميّة Ù…ÙØªÙˆØ­Ø© المصدر ومجّانيّة، ØªÙØ³ØªØ®Ø¯Ù… لإنشاء ملÙّات قواعد بيانات SQLite وتصميمها وتحريرها.</p><p>الأداة مرخّصة برخصتين، الإصدارة الثّانية من رخصة موزيلا العموميّة، والإصدارة الثّالثة وما بعدها من رخصة غنو العموميّة. يمكنك تعديل الأداة أو إعادة توزيعها بشروط تلك الرّخص. -</p><p>طالع <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> Ùˆ<a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> Ù„Ù„ØªÙ‘ÙØ§ØµÙŠÙ„.</p><p>لمعلومات أكثر عن البرمجيّة، ÙØ¶Ù„ًا Ø²ÙØ± موقع الوبّ هذا: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">تستخدم هذه البرمجيّة عدّة أدوات كيوت المرخّصة تحت GPL/LGPL وذلك من </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>طالع </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> لشروط التّرخيص والمعلومات.</span></p><p><span style=" font-size:small;">تستخدم البرمجيّة أيضًا طقم أيقونات الحرير/Silk ل†Mark James المرخّصة برخصة المشاع الإبداعي - النّسبة 2.5 Ùˆ 3.0.<br/>طالع </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> Ù„Ù„ØªÙ‘ÙØ§ØµÙŠÙ„.</span></p></body></html> +</p><p>طالع <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> Ùˆ<a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> Ù„Ù„ØªÙ‘ÙØ§ØµÙŠÙ„.</p><p>لمعلومات أكثر عن البرمجيّة، ÙØ¶Ù„ًا Ø²ÙØ± موقع الوبّ هذا: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">تستخدم هذه البرمجيّة عدّة أدوات كيوت المرخّصة تحت GPL/LGPL وذلك من </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>طالع </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> لشروط التّرخيص والمعلومات.</span></p><p><span style=" font-size:small;">تستخدم البرمجيّة أيضًا طقم أيقونات الحرير/Silk ل†Mark James المرخّصة برخصة المشاع الإبداعي - النّسبة 2.5 Ùˆ 3.0.<br/>طالع </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> Ù„Ù„ØªÙ‘ÙØ§ØµÙŠÙ„.</span></p></body></html> diff --git a/src/translations/sqlb_cs.ts b/src/translations/sqlb_cs.ts index 8ced802a..a2a7b93b 100644 --- a/src/translations/sqlb_cs.ts +++ b/src/translations/sqlb_cs.ts @@ -15,8 +15,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>DB Browser pro SQLite je open source, freeware a vizualizaÄní nástroj užívaný k tvorbÄ›, návrhu a úpravÄ› SQLite souborů databáze.</p><p>Je multilicencován pod Mozilla Public License Version 2, jakož i GNU General Public License Version 3 nebo pozdÄ›jší. Můžete jej upravovat nebo redistribuovat podle podmínek tÄ›chto licencí.</p><p>Viz <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> a <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> pro více informací.</p><p>Pro získání více informací o tomto programu prosím navÅ¡tivte naÅ¡e webové stránky na: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Tento software užívá GPL/LGPL Qt Toolkit od </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Viz </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> pro licenÄní podmínky a informace.</span></p><p><span style=" font-size:small;">Také využívá Silk icon set od Marka Jamese licencovaný pod licencí Creative Commons Attribution 2.5 a 3.0.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> pro více informací.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser pro SQLite je open source, freeware a vizualizaÄní nástroj užívaný k tvorbÄ›, návrhu a úpravÄ› SQLite souborů databáze.</p><p>Je multilicencován pod Mozilla Public License Version 2, jakož i GNU General Public License Version 3 nebo pozdÄ›jší. Můžete jej upravovat nebo redistribuovat podle podmínek tÄ›chto licencí.</p><p>Viz <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> a <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> pro více informací.</p><p>Pro získání více informací o tomto programu prosím navÅ¡tivte naÅ¡e webové stránky na: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Tento software užívá GPL/LGPL Qt Toolkit od </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Viz </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> pro licenÄní podmínky a informace.</span></p><p><span style=" font-size:small;">Také využívá Silk icon set od Marka Jamese licencovaný pod licencí Creative Commons Attribution 2.5 a 3.0.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> pro více informací.</span></p></body></html> diff --git a/src/translations/sqlb_de.ts b/src/translations/sqlb_de.ts index 35ec2b35..da110218 100644 --- a/src/translations/sqlb_de.ts +++ b/src/translations/sqlb_de.ts @@ -15,8 +15,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>DB-Browser für SQLite ist ein grafisches, freies Open Source Tool zum Erstellen, Bearbeiten und Ändern von SQLite-Datenbankdateien.</p><p>Es steht unter zwei Lizenzen, der Mozilla Public License Version 2 und der GNU General Public License Version 3 oder aktueller. Sie können das Programm unter den Bedingungen dieser Lizenzen ändern und weitergeben.</p><p>Siehe <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> und <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> für Details.</p><p>Für mehr Informationen über dieses Programm besuchen Sie unsere Website unter: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Diese Anwendung verwendet das GPL/LGPL Qt Toolkit von </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Siehe </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> für Lizenzinformationenund weitere Informationen.</span></p><p><span style=" font-size:small;">Sie verwendet außerdem das Silk Iconset von Mark James, das unter einer Creative Commons Attribution 2.5 und 3.0 Lizenz steht.<br/>Siehe </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> für Details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB-Browser für SQLite ist ein grafisches, freies Open Source Tool zum Erstellen, Bearbeiten und Ändern von SQLite-Datenbankdateien.</p><p>Es steht unter zwei Lizenzen, der Mozilla Public License Version 2 und der GNU General Public License Version 3 oder aktueller. Sie können das Programm unter den Bedingungen dieser Lizenzen ändern und weitergeben.</p><p>Siehe <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> und <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> für Details.</p><p>Für mehr Informationen über dieses Programm besuchen Sie unsere Website unter: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Diese Anwendung verwendet das GPL/LGPL Qt Toolkit von </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Siehe </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> für Lizenzinformationenund weitere Informationen.</span></p><p><span style=" font-size:small;">Sie verwendet außerdem das Silk Iconset von Mark James, das unter einer Creative Commons Attribution 2.5 und 3.0 Lizenz steht.<br/>Siehe </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> für Details.</span></p></body></html> Qt Version @@ -27,8 +27,8 @@ SQLite-Version - <html><head/><body><p>SQLite Database Browser is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>SQLite Database Browser ist ein grafisches, freies Open Source Tool zum Erstellen, Bearbeiten und Ändern von SQLite-Datenbankdateien.</p><p>Es steht unter zwei Lizenzen, der Mozilla Public License Version 2 und der GNU General Public License Version 3 oder aktueller. Sie können das Programm unter den Bedingungen dieser Lizenzen ändern und weitergeben.</p><p>Siehe <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> und <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> für Details.</p><p>Für mehr Informationen über dieses Programm besuchen Sie unsere Website unter: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Diese Anwendung verwendet das GPL/LGPL Qt Toolkit von </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Siehe </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> für Lizenzinformationenund weitere Informationen.</span></p><p><span style=" font-size:small;">Sie verwendet außerdem das Silk iconset von Mark James, das unter einer Creative Commons Attribution 2.5 und 3.0 Lizenz steht.<br/>Siehe </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> für Details.</span></p></body></html> + <html><head/><body><p>SQLite Database Browser is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>SQLite Database Browser ist ein grafisches, freies Open Source Tool zum Erstellen, Bearbeiten und Ändern von SQLite-Datenbankdateien.</p><p>Es steht unter zwei Lizenzen, der Mozilla Public License Version 2 und der GNU General Public License Version 3 oder aktueller. Sie können das Programm unter den Bedingungen dieser Lizenzen ändern und weitergeben.</p><p>Siehe <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> und <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> für Details.</p><p>Für mehr Informationen über dieses Programm besuchen Sie unsere Website unter: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Diese Anwendung verwendet das GPL/LGPL Qt Toolkit von </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Siehe </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> für Lizenzinformationenund weitere Informationen.</span></p><p><span style=" font-size:small;">Sie verwendet außerdem das Silk iconset von Mark James, das unter einer Creative Commons Attribution 2.5 und 3.0 Lizenz steht.<br/>Siehe </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> für Details.</span></p></body></html> diff --git a/src/translations/sqlb_en_GB.ts b/src/translations/sqlb_en_GB.ts index 64faef0d..1b2f5a21 100644 --- a/src/translations/sqlb_en_GB.ts +++ b/src/translations/sqlb_en_GB.ts @@ -15,7 +15,7 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> diff --git a/src/translations/sqlb_es_ES.ts b/src/translations/sqlb_es_ES.ts index 7c279036..7dff81a0 100644 --- a/src/translations/sqlb_es_ES.ts +++ b/src/translations/sqlb_es_ES.ts @@ -15,12 +15,12 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html><head/><body> <p>DB Browser para SQLite es una herramienta gratuita y de código abierto usada para crear, diseñar y editar archivos de bases de datos de SQLite.</p> <p>Está doblemente licenciada con Mozilla Public License Version 2, y también con GNU General Public License Version 3 o posterior. Puede modificarla o redistribuirla bajo las condiciones de esas licencias.</p> <p>Vea <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> y <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> para los detalles.</p> -<p>Para más información acerca de este programa visite, por favor, nuestra página web en: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p> +<p>Para más información acerca de este programa visite, por favor, nuestra página web en: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p> <p><span style=" font-size:small;">Este software usa el GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Vea </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> para más información y las condiciones de la licencia.</span> </p><p><span style=" font-size:small;">También usa el conjunto de iconos Silk de Mark James licenciado bajo Creative Commons Attribution 2.5 y 3.0.<br/>Vea </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> para los detalles.</span></p></body></html> diff --git a/src/translations/sqlb_fr.ts b/src/translations/sqlb_fr.ts index 07885f45..3818161a 100644 --- a/src/translations/sqlb_fr.ts +++ b/src/translations/sqlb_fr.ts @@ -19,9 +19,9 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> DB Browser for SQLite est un logiciel libre, open-source utilisé pour créer, concevoir et modifier des bases de données SQLite. - <html><head/><body><p>DB Browser pour SQLite est un logiciel libre, open-source utilisé pour créer, concevoir et modifier des Bases de Données SQLite.</p><p>Ce programme est proposé sous une double licence : Mozilla Public License Version 2 et GNU General Public License Version 3 ou suivante. Vous pouvez le modifier ou le redistribuer en respectant les conditions de ces licences.</p><p>Voir <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> et <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> pour plus de détails.</p><p>Pour plus d'information concernant ce programme, visitez notre site Internet sur : <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Ce logiciel utilise le GPL/LGPL Qt Toolkit fourni par </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Voir </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> pour les conditions de licence et toute autre information.</span></p><p><span style=" font-size:small;">Il utilise le jeu d'icones Silk créé par Mark James disponible selon la licence Creative Commons Attribution 2.5 and 3.0.<br/>Voir </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> pour plus de détails.</span></p></body></html> + <html><head/><body><p>DB Browser pour SQLite est un logiciel libre, open-source utilisé pour créer, concevoir et modifier des Bases de Données SQLite.</p><p>Ce programme est proposé sous une double licence : Mozilla Public License Version 2 et GNU General Public License Version 3 ou suivante. Vous pouvez le modifier ou le redistribuer en respectant les conditions de ces licences.</p><p>Voir <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> et <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> pour plus de détails.</p><p>Pour plus d'information concernant ce programme, visitez notre site Internet sur : <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Ce logiciel utilise le GPL/LGPL Qt Toolkit fourni par </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Voir </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> pour les conditions de licence et toute autre information.</span></p><p><span style=" font-size:small;">Il utilise le jeu d'icones Silk créé par Mark James disponible selon la licence Creative Commons Attribution 2.5 and 3.0.<br/>Voir </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> pour plus de détails.</span></p></body></html> Qt Version @@ -32,8 +32,8 @@ Version de SQLite - &lt;html><head/><body><p>SQLite Database Browser is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - &lt;head/><meta charset="UTF-8"><body><p>SQLite Database Browser est un outil visuel, libre et open-source, pour créer, définir et éditer des bases de données SQLite.</p><p>Il est fourni sous une double licence, la licence Mozilla Public License Version 2 et la licence GNU General Public License Version 3 ou ultérieure. Vous pouvez modifier ou redistribuer de programme dans les mêmes conditions de licence.</p><p>Pour plus de détails, voir : <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> et <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a>.</p><p>Pour plus d'information à propos de ce programme, merci de visiter notre site Internet à l'adresse suivante : <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a>.</p><p><span style=" font-size:small;">Ce logiciel utilise le boite à outils GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a>.<span style=" font-size:small;"><br/>Pour toute information et licences, voir : </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a>.</p><p><span style=" font-size:small;">Il utilise aussi le jeu d'icônes Silk créé par Mark James, qui est sous licence Creative Commons Attribution 2.5 et 3.0.<br/>Pour plus de détails, voir : </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a>.</p></body></html> + &lt;html><head/><body><p>SQLite Database Browser is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + &lt;head/><meta charset="UTF-8"><body><p>SQLite Database Browser est un outil visuel, libre et open-source, pour créer, définir et éditer des bases de données SQLite.</p><p>Il est fourni sous une double licence, la licence Mozilla Public License Version 2 et la licence GNU General Public License Version 3 ou ultérieure. Vous pouvez modifier ou redistribuer de programme dans les mêmes conditions de licence.</p><p>Pour plus de détails, voir : <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> et <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a>.</p><p>Pour plus d'information à propos de ce programme, merci de visiter notre site Internet à l'adresse suivante : <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a>.</p><p><span style=" font-size:small;">Ce logiciel utilise le boite à outils GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a>.<span style=" font-size:small;"><br/>Pour toute information et licences, voir : </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a>.</p><p><span style=" font-size:small;">Il utilise aussi le jeu d'icônes Silk créé par Mark James, qui est sous licence Creative Commons Attribution 2.5 et 3.0.<br/>Pour plus de détails, voir : </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a>.</p></body></html> diff --git a/src/translations/sqlb_ko_KR.ts b/src/translations/sqlb_ko_KR.ts index e6350789..76b6987b 100644 --- a/src/translations/sqlb_ko_KR.ts +++ b/src/translations/sqlb_ko_KR.ts @@ -16,8 +16,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>DB Browser for SQLite는 오픈소스, 프리웨어 시ê°í™” 툴로 SQLite ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê³ , 설계하고 수정할 수 있습니다.</p><p>ì´ í”„ë¡œê·¸ëž¨ì€ ë‘ ê°€ì§€ ë¼ì´ì„¼ìŠ¤ë¥¼ ë”°ë¥´ëŠ”ë° Mozilla Public License Version 2와 GNU General Public License Version 3 ë˜ëŠ” ê·¸ ì´í›„ ë²„ì „ì˜ ë¼ì´ì„¼ìŠ¤ë¥¼ 따릅니다. ì—¬ëŸ¬ë¶„ì€ ì´ ë¼ì´ì„¼ìФ 하ì—서 수정하거나 ìž¬ë°°í¬ í•  수 있습니다.</p><p>ìžì„¸í•œ ë‚´ìš©ì€ <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> ê³¼ <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> 를 참고하시기 ë°”ëžë‹ˆë‹¤.</p><p>ì´ í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ 추가 정보를 알고 싶으시면 우리 웹사ì´íŠ¸ì— ë°©ë¬¸í•˜ì„¸ìš”: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">ì´ ì†Œí”„íŠ¸ì›¨ì–´ëŠ” </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;">ì˜ GPL/LGPL Qt Toolkitì„ ì‚¬ìš©í•©ë‹ˆë‹¤.</span><span style=" font-size:small;"><br/>ë¼ì´ì„¼ìФ ì¡°ê±´ê³¼ 정보는 </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> ì—서 보실 수 있습니다.</span></p><p><span style=" font-size:small;">ë˜í•œ ì´ í”„ë¡œê·¸ëž¨ì€ Mark Jamesê°€ 제작한 ì‹¤í¬ ì•„ì´ì½˜ 세트를 Creative Commons Attribution 2.5와 3.0 버전 ë¼ì´ì„¼ìФ 하ì—서 사용하고 있습니다.<br/>ìžì„¸í•œ ê²ƒì€ </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 를 참고하세요.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite는 오픈소스, 프리웨어 시ê°í™” 툴로 SQLite ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê³ , 설계하고 수정할 수 있습니다.</p><p>ì´ í”„ë¡œê·¸ëž¨ì€ ë‘ ê°€ì§€ ë¼ì´ì„¼ìŠ¤ë¥¼ ë”°ë¥´ëŠ”ë° Mozilla Public License Version 2와 GNU General Public License Version 3 ë˜ëŠ” ê·¸ ì´í›„ ë²„ì „ì˜ ë¼ì´ì„¼ìŠ¤ë¥¼ 따릅니다. ì—¬ëŸ¬ë¶„ì€ ì´ ë¼ì´ì„¼ìФ 하ì—서 수정하거나 ìž¬ë°°í¬ í•  수 있습니다.</p><p>ìžì„¸í•œ ë‚´ìš©ì€ <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> ê³¼ <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> 를 참고하시기 ë°”ëžë‹ˆë‹¤.</p><p>ì´ í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ 추가 정보를 알고 싶으시면 우리 웹사ì´íŠ¸ì— ë°©ë¬¸í•˜ì„¸ìš”: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">ì´ ì†Œí”„íŠ¸ì›¨ì–´ëŠ” </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;">ì˜ GPL/LGPL Qt Toolkitì„ ì‚¬ìš©í•©ë‹ˆë‹¤.</span><span style=" font-size:small;"><br/>ë¼ì´ì„¼ìФ ì¡°ê±´ê³¼ 정보는 </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> ì—서 보실 수 있습니다.</span></p><p><span style=" font-size:small;">ë˜í•œ ì´ í”„ë¡œê·¸ëž¨ì€ Mark Jamesê°€ 제작한 ì‹¤í¬ ì•„ì´ì½˜ 세트를 Creative Commons Attribution 2.5와 3.0 버전 ë¼ì´ì„¼ìФ 하ì—서 사용하고 있습니다.<br/>ìžì„¸í•œ ê²ƒì€ </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 를 참고하세요.</span></p></body></html> diff --git a/src/translations/sqlb_pt_BR.ts b/src/translations/sqlb_pt_BR.ts index 6f85c643..d28019a2 100644 --- a/src/translations/sqlb_pt_BR.ts +++ b/src/translations/sqlb_pt_BR.ts @@ -12,8 +12,8 @@ Versão - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>DB Browser para SQLite é uma ferramenta visual gratuita utilizada para criar, desenhar e editar bancos de dados SQLite.</p><p>É bilicenciada sob a Mozilla Public License Version 2 e a GNU General Public License Version 3 ou posterior. Você pode modificar ou redistribuí-la sob as condições dessas licenças.</p><p>Veja <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> e <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> para mais detalhes.</p><p>Para mais informação sobre esse programa visite nosso website: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Esse software utiliza o GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Veja </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> para termos de licença e informação.</span></p><p><span style=" font-size:small;">Também utiliza o Silk icon set de Mark James licenciado sob uma licença Creative Commons Attribution 2.5 e 3.0.<br/>Veja </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> para mais detalhes.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser para SQLite é uma ferramenta visual gratuita utilizada para criar, desenhar e editar bancos de dados SQLite.</p><p>É bilicenciada sob a Mozilla Public License Version 2 e a GNU General Public License Version 3 ou posterior. Você pode modificar ou redistribuí-la sob as condições dessas licenças.</p><p>Veja <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> e <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> para mais detalhes.</p><p>Para mais informação sobre esse programa visite nosso website: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Esse software utiliza o GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Veja </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> para termos de licença e informação.</span></p><p><span style=" font-size:small;">Também utiliza o Silk icon set de Mark James licenciado sob uma licença Creative Commons Attribution 2.5 e 3.0.<br/>Veja </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> para mais detalhes.</span></p></body></html> Version diff --git a/src/translations/sqlb_ru.ts b/src/translations/sqlb_ru.ts index c905dd72..35e6b94f 100755 --- a/src/translations/sqlb_ru.ts +++ b/src/translations/sqlb_ru.ts @@ -15,8 +15,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>Обозреватель Ð´Ð»Ñ SQLite - Ñто беÑÐ¿Ð»Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°, Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом, Ð¿Ñ€ÐµÐ´Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ð°Ñ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ð°Ð· данных SQLite.</p><p>Программа лицензирована по двум лицензиÑм: Mozilla Public License Version 2 и GNU General Public License Version 3 or later. Можно изменÑть или раÑпроÑтранÑть её на уÑловиÑÑ… Ñтих лицензий.</p><p>Лицензии можно проÑмотреть по ÑÑылкам <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> и <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a>.</p><p>Дополнительную информацию о программе можно узнать на веб-Ñайте:<br/><a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Это программное обеÑпечение иÑпользует GPL/LGPL Qt Toolkit </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>УÑÐ»Ð¾Ð²Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð¸ на Qt Toolkit </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;">.</span></p><p><span style=" font-size:small;">Эта программа также иÑпользует набор иконок Silk от Марка ДжеймÑа (Mark James), лицензированный под лицензией Creative Commons Attribution 2.5 and 3.0.<br/>ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾ адреÑу </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;">.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>Обозреватель Ð´Ð»Ñ SQLite - Ñто беÑÐ¿Ð»Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°, Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом, Ð¿Ñ€ÐµÐ´Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ð°Ñ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ð°Ð· данных SQLite.</p><p>Программа лицензирована по двум лицензиÑм: Mozilla Public License Version 2 и GNU General Public License Version 3 or later. Можно изменÑть или раÑпроÑтранÑть её на уÑловиÑÑ… Ñтих лицензий.</p><p>Лицензии можно проÑмотреть по ÑÑылкам <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> и <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a>.</p><p>Дополнительную информацию о программе можно узнать на веб-Ñайте:<br/><a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Это программное обеÑпечение иÑпользует GPL/LGPL Qt Toolkit </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>УÑÐ»Ð¾Ð²Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð¸ на Qt Toolkit </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;">.</span></p><p><span style=" font-size:small;">Эта программа также иÑпользует набор иконок Silk от Марка ДжеймÑа (Mark James), лицензированный под лицензией Creative Commons Attribution 2.5 and 3.0.<br/>ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾ адреÑу </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;">.</span></p></body></html> diff --git a/src/translations/sqlb_tr.ts b/src/translations/sqlb_tr.ts index bf6fecd8..06a4215e 100644 --- a/src/translations/sqlb_tr.ts +++ b/src/translations/sqlb_tr.ts @@ -15,8 +15,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>SQLite DB Browser, SQLite veritabanlarını tasarlamak ve düzenlemek için kullanılan, açık kaynak kodlu, ücretsiz bir görsel araçtır.</p><p>Bu program 'Mozilla Ortak Lisans Versiyon 2' altında lisanslanmasının yanı sıra 'GNU Genel Ortak Lisansı Versiyon 3 veya üzeri' lisansa sahiptir. Bu programı, lisans koÅŸulları çerçevesinde deÄŸiÅŸtirebilir ve yeniden dağıtabilirsiniz.</p><p>Detaylı bilgiler için <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> ve <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> adreslerine bakabilirsiniz.</p><p>Program üzerine daha fazla bilgiye ulaÅŸmak için web sitemizi ziyaret edebilirsiniz: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Bu program belirtilen adresteki GPL/LGPL Qt Toolkit kullanmaktadır: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Lisans koÅŸulları için ÅŸurayı ziyaret edin: </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"></span></p><p><span style=" font-size:small;">Ayrıca bu program, Mark James tarafından saÄŸlanan Creative Commons Attribution 2.5 ve 3.0 lisansına sahip Silk ikon setini kullanmaktadır.<br/>Detaylar için: </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"></span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>SQLite DB Browser, SQLite veritabanlarını tasarlamak ve düzenlemek için kullanılan, açık kaynak kodlu, ücretsiz bir görsel araçtır.</p><p>Bu program 'Mozilla Ortak Lisans Versiyon 2' altında lisanslanmasının yanı sıra 'GNU Genel Ortak Lisansı Versiyon 3 veya üzeri' lisansa sahiptir. Bu programı, lisans koÅŸulları çerçevesinde deÄŸiÅŸtirebilir ve yeniden dağıtabilirsiniz.</p><p>Detaylı bilgiler için <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> ve <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> adreslerine bakabilirsiniz.</p><p>Program üzerine daha fazla bilgiye ulaÅŸmak için web sitemizi ziyaret edebilirsiniz: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Bu program belirtilen adresteki GPL/LGPL Qt Toolkit kullanmaktadır: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Lisans koÅŸulları için ÅŸurayı ziyaret edin: </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"></span></p><p><span style=" font-size:small;">Ayrıca bu program, Mark James tarafından saÄŸlanan Creative Commons Attribution 2.5 ve 3.0 lisansına sahip Silk ikon setini kullanmaktadır.<br/>Detaylar için: </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"></span></p></body></html> diff --git a/src/translations/sqlb_uk_UA.ts b/src/translations/sqlb_uk_UA.ts index 5decff62..402c9ea1 100644 --- a/src/translations/sqlb_uk_UA.ts +++ b/src/translations/sqlb_uk_UA.ts @@ -15,8 +15,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>ОглÑдач БД Ð´Ð»Ñ SQLite - це безкоштовна програма з відкритим вихідним кодом, призначена Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ– Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð· даних SQLite.</p><p>Програма має дозволи за двома ліцензіÑми: Mozilla Public License Version 2 та GNU General Public License Version 3 або пізніші. Можна змінювати або розповÑюджувати Ñ—Ñ— за умовами цих ліцензій.</p><p>ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ <a href="http://www.gnu.org/licenses/gpl.html"><span style="text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> та <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> Ð´Ð»Ñ Ð´ÐµÑ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— інформації.</p><p>Більше інформації про програму можна отримати на веб-Ñайті: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Це програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸Ñтовує GPL/LGPL Qt Toolkit </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду інформації про умови ліцензії.</span></p><p><span style=" font-size:small;">Ð¦Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð° також викориÑтовує набір значків Silk від Марка ДжеймÑа (Mark James) з ліцензіÑми Creative Commons Attribution 2.5 та 3.0.<br />ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> Ð´Ð»Ñ Ð´ÐµÑ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— інформації.</span></p> <p><span style="font-size: small;">Переклад українÑькою здійÑнив Ðндрій Кондратьєв <a href="mailto:inbox@kondratyev.dp.ua">inbox@kondratyev.dp.ua</a><br /> Зв'Ñзок з автором: </span><a href="https://www.facebook.com/a.s.kondratyev"><span style="font-size: small; text-decoration: underline; color: #0000ff;">https://www.facebook.com/a.s.kondratyev</span></a><span style="font-size:small;">. </p><p> Редактор - Genyk <a href="mailto:Genyk95@gmail.com">Genyk95@gmail.com</a><br/> </span></p> </body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>ОглÑдач БД Ð´Ð»Ñ SQLite - це безкоштовна програма з відкритим вихідним кодом, призначена Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ– Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð· даних SQLite.</p><p>Програма має дозволи за двома ліцензіÑми: Mozilla Public License Version 2 та GNU General Public License Version 3 або пізніші. Можна змінювати або розповÑюджувати Ñ—Ñ— за умовами цих ліцензій.</p><p>ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ <a href="http://www.gnu.org/licenses/gpl.html"><span style="text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> та <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> Ð´Ð»Ñ Ð´ÐµÑ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— інформації.</p><p>Більше інформації про програму можна отримати на веб-Ñайті: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Це програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸Ñтовує GPL/LGPL Qt Toolkit </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду інформації про умови ліцензії.</span></p><p><span style=" font-size:small;">Ð¦Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð° також викориÑтовує набір значків Silk від Марка ДжеймÑа (Mark James) з ліцензіÑми Creative Commons Attribution 2.5 та 3.0.<br />ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> Ð´Ð»Ñ Ð´ÐµÑ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— інформації.</span></p> <p><span style="font-size: small;">Переклад українÑькою здійÑнив Ðндрій Кондратьєв <a href="mailto:inbox@kondratyev.dp.ua">inbox@kondratyev.dp.ua</a><br /> Зв'Ñзок з автором: </span><a href="https://www.facebook.com/a.s.kondratyev"><span style="font-size: small; text-decoration: underline; color: #0000ff;">https://www.facebook.com/a.s.kondratyev</span></a><span style="font-size:small;">. </p><p> Редактор - Genyk <a href="mailto:Genyk95@gmail.com">Genyk95@gmail.com</a><br/> </span></p> </body></html> diff --git a/src/translations/sqlb_zh.ts b/src/translations/sqlb_zh.ts index 52ac1bb2..a521b817 100644 --- a/src/translations/sqlb_zh.ts +++ b/src/translations/sqlb_zh.ts @@ -15,8 +15,8 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>DB Browser for SQLite 是一个开æºçš„å…è´¹å¯è§†åŒ–工具,用于创建ã€è®¾è®¡å’Œç¼–辑 SQLite æ•°æ®åº“文件。</p><p>它是以第 2 版 Mozilla 公共许å¯ï¼Œä»¥åŠç¬¬ 3 版åŠä¹‹åŽç‰ˆæœ¬çš„ GNU é€šç”¨è®¸å¯æ–¹å¼æŽˆæƒã€‚ä½ å¯ä»¥åœ¨éµå¾ªè¿™äº›è®¸å¯çš„æ¡ä»¶ä¸‹ä¿®æ”¹æˆ–é‡æ–°å‘布它。</p><p>å‚阅 <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> å’Œ <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> 了解细节。</p><p>è¦èŽ·å¾—æœ¬ç¨‹åºçš„æ›´å¤šä¿¡æ¯ï¼Œè¯·è®¿é—®æˆ‘们的网站: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">这个软件使用了 GPL/LGPL Qt Toolkit: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>å‚阅 </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> äº†è§£è®¸å¯æ¡æ¬¾å’Œä¿¡æ¯ã€‚</span></p><p><span style=" font-size:small;">它还是用了由 Mark James æä¾›çš„ Silk 图标集,以第 2.5 å’Œ 3.0 版知识共享署å(CCA)è®¸å¯æ–¹å¼æŽˆæƒã€‚<br/>å‚阅 </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 了解细节。</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite 是一个开æºçš„å…è´¹å¯è§†åŒ–工具,用于创建ã€è®¾è®¡å’Œç¼–辑 SQLite æ•°æ®åº“文件。</p><p>它是以第 2 版 Mozilla 公共许å¯ï¼Œä»¥åŠç¬¬ 3 版åŠä¹‹åŽç‰ˆæœ¬çš„ GNU é€šç”¨è®¸å¯æ–¹å¼æŽˆæƒã€‚ä½ å¯ä»¥åœ¨éµå¾ªè¿™äº›è®¸å¯çš„æ¡ä»¶ä¸‹ä¿®æ”¹æˆ–é‡æ–°å‘布它。</p><p>å‚阅 <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> å’Œ <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> 了解细节。</p><p>è¦èŽ·å¾—æœ¬ç¨‹åºçš„æ›´å¤šä¿¡æ¯ï¼Œè¯·è®¿é—®æˆ‘们的网站: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">这个软件使用了 GPL/LGPL Qt Toolkit: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>å‚阅 </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> äº†è§£è®¸å¯æ¡æ¬¾å’Œä¿¡æ¯ã€‚</span></p><p><span style=" font-size:small;">它还是用了由 Mark James æä¾›çš„ Silk 图标集,以第 2.5 å’Œ 3.0 版知识共享署å(CCA)è®¸å¯æ–¹å¼æŽˆæƒã€‚<br/>å‚阅 </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 了解细节。</span></p></body></html> diff --git a/src/translations/sqlb_zh_TW.ts b/src/translations/sqlb_zh_TW.ts index 0162e83e..316baa40 100644 --- a/src/translations/sqlb_zh_TW.ts +++ b/src/translations/sqlb_zh_TW.ts @@ -19,7 +19,7 @@ - <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> @@ -31,8 +31,8 @@ SQLite 版本 - <html><head/><body><p>SQLite Database Browser is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> - <html><head/><body><p>SQLite Database Browser 是一個開放原始碼的å…費視覺化工具,用於建立ã€è¨­è¨ˆå’Œç·¨è¼¯ SQLite 資料庫檔案。</p><p>它是以第 2 版 Mozilla 公共許å¯ï¼Œä»¥åŠç¬¬ 3 版åŠä¹‹å¾Œç‰ˆæœ¬çš„ GNU é€šç”¨è¨±å¯æ–¹å¼æŽˆæ¬Šã€‚ä½ å¯ä»¥åœ¨éµå¾ªé€™äº›è¨±å¯çš„æ¢ä»¶ä¸‹ä¿®æ”¹æˆ–é‡æ–°ç™¼ä½ˆå®ƒã€‚</p><p>åƒé–± <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> å’Œ <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> 瞭解細節。</p><p>è¦ç²å¾—本程å¼çš„æ›´å¤šè³‡è¨Šï¼Œè«‹è¨ªå•我們的網站: <a href="http://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">這個軟體使用了 GPL/LGPL Qt Toolkit: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>åƒé–± </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> çž­è§£è¨±å¯æ¢æ¬¾å’Œè³‡è¨Šã€‚</span></p><p><span style=" font-size:small;">它還是用了由 Mark James æä¾›çš„ Silk 圖示集,以第 2.5 å’Œ 3.0 版知識共用署å(CCA)è¨±å¯æ–¹å¼æŽˆæ¬Šã€‚<br/>åƒé–± </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 瞭解細節。</span></p></body></html> + <html><head/><body><p>SQLite Database Browser is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>SQLite Database Browser 是一個開放原始碼的å…費視覺化工具,用於建立ã€è¨­è¨ˆå’Œç·¨è¼¯ SQLite 資料庫檔案。</p><p>它是以第 2 版 Mozilla 公共許å¯ï¼Œä»¥åŠç¬¬ 3 版åŠä¹‹å¾Œç‰ˆæœ¬çš„ GNU é€šç”¨è¨±å¯æ–¹å¼æŽˆæ¬Šã€‚ä½ å¯ä»¥åœ¨éµå¾ªé€™äº›è¨±å¯çš„æ¢ä»¶ä¸‹ä¿®æ”¹æˆ–é‡æ–°ç™¼ä½ˆå®ƒã€‚</p><p>åƒé–± <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> å’Œ <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> 瞭解細節。</p><p>è¦ç²å¾—本程å¼çš„æ›´å¤šè³‡è¨Šï¼Œè«‹è¨ªå•我們的網站: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">這個軟體使用了 GPL/LGPL Qt Toolkit: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>åƒé–± </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> çž­è§£è¨±å¯æ¢æ¬¾å’Œè³‡è¨Šã€‚</span></p><p><span style=" font-size:small;">它還是用了由 Mark James æä¾›çš„ Silk 圖示集,以第 2.5 å’Œ 3.0 版知識共用署å(CCA)è¨±å¯æ–¹å¼æŽˆæ¬Šã€‚<br/>åƒé–± </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 瞭解細節。</span></p></body></html> From 4c86acd1018679497a1c26ef3b142a54c3c310b2 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Mon, 7 May 2018 22:04:24 +0200 Subject: [PATCH 27/63] Update issue templates Upgrade our legacy issue template to the new and upgraded multiple issue template builder to be able to create multiple issue templates. --- .github/ISSUE_TEMPLATE/Bug_report.md | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Bug_report.md diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md new file mode 100644 index 00000000..abc8fe55 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -0,0 +1,48 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + + + +Details for the issue +-------------------- + +#### What did you do? + + +#### What did you expect to see? + + +#### What did you see instead? + + +Useful extra information +------------------------- + +The info below often helps, please fill it out if you're able to. :) + +#### What operating system are you using? + +- [ ] Windows: ( _version:_ ___ ) +- [ ] Linux: ( _distro:_ ___ ) +- [ ] Mac OS: ( _version:_ ___ ) +- [ ] Other: ___ + +#### What is your DB4S version? + +- [ ] 3.10.1 +- [ ] 3.10.0 +- [ ] 3.9.1 +- [ ] Other: ___ + +#### Did you also + +- [ ] Try out the latest nightly version: https://github.com/sqlitebrowser/sqlitebrowser#nightly-builds +- [ ] Search for an existing similar issue: https://github.com/sqlitebrowser/sqlitebrowser/issues?utf8=%E2%9C%93&q=is%3Aissue%20 From 676a457db46453c32169966f82c221fcec3912d6 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Tue, 8 May 2018 00:13:47 +0200 Subject: [PATCH 28/63] Update issue templates to add Feature Request template --- .github/ISSUE_TEMPLATE/Feature_request.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Feature_request.md diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md new file mode 100644 index 00000000..770e6cf3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -0,0 +1,23 @@ +--- +name: Feature Request +about: Suggest an idea or request a new feature + +--- + + + +Describe the new feature +-------------------------- + + +Additional info +--------------- +Please answer these questions before submitting your feature request. + +#### Is your feature request related to an issue? Please include the issue number. + + +#### Does this feature exist in another product or project? Please provide a link. + + +#### Do you have a screenshot? Please add screenshots to help explain your idea. From c02cbdf28b7c300aab58008e0b0b15e7eb16acc2 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Tue, 8 May 2018 03:32:00 +0200 Subject: [PATCH 29/63] Update issue templates to add Question template --- .github/ISSUE_TEMPLATE/Custom.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Custom.md diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Custom.md new file mode 100644 index 00000000..1fc2211d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Custom.md @@ -0,0 +1,14 @@ +--- +name: Question +about: Ask a question related to this project or SQLite in general + +--- + + + +What is your question +----------------------- From 82307e0d4628f98134418318d40a1458d6b576ed Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Tue, 8 May 2018 03:50:25 +0200 Subject: [PATCH 30/63] Cosmetic changes to issue templates --- .github/ISSUE_TEMPLATE/Bug_report.md | 2 +- .../ISSUE_TEMPLATE/{Custom.md => Question.md} | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) rename .github/ISSUE_TEMPLATE/{Custom.md => Question.md} (95%) diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index abc8fe55..372c33e1 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -1,5 +1,5 @@ --- -name: Bug report +name: Bug Report about: Create a report to help us improve --- diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Question.md similarity index 95% rename from .github/ISSUE_TEMPLATE/Custom.md rename to .github/ISSUE_TEMPLATE/Question.md index 1fc2211d..b14c391a 100644 --- a/.github/ISSUE_TEMPLATE/Custom.md +++ b/.github/ISSUE_TEMPLATE/Question.md @@ -1,14 +1,14 @@ ---- -name: Question -about: Ask a question related to this project or SQLite in general - ---- - - - -What is your question ------------------------ +--- +name: Question +about: Ask a question related to this project or SQLite in general + +--- + + + +What is your question +----------------------- From f79f2550fb2f5c462c4610db72c39343a586c4c6 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Sat, 12 May 2018 14:06:18 +0200 Subject: [PATCH 31/63] Add VERSIONINFO for Windows executable --- src/winapp.rc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/winapp.rc b/src/winapp.rc index 3bccc7be..07c21715 100644 --- a/src/winapp.rc +++ b/src/winapp.rc @@ -1 +1,30 @@ -IDI_ICON1 ICON DISCARDABLE "iconwin.ico" \ No newline at end of file +#include +#include "version.h" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0 +PRODUCTVERSION MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004B0" + BEGIN + VALUE "FileVersion", APP_VERSION + VALUE "ProductVersion", APP_VERSION + VALUE "FileDescription", "DB Browser for SQLite" + VALUE "ProductName", "DB Browser for SQLite" + VALUE "InternalName", "DB Browser for SQLite" + VALUE "OriginalFilename", "DB Browser for SQLite.exe" + VALUE "CompanyName", "DB Browser for SQLite Team" + VALUE "LegalCopyright", "Copyright © DB Browser for SQLite Team" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0000, 0x04B0 + END +END + +IDI_DB4S ICON "iconwin.ico" From e6a4326e9bc1d48d027278171e8ab335c1f91e82 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 15:01:22 +0200 Subject: [PATCH 32/63] Fix filters Fix a bug that causes the rowid column to be always shown when changing the filters. I *believe* this was happening since updating to Qt 5.10. --- src/MainWindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3acef0cd..7ebca529 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -2429,6 +2429,9 @@ void MainWindow::updateFilter(int column, const QString& value) m_browseTableModel->updateFilter(column, value); browseTableSettings[currentlyBrowsedTableName()].filterValues[column] = value; setRecordsetLabel(); + + // This seems to be necessary as a workaround for newer Qt versions. Otherwise the rowid column is always shown after changing the filters. + showRowidColumn(browseTableSettings[currentlyBrowsedTableName()].showRowid); } void MainWindow::editEncryption() From c25ce1399ab16ac4011932491b5ac08479dd955a Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 15:32:12 +0200 Subject: [PATCH 33/63] Minor wording tweak --- src/ExportSqlDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ExportSqlDialog.cpp b/src/ExportSqlDialog.cpp index b4a5f6b2..96ba4448 100644 --- a/src/ExportSqlDialog.cpp +++ b/src/ExportSqlDialog.cpp @@ -71,7 +71,7 @@ void ExportSqlDialog::accept() if(selectedItems.isEmpty()) { QMessageBox::warning(this, QApplication::applicationName(), - tr("Please select at least 1 table.")); + tr("Please select at least one table.")); return; } From aebfc5151ec1c2e0cb2c5a01a81a4e53f682f7c7 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 16:18:03 +0200 Subject: [PATCH 34/63] No need to commit when setting defer_foreign_keys pragma Don't commit the current transaction when setting the defer_foreign_keys pragma in the Execute SQL tab. Not only isn't it required by SQLite but it's quite contrary to the point of a pragma the purpose of which is to change the current transaction. --- src/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 7ebca529..759f8a06 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1060,7 +1060,7 @@ void MainWindow::executeQuery() structure_updated = true; // Check whether this is trying to set a pragma or to vacuum the database - if((query_type == PragmaStatement && qtail.contains('=')) || query_type == VacuumStatement) + if((query_type == PragmaStatement && qtail.contains('=') && !qtail.contains("defer_foreign_keys", Qt::CaseInsensitive)) || query_type == VacuumStatement) { // We're trying to set a pragma. If the database has been modified it needs to be committed first. We'll need to ask the // user about that From 431c67138ba22445f42a6d95a638fd90284a442b Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 17:20:15 +0200 Subject: [PATCH 35/63] Improve error messages when importing SQL files When executing multiple SQL statements at once, e.g. when importing an SQL file (but not in the Execute SQL tab!), and hitting an error save the error message before reverting the transaction. This preserves the error message which is otherwise replaced by "not an error" because the rollback doesn't fail. --- src/sqlitedb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 1864d2ad..7ff4694f 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -808,13 +808,13 @@ bool DBBrowserDB::executeMultiSQL(const QString& statement, bool dirty, bool log return false; } } else { - if(dirty) - revertToSavepoint(savepoint_name); lastErrorMessage = tr("Error in statement #%1: %2.\nAborting execution%3.") .arg(line) .arg(sqlite3_errmsg(_db)) .arg(dirty ? tr(" and rolling back") : ""); qWarning() << lastErrorMessage; + if(dirty) + revertToSavepoint(savepoint_name); return false; } } From 28baba8ec88beb54bb7ff642dc1ad0c95e7c9486 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 17:49:12 +0200 Subject: [PATCH 36/63] Fix icons in Export SQL dialog Fix the type icons in the Export SQL dialog which weren't show before. --- src/ExportSqlDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ExportSqlDialog.cpp b/src/ExportSqlDialog.cpp index 96ba4448..a483d07e 100644 --- a/src/ExportSqlDialog.cpp +++ b/src/ExportSqlDialog.cpp @@ -30,7 +30,7 @@ ExportSqlDialog::ExportSqlDialog(DBBrowserDB* db, QWidget* parent, const QString // Get list of tables to export objectMap objects = pdb->getBrowsableObjects("main"); for(auto it=objects.constBegin();it!=objects.constEnd();++it) - ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg((*it)->type())), (*it)->name())); + ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg(sqlb::Object::typeToString((*it)->type()))), (*it)->name())); // Sort list of tables and select the table specified in the // selection parameter or all tables if table not specified From b384027378aa7d72ad420568543080cd6e15ea1e Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 18:01:19 +0200 Subject: [PATCH 37/63] Only allow selection of tables in Export SQL dialog Only allow the user to select which tables to export in the Export SQL dialog instead of tables and views. The selection of views wasn't respected anyway, so the list including views is just confusing. --- src/ExportSqlDialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ExportSqlDialog.cpp b/src/ExportSqlDialog.cpp index a483d07e..46900ea3 100644 --- a/src/ExportSqlDialog.cpp +++ b/src/ExportSqlDialog.cpp @@ -28,9 +28,9 @@ ExportSqlDialog::ExportSqlDialog(DBBrowserDB* db, QWidget* parent, const QString ui->comboOldSchema->setCurrentIndex(Settings::getValue("exportsql", "oldschema").toInt()); // Get list of tables to export - objectMap objects = pdb->getBrowsableObjects("main"); - for(auto it=objects.constBegin();it!=objects.constEnd();++it) - ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg(sqlb::Object::typeToString((*it)->type()))), (*it)->name())); + QList objects = pdb->schemata["main"].values("table"); + for(const sqlb::ObjectPtr& it : objects) + ui->listTables->addItem(new QListWidgetItem(QIcon(QString(":icons/%1").arg(sqlb::Object::typeToString(it->type()))), it->name())); // Sort list of tables and select the table specified in the // selection parameter or all tables if table not specified From b6c05609dc496e1aedd8f9a9c98cf667bdab1a08 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 18:18:56 +0200 Subject: [PATCH 38/63] Change order of statements in exported SQL file When exporting a database to an SQL file we used to export it like this: - Table 1 schema - Table 1 data - Table 2 schema - Table 2 data With this commit that is changed like this: - Table 1 schema - Table 2 schema - Table 1 data - Table 2 data This makes the resulting SQL file more robust for import because it avoids any foreign key errors as long as foreign keys are deferred. --- src/sqlitedb.cpp | 200 ++++++++++++++++++++++++----------------------- src/sqlitedb.h | 2 +- 2 files changed, 102 insertions(+), 100 deletions(-) diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 7ff4694f..23b146ac 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -488,7 +488,7 @@ bool DBBrowserDB::close() } bool DBBrowserDB::dump(const QString& filename, - const QStringList & tablesToDump, + const QStringList& tablesToDump, bool insertColNames, bool insertNewSyntx, bool exportSchema, @@ -501,6 +501,7 @@ bool DBBrowserDB::dump(const QString& filename, { QApplication::setOverrideCursor(Qt::WaitCursor); + // Count the total number of all records in all tables for the progress dialog size_t numRecordsTotal = 0, numRecordsCurrent = 0; objectMap objMap = schemata["main"]; // We only always export the main database, not the attached databases QList tables = objMap.values("table"); @@ -509,8 +510,8 @@ bool DBBrowserDB::dump(const QString& filename, { it.next(); - // Remove the sqlite_stat1 table if there is one - if(it.value()->name() == "sqlite_stat1" || it.value()->name() == "sqlite_sequence") + // Remove the sqlite_stat1 and the sqlite_sequence tables if they exist. Also remove any tables which are not selected for export. + if(it.value()->name() == "sqlite_stat1" || it.value()->name() == "sqlite_sequence" || !tablesToDump.contains(it.value()->name())) { it.remove(); } else { @@ -533,140 +534,141 @@ bool DBBrowserDB::dump(const QString& filename, // Put the SQL commands in a transaction block stream << "BEGIN TRANSACTION;\n"; - // Loop through all tables first as they are required to generate views, indices etc. later - for(auto it=tables.constBegin();it!=tables.constEnd();++it) + // First export the schema of all selected tables. We need to export the schema of all tables before we export the first INSERT statement to + // make sure foreign keys are working properly. + if(exportSchema) { - if (tablesToDump.indexOf((*it)->name()) == -1) - continue; - - // Write the SQL string used to create this table to the output file - if(exportSchema) + for(auto it : tables) { + // Write the SQL string used to create this table to the output file if(!keepOldSchema) - stream << QString("DROP TABLE IF EXISTS %1;\n").arg(sqlb::escapeIdentifier((*it)->name())); + stream << QString("DROP TABLE IF EXISTS %1;\n").arg(sqlb::escapeIdentifier(it->name())); - if((*it)->fullyParsed()) - stream << (*it)->sql("main", true) << "\n"; + if(it->fullyParsed()) + stream << it->sql("main", true) << "\n"; else - stream << (*it)->originalSql() << ";\n"; - } + stream << it->originalSql() << ";\n"; + } + } - // If the user doesn't want the data to be exported skip the rest of the loop block here - if(!exportData) - continue; - - // get columns - QStringList cols((*it).dynamicCast()->fieldNames()); - - QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::escapeIdentifier((*it)->name())); - QByteArray utf8Query = sQuery.toUtf8(); - sqlite3_stmt *stmt; - QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';')); - - int status = sqlite3_prepare_v2(this->_db, utf8Query.data(), utf8Query.size(), &stmt, NULL); - if(SQLITE_OK == status) + // Now export the data as well + if(exportData) + { + for(auto it : tables) { - int columns = sqlite3_column_count(stmt); - size_t counter = 0; - qApp->processEvents(); - while(sqlite3_step(stmt) == SQLITE_ROW) + // get columns + QStringList cols(it.dynamicCast()->fieldNames()); + + QString sQuery = QString("SELECT * FROM %1;").arg(sqlb::escapeIdentifier(it->name())); + QByteArray utf8Query = sQuery.toUtf8(); + sqlite3_stmt *stmt; + QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';')); + + int status = sqlite3_prepare_v2(this->_db, utf8Query.data(), utf8Query.size(), &stmt, NULL); + if(SQLITE_OK == status) { - if (counter) stream << lineSep; - - if (!insertNewSyntx || !counter) + int columns = sqlite3_column_count(stmt); + size_t counter = 0; + qApp->processEvents(); + while(sqlite3_step(stmt) == SQLITE_ROW) { - stream << "INSERT INTO " << sqlb::escapeIdentifier((*it)->name()); - if (insertColNames) - stream << " (" << cols.join(",") << ")"; - stream << " VALUES ("; - } - else - { - stream << " ("; - } + if (counter) stream << lineSep; - for (int i = 0; i < columns; ++i) - { - int fieldsize = sqlite3_column_bytes(stmt, i); - int fieldtype = sqlite3_column_type(stmt, i); - QByteArray bcontent( - (const char*)sqlite3_column_blob(stmt, i), - fieldsize); - - if(bcontent.left(2048).contains('\0')) // binary check + if (!insertNewSyntx || !counter) { - stream << QString("X'%1'").arg(QString(bcontent.toHex())); + stream << "INSERT INTO " << sqlb::escapeIdentifier(it->name()); + if (insertColNames) + stream << " (" << cols.join(",") << ")"; + stream << " VALUES ("; } else { - switch(fieldtype) - { - case SQLITE_TEXT: - case SQLITE_BLOB: - stream << "'" << bcontent.replace("'", "''") << "'"; - break; - case SQLITE_NULL: - stream << "NULL"; - break; - case SQLITE_FLOAT: - if(bcontent.indexOf("Inf") != -1) - stream << "'" << bcontent << "'"; - else - stream << bcontent; - break; - default: - stream << bcontent; - } + stream << " ("; } - if(i != columns - 1) - stream << ','; - } - progress.setValue(++numRecordsCurrent); - if(counter % 5000 == 0) - qApp->processEvents(); - counter++; + for (int i = 0; i < columns; ++i) + { + int fieldsize = sqlite3_column_bytes(stmt, i); + int fieldtype = sqlite3_column_type(stmt, i); + QByteArray bcontent( + (const char*)sqlite3_column_blob(stmt, i), + fieldsize); - if(progress.wasCanceled()) - { - sqlite3_finalize(stmt); - file.close(); - file.remove(); - QApplication::restoreOverrideCursor(); - return false; + if(bcontent.left(2048).contains('\0')) // binary check + { + stream << QString("X'%1'").arg(QString(bcontent.toHex())); + } + else + { + switch(fieldtype) + { + case SQLITE_TEXT: + case SQLITE_BLOB: + stream << "'" << bcontent.replace("'", "''") << "'"; + break; + case SQLITE_NULL: + stream << "NULL"; + break; + case SQLITE_FLOAT: + if(bcontent.indexOf("Inf") != -1) + stream << "'" << bcontent << "'"; + else + stream << bcontent; + break; + default: + stream << bcontent; + } + } + if(i != columns - 1) + stream << ','; + } + + progress.setValue(++numRecordsCurrent); + if(counter % 5000 == 0) + qApp->processEvents(); + counter++; + + if(progress.wasCanceled()) + { + sqlite3_finalize(stmt); + file.close(); + file.remove(); + QApplication::restoreOverrideCursor(); + return false; + } } + if (counter > 0) stream << ");\n"; } - if (counter > 0) stream << ");\n"; + sqlite3_finalize(stmt); } - sqlite3_finalize(stmt); } - // Now dump all the other objects (but only if we are exporting the schema) + // Finally export all objects other than tables if(exportSchema) { - for(auto it=objMap.constBegin();it!=objMap.constEnd();++it) + for(auto it : objMap) { // Make sure it's not a table again - if(it.value()->type() == sqlb::Object::Types::Table) + if(it->type() == sqlb::Object::Types::Table) continue; // If this object is based on a table (e.g. is an index for that table) it depends on the existence of this table. // So if we didn't export the base table this depends on, don't export this object either. - if(!(*it)->baseTable().isEmpty() && !tablesToDump.contains((*it)->baseTable())) + if(!it->baseTable().isEmpty() && !tablesToDump.contains(it->baseTable())) continue; // Write the SQL string used to create this object to the output file - if(!(*it)->originalSql().isEmpty()) + if(!it->originalSql().isEmpty()) { if(!keepOldSchema) stream << QString("DROP %1 IF EXISTS %2;\n") - .arg(sqlb::Object::typeToString((*it)->type()).toUpper()) - .arg(sqlb::escapeIdentifier((*it)->name())); + .arg(sqlb::Object::typeToString(it->type()).toUpper()) + .arg(sqlb::escapeIdentifier(it->name())); - if((*it)->fullyParsed()) - stream << (*it)->sql("main", true) << "\n"; + if(it->fullyParsed()) + stream << it->sql("main", true) << "\n"; else - stream << (*it)->originalSql() << ";\n"; + stream << it->originalSql() << ";\n"; } } } diff --git a/src/sqlitedb.h b/src/sqlitedb.h index bc6fb19b..03116152 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -37,7 +37,7 @@ public: bool revertToSavepoint(const QString& pointname = "RESTOREPOINT"); bool releaseAllSavepoints(); bool revertAll(); - bool dump(const QString & filename, const QStringList &tablesToDump, bool insertColNames, bool insertNew, bool exportSchema, bool exportData, bool keepOldSchema); + bool dump(const QString& filename, const QStringList& tablesToDump, bool insertColNames, bool insertNew, bool exportSchema, bool exportData, bool keepOldSchema); bool executeSQL(QString statement, bool dirtyDB = true, bool logsql = true); bool executeMultiSQL(const QString& statement, bool dirty = true, bool log = false); const QString& lastError() const { return lastErrorMessage; } From a5d36694db73c1143f654c59888e2e21f2b4a99a Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 18:26:48 +0200 Subject: [PATCH 39/63] Simplify code --- src/DbStructureModel.cpp | 18 +++++++++--------- src/EditIndexDialog.cpp | 4 ++-- src/MainWindow.cpp | 6 +++--- src/sqlitedb.cpp | 16 ++++++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/DbStructureModel.cpp b/src/DbStructureModel.cpp index e9623548..040eed3a 100644 --- a/src/DbStructureModel.cpp +++ b/src/DbStructureModel.cpp @@ -303,27 +303,27 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema) // Get all database objects and sort them by their name QMultiMap dbobjs; - for(auto it=objmap.constBegin(); it != objmap.constEnd(); ++it) - dbobjs.insert((*it)->name(), (*it)); + for(auto it : objmap) + dbobjs.insert(it->name(), it); // Add the database objects to the tree nodes - for(auto it=dbobjs.constBegin();it!=dbobjs.constEnd();++it) + for(auto it : dbobjs) { // Object node - QTreeWidgetItem* item = addNode(typeToParentItem.value(sqlb::Object::typeToString((*it)->type())), *it, schema); + QTreeWidgetItem* item = addNode(typeToParentItem.value(sqlb::Object::typeToString(it->type())), it, schema); // If it is a table or view add the field nodes, add an extra node for the browsable section - if((*it)->type() == sqlb::Object::Types::Table || (*it)->type() == sqlb::Object::Types::View) - addNode(browsablesRootItem, *it, schema); + if(it->type() == sqlb::Object::Types::Table || it->type() == sqlb::Object::Types::View) + addNode(browsablesRootItem, it, schema); // Add field nodes if there are any - sqlb::FieldInfoList fieldList = (*it)->fieldInformation(); + sqlb::FieldInfoList fieldList = it->fieldInformation(); if(!fieldList.empty()) { QStringList pk_columns; - if((*it)->type() == sqlb::Object::Types::Table) + if(it->type() == sqlb::Object::Types::Table) { - sqlb::FieldVector pk = (*it).dynamicCast()->primaryKey(); + sqlb::FieldVector pk = it.dynamicCast()->primaryKey(); for(const sqlb::FieldPtr& pk_col : pk) pk_columns.push_back(pk_col->name()); diff --git a/src/EditIndexDialog.cpp b/src/EditIndexDialog.cpp index 3b7b0e98..8c8ed760 100644 --- a/src/EditIndexDialog.cpp +++ b/src/EditIndexDialog.cpp @@ -33,10 +33,10 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& } } else { // If this is an existing index, only offer tables of the current database schema QList tables = pdb.schemata[curIndex.schema()].values("table"); - for(auto it=tables.constBegin();it!=tables.constEnd();++it) + for(auto it : tables) { // Only show the schema name for non-main schemata - sqlb::ObjectIdentifier obj(curIndex.schema(), (*it)->name()); + sqlb::ObjectIdentifier obj(curIndex.schema(), it->name()); dbobjs.insert(obj.toDisplayString(), obj); } } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 759f8a06..3df89026 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -427,11 +427,11 @@ void MainWindow::populateStructure(const QString& old_table) for(auto it=db.schemata.constBegin();it!=db.schemata.constEnd();++it) { objectMap tab = db.getBrowsableObjects(it.key()); - for(auto it=tab.constBegin();it!=tab.constEnd();++it) + for(auto it : tab) { - QString objectname = (*it)->name(); + QString objectname = it->name(); - sqlb::FieldInfoList fi = (*it)->fieldInformation(); + sqlb::FieldInfoList fi = it->fieldInformation(); for(const sqlb::FieldInfo& f : fi) tablesToColumnsMap[objectname].append(f.name); } diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 23b146ac..ada6b4b6 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -1205,16 +1205,16 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb // Save all indices, triggers and views associated with this table because SQLite deletes them when we drop the table in the next step QStringList otherObjectsSql; - for(auto it=schemata[tablename.schema()].constBegin();it!=schemata[tablename.schema()].constEnd();++it) + for(auto it : schemata[tablename.schema()]) { // If this object references the table and it's not the table itself save it's SQL string - if((*it)->baseTable() == tablename.name() && (*it)->type() != sqlb::Object::Types::Table) + if(it->baseTable() == tablename.name() && it->type() != sqlb::Object::Types::Table) { // If this is an index, update the fields first. This highly increases the chance that the SQL statement won't throw an // error later on when we try to recreate it. - if((*it)->type() == sqlb::Object::Types::Index) + if(it->type() == sqlb::Object::Types::Index) { - sqlb::IndexPtr idx = (*it).dynamicCast(); + sqlb::IndexPtr idx = it.dynamicCast(); // Are we updating a field name or are we removing a field entirely? if(to) @@ -1238,7 +1238,7 @@ bool DBBrowserDB::alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb } else { // If it's a view or a trigger we don't have any chance to corrections yet. Just store the statement as is and // hope for the best. - otherObjectsSql << (*it)->originalSql().trimmed() + ";"; + otherObjectsSql << it->originalSql().trimmed() + ";"; } } } @@ -1352,10 +1352,10 @@ objectMap DBBrowserDB::getBrowsableObjects(const QString& schema) const const sqlb::ObjectPtr DBBrowserDB::getObjectByName(const sqlb::ObjectIdentifier& name) const { - for(auto it=schemata[name.schema()].constBegin();it!=schemata[name.schema()].constEnd();++it) + for(auto it : schemata[name.schema()]) { - if((*it)->name() == name.name()) - return *it; + if(it->name() == name.name()) + return it; } return sqlb::ObjectPtr(nullptr); } From 13d9f98aabeb66d6d466f301a139ec2b975482bf Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 18:39:51 +0200 Subject: [PATCH 40/63] Fix the text of the toolbar actions for deleting and modifying objects When selecting an object other than a table the toolbar actions would say "Modify/Delete Table" nonetheless. I don't remember it being this way, so I suspect this was changed by updating to Qt 5. Either way, this commit makes absolutely sure the texts are updated properly. --- src/MainWindow.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3df89026..3246641f 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -256,6 +256,16 @@ void MainWindow::init() statusEncodingLabel->setToolTip(tr("Database encoding")); ui->statusbar->addPermanentWidget(statusEncodingLabel); + // When changing the text of the toolbar actions, also automatically change their icon text and their tooltip text + connect(ui->editModifyObjectAction, &QAction::changed, [=]() { + ui->editModifyObjectAction->setIconText(ui->editModifyObjectAction->text()); + ui->editModifyObjectAction->setToolTip(ui->editModifyObjectAction->text()); + }); + connect(ui->editDeleteObjectAction, &QAction::changed, [=]() { + ui->editDeleteObjectAction->setIconText(ui->editDeleteObjectAction->text()); + ui->editDeleteObjectAction->setToolTip(ui->editDeleteObjectAction->text()); + }); + // Connect some more signals and slots connect(ui->dataTable->filterHeader(), SIGNAL(sectionClicked(int)), this, SLOT(browseTableHeaderClicked(int))); connect(ui->dataTable->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setRecordsetLabel())); @@ -1411,7 +1421,7 @@ void MainWindow::createTreeContextMenu(const QPoint &qPoint) if(type == "table" || type == "view" || type == "trigger" || type == "index") popupTableMenu->exec(ui->dbTreeWidget->mapToGlobal(qPoint)); } -//** Tree selection changed + void MainWindow::changeTreeSelection() { // Just assume first that something's selected that can not be edited at all @@ -1436,24 +1446,16 @@ void MainWindow::changeTreeSelection() if (type == "view") { ui->editDeleteObjectAction->setText(tr("Delete View")); - ui->editDeleteObjectAction->setToolTip(tr("Delete View")); ui->editModifyObjectAction->setText(tr("Modify View")); - ui->editModifyObjectAction->setToolTip(tr("Modify View")); } else if(type == "trigger") { ui->editDeleteObjectAction->setText(tr("Delete Trigger")); - ui->editDeleteObjectAction->setToolTip(tr("Delete Trigger")); ui->editModifyObjectAction->setText(tr("Modify Trigger")); - ui->editModifyObjectAction->setToolTip(tr("Modify Trigger")); } else if(type == "index") { ui->editDeleteObjectAction->setText(tr("Delete Index")); - ui->editDeleteObjectAction->setToolTip(tr("Delete Index")); ui->editModifyObjectAction->setText(tr("Modify Index")); - ui->editModifyObjectAction->setToolTip(tr("Modify Index")); } else { ui->editDeleteObjectAction->setText(tr("Delete Table")); - ui->editDeleteObjectAction->setToolTip(tr("Delete Table")); ui->editModifyObjectAction->setText(tr("Modify Table")); - ui->editModifyObjectAction->setToolTip(tr("Modify Table")); } // Activate actions From 817de2d3f55b4337cd89d0428395b2acb9bbf861 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Wed, 16 May 2018 19:01:13 +0200 Subject: [PATCH 41/63] Update Report bug link to include the system information (#1388) When reporting an issue from the application, via the menu 'Help | Bug report', the new link will add the label 'bug' and include the system information automatically. See issue #1386 --- src/MainWindow.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3246641f..1b0b4763 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1,6 +1,7 @@ #include "MainWindow.h" #include "ui_MainWindow.h" +#include "Application.h" #include "EditIndexDialog.h" #include "AboutDialog.h" #include "EditTableDialog.h" @@ -48,6 +49,7 @@ #include #include #include +#include MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), @@ -2012,9 +2014,23 @@ void MainWindow::on_actionWiki_triggered() QDesktopServices::openUrl(QUrl("https://github.com/sqlitebrowser/sqlitebrowser/wiki")); } +// 'Help | Bug report...' link will add the system information and set the label 'bug' automatically to the issue void MainWindow::on_actionBug_report_triggered() { - QDesktopServices::openUrl(QUrl("https://github.com/sqlitebrowser/sqlitebrowser/issues/new")); + const QString version = Application::versionString(); + const QString os = QSysInfo::prettyProductName(); + const QString kernelType = QSysInfo::kernelType(); + const QString kernelVersion = QSysInfo::kernelVersion(); + const QString arch = QSysInfo::currentCpuArchitecture(); + const QString body = QString("\n\n\n\n\n\n\n\n> DB4S v%1 on %2 (%3/%4) [%5]").arg(version, os, kernelType, kernelVersion, arch); + + QUrlQuery query; + query.addQueryItem("labels", "bug"); + query.addQueryItem("body", body); + + QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); + url.setQuery(query); + QDesktopServices::openUrl(url); } void MainWindow::on_actionSqlCipherFaq_triggered() From abf70ea7bd4a1683f2ff0d1df84cd7e5e8d429b7 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Wed, 16 May 2018 19:20:36 +0200 Subject: [PATCH 42/63] Use nullptr instead of NULL --- src/ExportDataDialog.cpp | 4 ++-- src/RemoteDatabase.cpp | 6 +++--- src/sqlitedb.cpp | 26 +++++++++++++------------- src/sqlitetablemodel.cpp | 8 ++++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ExportDataDialog.cpp b/src/ExportDataDialog.cpp index 827a23ff..d252453f 100644 --- a/src/ExportDataDialog.cpp +++ b/src/ExportDataDialog.cpp @@ -116,7 +116,7 @@ bool ExportDataDialog::exportQueryCsv(const QString& sQuery, const QString& sFil QByteArray utf8Query = sQuery.toUtf8(); sqlite3_stmt *stmt; - int status = sqlite3_prepare_v2(pdb._db, utf8Query.data(), utf8Query.size(), &stmt, NULL); + int status = sqlite3_prepare_v2(pdb._db, utf8Query.data(), utf8Query.size(), &stmt, nullptr); if(SQLITE_OK == status) { if(ui->checkHeader->isChecked()) @@ -198,7 +198,7 @@ bool ExportDataDialog::exportQueryJson(const QString& sQuery, const QString& sFi { QByteArray utf8Query = sQuery.toUtf8(); sqlite3_stmt *stmt; - int status = sqlite3_prepare_v2(pdb._db, utf8Query.data(), utf8Query.size(), &stmt, NULL); + int status = sqlite3_prepare_v2(pdb._db, utf8Query.data(), utf8Query.size(), &stmt, nullptr); QJsonArray json_table; diff --git a/src/RemoteDatabase.cpp b/src/RemoteDatabase.cpp index 6f4722ef..a5ad9d93 100644 --- a/src/RemoteDatabase.cpp +++ b/src/RemoteDatabase.cpp @@ -535,7 +535,7 @@ void RemoteDatabase::localAssureOpened() // Open file QString database_file = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/remotedbs.db"; - if(sqlite3_open_v2(database_file.toUtf8(), &m_dbLocal, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) + if(sqlite3_open_v2(database_file.toUtf8(), &m_dbLocal, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error opening local databases list.\n%1").arg(QString::fromUtf8(sqlite3_errmsg(m_dbLocal)))); return; @@ -553,7 +553,7 @@ void RemoteDatabase::localAssureOpened() "\"modified\" INTEGER DEFAULT 0," "\"branch\" TEXT NOT NULL DEFAULT \"master\"" ")"); - if(sqlite3_exec(m_dbLocal, statement.toUtf8(), NULL, NULL, &errmsg) != SQLITE_OK) + if(sqlite3_exec(m_dbLocal, statement.toUtf8(), nullptr, nullptr, &errmsg) != SQLITE_OK) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error creating local databases list.\n%1").arg(QString::fromUtf8(errmsg))); sqlite3_free(errmsg); @@ -819,7 +819,7 @@ QString RemoteDatabase::localLastCommitId(QString identity, const QUrl& url) // Query commit id for that file name QString sql = QString("SELECT commit_id FROM local WHERE identity=? AND url=?"); sqlite3_stmt* stmt; - if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, NULL) != SQLITE_OK) + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return QString(); QFileInfo f(identity); // Remove the path diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index ada6b4b6..114dcdcb 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -108,7 +108,7 @@ bool DBBrowserDB::open(const QString& db, bool readOnly) return false; // Open database file - if(sqlite3_open_v2(db.toUtf8(), &_db, readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) + if(sqlite3_open_v2(db.toUtf8(), &_db, readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, nullptr) != SQLITE_OK) { lastErrorMessage = QString::fromUtf8((const char*)sqlite3_errmsg(_db)); return false; @@ -135,7 +135,7 @@ bool DBBrowserDB::open(const QString& db, bool readOnly) // register collation callback Callback::func = std::bind(&DBBrowserDB::collationNeeded, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); void (*c_callback)(void*, sqlite3*, int, const char*) = static_cast(Callback::callback); - sqlite3_collation_needed(_db, NULL, c_callback); + sqlite3_collation_needed(_db, nullptr, c_callback); // Set foreign key settings as requested in the preferences bool foreignkeys = Settings::getValue("db", "foreignkeys").toBool(); @@ -146,7 +146,7 @@ bool DBBrowserDB::open(const QString& db, bool readOnly) // Register REGEXP function if(Settings::getValue("extensions", "disableregex").toBool() == false) - sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, NULL, regexp, NULL, NULL); + sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, nullptr, regexp, nullptr, nullptr); // Check if file is read only QFileInfo fi(db); @@ -177,7 +177,7 @@ bool DBBrowserDB::attach(const QString& filename, QString attach_as) QString sql = "PRAGMA database_list;"; logSQL(sql, kLogMsg_App); sqlite3_stmt* db_vm; - if(sqlite3_prepare_v2(_db, sql.toUtf8(), sql.toUtf8().length(), &db_vm, NULL) == SQLITE_OK) + if(sqlite3_prepare_v2(_db, sql.toUtf8(), sql.toUtf8().length(), &db_vm, nullptr) == SQLITE_OK) { // Loop through all the databases QFileInfo fi(filename); @@ -249,7 +249,7 @@ bool DBBrowserDB::tryEncryptionSettings(const QString& filename, bool* encrypted // Open database file sqlite3* dbHandle; - if(sqlite3_open_v2(filename.toUtf8(), &dbHandle, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) + if(sqlite3_open_v2(filename.toUtf8(), &dbHandle, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) return false; // Try reading from database @@ -426,7 +426,7 @@ bool DBBrowserDB::create ( const QString & db) // Register REGEXP function if(Settings::getValue("extensions", "disableregex").toBool() == false) - sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, NULL, regexp, NULL, NULL); + sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, nullptr, regexp, nullptr, nullptr); // force sqlite3 do write proper file header // if we don't create and drop the table we might end up @@ -564,7 +564,7 @@ bool DBBrowserDB::dump(const QString& filename, sqlite3_stmt *stmt; QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';')); - int status = sqlite3_prepare_v2(this->_db, utf8Query.data(), utf8Query.size(), &stmt, NULL); + int status = sqlite3_prepare_v2(this->_db, utf8Query.data(), utf8Query.size(), &stmt, nullptr); if(SQLITE_OK == status) { int columns = sqlite3_column_count(stmt); @@ -698,7 +698,7 @@ bool DBBrowserDB::executeSQL(QString statement, bool dirtyDB, bool logsql) if (dirtyDB) setSavepoint(); char* errmsg; - if (SQLITE_OK == sqlite3_exec(_db, statement.toUtf8(), NULL, NULL, &errmsg)) + if (SQLITE_OK == sqlite3_exec(_db, statement.toUtf8(), nullptr, nullptr, &errmsg)) { // Update DB structure after executing an SQL statement. But try to avoid doing unnecessary updates. if(!dontCheckForStructureUpdates && (statement.startsWith("ALTER", Qt::CaseInsensitive) || @@ -839,7 +839,7 @@ bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& row QByteArray utf8Query = sQuery.toUtf8(); sqlite3_stmt *stmt; bool ret = false; - if(sqlite3_prepare_v2(_db, utf8Query, utf8Query.size(), &stmt, NULL) == SQLITE_OK) + if(sqlite3_prepare_v2(_db, utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) { // even this is a while loop, the statement should always only return 1 row while(sqlite3_step(stmt) == SQLITE_ROW) @@ -872,7 +872,7 @@ QString DBBrowserDB::max(const sqlb::ObjectIdentifier& tableName, sqlb::FieldPtr sqlite3_stmt *stmt; QString ret = "0"; - if(sqlite3_prepare_v2(_db, utf8Query, utf8Query.size(), &stmt, NULL) == SQLITE_OK) + if(sqlite3_prepare_v2(_db, utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) { // even this is a while loop, the statement should always only return 1 row while(sqlite3_step(stmt) == SQLITE_ROW) @@ -1031,7 +1031,7 @@ bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const QStrin // If we get a NULL QByteArray we insert a NULL value, and for that // we can pass NULL to sqlite3_bind_text() so that it behaves like sqlite3_bind_null() - const char *rawValue = value.isNull() ? NULL : value.constData(); + const char *rawValue = value.isNull() ? nullptr : value.constData(); sqlite3_stmt* stmt; int success = 1; @@ -1396,7 +1396,7 @@ void DBBrowserDB::updateSchema() QByteArray db_utf8Statement = db_statement.toUtf8(); logSQL(db_statement, kLogMsg_App); sqlite3_stmt* db_vm; - if(sqlite3_prepare_v2(_db, db_utf8Statement, db_utf8Statement.length(), &db_vm, NULL) == SQLITE_OK) + if(sqlite3_prepare_v2(_db, db_utf8Statement, db_utf8Statement.length(), &db_vm, nullptr) == SQLITE_OK) { // Loop through all the databases while(sqlite3_step(db_vm) == SQLITE_ROW) @@ -1418,7 +1418,7 @@ void DBBrowserDB::updateSchema() logSQL(statement, kLogMsg_App); sqlite3_stmt* vm; - int err = sqlite3_prepare_v2(_db, utf8Statement, utf8Statement.length(), &vm, NULL); + int err = sqlite3_prepare_v2(_db, utf8Statement, utf8Statement.length(), &vm, nullptr); if(err == SQLITE_OK) { while(sqlite3_step(vm) == SQLITE_ROW) diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index 547c7aa1..cee74be6 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -164,7 +164,7 @@ int SqliteTableModel::getQueryRowCount() // So just execute the statement as it is and fetch all results counting the rows sqlite3_stmt* stmt; QByteArray utf8Query = m_sQuery.toUtf8(); - if(sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, NULL) == SQLITE_OK) + if(sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) { retval = 0; while(sqlite3_step(stmt) == SQLITE_ROW) @@ -183,7 +183,7 @@ int SqliteTableModel::getQueryRowCount() QByteArray utf8Query = sCountQuery.toUtf8(); sqlite3_stmt* stmt; - int status = sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, NULL); + int status = sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, nullptr); if(status == SQLITE_OK) { status = sqlite3_step(stmt); @@ -560,7 +560,7 @@ void SqliteTableModel::fetchData(unsigned int from, unsigned to) m_db.logSQL(sLimitQuery, kLogMsg_App); QByteArray utf8Query = sLimitQuery.toUtf8(); sqlite3_stmt *stmt; - int status = sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, NULL); + int status = sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, nullptr); if(SQLITE_OK == status) { @@ -722,7 +722,7 @@ QStringList SqliteTableModel::getColumns(const QString& sQuery, QVector& fi { sqlite3_stmt* stmt; QByteArray utf8Query = sQuery.toUtf8(); - int status = sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, NULL); + int status = sqlite3_prepare_v2(m_db._db, utf8Query, utf8Query.size(), &stmt, nullptr); QStringList listColumns; if(SQLITE_OK == status) { From 4ab2bee2ac7294fc20bf7526025838fdbb45980a Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sun, 20 May 2018 13:22:13 +0200 Subject: [PATCH 43/63] When selecting an entire row and deleting it, remove the record When selecting an entire row or multiple entire rows in the table view and hitting the delete key, delete the records and not just the cell contents. See issue #1391. --- src/ExtendedTableWidget.cpp | 29 ++++++++++++++++++++++------- src/ExtendedTableWidget.h | 1 + src/MainWindow.cpp | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/ExtendedTableWidget.cpp b/src/ExtendedTableWidget.cpp index 9ed7e11b..19d8f889 100644 --- a/src/ExtendedTableWidget.cpp +++ b/src/ExtendedTableWidget.cpp @@ -551,15 +551,30 @@ void ExtendedTableWidget::keyPressEvent(QKeyEvent* event) // If the Tab key was pressed while the focus was on the last cell of the last row insert a new row automatically model()->insertRow(model()->rowCount()); } else if ((event->key() == Qt::Key_Delete) || (event->key() == Qt::Key_Backspace)) { - if(event->modifiers().testFlag(Qt::AltModifier)) + // Check if entire rows are selected. We call the selectedRows() method here not only for simplicity reasons but also because it distinguishes between + // "an entire row is selected" and "all cells of a row are selected", the former is e.g. the case when the row number is clicked, the latter when all cells + // are selected manually. This is an important distinction (especially when a table has only one column!) to match the users' expectations. Also never + // delete records when the backspace key was pressed. + if(event->key() == Qt::Key_Delete && selectionModel()->selectedRows().size()) { - // When pressing Alt+Delete set the value to NULL - for(const QModelIndex& index : selectedIndexes()) - model()->setData(index, QVariant()); + // At least on entire row is selected. Because we don't allow completely arbitrary selections (at least at the moment) but only block selections, + // this means that only entire entire rows are selected. If an entire row is (or multiple entire rows are) selected, we delete that record instead + // of deleting only the cell contents. + + emit selectedRowsToBeDeleted(); } else { - // When pressing Delete only set the value to empty string - for(const QModelIndex& index : selectedIndexes()) - model()->setData(index, ""); + // No entire row is selected. So just set the selected cells to null or empty string depending on the modifier keys + + if(event->modifiers().testFlag(Qt::AltModifier)) + { + // When pressing Alt+Delete set the value to NULL + for(const QModelIndex& index : selectedIndexes()) + model()->setData(index, QVariant()); + } else { + // When pressing Delete only set the value to empty string + for(const QModelIndex& index : selectedIndexes()) + model()->setData(index, ""); + } } } else if(event->modifiers().testFlag(Qt::ControlModifier) && (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_PageDown)) { // When pressing Ctrl + Page up/down send a signal indicating the user wants to change the current table diff --git a/src/ExtendedTableWidget.h b/src/ExtendedTableWidget.h index fe4fd751..be3c8d98 100644 --- a/src/ExtendedTableWidget.h +++ b/src/ExtendedTableWidget.h @@ -47,6 +47,7 @@ signals: void foreignKeyClicked(const sqlb::ObjectIdentifier& table, const QString& column, const QByteArray& value); void switchTable(bool next); // 'next' parameter is set to true if next table should be selected and to false if previous table should be selected void openFileFromDropEvent(QString); + void selectedRowsToBeDeleted(); private: void copy(const bool withHeaders = false); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 1b0b4763..7a12395d 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -281,6 +281,7 @@ void MainWindow::init() connect(m_remoteDb, SIGNAL(openFile(QString)), this, SLOT(fileOpen(QString))); connect(m_remoteDb, &RemoteDatabase::gotCurrentVersion, this, &MainWindow::checkNewVersion); connect(m_browseTableModel, &SqliteTableModel::finishedFetch, this, &MainWindow::setRecordsetLabel); + connect(ui->dataTable, &ExtendedTableWidget::selectedRowsToBeDeleted, this, &MainWindow::deleteRecord); // Lambda function for keyboard shortcuts for selecting next/previous table in Browse Data tab connect(ui->dataTable, &ExtendedTableWidget::switchTable, [this](bool next) { From b69e7cd03459c04e7e3dee1daa38a73c9ad84373 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Sun, 20 May 2018 14:54:24 +0200 Subject: [PATCH 44/63] Add build version to the nightly builds (#1390) Make the Windows nightly build versioning information meaningful. ;) --- CMakeLists.txt | 13 ++++++++++++- src/version.h | 6 ++++++ src/winapp.rc | 4 ++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a306ad95..485e09c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,16 @@ project(sqlitebrowser) -cmake_minimum_required(VERSION 2.8.7) +cmake_minimum_required(VERSION 2.8.11) + +# BUILD_VERSION is the current date in YYYYMMDD format. It is only +# used by the nightly version to add the date of the build. +string(TIMESTAMP BUILD_VERSION "%Y%m%d") + +# Choose between building a stable version or nightly (the default), depending +# on whether '-DBUILD_STABLE_VERSION=1' is passed on the command line or not. +option(BUILD_STABLE_VERSION "Don't build the stable version by default" OFF) +if(NOT BUILD_STABLE_VERSION) + add_definitions(-DBUILD_VERSION=${BUILD_VERSION}) +endif() set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}") diff --git a/src/version.h b/src/version.h index ead16230..9e110e06 100644 --- a/src/version.h +++ b/src/version.h @@ -7,4 +7,10 @@ #define str(s) #s #define xstr(s) str(s) #define APP_VERSION xstr(MAJOR_VERSION) "." xstr(MINOR_VERSION) "." xstr(PATCH_VERSION) + +// If it is defined by the compiler, then it is a nightly build, and in the YYYYMMDD format. +#ifndef BUILD_VERSION + #define BUILD_VERSION 0 +#endif + #endif diff --git a/src/winapp.rc b/src/winapp.rc index 07c21715..2acbe5db 100644 --- a/src/winapp.rc +++ b/src/winapp.rc @@ -11,8 +11,8 @@ BEGIN BEGIN BLOCK "000004B0" BEGIN - VALUE "FileVersion", APP_VERSION - VALUE "ProductVersion", APP_VERSION + VALUE "FileVersion", APP_VERSION "." xstr(BUILD_VERSION) + VALUE "ProductVersion", APP_VERSION "." xstr(BUILD_VERSION) VALUE "FileDescription", "DB Browser for SQLite" VALUE "ProductName", "DB Browser for SQLite" VALUE "InternalName", "DB Browser for SQLite" From e7752d7398a267e4cbd0786e20b0822e099d5109 Mon Sep 17 00:00:00 2001 From: GortiZ Date: Sun, 20 May 2018 15:56:01 +0200 Subject: [PATCH 45/63] KUbuntu 14.04 support restored (#1298) * - [NEW] Add new interface and functionality to manage database file extension. (Implements feature request #659) * - [FIX] Fixed CMake file to src.pro * - Applied changes requested by mgrojo to uniform code with sqlitebrowser standards - Add "history" when closing editor window, but reopen before closing preferences - Revert some changes done by QtCreator * Refuse from previous commit * Additional changes requested by MKleusberg: - [CHG] Always add "All files (*)" to filters - [FIX] Removed unused include * merged from master * Merge sqlitebrowser master * [FIX] Fixed compatibility to compile on KUbuntu 14.04 with Qt 5.2.1 * [FIX] Fix Qt version for QOpenGLWidget support on previous commit * [CHG] Uniformed QT_VERSION_CHECK style [CHG] Reverted macOS check on Mainwindow for OpenGL context creation --- libs/qscintilla/Qt4Qt5/qscintilla.pro | 7 +++++++ src/EditTableDialog.cpp | 11 +++++++++++ src/ExtendedTableWidget.cpp | 4 ++++ src/MainWindow.cpp | 7 +++++-- src/PreferencesDialog.cpp | 16 ++++++++++++++-- src/RemoteDatabase.cpp | 16 +++++++++++++++- src/Settings.cpp | 6 +++++- src/sqlitetypes.h | 18 ++++++++++++++++++ src/src.pro | 7 ++++++- 9 files changed, 85 insertions(+), 7 deletions(-) diff --git a/libs/qscintilla/Qt4Qt5/qscintilla.pro b/libs/qscintilla/Qt4Qt5/qscintilla.pro index 1901b09b..e14f47b9 100644 --- a/libs/qscintilla/Qt4Qt5/qscintilla.pro +++ b/libs/qscintilla/Qt4Qt5/qscintilla.pro @@ -27,6 +27,13 @@ TARGET = qscintilla2 CONFIG += qt warn_off thread exceptions hide_symbols staticlib debug_and_release INCLUDEPATH += . ../include ../lexlib ../src +contains(QT_VERSION, ^4\\..*\\..*) { + QMAKE_CXXFLAGS += -std=c++0x +} +contains(QT_VERSION, ^5\\..*\\..*) { + QMAKE_CXXFLAGS += -std=c++11 +} + !CONFIG(staticlib) { DEFINES += QSCINTILLA_MAKE_DLL } diff --git a/src/EditTableDialog.cpp b/src/EditTableDialog.cpp index 58fc3d15..e7e04361 100644 --- a/src/EditTableDialog.cpp +++ b/src/EditTableDialog.cpp @@ -342,7 +342,18 @@ void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column) if(item->checkState(column) == Qt::Checked) pk.push_back(field); else +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) pk.removeAll(field); +#else + { + int idx = pk.indexOf (field); + while ( idx != -1 ) + { + pk.remove (idx); + idx = pk.indexOf (field); + } + } +#endif } else if(item->checkState(column) == Qt::Checked) { // There is no primary key in the table yet. This means we need to add a default one. m_table.addConstraint({field}, sqlb::ConstraintPtr(new sqlb::PrimaryKeyConstraint())); diff --git a/src/ExtendedTableWidget.cpp b/src/ExtendedTableWidget.cpp index 19d8f889..d26e73e5 100644 --- a/src/ExtendedTableWidget.cpp +++ b/src/ExtendedTableWidget.cpp @@ -18,6 +18,10 @@ #include #include +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) + typedef QList QByteArrayList; +#endif + QList ExtendedTableWidget::m_buffer; QString ExtendedTableWidget::m_generatorStamp; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 7a12395d..5b1038fb 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -48,9 +48,12 @@ #include #include #include -#include #include +#ifdef Q_OS_MACX //Needed only on macOS + #include +#endif + MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), @@ -84,8 +87,8 @@ void MainWindow::init() tabifyDockWidget(ui->dockLog, ui->dockSchema); tabifyDockWidget(ui->dockLog, ui->dockRemote); - // Add OpenGL Context for macOS #ifdef Q_OS_MACX + // Add OpenGL Context for macOS QOpenGLWidget *ogl = new QOpenGLWidget(this); ui->horizontalLayout->addWidget(ogl); ogl->setHidden(true); diff --git a/src/PreferencesDialog.cpp b/src/PreferencesDialog.cpp index 89289199..c9299364 100644 --- a/src/PreferencesDialog.cpp +++ b/src/PreferencesDialog.cpp @@ -254,7 +254,13 @@ void PreferencesDialog::saveSettings() // This is a new certificate. Copy file to a safe place. // Generate unique destination file name - QString copy_to = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).append("/").append(QFileInfo(path).fileName()); + QString copy_to = QStandardPaths::writableLocation( +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QStandardPaths::AppDataLocation +#else + QStandardPaths::GenericDataLocation +#endif + ).append("/").append(QFileInfo(path).fileName()); int suffix = 0; do { @@ -263,7 +269,13 @@ void PreferencesDialog::saveSettings() // Copy file copy_to.append(QString::number(suffix)); - QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + QDir().mkpath(QStandardPaths::writableLocation( +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QStandardPaths::AppDataLocation +#else + QStandardPaths::GenericDataLocation +#endif + )); QFile::copy(path, copy_to); new_client_certs.push_back(copy_to); diff --git a/src/RemoteDatabase.cpp b/src/RemoteDatabase.cpp index a5ad9d93..08839263 100644 --- a/src/RemoteDatabase.cpp +++ b/src/RemoteDatabase.cpp @@ -205,7 +205,15 @@ void RemoteDatabase::gotReply(QNetworkReply* reply) branches.append(it.key()); // Get default branch +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) QString default_branch = obj["default_branch"].toString("master"); +#else + QString default_branch = obj["default_branch"].toString(); + if ( default_branch.isEmpty () ) + { + default_branch = "master"; + } +#endif // Send branch list to anyone who is interested emit gotBranchList(branches, default_branch); @@ -534,7 +542,13 @@ void RemoteDatabase::localAssureOpened() return; // Open file - QString database_file = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/remotedbs.db"; + QString database_file = QStandardPaths::writableLocation( +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QStandardPaths::AppDataLocation +#else + QStandardPaths::GenericDataLocation +#endif + ) + "/remotedbs.db"; if(sqlite3_open_v2(database_file.toUtf8(), &m_dbLocal, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error opening local databases list.\n%1").arg(QString::fromUtf8(sqlite3_errmsg(m_dbLocal)))); diff --git a/src/Settings.cpp b/src/Settings.cpp index 763a3ca7..3e581b5d 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -276,7 +276,7 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) // editor/fontsize or log/fontsize? if((group == "editor" || group == "log") && name == "fontsize") #ifdef Q_OS_MAC - // Use 12 pt size as the default on OSX + // Use 12 pt size as the default on OSX return 12; #else return 9; @@ -339,7 +339,11 @@ QVariant Settings::getDefaultValue(const QString& group, const QString& name) // Clone directory if(name == "clonedirectory") +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); +#else + return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); +#endif } // Unknown combination of group and name? Return an invalid QVariant! diff --git a/src/sqlitetypes.h b/src/sqlitetypes.h index 2e86b28f..b1e72b7c 100644 --- a/src/sqlitetypes.h +++ b/src/sqlitetypes.h @@ -12,6 +12,24 @@ namespace sqlb { #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) + +#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) +struct QHashCombine { + typedef uint result_type; + template + Q_DECL_CONSTEXPR result_type operator()(uint seed, const T &t) const Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t))) + // combiner taken from N3876 / boost::hash_combine + { return seed ^ (qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2)) ; } +}; + +template +inline uint qHashRange(InputIterator first, InputIterator last, uint seed = 0) + Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(*first))) // assume iterator operations don't throw +{ + return std::accumulate(first, last, seed, QHashCombine()); +} +#endif + template uint qHash(const QVector& key, uint seed = 0) Q_DECL_NOEXCEPT_EXPR(noexcept(qHashRange(key.cbegin(), key.cend(), seed))) diff --git a/src/src.pro b/src/src.pro index b6b6f934..73eee7e4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -9,7 +9,12 @@ CONFIG += debug_and_release CONFIG += qt CONFIG += warn_on -QMAKE_CXXFLAGS += -std=c++11 +contains(QT_VERSION, ^4\\..*\\..*) { + QMAKE_CXXFLAGS += -std=c++0x +} +contains(QT_VERSION, ^5\\..*\\..*) { + QMAKE_CXXFLAGS += -std=c++11 +} # create a unittest option CONFIG(unittest) { From a117c11064afe85a946c7442b367be9ba4a8b541 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sun, 20 May 2018 15:58:24 +0200 Subject: [PATCH 46/63] Simplify qmake files --- libs/qscintilla/Qt4Qt5/qscintilla.pro | 7 +------ src/src.pro | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/libs/qscintilla/Qt4Qt5/qscintilla.pro b/libs/qscintilla/Qt4Qt5/qscintilla.pro index e14f47b9..d642c1fd 100644 --- a/libs/qscintilla/Qt4Qt5/qscintilla.pro +++ b/libs/qscintilla/Qt4Qt5/qscintilla.pro @@ -27,12 +27,7 @@ TARGET = qscintilla2 CONFIG += qt warn_off thread exceptions hide_symbols staticlib debug_and_release INCLUDEPATH += . ../include ../lexlib ../src -contains(QT_VERSION, ^4\\..*\\..*) { - QMAKE_CXXFLAGS += -std=c++0x -} -contains(QT_VERSION, ^5\\..*\\..*) { - QMAKE_CXXFLAGS += -std=c++11 -} +QMAKE_CXXFLAGS += -std=c++11 !CONFIG(staticlib) { DEFINES += QSCINTILLA_MAKE_DLL diff --git a/src/src.pro b/src/src.pro index 73eee7e4..b6b6f934 100644 --- a/src/src.pro +++ b/src/src.pro @@ -9,12 +9,7 @@ CONFIG += debug_and_release CONFIG += qt CONFIG += warn_on -contains(QT_VERSION, ^4\\..*\\..*) { - QMAKE_CXXFLAGS += -std=c++0x -} -contains(QT_VERSION, ^5\\..*\\..*) { - QMAKE_CXXFLAGS += -std=c++11 -} +QMAKE_CXXFLAGS += -std=c++11 # create a unittest option CONFIG(unittest) { From 189b750a009b71bc7de021647309d0b0d8c40232 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sun, 20 May 2018 20:22:55 +0200 Subject: [PATCH 47/63] Fix e6a4326e9bc1d48d027278171e8ab335c1f91e82 Fix the fix for a Qt issue which messes up the table view when using the filters. Without any fix, the rowid column is always shown when changing the filters, but because the filter bar isn't regenerated the filters are all displaced. With the first commit this is fixed, however changing the filters always regenerated the filter bar which in turn deleted the current filter value. With this commit this is fixed. The filters are now working as expected. --- src/MainWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 5b1038fb..413c6c0c 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -2453,7 +2453,8 @@ void MainWindow::updateFilter(int column, const QString& value) setRecordsetLabel(); // This seems to be necessary as a workaround for newer Qt versions. Otherwise the rowid column is always shown after changing the filters. - showRowidColumn(browseTableSettings[currentlyBrowsedTableName()].showRowid); + bool showRowid = browseTableSettings[currentlyBrowsedTableName()].showRowid; + ui->dataTable->setColumnHidden(0, !showRowid); } void MainWindow::editEncryption() From 17f1eabb65ee19346efac42c9533b3d6cff0903e Mon Sep 17 00:00:00 2001 From: Remi Rampin Date: Tue, 22 May 2018 14:56:11 -0400 Subject: [PATCH 48/63] Import CSV: Add option to insert missing values as NULL (#1349) * Add a combo box for missing values in import ui * Add ui pieces to .cpp file * Insert NULL values if requested * Allow inserting NULLs in new table also --- src/ImportCsvDialog.cpp | 34 +++++++++++++++++++++++++---- src/ImportCsvDialog.h | 3 +++ src/ImportCsvDialog.ui | 47 +++++++++++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src/ImportCsvDialog.cpp b/src/ImportCsvDialog.cpp index 7cb21e6b..19ba88a9 100644 --- a/src/ImportCsvDialog.cpp +++ b/src/ImportCsvDialog.cpp @@ -53,6 +53,7 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, ui->comboSeparator->blockSignals(true); ui->comboQuote->blockSignals(true); ui->comboEncoding->blockSignals(true); + ui->comboMissingValues->blockSignals(true); ui->checkboxHeader->setChecked(Settings::getValue("importcsv", "firstrowheader").toBool()); ui->checkBoxTrimFields->setChecked(Settings::getValue("importcsv", "trimfields").toBool()); @@ -60,6 +61,7 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, setSeparatorChar(Settings::getValue("importcsv", "separator").toInt()); setQuoteChar(Settings::getValue("importcsv", "quotecharacter").toInt()); setEncoding(Settings::getValue("importcsv", "encoding").toString()); + setMissingValues(Settings::getValue("importcsv", "missingvalues").toString()); ui->checkboxHeader->blockSignals(false); ui->checkBoxTrimFields->blockSignals(false); @@ -67,6 +69,7 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, ui->comboSeparator->blockSignals(false); ui->comboQuote->blockSignals(false); ui->comboEncoding->blockSignals(false); + ui->comboMissingValues->blockSignals(false); // Prepare and show interface depending on how many files are selected if (csvFilenames.length() > 1) @@ -166,6 +169,7 @@ void ImportCsvDialog::accept() Settings::setValue("importcsv", "trimfields", ui->checkBoxTrimFields->isChecked()); Settings::setValue("importcsv", "separatetables", ui->checkBoxSeparateTables->isChecked()); Settings::setValue("importcsv", "encoding", currentEncoding()); + Settings::setValue("importcsv", "missingvalues", missingValues()); // Get all the selected files and start the import if (ui->filePickerBlock->isVisible()) @@ -536,6 +540,7 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) // Create table QVector nullValues; + bool missingValuesAsNull = missingValues() == "null"; if(!importToExistingTable) { if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName), fieldList)) @@ -561,7 +566,9 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) nullValues << "0"; else if(f->isInteger() && !f->notnull()) // If this is an integer column and NULL is allowed, insert NULL nullValues << QByteArray(); - else // Otherwise (i.e. if this isn't an integer column), insert an empty string + else if(missingValuesAsNull) // If we requested NULL values, do that + nullValues << QByteArray(); + else // Otherwise, insert an empty string, like .import does nullValues << ""; } } @@ -595,16 +602,19 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) // Bind all values for(size_t i=0;i(nullValues.size()) > i) { // This is an empty value. We'll need to look up how to handle it depending on the field to be inserted into. const QByteArray& val = nullValues.at(i); if(!val.isNull()) // No need to bind NULL values here as that is the default bound value in SQLite sqlite3_bind_text(stmt, i+1, val, val.size(), SQLITE_STATIC); + // When importing into a new table, use the missing values setting directly + } else if(!importToExistingTable && data.fields[i].data_length == 0 && missingValuesAsNull) { + // No need to bind NULL values here as that is the default bound value in SQLite } else { - // This is a non-empty value. Just add it to the statement + // This is a non-empty value, or we want to insert the empty string. Just add it to the statement sqlite3_bind_text(stmt, i+1, data.fields[i].data, data.fields[i].data_length, SQLITE_STATIC); } } @@ -731,3 +741,19 @@ QString ImportCsvDialog::currentEncoding() const else return ui->comboEncoding->currentText(); } + +void ImportCsvDialog::setMissingValues(const QString& sValue) +{ + if(sValue == "null") + ui->comboMissingValues->setCurrentIndex(1); + else + ui->comboMissingValues->setCurrentIndex(0); +} + +QString ImportCsvDialog::missingValues() const +{ + if(ui->comboMissingValues->currentIndex() == 0) + return "emptystring"; + else + return "null"; +} diff --git a/src/ImportCsvDialog.h b/src/ImportCsvDialog.h index 6f48c5d1..af6c5fac 100644 --- a/src/ImportCsvDialog.h +++ b/src/ImportCsvDialog.h @@ -53,6 +53,9 @@ private: void setEncoding(const QString& sEnc); QString currentEncoding() const; + + void setMissingValues(const QString& sValue); + QString missingValues() const; }; #endif diff --git a/src/ImportCsvDialog.ui b/src/ImportCsvDialog.ui index 8dbabb56..01ce8453 100644 --- a/src/ImportCsvDialog.ui +++ b/src/ImportCsvDialog.ui @@ -6,8 +6,8 @@ 0 0 - 738 - 490 + 788 + 637 @@ -225,13 +225,51 @@ + + + Missing values + + + + + + + + + + Empty string + + + + + NULL + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + Trim fields? - + @@ -241,9 +279,6 @@ - - - From b64702605114949393a462f195c7e533a2598c36 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Fri, 25 May 2018 18:48:23 +0200 Subject: [PATCH 49/63] Show warning when opening a project file with the old file format Thanks to Iulian for idea! --- src/MainWindow.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 413c6c0c..8187ce07 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -2214,6 +2214,25 @@ bool MainWindow::loadProject(QString filename, bool readOnly) defaultBrowseTableEncoding = xml.attributes().value("codec").toString(); xml.skipCurrentElement(); } else if(xml.name() == "browsetable_info") { + // This tag is only found in old project files. In newer versions (>= 3.11) it is replaced by a new implementation. + // We still support loading it though we might decide to drop that support later. But for now we show a warning to the + // user when loading an old file. + if(!Settings::getValue("idontcare", "projectBrowseTable").toBool()) + { + QMessageBox msgBox; + QPushButton* idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); + msgBox.addButton(QMessageBox::Ok); + msgBox.setTextFormat(Qt::RichText); + msgBox.setWindowTitle(qApp->applicationName()); + msgBox.setText(tr("This project file is using an old file format because it was created using DB Browser for SQLite " + "version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert " + "all your project files to the new file format because support for older formats might be dropped " + "at some point in the future. You can convert your files by simply opening and re-saving them.")); + msgBox.exec(); + if(msgBox.clickedButton() == idontcarebutton) + Settings::setValue("idontcare", "projectBrowseTable", true); + } + QString attrData = xml.attributes().value("data").toString(); QByteArray temp = QByteArray::fromBase64(attrData.toUtf8()); QDataStream stream(temp); From e851c161d6c970a46e07cb0b222cf45d4ede3114 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Fri, 25 May 2018 21:06:16 +0200 Subject: [PATCH 50/63] Implement better default behaviour for CSV import This changes the default behaviour for the CSV import to follow a set of rules which hopefully makes most people happy. It also add an "Advanced" section to the settings bits of the dialog to modify this new default behaviour. See issue #1395. --- src/ImportCsvDialog.cpp | 76 ++++++++++++------- src/ImportCsvDialog.h | 4 +- src/ImportCsvDialog.ui | 162 +++++++++++++++++++++++++--------------- 3 files changed, 150 insertions(+), 92 deletions(-) diff --git a/src/ImportCsvDialog.cpp b/src/ImportCsvDialog.cpp index 19ba88a9..79d90249 100644 --- a/src/ImportCsvDialog.cpp +++ b/src/ImportCsvDialog.cpp @@ -33,6 +33,9 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, { ui->setupUi(this); + // Hide "Advanced" section of the settings + toggleAdvancedSection(false); + // Get the actual file name out of the provided path and use it as the default table name for import // For importing several files at once, the fields have to be the same so we can safely use the first QFileInfo file(filenames.first()); @@ -53,7 +56,6 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, ui->comboSeparator->blockSignals(true); ui->comboQuote->blockSignals(true); ui->comboEncoding->blockSignals(true); - ui->comboMissingValues->blockSignals(true); ui->checkboxHeader->setChecked(Settings::getValue("importcsv", "firstrowheader").toBool()); ui->checkBoxTrimFields->setChecked(Settings::getValue("importcsv", "trimfields").toBool()); @@ -61,7 +63,6 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, setSeparatorChar(Settings::getValue("importcsv", "separator").toInt()); setQuoteChar(Settings::getValue("importcsv", "quotecharacter").toInt()); setEncoding(Settings::getValue("importcsv", "encoding").toString()); - setMissingValues(Settings::getValue("importcsv", "missingvalues").toString()); ui->checkboxHeader->blockSignals(false); ui->checkBoxTrimFields->blockSignals(false); @@ -69,7 +70,6 @@ ImportCsvDialog::ImportCsvDialog(const QStringList &filenames, DBBrowserDB* db, ui->comboSeparator->blockSignals(false); ui->comboQuote->blockSignals(false); ui->comboEncoding->blockSignals(false); - ui->comboMissingValues->blockSignals(false); // Prepare and show interface depending on how many files are selected if (csvFilenames.length() > 1) @@ -169,7 +169,6 @@ void ImportCsvDialog::accept() Settings::setValue("importcsv", "trimfields", ui->checkBoxTrimFields->isChecked()); Settings::setValue("importcsv", "separatetables", ui->checkBoxSeparateTables->isChecked()); Settings::setValue("importcsv", "encoding", currentEncoding()); - Settings::setValue("importcsv", "missingvalues", missingValues()); // Get all the selected files and start the import if (ui->filePickerBlock->isVisible()) @@ -540,7 +539,9 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) // Create table QVector nullValues; - bool missingValuesAsNull = missingValues() == "null"; + std::vector failOnMissingFieldList; + bool ignoreDefaults = ui->checkIgnoreDefaults->isChecked(); + bool failOnMissing = ui->checkFailOnMissing->isChecked(); if(!importToExistingTable) { if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName), fieldList)) @@ -562,14 +563,39 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) { for(const sqlb::FieldPtr& f : tbl->fields()) { - if(f->isInteger() && f->notnull()) // If this is an integer column but NULL isn't allowed, insert 0 - nullValues << "0"; - else if(f->isInteger() && !f->notnull()) // If this is an integer column and NULL is allowed, insert NULL - nullValues << QByteArray(); - else if(missingValuesAsNull) // If we requested NULL values, do that - nullValues << QByteArray(); - else // Otherwise, insert an empty string, like .import does - nullValues << ""; + // For determining the value for empty fields we follow a set of rules + + // Normally we don't have to fail the import when importing an empty field. This last value of the vector + // is changed to true later if we actually do want to fail the import for this field. + failOnMissingFieldList.push_back(false); + + // If a field has a default value, that gets priority over everything else. + // Exception: if the user wants to ignore default values we never use them. + if(!ignoreDefaults && !f->defaultValue().isNull()) + { + nullValues << f->defaultValue().toUtf8(); + } else { + // If it has no default value, check if the field is NOT NULL + if(f->notnull()) + { + // The field is NOT NULL + + // If this is an integer column insert 0. Otherwise insert an empty string. + if(f->isInteger()) + nullValues << "0"; + else + nullValues << ""; + + // If the user wants to fail the import, remember this field + if(failOnMissing) + failOnMissingFieldList.back() = true; + } else { + // The field is not NOT NULL (stupid double negation here! NULL values are allowed in this case) + + // Just insert a NULL value + nullValues << QByteArray(); + } + } } } } @@ -606,12 +632,16 @@ bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) // When importing into an existing table where we could find out something about its table definition if(importToExistingTable && data.fields[i].data_length == 0 && static_cast(nullValues.size()) > i) { + // Do we want to fail when trying to import an empty value into this field? Then exit with an error. + if(failOnMissingFieldList.at(i)) + return false; + // This is an empty value. We'll need to look up how to handle it depending on the field to be inserted into. const QByteArray& val = nullValues.at(i); if(!val.isNull()) // No need to bind NULL values here as that is the default bound value in SQLite sqlite3_bind_text(stmt, i+1, val, val.size(), SQLITE_STATIC); // When importing into a new table, use the missing values setting directly - } else if(!importToExistingTable && data.fields[i].data_length == 0 && missingValuesAsNull) { + } else if(!importToExistingTable && data.fields[i].data_length == 0) { // No need to bind NULL values here as that is the default bound value in SQLite } else { // This is a non-empty value, or we want to insert the empty string. Just add it to the statement @@ -742,18 +772,10 @@ QString ImportCsvDialog::currentEncoding() const return ui->comboEncoding->currentText(); } -void ImportCsvDialog::setMissingValues(const QString& sValue) +void ImportCsvDialog::toggleAdvancedSection(bool show) { - if(sValue == "null") - ui->comboMissingValues->setCurrentIndex(1); - else - ui->comboMissingValues->setCurrentIndex(0); -} - -QString ImportCsvDialog::missingValues() const -{ - if(ui->comboMissingValues->currentIndex() == 0) - return "emptystring"; - else - return "null"; + ui->labelFailOnMissing->setVisible(show); + ui->checkFailOnMissing->setVisible(show); + ui->labelIgnoreDefaults->setVisible(show); + ui->checkIgnoreDefaults->setVisible(show); } diff --git a/src/ImportCsvDialog.h b/src/ImportCsvDialog.h index af6c5fac..e74c5fe4 100644 --- a/src/ImportCsvDialog.h +++ b/src/ImportCsvDialog.h @@ -31,6 +31,7 @@ private slots: void updateSelectedFilePreview(); void updateSelection(bool); void matchSimilar(); + void toggleAdvancedSection(bool show); private: Ui::ImportCsvDialog* ui; @@ -53,9 +54,6 @@ private: void setEncoding(const QString& sEnc); QString currentEncoding() const; - - void setMissingValues(const QString& sValue); - QString missingValues() const; }; #endif diff --git a/src/ImportCsvDialog.ui b/src/ImportCsvDialog.ui index 01ce8453..fe24d725 100644 --- a/src/ImportCsvDialog.ui +++ b/src/ImportCsvDialog.ui @@ -7,13 +7,13 @@ 0 0 788 - 637 + 717 Import CSV file - + @@ -22,7 +22,7 @@ - &Table name + Table na&me editName @@ -49,7 +49,7 @@ - + Field &separator @@ -59,7 +59,7 @@ - + @@ -112,7 +112,7 @@ - + &Quote character @@ -122,7 +122,7 @@ - + @@ -170,7 +170,7 @@ - + &Encoding @@ -180,7 +180,7 @@ - + @@ -224,52 +224,17 @@ - - - - Missing values - - - - - - - - - - Empty string - - - - - NULL - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - + Trim fields? + + checkBoxTrimFields + - + @@ -279,20 +244,71 @@ - + Separate tables + + checkBoxSeparateTables + - + + + + + Advanced + + + + :/icons/down:/icons/down + + + true + + + + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + + + Ignore default &values + + + checkIgnoreDefaults + + + + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + + + Fail on missing values + + + checkFailOnMissing + + + @@ -400,12 +416,17 @@ editCustomEncoding checkBoxTrimFields checkBoxSeparateTables + buttonAdvanced + checkIgnoreDefaults + checkFailOnMissing filePicker toggleSelected matchSimilar tablePreview - + + + comboSeparator @@ -510,8 +531,8 @@ updatePreview() - 266 - 165 + 263 + 183 572 @@ -542,8 +563,8 @@ updateSelection(bool) - 674 - 258 + 780 + 337 368 @@ -575,7 +596,7 @@ 272 - 478 + 677 157 @@ -591,7 +612,7 @@ 340 - 478 + 677 286 @@ -606,8 +627,8 @@ checkInput() - 176 - 216 + 194 + 236 368 @@ -622,8 +643,8 @@ matchSimilar() - 682 - 279 + 780 + 378 368 @@ -631,11 +652,28 @@ + + buttonAdvanced + toggled(bool) + ImportCsvDialog + toggleAdvancedSection(bool) + + + 214 + 259 + + + 393 + 358 + + + updatePreview() checkInput() updateSelection(bool) matchSimilar() + toggleAdvancedSection(bool) From 3995ad2442a22029bcf75e618d42c9d716ff1d98 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Fri, 25 May 2018 22:11:43 +0200 Subject: [PATCH 51/63] Add option to disable automatic type detection in CSV import Because there are some circumstances under which the automatic type detection can cause problems with the imported data and because it is not accurate when the data changes a lot after the first couple of rows, we need an option to disable it. See issue #1382. --- src/ImportCsvDialog.cpp | 6 ++++-- src/ImportCsvDialog.ui | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/ImportCsvDialog.cpp b/src/ImportCsvDialog.cpp index 79d90249..daa5ad3d 100644 --- a/src/ImportCsvDialog.cpp +++ b/src/ImportCsvDialog.cpp @@ -415,8 +415,8 @@ sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename) fieldList.push_back(sqlb::FieldPtr(new sqlb::Field(fieldname, ""))); } - // Try to find out a data type for each column - if(!(rowNum == 0 && ui->checkboxHeader->isChecked())) + // Try to find out a data type for each column. Skip the header row if there is one. + if(!ui->checkNoTypeDetection->isChecked() && !(rowNum == 0 && ui->checkboxHeader->isChecked())) { for(size_t i=0;ilabelNoTypeDetection->setVisible(show); + ui->checkNoTypeDetection->setVisible(show); ui->labelFailOnMissing->setVisible(show); ui->checkFailOnMissing->setVisible(show); ui->labelIgnoreDefaults->setVisible(show); diff --git a/src/ImportCsvDialog.ui b/src/ImportCsvDialog.ui index fe24d725..ebf08fc0 100644 --- a/src/ImportCsvDialog.ui +++ b/src/ImportCsvDialog.ui @@ -275,14 +275,14 @@ - + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. - + Ignore default &values @@ -292,14 +292,14 @@ - + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. - + Fail on missing values @@ -309,6 +309,20 @@ + + + + Disable data type detection + + + + + + + Disable the automatic data type detection when creating a new table. + + + From 39302f5b6061cf687a81984406e20070d60b4563 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Fri, 25 May 2018 23:47:47 +0200 Subject: [PATCH 52/63] Also fix rowid column being shown when changing the sort order Apply the same fix as in 189b750a009b71bc7de021647309d0b0d8c40232 for the filters for the sort order. --- src/MainWindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 8187ce07..81d7f8fb 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1640,6 +1640,10 @@ void MainWindow::browseTableHeaderClicked(int logicalindex) ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(0, logicalindex)); attachPlot(ui->dataTable, m_browseTableModel, &browseTableSettings[currentlyBrowsedTableName()]); + + // This seems to be necessary as a workaround for newer Qt versions. Otherwise the rowid column is always shown after changing the filters. + bool showRowid = browseTableSettings[currentlyBrowsedTableName()].showRowid; + ui->dataTable->setColumnHidden(0, !showRowid); } void MainWindow::resizeEvent(QResizeEvent*) From e50022c11ed9b2377bc940e5f13842454984ddae Mon Sep 17 00:00:00 2001 From: mgrojo Date: Sat, 2 Jun 2018 01:04:55 +0200 Subject: [PATCH 53/63] Export to CSV the currently browsed data as displayed A new option is added to the Browse Data tab toolbar for exporting the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file. This is done in coherence to the same popup options in the SQL tab for execution results. See issue #1402 --- src/MainWindow.cpp | 13 +++++++- src/MainWindow.h | 2 ++ src/MainWindow.ui | 74 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 81d7f8fb..25feb922 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -185,6 +185,12 @@ void MainWindow::init() ui->actionSqlResultsSave->setMenu(popupSaveSqlResultsMenu); qobject_cast(ui->toolbarSql->widgetForAction(ui->actionSqlResultsSave))->setPopupMode(QToolButton::InstantPopup); + popupSaveFilterAsMenu = new QMenu(this); + popupSaveFilterAsMenu->addAction(ui->actionFilteredTableExportCsv); + popupSaveFilterAsMenu->addAction(ui->actionFilterSaveAsView); + ui->buttonSaveFilterAsPopup->setMenu(popupSaveFilterAsMenu); + ui->buttonSaveFilterAsPopup->setPopupMode(QToolButton::InstantPopup); + popupBrowseDataHeaderMenu = new QMenu(this); popupBrowseDataHeaderMenu->addAction(ui->actionShowRowidColumn); popupBrowseDataHeaderMenu->addAction(ui->actionUnlockViewEditing); @@ -1600,7 +1606,7 @@ void MainWindow::activateFields(bool enable) ui->actionSaveProject->setEnabled(enable); ui->actionEncryption->setEnabled(enable && write); ui->buttonClearFilters->setEnabled(enable); - ui->buttonSaveFilterAsView->setEnabled(enable); + ui->buttonSaveFilterAsPopup->setEnabled(enable); ui->dockEdit->setEnabled(enable); ui->dockPlot->setEnabled(enable); @@ -2954,6 +2960,11 @@ void MainWindow::saveAsView(QString query) QMessageBox::warning(this, qApp->applicationName(), tr("Error creating view: %1").arg(db.lastError())); } +void MainWindow::exportFilteredTable() +{ + ExportDataDialog dialog(db, ExportDataDialog::ExportFormatCsv, this, m_browseTableModel->customQuery(false)); + dialog.exec(); +} void MainWindow::saveFilterAsView() { diff --git a/src/MainWindow.h b/src/MainWindow.h index 3341ffcc..fc0568a9 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -142,6 +142,7 @@ private: QMenu* recentFilesMenu; QMenu* popupSaveSqlFileMenu; QMenu* popupSaveSqlResultsMenu; + QMenu* popupSaveFilterAsMenu; QMenu* popupBrowseDataHeaderMenu; QLabel* statusEncodingLabel; @@ -281,6 +282,7 @@ private slots: void setFindFrameVisibility(bool show); void openFindReplaceDialog(); void saveFilterAsView(); + void exportFilteredTable(); }; #endif diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 0206c3cf..57efc2a4 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -167,12 +167,12 @@ You can drag SQL statements from an object row and drop them into other applicat - + - Save the current filter, sort column and display formats as a view + Save the table as currently displayed - This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> ... @@ -396,8 +396,8 @@ You can drag SQL statements from an object row and drop them into other applicat 0 0 - 566 - 531 + 601 + 484 @@ -887,7 +887,7 @@ You can drag SQL statements from an object row and drop them into other applicat 0 0 1037 - 25 + 20 @@ -2041,6 +2041,34 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed Extra DB Toolbar + + + Export to &CSV + + + Export the filtered data to CSV + + + Export the filtered data to CSV + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + + + Save the current filter, sort column and display formats as a view + + + Save the current filter, sort column and display formats as a view + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + @@ -3206,7 +3234,7 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed - buttonSaveFilterAsView + buttonSaveFilterAsPopup clicked() MainWindow saveFilterAsView() @@ -3301,6 +3329,38 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed + + actionFilteredTableExportCsv + triggered() + MainWindow + exportFilteredTable() + + + -1 + -1 + + + 518 + 314 + + + + + actionFilterSaveAsView + triggered() + MainWindow + saveFilterAsView() + + + -1 + -1 + + + 518 + 314 + + + fileOpen() From c8eddc43e0016c8b1aa60434e05be5bb3e8d217a Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Sat, 2 Jun 2018 19:32:17 +0200 Subject: [PATCH 54/63] Add support to create MSI installer for Windows build (#1400) --- installer/windows/background.bmp | Bin 0 -> 615402 bytes installer/windows/banner.bmp | Bin 0 -> 114514 bytes installer/windows/build.cmd | 34 +++ installer/windows/license.rtf | 238 +++++++++++++++++++++ installer/windows/product.wxs | 173 +++++++++++++++ installer/windows/resources/background.xcf | Bin 0 -> 40510 bytes installer/windows/resources/banner.xcf | Bin 0 -> 7731 bytes installer/windows/resources/icon.png | Bin 0 -> 9376 bytes installer/windows/variables.wxi | 62 ++++++ 9 files changed, 507 insertions(+) create mode 100644 installer/windows/background.bmp create mode 100644 installer/windows/banner.bmp create mode 100644 installer/windows/build.cmd create mode 100644 installer/windows/license.rtf create mode 100644 installer/windows/product.wxs create mode 100644 installer/windows/resources/background.xcf create mode 100644 installer/windows/resources/banner.xcf create mode 100644 installer/windows/resources/icon.png create mode 100644 installer/windows/variables.wxi diff --git a/installer/windows/background.bmp b/installer/windows/background.bmp new file mode 100644 index 0000000000000000000000000000000000000000..79d3711c229cca797a93248f853167ba07bcbe3b GIT binary patch literal 615402 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 ZKmYKm\par +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\par +\par +\pard\sa200\sl276\slmult1\qc\b Preamble\b0\par +\pard\fi142\sa200\sl276\slmult1\qj The GNU General Public License is a free, copyleft license for software and other kinds of works.\par +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.\par +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.\par +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.\par +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\par +Developers that use the GNU GPL protect your rights with two steps:\par +\pard\sa200\sl276\slmult1\qj (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.\par +\pard\fi142\sa200\sl276\slmult1\qj For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.\par +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.\par +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.\par +The precise terms and conditions for copying, distribution and modification follow.\par +\pard\sa200\sl276\slmult1\par +\pard\sa200\sl276\slmult1\qc\b TERMS AND CONDITIONS\b0\par +\pard\sa200\sl276\slmult1 0. Definitions.\par +\pard\fi142\sa200\sl276\slmult1 "This License" refers to version 3 of the GNU General Public License.\par +\pard\fi142\sa200\sl276\slmult1\qj "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.\par +"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.\par +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.\par +A "covered work" means either the unmodified Program or a work based on the Program.\par +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.\par +To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.\par +An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.\par +\pard\sa200\sl276\slmult1 1. Source Code.\par +\pard\fi142\sa200\sl276\slmult1\qj The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.\par +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.\par +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.\par +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.\par +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.\par +\pard\fi142\sa200\sl276\slmult1 The Corresponding Source for a work in source code form is that same work.\par +\pard\sa200\sl276\slmult1 2. Basic Permissions.\par +\pard\fi142\sa200\sl276\slmult1\qj All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.\par +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.\par +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.\par +\pard\sa200\sl276\slmult1 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\par +\pard\fi142\sa200\sl276\slmult1\qj No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.\par +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.\par +\pard\sa200\sl276\slmult1 4. Conveying Verbatim Copies.\par +\pard\fi142\sa200\sl276\slmult1\qj You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.\par +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.\par +\pard\sa200\sl276\slmult1 5. Conveying Modified Source Versions.\par +\pard\fi142\sa200\sl276\slmult1\qj You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:\par +\pard\li284\sa200\sl276\slmult1\qj a) The work must carry prominent notices stating that you modified it, and giving a relevant date.\par +b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".\par +c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.\par +d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.\par +\pard\fi142\sa200\sl276\slmult1\qj A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.\par +\pard\sa200\sl276\slmult1 6. Conveying Non-Source Forms.\par +\pard\fi142\sa200\sl276\slmult1\qj You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:\par +\pard\li284\sa200\sl276\slmult1\qj a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.\par +b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.\par +c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.\par +d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.\par +e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.\par +\pard\fi142\sa200\sl276\slmult1\qj A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.\par +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.\par +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.\par +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).\par +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.\par +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.\par +\pard\sa200\sl276\slmult1 7. Additional Terms.\par +\pard\fi142\sa200\sl276\slmult1\qj "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.\par +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.\par +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:\par +\pard\li284\sa200\sl276\slmult1\qj a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or\par +b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or\par +c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or\par +d) Limiting the use for publicity purposes of names of licensors or authors of the material; or\par +e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or\par +f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.\par +\pard\fi142\sa200\sl276\slmult1\qj All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.\par +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.\par +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.\par +\pard\sa200\sl276\slmult1 8. Termination.\par +\pard\fi142\sa200\sl276\slmult1\qj You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).\par +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.\par +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.\par +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.\par +\pard\sa200\sl276\slmult1 9. Acceptance Not Required for Having Copies.\par +\pard\fi142\sa200\sl276\slmult1\qj You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.\par +\pard\sa200\sl276\slmult1 10. Automatic Licensing of Downstream Recipients.\par +\pard\fi142\sa200\sl276\slmult1\qj Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.\par +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.\par +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.\par +\pard\sa200\sl276\slmult1 11. Patents.\par +\pard\fi142\sa200\sl276\slmult1\qj A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".\par +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.\par +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.\par +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.\par +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.\par +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.\par +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.\par +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.\par +\pard\sa200\sl276\slmult1 12. No Surrender of Others' Freedom.\par +\pard\fi142\sa200\sl276\slmult1\qj If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.\par +\pard\sa200\sl276\slmult1 13. Use with the GNU Affero General Public License.\par +\pard\fi142\sa200\sl276\slmult1\qj Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.\par +\pard\sa200\sl276\slmult1 14. Revised Versions of this License.\par +\pard\fi142\sa200\sl276\slmult1\qj The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\par +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.\par +If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.\par +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.\par +\pard\sa200\sl276\slmult1 15. Disclaimer of Warranty.\par +\pard\fi142\sa200\sl276\slmult1\qj THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\par +\pard\sa200\sl276\slmult1 16. Limitation of Liability.\par +\pard\fi142\sa200\sl276\slmult1\qj IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\par +\pard\sa200\sl276\slmult1 17. Interpretation of Sections 15 and 16.\par +\pard\fi142\sa200\sl276\slmult1\qj If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.\par +\pard\sa200\sl276\slmult1\qc\b END OF TERMS AND CONDITIONS\b0\par +\pard\sa200\sl276\slmult1\par +\pard\sa200\sl276\slmult1\qc\b How to Apply These Terms to Your New Programs\par +\pard\fi142\sa200\sl276\slmult1\qj\b0 If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.\par +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.\par +\pard\sa200\sl276\slmult1 \par +\pard\li284\sa200\sl276\slmult1\qj Copyright (C) \par +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\par +You should have received a copy of the GNU General Public License along with this program. If not, see <{\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/"}}{\fldrslt{\ul\cf1 http://www.gnu.org/licenses/}}}\f0\fs20 >.\par +\pard\sa200\sl276\slmult1 Also add information on how to contact you by electronic and paper mail.\par +\pard\fi142\sa200\sl276\slmult1\qj If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:\par +\pard\li284\sa200\sl276\slmult1\qj Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.\par +\pard\sa200\sl276\slmult1\qj The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box".\par +\pard\fi142\sa200\sl276\slmult1\qj You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <{\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/"}}{\fldrslt{\ul\cf1 http://www.gnu.org/licenses/}}}\f0\fs20 >.\par +The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <{\field{\*\fldinst{HYPERLINK "http://www.gnu.org/philosophy/why-not-lgpl.html"}}{\fldrslt{\ul\cf1 http://www.gnu.org/philosophy/why-not-lgpl.html}}}\f0\fs20 >.\par +\pard\sa200\sl276\slmult1\par +\pard\sa200\sl276\slmult1\qc ----------------------------------------------------------------------------------------------------\par +\pard\sa200\sl276\slmult1\par +\pard\sa200\sl276\slmult1\qc\b\fs22 Mozilla Public License Version 2.0\par +\pard\sa200\sl276\slmult1\b0\fs20\par +\fs22 1. Definitions\fs20\par +1.1. "Contributor"\par +\pard\fi-10\li426\sa200\sl276\slmult1\qj means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.\par +\pard\sa200\sl276\slmult1 1.2. "Contributor Version"\par +\pard\li426\sa200\sl276\slmult1\qj means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution.\par +\pard\sa200\sl276\slmult1 1.3. "Contribution"\par +\pard\li426\sa200\sl276\slmult1\qj means Covered Software of a particular Contributor.\par +\pard\sa200\sl276\slmult1 1.4. "Covered Software"\par +\pard\li426\sa200\sl276\slmult1\qj means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.\par +\pard\sa200\sl276\slmult1 1.5. "Incompatible With Secondary Licenses"\par +\pard\li426\sa200\sl276\slmult1\qj means\par +(a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or\par +(b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License.\par +\pard\sa200\sl276\slmult1 1.6. "Executable Form"\par +\pard\li426\sa200\sl276\slmult1\qj means any form of the work other than Source Code Form.\par +\pard\sa200\sl276\slmult1 1.7. "Larger Work"\par +\pard\li426\sa200\sl276\slmult1\qj means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.\par +\pard\sa200\sl276\slmult1 1.8. "License"\par +\pard\li426\sa200\sl276\slmult1\qj means this document.\par +\pard\sa200\sl276\slmult1 1.9. "Licensable"\par +\pard\li426\sa200\sl276\slmult1\qj means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.\par +\pard\sa200\sl276\slmult1 1.10. "Modifications"\par +\pard\li426\sa200\sl276\slmult1\qj means any of the following:\par +(a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or\par +(b) any new file in Source Code Form that contains any Covered Software.\par +\pard\sa200\sl276\slmult1 1.11. "Patent Claims" of a Contributor\par +\pard\li426\sa200\sl276\slmult1\qj means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.\par +\pard\sa200\sl276\slmult1 1.12. "Secondary License"\par +\pard\li426\sa200\sl276\slmult1\qj means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.\par +\pard\sa200\sl276\slmult1 1.13. "Source Code Form"\par +\pard\li426\sa200\sl276\slmult1\qj means the form of the work preferred for making modifications.\par +\pard\sa200\sl276\slmult1 1.14. "You" (or "Your")\par +\pard\li426\sa200\sl276\slmult1\qj means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.\par +\pard\sa200\sl276\slmult1\fs22 2. License Grants and Conditions\fs20\par +2.1. Grants\par +Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:\par +\pard\li426\sa200\sl276\slmult1\qj (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and\par +(b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.\par +\pard\sa200\sl276\slmult1 2.2. Effective Date\par +\pard\sa200\sl276\slmult1\qj The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.\par +\pard\sa200\sl276\slmult1 2.3. Limitations on Grant Scope\par +\pard\sa200\sl276\slmult1\qj The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:\par +\pard\li426\sa200\sl276\slmult1 (a) for any code that a Contributor has removed from Covered Software; or\par +(b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or\par +(c) under Patent Claims infringed by Covered Software in the absence of its Contributions.\par +\pard\sa200\sl276\slmult1\qj This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).\par +\pard\sa200\sl276\slmult1 2.4. Subsequent Licenses\par +\pard\sa200\sl276\slmult1\qj No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).\par +\pard\sa200\sl276\slmult1 2.5. Representation\par +\pard\sa200\sl276\slmult1\qj Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.\par +\pard\sa200\sl276\slmult1 2.6. Fair Use\par +\pard\sa200\sl276\slmult1\qj This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.\par +\pard\sa200\sl276\slmult1 2.7. Conditions\par +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.\par +\fs22 3. Responsibilities\par +\fs20 3.1. Distribution of Source Form\par +\pard\sa200\sl276\slmult1\qj All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form.\par +\pard\sa200\sl276\slmult1 3.2. Distribution of Executable Form\par +If You distribute Covered Software in Executable Form then:\par +\pard\li426\sa200\sl276\slmult1\qj (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and\par +(b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License.\par +\pard\sa200\sl276\slmult1 3.3. Distribution of a Larger Work\par +\pard\sa200\sl276\slmult1\qj You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).\par +\pard\sa200\sl276\slmult1 3.4. Notices\par +\pard\sa200\sl276\slmult1\qj You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.\par +\pard\sa200\sl276\slmult1 3.5. Application of Additional Terms\par +\pard\sa200\sl276\slmult1\qj You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.\par +\pard\sa200\sl276\slmult1\fs22 4. Inability to Comply Due to Statute or Regulation\par +\pard\sa200\sl276\slmult1\qj\fs20 If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.\par +\pard\sa200\sl276\slmult1\fs22 5. Termination\fs20\par +\pard\sa200\sl276\slmult1\qj 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.\par +5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.\par +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.\par +\pard\sa200\sl276\slmult1\fs22 6. Disclaimer of Warranty\fs20\par +\pard\sa200\sl276\slmult1\qj Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer.\par +\pard\sa200\sl276\slmult1\fs22 7. Limitation of Liability\fs20\par +\pard\sa200\sl276\slmult1\qj Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.\par +\pard\sa200\sl276\slmult1\fs22 8. Litigation\fs20\par +\pard\sa200\sl276\slmult1\qj Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims.\par +\pard\sa200\sl276\slmult1\fs22 9. Miscellaneous\fs20\par +\pard\sa200\sl276\slmult1\qj This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.\par +\pard\sa200\sl276\slmult1\fs22 10. Versions of the License\par +\fs20 10.1. New Versions\par +\pard\sa200\sl276\slmult1\qj Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.\par +\pard\sa200\sl276\slmult1 10.2. Effect of New Versions\par +\pard\sa200\sl276\slmult1\qj You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.\par +\pard\sa200\sl276\slmult1 10.3. Modified Versions\par +\pard\sa200\sl276\slmult1\qj If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).\par +\pard\sa200\sl276\slmult1 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses\par +\pard\sa200\sl276\slmult1\qj If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.\par +\pard\sa200\sl276\slmult1\fs22 Exhibit A - Source Code Form License Notice\par +\pard\li284\sa200\sl276\slmult1\qj\fs20 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at {\field{\*\fldinst{HYPERLINK "http://mozilla.org/MPL/2.0/"}}{\fldrslt{\ul\cf1 http://mozilla.org/MPL/2.0/}}}\f0\fs20 .\par +\pard\sa200\sl276\slmult1\qj If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.\par +\pard\sa200\sl276\slmult1 You may add additional accurate notices of copyright ownership.\par +\fs22 Exhibit B - "Incompatible With Secondary Licenses" Notice\par +\pard\li284\sa200\sl276\slmult1\qj\fs20 This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.\par +} + \ No newline at end of file diff --git a/installer/windows/product.wxs b/installer/windows/product.wxs new file mode 100644 index 00000000..c4546e93 --- /dev/null +++ b/installer/windows/product.wxs @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed + + + + diff --git a/installer/windows/resources/background.xcf b/installer/windows/resources/background.xcf new file mode 100644 index 0000000000000000000000000000000000000000..5ab8ccddc7a114d2a65a2532eabc6a31dcb1395d GIT binary patch literal 40510 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 S@b_;J4$>)vHbYF08UF`(c50ab literal 0 HcmV?d00001 diff --git a/installer/windows/resources/banner.xcf b/installer/windows/resources/banner.xcf new file mode 100644 index 0000000000000000000000000000000000000000..b904af739fd304d829f210891a9c1679ff9f6ae2 GIT binary patch literal 7731 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 VgN15b$o#7aur#$bsWWnq|33+izFPnQ literal 0 HcmV?d00001 diff --git a/installer/windows/variables.wxi b/installer/windows/variables.wxi new file mode 100644 index 00000000..b8a5c6ea --- /dev/null +++ b/installer/windows/variables.wxi @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0f207cebae6f0ca72556792d7d4fd9eba4194e8e Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Sat, 2 Jun 2018 13:18:56 +0100 Subject: [PATCH 55/63] Add the windows nightly build script --- .../windows/nightly_build_script/winbuild.bat | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 installer/windows/nightly_build_script/winbuild.bat diff --git a/installer/windows/nightly_build_script/winbuild.bat b/installer/windows/nightly_build_script/winbuild.bat new file mode 100644 index 00000000..72b956bb --- /dev/null +++ b/installer/windows/nightly_build_script/winbuild.bat @@ -0,0 +1,125 @@ +:: Destination path - specify where to move package after build +set DEST_PATH=C:\\builds +MKDIR "%DEST_PATH%" + +set SQLITE_DIR=C:\\dev\\SQLite- +set SQLCIPHER_DIR=C:\\git_repos\\SQLCipher- + +:: You need to change the date format in Windows settings to YYYY-MM-DD +:: before this will work properly. ;) +set RUN_DATE=%DATE% + +:: If no branch given on the command line, use master +IF "%1"=="" (SET BRANCH="master") ELSE (SET BRANCH="%1") + +cd /d "C:\" +if exist "git_repos" rd /q /s "git_repos" +if exist "%SQLITE_DIR%Win32" rd /q /s "%SQLITE_DIR%Win32" +if exist "%SQLITE_DIR%Win64" rd /q /s "%SQLITE_DIR%Win64" +if exist "%SQLCIPHER_DIR%Win32" rd /q /s "%SQLCIPHER_DIR%Win32" +if exist "%SQLCIPHER_DIR%Win64" rd /q /s "%SQLCIPHER_DIR%Win64" + +:: Unpack SQLite +cd C:\dev +"C:\Program Files\7-Zip\7z.exe" e sqlite*zip "-o%SQLITE_DIR%Win32" +"C:\Program Files\7-Zip\7z.exe" e sqlite*zip "-o%SQLITE_DIR%Win64" + +:: Clone repositories +MKDIR "C:\\git_repos" +cd C:\\git_repos +git clone -b msvc2013_win32 --depth 1 https://github.com/justinclift/sqlcipher.git SQLCipher-Win32 +git clone -b msvc2013_win64 --depth 1 https://github.com/justinclift/sqlcipher.git SQLCipher-Win64 +git clone -b %BRANCH% https://github.com/sqlitebrowser/sqlitebrowser.git + +:: WIN32 SQLITE BUILD PROCEDURE + +:: Set path variables +call "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\vcvars32.bat" + +:: Build SQLite x86 +cd %SQLITE_DIR%Win32 +cl sqlite3.c -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_JSON1 -DSQLITE_API=_declspec(dllexport) -link -dll -out:sqlite3.dll + +:: Run CMake for SQLite x86 +cd C:\\git_repos\\sqlitebrowser +MKDIR "release-sqlite-win32" +cd "release-sqlite-win32" +cmake -G "Visual Studio 12 2013" -Wno-dev .. + +:: Build package +FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" + +:: Move package to DEST_PATH +MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win32.exe" + +:: WIN32 SQLCIPHER BUILD PROCEDURE + +:: Build SQLCipher x86 +cd %SQLCIPHER_DIR%Win32 +nmake /f Makefile.msc + +:: Run CMake for SQLCipher x86 +cd C:\\git_repos\\sqlitebrowser +MKDIR "release-sqlcipher-win32" +cd "release-sqlcipher-win32" +cmake -G "Visual Studio 12 2013" -Wno-dev -Dsqlcipher=1 .. + +:: Build package +FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" + +:: Move package to DEST_PATH +MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win32.exe" + +:: WIN64 SQLITE BUILD PROCEDURE + +:: Set path variables +call "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\vcvars64.bat" + +:: Build SQLite x64 +cd %SQLITE_DIR%Win64 +cl sqlite3.c -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_JSON1 -DSQLITE_API=_declspec(dllexport) -link -dll -out:sqlite3.dll + +:: Run CMake for SQLite x64 +cd C:\\git_repos\\sqlitebrowser +MKDIR "release-sqlite-win64" +cd "release-sqlite-win64" +cmake -G "Visual Studio 12 2013 Win64" -Wno-dev .. + +:: Build package +FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" + +:: Move package to DEST_PATH +MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win64.exe" + +:: WIN64 SQLCIPHER BUILD PROCEDURE + +:: Build SQLCipher x64 +cd %SQLCIPHER_DIR%Win64 +nmake /f Makefile.msc + +:: Run CMake for SQLCipher x64 +cd C:\\git_repos\\sqlitebrowser +MKDIR "release-sqlcipher-win64" +cd "release-sqlcipher-win64" +cmake -G "Visual Studio 12 2013 Win64" -Wno-dev -Dsqlcipher=1 .. + +:: Build package +FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" + +:: Move package to DEST_PATH +MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win64.exe" + +:: Upload the packages to the nightlies server +pscp -q -p -i C:\dev\puttygen_private.ppk "%DEST_PATH%\DB*%RUN_DATE%*win32.exe" nightlies@nightlies.sqlitebrowser.org:/nightlies/win32 +pscp -q -p -i C:\dev\puttygen_private.ppk "%DEST_PATH%\DB*%RUN_DATE%*win64.exe" nightlies@nightlies.sqlitebrowser.org:/nightlies/win64 + +:: Copy the new binaries to /latest directory on the nightlies server +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cd /nightlies/latest; rm -f *.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win32/DB*SQLite-%RUN_DATE%-win32.exe /nightlies/latest/DB.Browser.for.SQLite-win32.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win32/DB*sqlcipher-%RUN_DATE%-win32.exe /nightlies/latest/DB.Browser.for.SQLite-sqlcipher-win32.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win64/DB*SQLite-%RUN_DATE%-win64.exe /nightlies/latest/DB.Browser.for.SQLite-win64.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win64/DB*sqlcipher-%RUN_DATE%-win64.exe /nightlies/latest/DB.Browser.for.SQLite-sqlcipher-win64.exe" + +:: Wipe working dir +cd /d C:\ +rd /q /s "C:\\git_repos" From 8fe09f152dd69416a0eef126f06edf6c01feb697 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Sat, 2 Jun 2018 23:13:51 +0200 Subject: [PATCH 56/63] Update Windows Installer to include SQLCipher --- installer/windows/build.cmd | 29 +++++++++++++++++++++-------- installer/windows/product.wxs | 14 +++++++++++--- installer/windows/variables.wxi | 2 ++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/installer/windows/build.cmd b/installer/windows/build.cmd index 2e210867..2bda8b9e 100644 --- a/installer/windows/build.cmd +++ b/installer/windows/build.cmd @@ -1,17 +1,30 @@ @echo off -:: Set the output MSI and ARCH based on the calling parameter +:: Output file name +set MSI=DB.Browser.for.SQLite + +:: Set the ARCH based on the first parameter if "%1"=="" ( - echo ERROR: You must select "Win64" or "Win32" + echo ERROR: You must select a build type, either "win64" or "win32" goto :eof -) else if "%1"=="Win32" ( - set MSI=DB.Browser.for.SQLite-win32 +) else if "%1"=="win32" ( set ARCH=x86 -) else if "%1"=="Win64" ( - set MSI=DB.Browser.for.SQLite-win64 +) else if "%1"=="win64" ( set ARCH=x64 ) else ( - echo ERROR: Unknown ARCH="%1" + echo ERROR: Unknown build type="%1" + goto :eof +) + +:: Choose between building the application with SQLite (default) or SQLCipher library +if "%2"=="" ( + set SQLCIPHER= + set MSI=%MSI%-%1 +) else if "%2"=="sqlcipher" ( + set MSI=%MSI%-sqlcipher-%1 + set SQLCIPHER=-dSQLCipher=1 +) else ( + echo ERROR: Second parameter can only be "sqlcipher" or nothing goto :eof ) @@ -26,7 +39,7 @@ set ICE=-sice:ICE03 -sice:ICE82 -sice:ICE61 -sice:ICE43 -sice:ICE57 set LIGHT=-sw1104 :: Compile & Link -"%WIX%\bin\candle.exe" -nologo -pedantic -arch %ARCH% product.wxs +"%WIX%\bin\candle.exe" -nologo -pedantic -arch %ARCH% %SQLCIPHER% product.wxs "%WIX%\bin\light.exe" -nologo -pedantic %LIGHT% %ICE% -ext WixUIExtension -ext WixUtilExtension product.wixobj -out %MSI%.msi :: Cleanup diff --git a/installer/windows/product.wxs b/installer/windows/product.wxs index c4546e93..0fedeb14 100644 --- a/installer/windows/product.wxs +++ b/installer/windows/product.wxs @@ -78,7 +78,11 @@ - + + + + + - - + + + + + + diff --git a/installer/windows/variables.wxi b/installer/windows/variables.wxi index b8a5c6ea..ca001087 100644 --- a/installer/windows/variables.wxi +++ b/installer/windows/variables.wxi @@ -52,10 +52,12 @@ + + From 5eee8cee3fffd79b388ace10b560d7fc14337412 Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Sun, 3 Jun 2018 03:35:34 +0100 Subject: [PATCH 57/63] Update winbuild.bat to create nightly MSI files as well --- .../windows/nightly_build_script/winbuild.bat | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/installer/windows/nightly_build_script/winbuild.bat b/installer/windows/nightly_build_script/winbuild.bat index 72b956bb..4bbf5579 100644 --- a/installer/windows/nightly_build_script/winbuild.bat +++ b/installer/windows/nightly_build_script/winbuild.bat @@ -1,6 +1,7 @@ :: Destination path - specify where to move package after build set DEST_PATH=C:\\builds MKDIR "%DEST_PATH%" +MKDIR "%DEST_PATH%\tmp\" set SQLITE_DIR=C:\\dev\\SQLite- set SQLCIPHER_DIR=C:\\git_repos\\SQLCipher- @@ -31,6 +32,7 @@ git clone -b msvc2013_win32 --depth 1 https://github.com/justinclift/sqlcipher.g git clone -b msvc2013_win64 --depth 1 https://github.com/justinclift/sqlcipher.git SQLCipher-Win64 git clone -b %BRANCH% https://github.com/sqlitebrowser/sqlitebrowser.git + :: WIN32 SQLITE BUILD PROCEDURE :: Set path variables @@ -49,8 +51,20 @@ cmake -G "Visual Studio 12 2013" -Wno-dev .. :: Build package FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" +:: Copy .exe to destination. Weirdly, this needs to be done in two steps as doing +:: it with a single MOVE always results in a broken .exe 4k in size +COPY /Y C:\\git_repos\\sqlitebrowser\\release-sqlite-win32\\DB*.exe "%DEST_PATH%\\tmp\\" +MOVE /Y %DEST_PATH%\\tmp\\DB*.exe "%DEST_PATH%\\DB Browser for SQLite-%RUN_DATE%-win32.exe" + +:: Build MSI +MKDIR C:\\git_repos\\sqlitebrowser\\Release +MOVE C:\\git_repos\\sqlitebrowser\\release-sqlite-win32\\Release\\*.exe C:\\git_repos\\sqlitebrowser\\Release +cd C:\\git_repos\\sqlitebrowser\\installer\\windows +CALL build.cmd win32 + :: Move package to DEST_PATH -MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win32.exe" +MOVE /Y *msi "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win32.msi" + :: WIN32 SQLCIPHER BUILD PROCEDURE @@ -67,8 +81,20 @@ cmake -G "Visual Studio 12 2013" -Wno-dev -Dsqlcipher=1 .. :: Build package FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" +:: Copy .exe to destination. Weirdly, this needs to be done in two steps as doing +:: it with a single MOVE always results in a broken .exe 4k in size +COPY /Y C:\\git_repos\\sqlitebrowser\\release-sqlcipher-win32\\DB*.exe "%DEST_PATH%\\tmp\\" +MOVE /Y %DEST_PATH%\\tmp\\DB*.exe "%DEST_PATH%\\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win32.exe" + +:: Build MSI +MKDIR C:\\git_repos\\sqlitebrowser\\Release +MOVE C:\\git_repos\\sqlitebrowser\\release-sqlcipher-win32\\Release\\*.exe C:\\git_repos\\sqlitebrowser\\Release +cd C:\\git_repos\\sqlitebrowser\\installer\\windows +CALL build.cmd win32 sqlcipher + :: Move package to DEST_PATH -MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win32.exe" +MOVE /Y *msi "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win32.msi" + :: WIN64 SQLITE BUILD PROCEDURE @@ -88,8 +114,20 @@ cmake -G "Visual Studio 12 2013 Win64" -Wno-dev .. :: Build package FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" +:: Copy .exe to destination. Weirdly, this needs to be done in two steps as doing +:: it with a single MOVE always results in a broken .exe 4k in size +COPY /Y C:\\git_repos\\sqlitebrowser\\release-sqlite-win64\\DB*.exe "%DEST_PATH%\\tmp\\" +MOVE /Y %DEST_PATH%\\tmp\\DB*.exe "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win64.exe" + +:: Build MSI +MKDIR C:\\git_repos\\sqlitebrowser\\Release +MOVE C:\\git_repos\\sqlitebrowser\\release-sqlite-win64\\Release\\*.exe C:\\git_repos\\sqlitebrowser\\Release +cd C:\\git_repos\\sqlitebrowser\\installer\\windows +CALL build.cmd win64 + :: Move package to DEST_PATH -MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win64.exe" +MOVE /Y *msi "%DEST_PATH%\DB Browser for SQLite-%RUN_DATE%-win64.msi" + :: WIN64 SQLCIPHER BUILD PROCEDURE @@ -106,19 +144,36 @@ cmake -G "Visual Studio 12 2013 Win64" -Wno-dev -Dsqlcipher=1 .. :: Build package FOR %%I IN (*.sln) DO devenv /Build Release "%%I" /project "PACKAGE" +:: Copy .exe to destination. Weirdly, this needs to be done in two steps as doing +:: it with a single MOVE always results in a broken .exe 4k in size +COPY /Y C:\\git_repos\\sqlitebrowser\\release-sqlcipher-win64\\DB*.exe "%DEST_PATH%\\tmp\\" +MOVE /Y %DEST_PATH%\\tmp\\DB*.exe "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win64.exe" + +:: Build MSI +MKDIR C:\\git_repos\\sqlitebrowser\\Release +MOVE C:\\git_repos\\sqlitebrowser\\release-sqlcipher-win64\\Release\\*.exe C:\\git_repos\\sqlitebrowser\\Release +cd C:\\git_repos\\sqlitebrowser\\installer\\windows +CALL build.cmd win64 sqlcipher + :: Move package to DEST_PATH -MOVE /Y *exe "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win64.exe" +MOVE /Y *msi "%DEST_PATH%\DB Browser for SQLite-sqlcipher-%RUN_DATE%-win64.msi" :: Upload the packages to the nightlies server pscp -q -p -i C:\dev\puttygen_private.ppk "%DEST_PATH%\DB*%RUN_DATE%*win32.exe" nightlies@nightlies.sqlitebrowser.org:/nightlies/win32 +pscp -q -p -i C:\dev\puttygen_private.ppk "%DEST_PATH%\DB*%RUN_DATE%*win32.msi" nightlies@nightlies.sqlitebrowser.org:/nightlies/win32 pscp -q -p -i C:\dev\puttygen_private.ppk "%DEST_PATH%\DB*%RUN_DATE%*win64.exe" nightlies@nightlies.sqlitebrowser.org:/nightlies/win64 +pscp -q -p -i C:\dev\puttygen_private.ppk "%DEST_PATH%\DB*%RUN_DATE%*win64.msi" nightlies@nightlies.sqlitebrowser.org:/nightlies/win64 :: Copy the new binaries to /latest directory on the nightlies server -plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cd /nightlies/latest; rm -f *.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cd /nightlies/latest; rm -f *.exe *.msi" plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win32/DB*SQLite-%RUN_DATE%-win32.exe /nightlies/latest/DB.Browser.for.SQLite-win32.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win32/DB*SQLite-%RUN_DATE%-win32.msi /nightlies/latest/DB.Browser.for.SQLite-win32.msi" plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win32/DB*sqlcipher-%RUN_DATE%-win32.exe /nightlies/latest/DB.Browser.for.SQLite-sqlcipher-win32.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win32/DB*sqlcipher-%RUN_DATE%-win32.msi /nightlies/latest/DB.Browser.for.SQLite-sqlcipher-win32.msi" plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win64/DB*SQLite-%RUN_DATE%-win64.exe /nightlies/latest/DB.Browser.for.SQLite-win64.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win64/DB*SQLite-%RUN_DATE%-win64.msi /nightlies/latest/DB.Browser.for.SQLite-win64.msi" plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win64/DB*sqlcipher-%RUN_DATE%-win64.exe /nightlies/latest/DB.Browser.for.SQLite-sqlcipher-win64.exe" +plink -i C:\dev\puttygen_private.ppk nightlies@nightlies.sqlitebrowser.org "cp /nightlies/win64/DB*sqlcipher-%RUN_DATE%-win64.msi /nightlies/latest/DB.Browser.for.SQLite-sqlcipher-win64.msi" :: Wipe working dir cd /d C:\ From 09c668a1126afa538827595a45547e1e684aa62d Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Sun, 3 Jun 2018 22:51:50 +0200 Subject: [PATCH 58/63] Update the welcome dialog text for Windows Installer --- installer/windows/build.cmd | 2 +- installer/windows/strings.wxl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 installer/windows/strings.wxl diff --git a/installer/windows/build.cmd b/installer/windows/build.cmd index 2bda8b9e..d03ac0c8 100644 --- a/installer/windows/build.cmd +++ b/installer/windows/build.cmd @@ -40,7 +40,7 @@ set LIGHT=-sw1104 :: Compile & Link "%WIX%\bin\candle.exe" -nologo -pedantic -arch %ARCH% %SQLCIPHER% product.wxs -"%WIX%\bin\light.exe" -nologo -pedantic %LIGHT% %ICE% -ext WixUIExtension -ext WixUtilExtension product.wixobj -out %MSI%.msi +"%WIX%\bin\light.exe" -nologo -pedantic %LIGHT% %ICE% -ext WixUIExtension -ext WixUtilExtension -cultures:en-us -loc strings.wxl product.wixobj -out %MSI%.msi :: Cleanup del product.wixobj diff --git a/installer/windows/strings.wxl b/installer/windows/strings.wxl new file mode 100644 index 00000000..ffcdcb0c --- /dev/null +++ b/installer/windows/strings.wxl @@ -0,0 +1,4 @@ + + + The Setup Wizard will install [ProductName] on your computer. If you have a previous version already installed, this installation process will update it. Click Next to continue or Cancel to exit the Setup Wizard. + From 7c0a7daab92165546d85ebbdb3a5de123fedd664 Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Sun, 3 Jun 2018 23:55:28 +0100 Subject: [PATCH 59/63] Adjust welcome message for white space. --- installer/windows/strings.wxl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/installer/windows/strings.wxl b/installer/windows/strings.wxl index ffcdcb0c..0ab05b16 100644 --- a/installer/windows/strings.wxl +++ b/installer/windows/strings.wxl @@ -1,4 +1,6 @@ - The Setup Wizard will install [ProductName] on your computer. If you have a previous version already installed, this installation process will update it. Click Next to continue or Cancel to exit the Setup Wizard. + This Setup Wizard will install [ProductName] on your computer. + +If you have a previous version already installed, this will update it. From bb57d04489ae7d853a1c34dc27100823d0b56867 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Mon, 4 Jun 2018 11:15:58 +0200 Subject: [PATCH 60/63] Add Desktop shortcut to Windows Installer --- installer/windows/product.wxs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/installer/windows/product.wxs b/installer/windows/product.wxs index 0fedeb14..e1f78a5b 100644 --- a/installer/windows/product.wxs +++ b/installer/windows/product.wxs @@ -48,6 +48,7 @@ + @@ -85,14 +86,8 @@ - + + From 0ee336670bd3b9ecc0ea16c4f251cc481b8ddff0 Mon Sep 17 00:00:00 2001 From: Karim ElDeeb Date: Tue, 5 Jun 2018 17:09:05 +0200 Subject: [PATCH 61/63] Make the application shortcuts configurable on Windows --- installer/windows/build.cmd | 4 ++-- installer/windows/product.wxs | 44 ++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/installer/windows/build.cmd b/installer/windows/build.cmd index d03ac0c8..602834e7 100644 --- a/installer/windows/build.cmd +++ b/installer/windows/build.cmd @@ -31,8 +31,8 @@ if "%2"=="" ( :: Suppress some ICE checks :: - 61 (major upgrade) :: - 03 & 82 (merge module) -:: - 43 & 57 (non-advertised shortcuts) -set ICE=-sice:ICE03 -sice:ICE82 -sice:ICE61 -sice:ICE43 -sice:ICE57 +:: - 38 & 43 & 57 (non-advertised shortcuts) +set ICE=-sice:ICE03 -sice:ICE82 -sice:ICE61 -sice:ICE38 -sice:ICE43 -sice:ICE57 :: Suppress 'light.exe' warning :: - 1104 (vcredist merge module installer version) diff --git a/installer/windows/product.wxs b/installer/windows/product.wxs index e1f78a5b..e4223b58 100644 --- a/installer/windows/product.wxs +++ b/installer/windows/product.wxs @@ -48,8 +48,6 @@ - - @@ -84,23 +82,40 @@ - - - - - - + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + - @@ -140,10 +155,7 @@ - - - - + From f8ff92c8e99f05a2a6941cf3c11c58f8e92e8c72 Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Tue, 5 Jun 2018 18:12:00 +0100 Subject: [PATCH 62/63] Use -sval when building .msi files Otherwise our nightly build process throws errors. --- installer/windows/build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/windows/build.cmd b/installer/windows/build.cmd index d03ac0c8..bee8e75a 100644 --- a/installer/windows/build.cmd +++ b/installer/windows/build.cmd @@ -40,7 +40,7 @@ set LIGHT=-sw1104 :: Compile & Link "%WIX%\bin\candle.exe" -nologo -pedantic -arch %ARCH% %SQLCIPHER% product.wxs -"%WIX%\bin\light.exe" -nologo -pedantic %LIGHT% %ICE% -ext WixUIExtension -ext WixUtilExtension -cultures:en-us -loc strings.wxl product.wixobj -out %MSI%.msi +"%WIX%\bin\light.exe" -sval -nologo -pedantic %LIGHT% %ICE% -ext WixUIExtension -ext WixUtilExtension -cultures:en-us -loc strings.wxl product.wixobj -out %MSI%.msi :: Cleanup del product.wixobj From 6466aac5eaaeb8cccace0aadc1b9415a747b6cbc Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Thu, 7 Jun 2018 12:39:58 +0100 Subject: [PATCH 63/63] Use Base64 encoding for BLOBs in JSON export (#1413) --- src/ExportDataDialog.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ExportDataDialog.cpp b/src/ExportDataDialog.cpp index d252453f..8580da03 100644 --- a/src/ExportDataDialog.cpp +++ b/src/ExportDataDialog.cpp @@ -11,6 +11,7 @@ #include #include #include +#include ExportDataDialog::ExportDataDialog(DBBrowserDB& db, ExportFormats format, QWidget* parent, const QString& query, const sqlb::ObjectIdentifier& selection) : QDialog(parent), @@ -237,14 +238,21 @@ bool ExportDataDialog::exportQueryJson(const QString& sQuery, const QString& sFi json_row.insert(column_names[i], QJsonValue()); break; } - case SQLITE_TEXT: - case SQLITE_BLOB: { + case SQLITE_TEXT: { QString content = QString::fromUtf8( - (const char*)sqlite3_column_blob(stmt, i), + (const char*)sqlite3_column_text(stmt, i), sqlite3_column_bytes(stmt, i)); json_row.insert(column_names[i], content); break; } + case SQLITE_BLOB: { + QByteArray content((const char*)sqlite3_column_blob(stmt, i), + sqlite3_column_bytes(stmt, i)); + QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + QString string = codec->toUnicode(content.toBase64(QByteArray::Base64Encoding)); + json_row.insert(column_names[i], string); + break; + } } } json_table.push_back(json_row);