Exemplo n.º 1
0
 def offerAssistance(self):
     """
     Offer to fulfill certain incomplete tasks evident from the state of the passage text.
     (Technically, none of this needs to be on passageFrame instead of passageWidget.)
     """
     
     # Offer to create passage for broken links
     if self.app.config.ReadBool('createPassagePrompt'):
         brokens = links = filter(lambda text: TweeLexer.linkStyle(text) == TweeLexer.BAD_LINK, self.widget.getBrokenLinks())
         if brokens :
             if len(brokens) > 1:
                 brokenmsg = 'create ' + str(len(brokens)) + ' new passages to match these broken links?'
             else:
                 brokenmsg = 'create the passage "' + brokens[0] + '"?'
             dialog = wx.MessageDialog(self, 'Do you want to ' + brokenmsg, 'Create Passages', \
                                               wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.YES_DEFAULT)
             check = dialog.ShowModal()
             if check == wx.ID_YES:
                 for title in brokens:
                     self.widget.parent.newWidget(title = title, pos = self.widget.parent.toPixels (self.widget.pos))
             elif check == wx.ID_CANCEL:
                 return
     
     # Offer to import external images
     if self.app.config.ReadBool('importImagePrompt'):
         regex = tweeregex.EXTERNAL_IMAGE_REGEX
         externalimages = re.finditer(regex, self.widget.passage.text)
         check = None
         downloadedurls = {}
         storyframe = self.widget.parent.parent
         for img in externalimages:
             if not check:
                 dialog = wx.MessageDialog(self, 'Do you want to import the image files linked\nin this passage into the story file?', 'Import Images', \
                                               wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.YES_DEFAULT);
                 check = dialog.ShowModal()
                 if check == wx.ID_NO:
                     break  
                 elif check == wx.ID_CANCEL:
                     return
             # Download the image if it's at an absolute URL
             imgurl = img.group(4) or img.group(7)
             if not imgurl:
                 continue
             # If we've downloaded it before, don't do it again
             if imgurl not in downloadedurls:
                 # Internet image, or local image?
                 if any(imgurl.startswith(t) for t in ['http://', 'https://', 'ftp://']):
                     imgpassagename = storyframe.importImageURL(imgurl, showdialog=False)
                 else:
                     imgpassagename = storyframe.importImageFile(storyframe.getLocalDir()+os.sep+imgurl, showdialog=False)
                 if not imgpassagename:
                     continue
                 downloadedurls[imgurl] = imgpassagename
         
         # Replace all found images
         for old, new in downloadedurls.iteritems():
             self.widget.passage.text = re.sub(regex.replace(tweeregex.IMAGE_FILENAME_REGEX, re.escape(old)),
                                               lambda m: m.group(0).replace(old, new), self.widget.passage.text)
     
     self.bodyInput.SetText(self.widget.passage.text)
Exemplo n.º 2
0
    def updateSubmenus(self, event=None):
        """
        Updates our passage menus. This should be called sparingly, i.e. not during
        a UI update event, as it is doing a bunch of removing and adding of items.
        """

        # separate outgoing and broken links

        outgoing = []
        incoming = []
        broken = []

        # Remove externals

        links = filter(lambda text: TweeLexer.linkStyle(text) == TweeLexer.BAD_LINK, self.widget.passage.links)
        for link in links:
            if len(link) > 0:
                if link in self.widget.parent.widgetDict:
                    outgoing.append(link)
                elif not self.widget.parent.includedPassageExists(link):
                    broken.append(link)

        # incoming links

        for widget in self.widget.parent.widgetDict.itervalues():
            if self.widget.passage.title in widget.passage.links and len(widget.passage.title) > 0:
                incoming.append(widget.passage.title)

        # repopulate the menus

        def populate(menu, links):
            for item in menu.GetMenuItems():
                menu.DeleteItem(item)

            if len(links):
                for link in links:
                    item = menu.Append(-1, link)
                    self.Bind(wx.EVT_MENU, self.openOtherEditor, item)
            else:
                item = menu.Append(wx.ID_ANY, "(None)")
                item.Enable(False)

        outTitle = "Outgoing Links"
        if len(outgoing) > 0:
            outTitle += " (" + str(len(outgoing)) + ")"
        self.outLinksMenuTitle.SetText(outTitle)
        populate(self.outLinksMenu, outgoing)

        inTitle = "Incoming Links"
        if len(incoming) > 0:
            inTitle += " (" + str(len(incoming)) + ")"
        self.inLinksMenuTitle.SetText(inTitle)
        populate(self.inLinksMenu, incoming)

        brokenTitle = "Broken Links"
        if len(broken) > 0:
            brokenTitle += " (" + str(len(broken)) + ")"
        self.brokenLinksMenuTitle.SetText(brokenTitle)
        populate(self.brokenLinksMenu, broken)
Exemplo n.º 3
0
    def update(self):
        """
        Update the lists of all passages linked/displayed by this one.
        Returns internal links and <<choice>>/<<actions>> macros.
        """
        if not self.isStoryText() and not self.isAnnotation() and not self.isStylesheet():
            self.displays = []
            self.links = []
            self.images = []
            self.macros = []
            return

        # <<display>>
        self.displays = list(set(re.findall(r'\<\<display\s+[\'"]?(.+?)[\'"]?\s?\>\>', self.text, re.IGNORECASE)))

        macros = set()
        # other macros (including shorthand <<display>>)
        for m in re.finditer(tweeregex.MACRO_REGEX, self.text):
            # Exclude shorthand <<print>>
            if m.group(1) and m.group(1)[0] != '$':
                macros.add(m.group(1))
        self.macros = list(macros)
        
        # avoid duplicates by collecting links in a set
        links = set()

        # Regular hyperlinks (also matches wiki-style links inside macros)
        for m in re.finditer(tweeregex.LINK_REGEX, self.text):
            # Exclude external links
            link = m.group(2) or m.group(1)
            if TweeLexer.linkStyle(link) != TweeLexer.EXTERNAL:
                links.add(m.group(2) or m.group(1))

        # Include images
        for m in re.finditer(tweeregex.IMAGE_REGEX, self.text):
            if m.group(5):
                links.add(m.group(5))

        # <<choice passage_name [link_text]>>
        for block in re.findall(r'\<\<choice\s+(.*?)\s?\>\>', self.text):
            item = re.match(r'(?:"([^"]*)")|(?:\'([^\']*)\')|([^"\'\[\s]\S*)', block)
            if item:
                links.add(''.join(item.groups('')))

        # <<actions '' ''>>
        for block in re.findall(r'\<\<actions\s+(.*?)\s?\>\>', self.text):
            links.update(re.findall(r'[\'"](.*?)[\'"]', block))

        self.links = list(links)

        # Images

        images = set()
        for block in re.finditer(tweeregex.IMAGE_REGEX, self.text):
            images.add(block.group(4))

        self.images = list(images)
Exemplo n.º 4
0
    def updateSubmenus(self, event = None):
        """
        Updates our passage menus. This should be called sparingly, i.e. not during
        a UI update event, as it is doing a bunch of removing and adding of items.
        """

        # separate outgoing and broken links

        outgoing = []
        incoming = []
        broken = []

        # Remove externals

        for link in self.widget.passage.links:
            if len(link) > 0 and TweeLexer.linkStyle(link) == TweeLexer.BAD_LINK:
                if link in self.widget.parent.widgetDict:
                    outgoing.append(link)
                elif not self.widget.parent.includedPassageExists(link):
                    broken.append(link)

        # incoming links

        for widget in self.widget.parent.widgetDict.values():
            if self.widget.passage.title in widget.passage.links \
            and len(widget.passage.title) > 0:
                incoming.append(widget.passage.title)

        # repopulate the menus

        def populate(menu, links):
            for item in menu.GetMenuItems():
                menu.DeleteItem(item)

            if len(links):
                for link in links:
                    item = menu.Append(-1, link)
                    self.Bind(wx.EVT_MENU, self.openOtherEditor, item)
            else:
                item = menu.Append(wx.ID_ANY, '(None)')
                item.Enable(False)

        outTitle = 'Outgoing Links'
        if len(outgoing) > 0: outTitle += ' (' + str(len(outgoing)) + ')'
        self.outLinksMenuTitle.SetText(outTitle)
        populate(self.outLinksMenu, outgoing)

        inTitle = 'Incoming Links'
        if len(incoming) > 0: inTitle += ' (' + str(len(incoming)) + ')'
        self.inLinksMenuTitle.SetText(inTitle)
        populate(self.inLinksMenu, incoming)

        brokenTitle = 'Broken Links'
        if len(broken) > 0: brokenTitle += ' (' + str(len(broken)) + ')'
        self.brokenLinksMenuTitle.SetText(brokenTitle)
        populate(self.brokenLinksMenu, broken)
Exemplo n.º 5
0
    def update(self):
        """
        Update the lists of all passages linked/displayed by this one.
        Returns internal links and <<choice>>/<<actions>> macros.
        """
        if not self.isStoryText() and not self.isAnnotation() and not self.isStylesheet():
            self.displays = []
            self.links = []
            self.images = []
            self.macros = []
            return

        images = set()
        macros = set()
        links = set()
        
        # <<display>>
        self.displays = list(set(re.findall(r'\<\<display\s+[\'"]?(.+?)[\'"]?\s?\>\>', self.text, re.IGNORECASE)))

        macros = set()
        # other macros (including shorthand <<display>>)
        for m in re.finditer(tweeregex.MACRO_REGEX, self.text):
            # Exclude shorthand <<print>>
            if m.group(1) and m.group(1)[0] != '$':
                macros.add(m.group(1))
        self.macros = list(macros)

        # Regular hyperlinks (also matches wiki-style links inside macros)
        for m in re.finditer(tweeregex.LINK_REGEX, self.text):
            # Exclude external links
            link = m.group(2) or m.group(1)
            if TweeLexer.linkStyle(link) != TweeLexer.EXTERNAL:
                links.add(m.group(2) or m.group(1))

        # Include images
        for m in re.finditer(tweeregex.IMAGE_REGEX, self.text):
            if m.group(5):
                links.add(m.group(5))
                
        # HTML data-passage links
        for m in re.finditer(tweeregex.HTML_REGEX, self.text):
            attrs = m.group(2)
            if attrs:
                dataPassage = re.search(r"""data-passage\s*=\s*(?:([^<>'"=`\s]+)|'((?:[^'\\]*\\.)*[^'\\]*)'|"((?:[^"\\]*\\.)*[^"\\]*)")""", attrs)
                if dataPassage:
                    theSet = images if m.group(1) == "img" else links
                    theSet.add(dataPassage.group(1) or dataPassage.group(2) or dataPassage.group(3))
                
        # <<choice passage_name [link_text]>>
        for block in re.findall(r'\<\<choice\s+(.*?)\s?\>\>', self.text):
            item = re.match(r'(?:"([^"]*)")|(?:\'([^\']*)\')|([^"\'\[\s]\S*)', block)
            if item:
                links.add(''.join(item.groups('')))

        # <<actions '' ''>>
        for block in re.findall(r'\<\<actions\s+(.*?)\s?\>\>', self.text):
            links.update(re.findall(r'[\'"](.*?)[\'"]', block))

        self.links = list(links)

        # Images

        for block in re.finditer(tweeregex.IMAGE_REGEX, self.text):
            images.add(block.group(4))

        self.images = list(images)
Exemplo n.º 6
0
 def addLink(link):
     style = TweeLexer.linkStyle(link)
     if style == TweeLexer.PARAM:
         variableLinks.add(link)
     elif style != TweeLexer.EXTERNAL:
         links.add(link)
Exemplo n.º 7
0
 def addLink(link):
     style = TweeLexer.linkStyle(link)
     if style == TweeLexer.PARAM:
         variableLinks.add(link)
     elif style != TweeLexer.EXTERNAL:
         links.add(link)
Exemplo n.º 8
0
    def update(self):
        """
        Update the lists of all passages linked/displayed by this one.
        Returns internal links and <<choice>>/<<actions>> macros.
        """
        if not self.isStoryText() and not self.isAnnotation(
        ) and not self.isStylesheet():
            self.displays = []
            self.links = []
            self.images = []
            self.macros = []
            return

        # <<display>>
        self.displays = list(
            set(
                re.findall(r'\<\<display\s+[\'"]?(.+?)[\'"]?\s?\>\>',
                           self.text, re.IGNORECASE)))

        macros = set()
        # other macros (including shorthand <<display>>)
        for m in re.finditer(tweeregex.MACRO_REGEX, self.text):
            # Exclude shorthand <<print>>
            if m.group(1) and m.group(1)[0] != '$':
                macros.add(m.group(1))
        self.macros = list(macros)

        # avoid duplicates by collecting links in a set
        links = set()

        # Regular hyperlinks (also matches wiki-style links inside macros)
        for m in re.finditer(tweeregex.LINK_REGEX, self.text):
            # Exclude external links
            link = m.group(2) or m.group(1)
            if TweeLexer.linkStyle(link) != TweeLexer.EXTERNAL:
                links.add(m.group(2) or m.group(1))

        # Include images
        for m in re.finditer(tweeregex.IMAGE_REGEX, self.text):
            if m.group(5):
                links.add(m.group(5))

        # <<choice passage_name [link_text]>>
        for block in re.findall(r'\<\<choice\s+(.*?)\s?\>\>', self.text):
            item = re.match(r'(?:"([^"]*)")|(?:\'([^\']*)\')|([^"\'\[\s]\S*)',
                            block)
            if item:
                links.add(''.join(item.groups('')))

        # <<actions '' ''>>
        for block in re.findall(r'\<\<actions\s+(.*?)\s?\>\>', self.text):
            links.update(re.findall(r'[\'"](.*?)[\'"]', block))

        self.links = list(links)

        # Images

        images = set()
        for block in re.finditer(tweeregex.IMAGE_REGEX, self.text):
            images.add(block.group(4))

        self.images = list(images)
Exemplo n.º 9
0
    def offerAssistance(self):
        """
        Offer to fulfill certain incomplete tasks evident from the state of the passage text.
        (Technically, none of this needs to be on passageFrame instead of passageWidget.)
        """

        # Offer to create passage for broken links
        if self.app.config.ReadBool('createPassagePrompt'):
            brokens = [link for link in self.widget.getBrokenLinks() if TweeLexer.linkStyle(link) == TweeLexer.BAD_LINK]
            if brokens :
                if len(brokens) > 1:
                    brokenmsg = 'create ' + str(len(brokens)) + ' new passages to match these broken links?'
                else:
                    brokenmsg = 'create the passage "' + brokens[0] + '"?'
                dialog = wx.MessageDialog(self, 'Do you want to ' + brokenmsg, 'Create Passages', \
                                                  wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.YES_DEFAULT)
                check = dialog.ShowModal()
                if check == wx.ID_YES:
                    for title in brokens:
                        self.widget.parent.newWidget(title = title, pos = self.widget.parent.toPixels (self.widget.pos))
                elif check == wx.ID_CANCEL:
                    return False

        # Offer to import external images
        if self.app.config.ReadBool('importImagePrompt'):
            regex = tweeregex.EXTERNAL_IMAGE_REGEX
            externalimages = re.finditer(regex, self.widget.passage.text)
            check = None
            downloadedurls = {}
            storyframe = self.widget.parent.parent
            for img in externalimages:
                if not check:
                    dialog = wx.MessageDialog(self, 'Do you want to import the image files linked\nin this passage into the story file?', 'Import Images', \
                                                  wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.YES_DEFAULT)
                    check = dialog.ShowModal()
                    if check == wx.ID_NO:
                        break
                    elif check == wx.ID_CANCEL:
                        return False
                # Download the image if it's at an absolute URL
                imgurl = img.group(4) or img.group(7)
                if not imgurl:
                    continue
                # If we've downloaded it before, don't do it again
                if imgurl not in downloadedurls:
                    # Internet image, or local image?
                    if isURL(imgurl):
                        imgpassagename = storyframe.importImageURL(imgurl, showdialog=False)
                    else:
                        imgpassagename = storyframe.importImageFile(storyframe.getLocalDir()+os.sep+imgurl, showdialog=False)
                    if not imgpassagename:
                        continue
                    downloadedurls[imgurl] = imgpassagename

            # Replace all found images
            for old, new in downloadedurls.items():
                self.widget.passage.text = re.sub(regex.replace(tweeregex.IMAGE_FILENAME_REGEX, re.escape(old)),
                                                  lambda m: m.group(0).replace(old, new), self.widget.passage.text)

        if self.bodyInput.GetText() != self.widget.passage.text:
            self.bodyInput.SetText(self.widget.passage.text)

        # If it's StoryIncludes, update the links
        if self.widget.passage.title == "StoryIncludes":
            self.widget.parent.refreshIncludedPassageList()

        return True