Esempio n. 1
0
 def buildUI(self):
     self.process = Process(self.dataReady, self.onError, self.onOutput,
                            self.isFinished, self)
     self.cmdField = PlainTextEdit({
         'lwm': QPlainTextEdit.NoWrap,
         'sfh': 25,
         'vsbp': SCROLLBAROFF,
         'adr': True
     })
     self.textWindow = PlainTextEdit({'rol': True}, self)
     self.cursor = self.cmdField.textCursor()
     self.copySelectedTextAction = ShortCut('Copy', 'Copy', 'Shift+Ctrl+c',
                                            self.copyText, self)
     self.cancelAction = ShortCut('Cancel', 'Cancel', 'Ctrl+c',
                                  self.killProcess, self)
     self.pasteTextAction = ShortCut('Paste', 'Paste', 'Shift+Ctrl+v',
                                     self.pasteText, self)
     self.textWindow.addActions(
         [self.cancelAction, self.copySelectedTextAction])
     self.cmdField.addAction(self.pasteTextAction)
     self.cmdField.installEventFilter(self)
     self.cursorEnd()
     sysinfo = QSysInfo()
     myMachine = "CPU Architecture: {0}***{1}***{2}***{3}".format(
         sysinfo.currentCpuArchitecture(), sysinfo.prettyProductName(),
         sysinfo.kernelType(), sysinfo.kernelVersion())
     self.statusBar = StatusBar(self)
     self.statusBar.showMessage(myMachine, 0)
     self.layout.addWidget(self.textWindow)
     self.layout.addWidget(self.cmdField)
     self.layout.addWidget(self.statusBar)
Esempio n. 2
0
    def get_os_name(self):
        global q_os_version_available
        try:
            os_name = QSysInfo.prettyProductName()

            if q_os_version_available:
                ver = QOperatingSystemVersion.current()
                if ver.name() != '':
                    os_name += ' {} '.format(ver.name())
                if ver.segmentCount() > 2:
                    os_name += '{}.{}.{}'.format(ver.majorVersion(),
                                                 ver.minorVersion(),
                                                 ver.microVersion())
                elif ver.segmentCount == 2:
                    os_name += '{}.{}'.format(ver.majorVersion(),
                                              ver.minorVersion())
                elif ver.segmentCount == 1:
                    os_name += '{}'.format(ver.majorVersion())

            kernel_name = QSysInfo.kernelType() + ' ' + QSysInfo.kernelVersion(
            )
            if os_name != kernel_name:
                os_name += ' ({})'.format(kernel_name)
            return os_name
        except Exception as e:
            return platform.platform()
Esempio n. 3
0
    def setMessage(self, exType, exValue, exTrace):
        """Generate a message and append session data, error info and
        error traceback.
        """
        from traceback import format_tb
        from novelwriter import __issuesurl__, __version__
        from PyQt5.Qt import PYQT_VERSION_STR
        from PyQt5.QtCore import QT_VERSION_STR, QSysInfo

        self.msgHead.setText((
            "<p>An unhandled error has been encountered.</p>"
            "<p>Please report this error by submitting an issue report on "
            "GitHub, providing a description and including the error "
            "message and traceback shown below.</p>"
            "<p>URL: <a href='{issueUrl}'>{issueUrl}</a></p>"
        ).format(
            issueUrl=__issuesurl__,
        ))

        try:
            kernelVersion = QSysInfo.kernelVersion()
        except Exception:
            kernelVersion = "Unknown"

        try:
            import lxml
            lxmlVersion = lxml.__version__
        except Exception:
            lxmlVersion = "Unknown"

        try:
            import enchant
            enchantVersion = enchant.__version__
        except Exception:
            enchantVersion = "Unknown"

        try:
            exTrace = "\n".join(format_tb(exTrace))
            self.msgBody.setPlainText((
                "Environment:\n"
                f"novelWriter Version: {__version__}\n"
                f"Host OS: {sys.platform} ({kernelVersion})\n"
                f"Python: {sys.version.split()[0]} ({sys.hexversion:#x})\n"
                f"Qt: {QT_VERSION_STR}, PyQt: {PYQT_VERSION_STR}\n"
                f"lxml: {lxmlVersion}\n"
                f"enchant: {enchantVersion}\n\n"
                f"{exType.__name__}:\n{str(exValue)}\n\n"
                f"Traceback:\n{exTrace}\n"
            ))
        except Exception:
            self.msgBody.setPlainText("Failed to generate error report ...")

        return
Esempio n. 4
0
    def setMessage(self, exType, exValue, exTrace):
        """Generate a message and append session data, error info and
        error traceback.
        """
        import sys
        from traceback import format_tb
        from nw import __issuesurl__, __version__
        from PyQt5.Qt import PYQT_VERSION_STR
        from PyQt5.QtCore import QT_VERSION_STR, QSysInfo

        self.msgHead.setText((
            "<p>An unhandled error has been encountered.</p>"
            "<p>Please report this error by submitting an issue report on "
            "GitHub, providing a description and including the error "
            "message and traceback shown below.</p>"
            "<p>URL: <a href='{issueUrl}'>{issueUrl}</a></p>"
        ).format(
            issueUrl = __issuesurl__,
        ))

        try:
            kernelVersion = QSysInfo.kernelVersion()
        except Exception:
            kernelVersion = "Unknown"

        try:
            self.msgBody.setPlainText((
                "Environment:\n"
                "novelWriter Version: {nwVersion}\n"
                "Host OS: {osType} ({osKernel})\n"
                "Python: {pyVersion} ({pyHexVer:#x})\n"
                "Qt: {qtVers}, PyQt: {pyqtVers}\n"
                "\n"
                "{exType}:\n{exMessage}\n"
                "\n"
                "Traceback:\n{exTrace}\n"
            ).format(
                nwVersion = __version__,
                osType    = sys.platform,
                osKernel  = kernelVersion,
                pyVersion = sys.version.split()[0],
                pyHexVer  = sys.hexversion,
                qtVers    = QT_VERSION_STR,
                pyqtVers  = PYQT_VERSION_STR,
                exType    = exType.__name__,
                exMessage = str(exValue),
                exTrace   = "\n".join(format_tb(exTrace)),
            ))
        except Exception:
            self.msgBody.setPlainText("Failed to generate error report ...")

        return
Esempio n. 5
0
def get_defaultstyle() -> str:
    style = STYLE_COOL

    if platform == "win32":
        version_str = QSysInfo.kernelVersion()
        if "." in version_str:
            dot_index = version_str.index(".")
            if dot_index != -1:
                version_str = version_str[: dot_index + 2]
                version_str.replace(".", "0")
        version_double, ok = QLocale().toDouble(version_str)
        if version_double >= 602:
            style = STYLE_THRESHOLD
    elif platform == "darwin":
        style = STYLE_VIENNA

    return style
Esempio n. 6
0
    def initConfig(self, confPath=None, dataPath=None):
        """Initialise the config class. The manual setting of confPath
        and dataPath is mainly intended for the test suite.
        """
        logger.debug("Initialising Config ...")
        if confPath is None:
            confRoot = QStandardPaths.writableLocation(
                QStandardPaths.ConfigLocation)
            self.confPath = os.path.join(os.path.abspath(confRoot),
                                         self.appHandle)
        else:
            logger.info("Setting config from alternative path: %s" % confPath)
            self.confPath = confPath

        if dataPath is None:
            if self.verQtValue >= 50400:
                dataRoot = QStandardPaths.writableLocation(
                    QStandardPaths.AppDataLocation)
            else:
                dataRoot = QStandardPaths.writableLocation(
                    QStandardPaths.DataLocation)
            self.dataPath = os.path.join(os.path.abspath(dataRoot),
                                         self.appHandle)
        else:
            logger.info("Setting data path from alternative path: %s" %
                        dataPath)
            self.dataPath = dataPath

        logger.verbose("Config path: %s" % self.confPath)
        logger.verbose("Data path: %s" % self.dataPath)

        self.confFile = self.appHandle + ".conf"
        self.lastPath = os.path.expanduser("~")
        self.appPath = getattr(sys, "_MEIPASS",
                               os.path.abspath(os.path.dirname(__file__)))
        self.appRoot = os.path.abspath(
            os.path.join(self.appPath, os.path.pardir))

        if os.path.isfile(self.appRoot):
            # novelWriter is packaged as a single file, so the app and
            # root paths are the same, and equal to the folder that
            # contains the single executable.
            self.appRoot = os.path.dirname(self.appRoot)
            self.appPath = self.appRoot

        # Assets
        self.assetPath = os.path.join(self.appPath, "assets")
        self.themeRoot = os.path.join(self.assetPath, "themes")
        self.dictPath = os.path.join(self.assetPath, "dict")
        self.iconPath = os.path.join(self.assetPath, "icons")
        self.appIcon = os.path.join(self.iconPath, "novelwriter.svg")

        # Internationalisation
        self.nwLangPath = os.path.join(self.appRoot, "i18n")

        logger.verbose("App path: %s" % self.appPath)
        logger.verbose("Last path: %s" % self.lastPath)

        # If config folder does not exist, create it.
        # This assumes that the os config folder itself exists.
        if not os.path.isdir(self.confPath):
            try:
                os.mkdir(self.confPath)
            except Exception as e:
                logger.error("Could not create folder: %s" % self.confPath)
                logException()
                self.hasError = True
                self.errData.append("Could not create folder: %s" %
                                    self.confPath)
                self.errData.append(str(e))
                self.confPath = None

        # Check if config file exists
        if self.confPath is not None:
            if os.path.isfile(os.path.join(self.confPath, self.confFile)):
                # If it exists, load it
                self.loadConfig()
            else:
                # If it does not exist, save a copy of the default values
                self.saveConfig()

        # If data folder does not exist, make it.
        # This assumes that the os data folder itself exists.
        if self.dataPath is not None:
            if not os.path.isdir(self.dataPath):
                try:
                    os.mkdir(self.dataPath)
                except Exception as e:
                    logger.error("Could not create folder: %s" % self.dataPath)
                    logException()
                    self.hasError = True
                    self.errData.append("Could not create folder: %s" %
                                        self.dataPath)
                    self.errData.append(str(e))
                    self.dataPath = None

        # Host and Kernel
        if self.verQtValue >= 50600:
            self.hostName = QSysInfo.machineHostName()
            self.kernelVer = QSysInfo.kernelVersion()

        # Load recent projects cache
        self.loadRecentCache()

        # Check the availability of optional packages
        self._checkOptionalPackages()

        if self.spellTool is None:
            self.spellTool = nwConst.SP_INTERNAL
        if self.spellLanguage is None:
            self.spellLanguage = "en"

        # Check if local help files exist
        self.helpPath = os.path.join(self.assetPath, "help", "novelWriter.qhc")
        self.hasHelp = os.path.isfile(self.helpPath)
        self.hasHelp &= os.path.isfile(
            os.path.join(self.assetPath, "help", "novelWriter.qch"))

        logger.debug("Config initialisation complete")

        return True
Esempio n. 7
0
    def createPanel(self):
        labelReportTitle = QLabel(
            self.translate("bugReport", "Bug Report Title: "))
        self.lineEditReportTitle = QLineEdit()

        labelTestedEnvironment = QLabel(
            self.translate("bugReport", "Tested Environment: "))
        self.lineEditTestedEnvironment = QLineEdit(
            self.translate(
                "bugReport",
                """System Platform:{}_{}   Python Version:{}.{}.{}-{}   PyQt Version:{}    QT Version:{}"""
            ).format(
                QSysInfo.prettyProductName() if QSysInfo.prettyProductName()
                == "unknown" else "{}-{}".format(QSysInfo.kernelType(),
                                                 QSysInfo.kernelVersion()),
                QSysInfo.currentCpuArchitecture(), sys.version_info.major,
                sys.version_info.minor, sys.version_info.micro,
                sys.version_info.releaselevel, PYQT_VERSION_STR,
                QT_VERSION_STR))

        radioBtnQuickReport = QRadioButton(
            self.translate("bugReport", "Quick Report"))
        radioBtnKnowHowFix = QRadioButton(
            self.translate("bugReport", "Know How Fix"))
        radioBtnKnowHowFix.setChecked(True)
        radioBtnFeatureRequest = QRadioButton(
            self.translate("bugReport", "Feature Request"))
        buttonOpenHowReportBugURL = QPushButton(
            self.translate(
                "bugReport",
                """Click Me! Read "HOW REPORT A BUG" before report a bug."""))

        self.buttonGroupBugReport = QButtonGroup()
        self.buttonGroupBugReport.addButton(radioBtnQuickReport)
        self.buttonGroupBugReport.addButton(radioBtnKnowHowFix)
        self.buttonGroupBugReport.addButton(radioBtnFeatureRequest)
        self.buttonGroupBugReport.addButton(buttonOpenHowReportBugURL)

        hboxRadiobutton = QHBoxLayout()
        hboxRadiobutton.addWidget(radioBtnKnowHowFix)
        hboxRadiobutton.addWidget(radioBtnQuickReport)
        hboxRadiobutton.addWidget(radioBtnFeatureRequest)
        hboxRadiobutton.addWidget(buttonOpenHowReportBugURL)
        hboxRadiobutton.addStretch()

        labelStepsToReproduce = QLabel(
            self.translate("bugReport", "Steps To Reproduce: "))
        self.textEditStepsToReproduce = QTextEdit()

        labelActualresults = QLabel(
            self.translate("bugReport", "Actual results: "))
        self.textEditActualresults = QTextEdit()
        self.textEditActualresults.insertPlainText(
            self.translate(
                "bugReport",
                "if have Python's Traceback, Please Paste.\nif is V2Ray-core JSON Editor issue, please Paste the JSON File without server information."
            ))
        self.textEditActualresults.setAcceptDrops(True)

        labelExpectedresults = QLabel(
            self.translate("bugReport", "Expected results: "))
        self.textEditExpectedresults = QTextEdit()

        labelFeatureRequest = QLabel(
            self.translate("bugReport", "Feature Request: "))
        self.textEditFeatureRequest = QTextEdit()

        labelQuickReport = QLabel(self.translate("bugReport",
                                                 "Quick Report: "))
        self.textEditQuickReport = QTextEdit()

        labelHowFix = QLabel(self.translate("bugReport", "How Fix: "))
        self.textEditHowFix = QTextEdit()

        gridBoxReport = QGridLayout()
        gridBoxReport.addWidget(labelReportTitle, 0, 0)
        gridBoxReport.addWidget(self.lineEditReportTitle, 0, 1)
        gridBoxReport.addWidget(labelTestedEnvironment, 1, 0)
        gridBoxReport.addWidget(self.lineEditTestedEnvironment, 1, 1)
        gridBoxReport.addLayout(hboxRadiobutton, 2, 0, 1, 2)

        gridBoxQuickReport = QGridLayout()
        gridBoxQuickReport.addWidget(labelQuickReport, 0, 0)
        gridBoxQuickReport.addWidget(self.textEditQuickReport, 0, 1)

        self.groupBoxQuickReport = QGroupBox("", self)
        self.groupBoxQuickReport.setLayout(gridBoxQuickReport)
        self.groupBoxQuickReport.hide()

        gridBoxKnowHowFix = QGridLayout()
        gridBoxKnowHowFix.addWidget(labelStepsToReproduce, 0, 0)
        gridBoxKnowHowFix.addWidget(self.textEditStepsToReproduce, 0, 1)
        gridBoxKnowHowFix.addWidget(labelActualresults, 1, 0)
        gridBoxKnowHowFix.addWidget(self.textEditActualresults, 1, 1)
        self.buttonInsertPiture = QPushButton(
            self.translate("bugReport", "Insert Picture From URL:"))
        self.lineEditInserPiture = QLineEdit()
        gridBoxKnowHowFix.addWidget(self.lineEditInserPiture, 2, 1)
        gridBoxKnowHowFix.addWidget(self.buttonInsertPiture, 2, 0)
        gridBoxKnowHowFix.addItem(QSpacerItem(50, 50), 3, 0, 1, 4)
        gridBoxKnowHowFix.addWidget(labelExpectedresults, 4, 0)
        gridBoxKnowHowFix.addWidget(self.textEditExpectedresults, 4, 1)
        gridBoxKnowHowFix.addWidget(labelHowFix, 5, 0)
        gridBoxKnowHowFix.addWidget(self.textEditHowFix, 5, 1)

        self.groupBoxKnowHowFix = QGroupBox()
        self.groupBoxKnowHowFix.setLayout(gridBoxKnowHowFix)

        gridBoxFeatureRequest = QGridLayout()
        gridBoxFeatureRequest.addWidget(labelFeatureRequest, 0, 0)
        gridBoxFeatureRequest.addWidget(self.textEditFeatureRequest, 0, 1)

        self.groupBoxFeatureRequest = QGroupBox("", self)
        self.groupBoxFeatureRequest.setLayout(gridBoxFeatureRequest)
        self.groupBoxFeatureRequest.hide()

        hboxButton = QHBoxLayout()
        self.buttonExportBugReportText = QPushButton(
            self.translate("bugReport", "Export Bug Report Text"))
        self.buttonExitButReport = QPushButton(
            self.translate("bugReport", "Exit"))
        hboxButton.addStretch()
        hboxButton.addWidget(self.buttonExportBugReportText)
        hboxButton.addWidget(self.buttonExitButReport)

        vboxBugReport = QVBoxLayout(self)
        vboxBugReport.addLayout(gridBoxReport)
        vboxBugReport.addWidget(self.groupBoxQuickReport)
        vboxBugReport.addWidget(self.groupBoxKnowHowFix)
        vboxBugReport.addWidget(self.groupBoxFeatureRequest)
        vboxBugReport.addLayout(hboxButton)
        vboxBugReport.addStretch()

        self.settextEidtReadonly(result=True)
        self.createSignals()
Esempio n. 8
0
 def createStatusBar(self):
     sysinfo = QSysInfo()
     myMachine = "current CPU Architecture: " + sysinfo.currentCpuArchitecture(
     ) + " *** " + sysinfo.prettyProductName(
     ) + " *** " + sysinfo.kernelType() + " " + sysinfo.kernelVersion()
     self.statusBar().showMessage(myMachine, 0)
Esempio n. 9
0
    def __init__(self):

        # Set Application Variables
        self.appName = "novelWriter"
        self.appHandle = self.appName.lower()

        # Debug Settings
        self.showGUI = True  # Allow blocking the GUI (disabled for testing)
        self.debugInfo = False  # True if log level is DEBUG or VERBOSE

        # Config Error Handling
        self.hasError = False  # True if the config class encountered an error
        self.errData = []  # List of error messages

        # Set Paths
        self.cmdOpen = None  # Path from command line for project to be opened on launch
        self.confPath = None  # Folder where the config is saved
        self.confFile = None  # The config file name
        self.dataPath = None  # Folder where app data is stored
        self.lastPath = None  # The last user-selected folder (browse dialogs)
        self.appPath = None  # The full path to the novelwriter package folder
        self.appRoot = None  # The full path to the novelwriter root folder
        self.appIcon = None  # The full path to the novelwriter icon file
        self.assetPath = None  # The full path to the nw/assets folder
        self.themeRoot = None  # The full path to the nw/assets/themes folder
        self.dictPath = None  # The full path to the nw/assets/dict folder
        self.iconPath = None  # The full path to the nw/assets/icons folder
        self.helpPath = None  # The full path to the novelwriter .qhc help file

        # Runtime Settings and Variables
        self.confChanged = False  # True whenever the config has chenged, false after save
        self.hasHelp = False  # True if the Qt help files are present in the assets folder

        ## General
        self.guiTheme = "default"
        self.guiSyntax = "default_light"
        self.guiIcons = "typicons_colour_light"
        self.guiDark = False  # Load icons for dark backgrounds, if available
        self.guiLang = "en"  # Hardcoded for now since the GUI is only in English
        self.guiFont = ""  # Defaults to system defualt font
        self.guiFontSize = 11
        self.guiScale = 1.0  # Set automatically by Theme class

        ## Sizes
        self.winGeometry = [1100, 650]
        self.treeColWidth = [120, 30, 50]
        self.projColWidth = [140, 55, 140]
        self.mainPanePos = [300, 800]
        self.docPanePos = [400, 400]
        self.viewPanePos = [500, 150]
        self.outlnPanePos = [500, 150]
        self.isFullScreen = False

        ## Features
        self.hideVScroll = False  # Hide vertical scroll bars on main widgets
        self.hideHScroll = False  # Hide horizontal scroll bars on main widgets

        ## Project
        self.autoSaveProj = 60  # Interval for auto-saving project in seconds
        self.autoSaveDoc = 30  # Interval for auto-saving document in seconds

        ## Text Editor
        self.textFont = None  # Editor font
        self.textSize = 12  # Editor font size
        self.textFixedW = True  # Keep editor text fixed width
        self.textWidth = 600  # Editor text width
        self.textMargin = 40  # Editor/viewer text margin
        self.tabWidth = 40  # Editor tabulator width

        self.focusWidth = 800  # Focus Mode text width
        self.hideFocusFooter = False  # Hide document footer in Focus Mode
        self.showFullPath = True  # Show full document path in editor header
        self.autoSelect = True  # Auto-select word when applying format with no selection

        self.doJustify = False  # Justify text
        self.showTabsNSpaces = False  # Show tabs and spaces in edior
        self.showLineEndings = False  # Show line endings in editor

        self.doReplace = True  # Enable auto-replace as you type
        self.doReplaceSQuote = True  # Smart single quotes
        self.doReplaceDQuote = True  # Smart double quotes
        self.doReplaceDash = True  # Replace multiple hyphens with dashes
        self.doReplaceDots = True  # Replace three dots with ellipsis

        self.scrollPastEnd = True  # Allow scrolling past end of document
        self.autoScroll = False  # Typewriter-like scrolling
        self.autoScrollPos = 30  # Start point for typewriter-like scrolling

        self.wordCountTimer = 5.0  # Interval for word count update in seconds
        self.bigDocLimit = 800  # Size threshold for heavy editor features in kilobytes

        self.highlightQuotes = True  # Highlight text in quotes
        self.highlightEmph = True  # Add colour to text emphasis

        ## User-Selected Symbols
        self.fmtApostrophe = nwUnicode.U_RSQUO
        self.fmtSingleQuotes = [nwUnicode.U_LSQUO, nwUnicode.U_RSQUO]
        self.fmtDoubleQuotes = [nwUnicode.U_LDQUO, nwUnicode.U_RDQUO]

        ## Spell Checking
        self.spellTool = None
        self.spellLanguage = None

        ## Search Bar Switches
        self.searchCase = False
        self.searchWord = False
        self.searchRegEx = False
        self.searchLoop = False
        self.searchNextFile = False
        self.searchMatchCap = False

        ## Backup
        self.backupPath = ""
        self.backupOnClose = False
        self.askBeforeBackup = True

        ## State
        self.showRefPanel = True
        self.viewComments = True
        self.viewSynopsis = True

        # Check Qt5 Versions
        verQt = splitVersionNumber(QT_VERSION_STR)
        self.verQtString = QT_VERSION_STR
        self.verQtMajor = verQt[0]
        self.verQtMinor = verQt[1]
        self.verQtPatch = verQt[2]
        self.verQtValue = verQt[3]

        verQt = splitVersionNumber(PYQT_VERSION_STR)
        self.verPyQtString = PYQT_VERSION_STR
        self.verPyQtMajor = verQt[0]
        self.verPyQtMinor = verQt[1]
        self.verPyQtPatch = verQt[2]
        self.verPyQtValue = verQt[3]

        # Check Python Version
        self.verPyString = sys.version.split()[0]
        self.verPyMajor = sys.version_info[0]
        self.verPyMinor = sys.version_info[1]
        self.verPyPatch = sys.version_info[2]
        self.verPyHexVal = sys.hexversion

        # Check OS Type
        self.osType = sys.platform
        self.osLinux = False
        self.osWindows = False
        self.osDarwin = False
        self.osUnknown = False
        if self.osType.startswith("linux"):
            self.osLinux = True
        elif self.osType.startswith("darwin"):
            self.osDarwin = True
        elif self.osType.startswith("win32"):
            self.osWindows = True
        elif self.osType.startswith("cygwin"):
            self.osWindows = True
        else:
            self.osUnknown = True

        # Other System Info
        if self.verQtValue >= 50600:
            self.hostName = QSysInfo.machineHostName()
            self.kernelVer = QSysInfo.kernelVersion()
        else:
            self.hostName = "Unknown"
            self.kernelVer = "Unknown"

        # Packages
        self.hasEnchant = False  # The pyenchant package
        self.hasAssistant = False  # The Qt Assistant executable

        # Recent Cache
        self.recentProj = {}

        return