def write(self, text):
        '''
        Output specified text with the appropriate timestamp
        prefix.
        '''
        self.ts_LineCount += 1
        if self.ts_LineCount <= self.ts_LastHeaderLine or \
           text == '\n':

            self.ts_File.write(text)

        else:

            self.ts_File.write('%s - %s' % (
                tsru.getDateTimeString(time.time()), text))
    def tsCreateScrollableRedirectionLog(self):
        '''
        Return file instance used for scrollable redirected output.
        '''
        # TBD - Begin prototype for Scrollable Redirection Window
        # Will need an application instance specific file name.
        theDirectory = os.getcwd()
        theWindowTitle = self.ts_Title
        theKeyWord = theWindowTitle.split(' ', 1)
        theNickName = theKeyWord[0].strip('_').title()
        theFileName = '%s-stdout' % theNickName

        if True:
            thePathName = os.path.join(
                tsLogger.TsLogger.defaultStandardOutputPath,
                '%s.log' % theFileName)
        else:
            thePathName = tsru.getNextPathName(theDirectory, theFileName)
 
        theLogFile = open(thePathName, 'w')

        theLogFileHeader = tsru.getSeparatorString(
            title='Begin %s on %s' % (
                'PRINT/STDOUT/STDERR log',
                tsru.getDateAndTimeString(time.time())),
            indent=0,
            position=tsru.layout['TitleIndent'],
            separatorCharacter='$',
            tab=4)

        theLogFile.write('%s\n\n' % theLogFileHeader)
        theLogFile.write('%s - Started logging to file "%s".\n\n' % (
            tsru.getDateTimeString(time.time(), msec=True),
            thePathName))
        # TBD - End prototype for Scrollable Redirection Window
        return (theLogFile)
    def write(self, text):
        '''
        Create the output window if needed and write the string to it.
        If not called in the context of the gui thread then uses CallAfter
        to do the work there.

        NOTE: In accordance with Python convention, this method supports the
        formating of a single line of output across multiple print statements.
        '''
        if self.ts_Frame is None:
 
            msg1 = 'Print statements and other standard output '
            msg2 = 'will now be directed to this window.'

            if wx.ThemeToUse['Stdio']['Timestamp']:
                theStartupText = '\n\n%s\n' % (msg1 + msg2)
            else:
                theStartupText = '%s\n' % (msg1 + msg2)

            if wx.ThemeToUse['Stdio']['Timestamp']:
                # Begin the new record with a timestamp.
                timestamp = tsru.getDateTimeString(time.time(), msec=True)
                self.ts_Cache += '%s - %s' % (timestamp, theStartupText)
            else:
                # Append the text to the existing record.
                self.ts_Cache += theStartupText

            self.CreateOutputWindow(theStartupText)

        if self.ts_logFile is None and \
           wx.ThemeToUse['Stdio']['ScrollableLogFile']:
            self.ts_logFile = self.tsCreateScrollableRedirectionLog()

        theMarkup = None
        if self.ts_Frame.display.HasColors:
            # TBD - Fix so that we pass Attributes without colors.
            for theKey in wx.ThemeToUse['Stdio']['Markup'].keys():

                thePriorityKey = '%s:' % theKey
                theKeyPosition = text.find(thePriorityKey)
                ## print('theKeyPosition[%s] = %d' % (theKey, theKeyPosition))
                if (theKeyPosition > -1):
                    theMarkup = wx.ThemeToUse['Stdio']['Markup'][theKey]
                    ## print('theKeyPosition[%s] = %d' % (
                    ##     theKey, theKeyPosition))

                    break

        # Original design based on wxPyOnDemandOutputWindow
        # without markup

        if theMarkup is None:

            # Apply default markup to increase brightness/conrtrast
            # in order to improve readability
            theKey = 'DEFAULT'
            theMarkup = wx.ThemeToUse['Stdio']['Markup'][theKey]

        if self.ts_Text is not None:

            terminalCharacter = len(text)
            terminalNewLine = text[
                terminalCharacter - 1:terminalCharacter] == '\n'

            if text not in list(printMarkupToIgnore.keys()):

                if (self.ts_Cache == wx.EmptyString):

                    # Begin the new record with a timestamp.
                    timestamp = tsru.getDateTimeString(time.time(),
                                                       msec=True)
                    self.ts_Cache += '%s - %s' % (timestamp, text)

                else:

                    # Append the text to the existing record.
##                    timestamp = wx.EmptyString
##                    theMarkup = None
                    self.ts_Cache += text

                if terminalNewLine:

                    # End and output those existing records that
                    # contain a new line.
                    self.ts_Text.AppendText(self.ts_Cache,
                                            markup=theMarkup)
                    self.tsUpdateScrollableRedirectionLog(self.ts_Cache)
                    self.ts_Cache = wx.EmptyString

            elif terminalNewLine:

                # End and output those existing records that
                # would now contain a new line.
                self.ts_Text.AppendText(self.ts_Cache, markup=theMarkup)
                self.tsUpdateScrollableRedirectionLog(self.ts_Cache)
                self.ts_Cache = wx.EmptyString

            else:

                # Append the text to the existing record.
                self.ts_Cache += text

        self.ts_Frame.Show(True)
                msg = "tsWxApp: %s" % fileStdioDevicesError
                raise tse.ProgramException(
                    tse.APPLICATION_TRAP, msg)

            theLogFileHeader = tsru.getSeparatorString(
                title='Begin %s on %s' % (
                    'PRINT/STDOUT/STDERR log',
                    tsru.getDateAndTimeString(time.time())),
                indent=0,
                position=tsru.layout['TitleIndent'],
                separatorCharacter='$',
                tab=4)

            self.stdioLog.write('%s\n\n' % theLogFileHeader)
            self.stdioLog.write('%s - Started logging to file "%s".\n\n' % (
                tsru.getDateTimeString(time.time()),
                filename))

            msg1 = 'Print statements and other standard output '
            msg2 = 'will now be directed to this file.'
            self.stdioLog.write('%s\n' % (msg1 + msg2))

            self.stdioLog.flush()

    #-----------------------------------------------------------------------

    def RestoreStdio(self):
        '''
        Restore sys.stdout and sys.stderr.
        '''
        try:
    def RedirectStdio(self, filename=None):
        '''
        Redirect sys.stdout and sys.stderr to a file or a popup window.
        '''
        # Verify user accessibility of one library known to be in hierarchy.
        try:
            preRedirectStdioDevices = {'stdout': sys.stdout,
                                       'stderr': sys.stderr,
                                       ' stdin': sys.stdin}

            for theKey in list(preRedirectStdioDevices.keys()):
                self.logger.debug(
                    '    Saved %s %s' % (
                        theKey, preRedirectStdioDevices[theKey]))
        except Exception as preRedirectStdioDevicesError:
            msg = "tsWxApp: %s" % preRedirectStdioDevicesError
            raise tse.ProgramException(
                tse.APPLICATION_TRAP, msg)

        # Save configuration for future restoration by RestoreStdio.
        self.saveStdio = (sys.stdout, sys.stderr)

        if filename is None:

            # Redirect output to a window on the screen.
            # Capture redirected output to a default file for scrolling.
            # TBD - How can this support the ThemeToUse Timestamp feature?
            self.stdioWin = self.outputWindowClass(wx.ThemeToUse['Stdio']['Title'])
            sys.stdout = self.stdioWin
            sys.stderr = self.stdioWin

            try:
                windowStdioDevices = {'stdout': sys.stdout,
                                      'stderr': sys.stderr,
                                      ' stdin': sys.stdin}

                for theKey in list(windowStdioDevices.keys()):
                    self.logger.debug(
                        '    Saved %s %s' % (
                            theKey, windowStdioDevices[theKey]))
            except Exception as windowStdioDevicesError:
                msg = "tsWxApp: %s" % windowStdioDevicesError
                raise tse.ProgramException(
                    tse.APPLICATION_TRAP, msg)

        else:
 
            # Redirect output to the specified file.
            # Setting buffer size of 0 eliminates need for flushing.
            if wx.ThemeToUse['Stdio']['Timestamp']:
                self.stdioLog = tsCustomStdioFile(filename, 'w', 1)
            else:
                self.stdioLog = open(filename, 'w', 1)

            sys.stdout = self.stdioLog
            sys.stderr = self.stdioLog

            try:
                fileStdioDevices = {'stdout': sys.stdout,
                                      'stderr': sys.stderr,
                                      ' stdin': sys.stdin}

                for theKey in list(fileStdioDevices.keys()):
                    self.logger.debug(
                        '    Saved %s %s' % (
                            theKey, fileStdioDevices[theKey]))
            except Exception as fileStdioDevicesError:
                msg = "tsWxApp: %s" % fileStdioDevicesError
                raise tse.ProgramException(
                    tse.APPLICATION_TRAP, msg)

            theLogFileHeader = tsru.getSeparatorString(
                title='Begin %s on %s' % (
                    'PRINT/STDOUT/STDERR log',
                    tsru.getDateAndTimeString(time.time())),
                indent=0,
                position=tsru.layout['TitleIndent'],
                separatorCharacter='$',
                tab=4)

            self.stdioLog.write('%s\n\n' % theLogFileHeader)
            self.stdioLog.write('%s - Started logging to file "%s".\n\n' % (
                tsru.getDateTimeString(time.time()),
                filename))

            msg1 = 'Print statements and other standard output '
            msg2 = 'will now be directed to this file.'
            self.stdioLog.write('%s\n' % (msg1 + msg2))

            self.stdioLog.flush()