Exemplo n.º 1
0
 def updateLabelColor(self, index):
     # px = QPixmap(64, 64)
     # px.fill(iconColor(self.mw.mdlLabels.item(index.row()).icon()))
     # self.btnLabelColor.setIcon(QIcon(px))
     self.btnLabelColor.setStyleSheet(
         "background:{};".format(iconColor(self.mw.mdlLabels.item(index.row()).icon()).name()))
     self.btnLabelColor.setEnabled(True)
Exemplo n.º 2
0
 def updateLabelColor(self, index):
     # px = QPixmap(64, 64)
     # px.fill(iconColor(self.mw.mdlLabels.item(index.row()).icon()))
     # self.btnLabelColor.setIcon(QIcon(px))
     self.btnLabelColor.setStyleSheet("background:{};".format(
         iconColor(self.mw.mdlLabels.item(index.row()).icon()).name()))
     self.btnLabelColor.setEnabled(True)
Exemplo n.º 3
0
 def setLabelColor(self):
     index = self.lstLabels.currentIndex()
     color = iconColor(self.mw.mdlLabels.item(index.row()).icon())
     self.colorDialog = QColorDialog(color, self)
     color = self.colorDialog.getColor(color)
     if color.isValid():
         px = QPixmap(32, 32)
         px.fill(color)
         self.mw.mdlLabels.item(index.row()).setIcon(QIcon(px))
         self.updateLabelColor(index)
Exemplo n.º 4
0
 def setLabelColor(self):
     index = self.lstLabels.currentIndex()
     color = iconColor(self.mw.mdlLabels.item(index.row()).icon())
     self.colorDialog = QColorDialog(color, self)
     color = self.colorDialog.getColor(color)
     if color.isValid():
         px = QPixmap(32, 32)
         px.fill(color)
         self.mw.mdlLabels.item(index.row()).setIcon(QIcon(px))
         self.updateLabelColor(index)
Exemplo n.º 5
0
 def chosePersoColor(self):
     idx = self.currentPersoIndex()
     item = self.item(idx.row(), Perso.name.value)
     if item:
         color = iconColor(item.icon())
     else:
         color = Qt.white
     self.colorDialog = QColorDialog(color, self.mw)
     color = self.colorDialog.getColor(color)
     if color.isValid():
         self.setPersoColor(item, color)
         self.updatePersoColor(idx)
Exemplo n.º 6
0
 def choseCharacterColor(self):
     ID = self.currentCharacterID()
     c = self._model.getCharacterByID(ID)
     if c:
         color = iconColor(c.icon)
     else:
         color = Qt.white
     self.colorDialog = QColorDialog(color, mainWindow())
     color = self.colorDialog.getColor(color)
     if color.isValid():
         c.setColor(color)
         mainWindow().updateCharacterColor(ID)
Exemplo n.º 7
0
 def choseCharacterColor(self):
     ID = self.currentCharacterID()
     c = self._model.getCharacterByID(ID)
     if c:
         color = iconColor(c.icon)
     else:
         color = Qt.white
     self.colorDialog = QColorDialog(color, mainWindow())
     color = self.colorDialog.getColor(color)
     if color.isValid():
         c.setColor(color)
         mainWindow().updateCharacterColor(ID)
Exemplo n.º 8
0
def saveItem(root, mdl, parent=QModelIndex()):
    for x in range(mdl.rowCount(parent)):
        row = ET.SubElement(root, "row")
        row.attrib["row"] = str(x)
        
        for y in range(mdl.columnCount(parent)):
            col = ET.SubElement(row, "col")
            col.attrib["col"] = str(y)
            if mdl.data(mdl.index(x, y, parent), Qt.DecorationRole) != None:
                color = iconColor(mdl.data(mdl.index(x, y, parent), Qt.DecorationRole)).name(QColor.HexArgb)
                col.attrib["color"] = color if color != "#ff000000" else "#00000000"
            if mdl.data(mdl.index(x, y, parent)) != "":
                col.text = mdl.data(mdl.index(x, y, parent))
            if mdl.hasChildren(mdl.index(x, y, parent)):
                saveItem(col, mdl, mdl.index(x, y, parent))
Exemplo n.º 9
0
def saveItem(root, mdl, parent=QModelIndex()):
    for x in range(mdl.rowCount(parent)):
        row = ET.SubElement(root, "row")
        row.attrib["row"] = str(x)

        for y in range(mdl.columnCount(parent)):
            col = ET.SubElement(row, "col")
            col.attrib["col"] = str(y)
            if mdl.data(mdl.index(x, y, parent), Qt.DecorationRole) != None:
                color = iconColor(
                    mdl.data(mdl.index(x, y, parent),
                             Qt.DecorationRole)).name(QColor.HexArgb)
                col.attrib[
                    "color"] = color if color != "#ff000000" else "#00000000"
            if mdl.data(mdl.index(x, y, parent)) != "":
                col.text = mdl.data(mdl.index(x, y, parent))
            if mdl.hasChildren(mdl.index(x, y, parent)):
                saveItem(col, mdl, mdl.index(x, y, parent))
Exemplo n.º 10
0
def test_several():

    from PyQt5.QtGui import QPainter, QPixmap, QIcon, QColor
    from PyQt5.QtCore import QRect

    # drawProgress
    px = QPixmap(10, 10)
    F.drawProgress(QPainter(px), QRect(0, 0, 100, 100), 0.5)

    # colorFromProgress
    a = F.colorFromProgress(0.1)
    b = F.colorFromProgress(0.5)
    c = F.colorFromProgress(1.0)
    d = F.colorFromProgress(1.5)
    assert a != b != c != d

    # iconColor & iconFromColor & iconFromColorString
    icon = F.iconFromColorString("#ff0000")
    assert F.iconColor(icon).name().lower() == "#ff0000"

    # themeIcon
    assert F.themeIcon("text") != None
    assert F.themeIcon("nonexistingname") != None

    # randomColor
    c1 = F.randomColor()
    c2 = F.randomColor(c1)
    assert c1.name() != c2.name()

    # mixColors
    c1 = QColor("#FFF")
    c2 = QColor("#000")
    assert F.mixColors(c1, c2).name() == "#7f7f7f"

    # colorifyPixmap
    assert F.colorifyPixmap(px, c1) != None
Exemplo n.º 11
0
def test_several():

    from PyQt5.QtGui import QPainter, QPixmap, QIcon, QColor
    from PyQt5.QtCore import QRect

    # drawProgress
    px = QPixmap(10, 10)
    F.drawProgress(QPainter(px), QRect(0, 0, 100, 100), 0.5)

    # colorFromProgress
    a = F.colorFromProgress(0.1)
    b = F.colorFromProgress(0.5)
    c = F.colorFromProgress(1.0)
    d = F.colorFromProgress(1.5)
    assert a != b != c != d

    # iconColor & iconFromColor & iconFromColorString
    icon = F.iconFromColorString("#ff0000")
    assert F.iconColor(icon).name().lower() == "#ff0000"

    # themeIcon
    assert F.themeIcon("text") is not None
    assert F.themeIcon("nonexistingname") is not None

    # randomColor
    c1 = F.randomColor()
    c2 = F.randomColor(c1)
    assert c1.name() != c2.name()

    # mixColors
    c1 = QColor("#FFF")
    c2 = QColor("#000")
    assert F.mixColors(c1, c2).name() == "#7f7f7f"

    # colorifyPixmap
    assert F.colorifyPixmap(px, c1) != None
Exemplo n.º 12
0
 def getPersoColorName(self, index):
     icon = self.item(index.row()).icon()
     return iconColor(icon).name() if icon else ""
Exemplo n.º 13
0
 def color(self):
     """
     Returns character's color in QColor
     @return: QColor
     """
     return iconColor(self.icon)
Exemplo n.º 14
0
def saveProject(zip=None):
    """
    Saves the project. If zip is False, the project is saved as a multitude of plain-text files for the most parts
    and some XML or zip? for settings and stuff.
    If zip is True, everything is saved as a single zipped file. Easier to carry around, but does not allow
    collaborative work, versionning, or third-party editing.
    @param zip: if True, saves as a single file. If False, saves as plain-text. If None, tries to determine based on
    settings.
    @return: True if successful, False otherwise.
    """
    if zip is None:
        zip = settings.saveToZip

    log("\n\nSaving to:", "zip" if zip else "folder")

    # List of files to be written
    files = []
    # List of files to be removed
    removes = []
    # List of files to be moved
    moves = []

    mw = mainWindow()

    # File format version
    files.append(("MANUSKRIPT", "1"))

    # General infos (book and author)
    # Saved in plain text, in infos.txt

    path = "infos.txt"
    content = ""
    for name, col in [
            ("Title", 0),
            ("Subtitle", 1),
            ("Serie", 2),
            ("Volume", 3),
            ("Genre", 4),
            ("License", 5),
            ("Author", 6),
            ("Email", 7),
            ]:
        item = mw.mdlFlatData.item(0, col)
        if item:
            val = item.text().strip()
        else:
            val = ""

        if val:
            content += "{name}:{spaces}{value}\n".format(
                name=name,
                spaces=" " * (15 - len(name)),
                value=val
            )
    files.append((path, content))

    ####################################################################################################################
    # Summary
    # In plain text, in summary.txt

    path = "summary.txt"
    content = ""
    for name, col in [
            ("Situation", 0),
            ("Sentence", 1),
            ("Paragraph", 2),
            ("Page", 3),
            ("Full", 4),
            ]:
        item = mw.mdlFlatData.item(1, col)
        if item:
            val = item.text().strip()
        else:
            val = ""

        if val:
            content += formatMetaData(name, val, 12)

    files.append((path, content))

    ####################################################################################################################
    # Label & Status
    # In plain text

    for mdl, path in [
        (mw.mdlStatus, "status.txt"),
        (mw.mdlLabels, "labels.txt")
    ]:

        content = ""

        # We skip the first row, which is empty and transparent
        for i in range(1, mdl.rowCount()):
            color = ""
            if mdl.data(mdl.index(i, 0), Qt.DecorationRole) is not None:
                color = iconColor(mdl.data(mdl.index(i, 0), Qt.DecorationRole)).name(QColor.HexRgb)
                color = color if color != "#ff000000" else "#00000000"

            text = mdl.data(mdl.index(i, 0))

            if text:
                content += "{name}{color}\n".format(
                    name=text,
                    color="" if color == "" else ":" + " " * (20 - len(text)) + color
                )

        files.append((path, content))

    ####################################################################################################################
    # Characters
    # In a character folder

    path = os.path.join("characters", "{name}.txt")
    mdl = mw.mdlCharacter

    # Review characters
    for c in mdl.characters:

        # Generates file's content
        content = ""
        for m in characterMap:
            val = mdl.data(c.index(m.value)).strip()
            if val:
                content += formatMetaData(characterMap[m], val, 20)

        # Character's color:
        content += formatMetaData("Color", c.color().name(QColor.HexRgb), 20)

        # Character's infos
        for info in c.infos:
            content += formatMetaData(info.description, info.value, 20)

        # generate file's path
        cpath = path.format(name="{ID}-{slugName}".format(
            ID=c.ID(),
            slugName=slugify(c.name())
        ))

        # Has the character been renamed?
        if c.lastPath and cpath != c.lastPath:
            moves.append((c.lastPath, cpath))

        # Update character's path
        c.lastPath = cpath

        files.append((cpath, content))

    ####################################################################################################################
    # Texts
    # In an outline folder

    mdl = mw.mdlOutline

    # Go through the tree
    f, m, r = exportOutlineItem(mdl.rootItem)
    files += f
    moves += m
    removes += r

    # Writes revisions (if asked for)
    if settings.revisions["keep"]:
        files.append(("revisions.xml", mdl.saveToXML()))

    ####################################################################################################################
    # World
    # Either in an XML file, or in lots of plain texts?
    # More probably text, since there might be writing done in third-party.

    path = "world.opml"
    mdl = mw.mdlWorld

    root = ET.Element("opml")
    root.attrib["version"] = "1.0"
    body = ET.SubElement(root, "body")
    addWorldItem(body, mdl)
    content = ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
    files.append((path, content))

    ####################################################################################################################
    # Plots (mw.mdlPlots)
    # Either in XML or lots of plain texts?
    # More probably XML since there is not really a lot if writing to do (third-party)

    path = "plots.xml"
    mdl = mw.mdlPlots

    root = ET.Element("root")
    addPlotItem(root, mdl)
    content = ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
    files.append((path, content))

    ####################################################################################################################
    # Settings
    # Saved in readable text (json) for easier versionning. But they mustn't be shared, it seems.
    # Maybe include them only if zipped?
    # Well, for now, we keep them here...

    files.append(("settings.txt", settings.save(protocol=0)))

    project = mw.currentProject

    # We check if the file exist and we have write access. If the file does
    # not exists, we check the parent folder, because it might be a new project.
    if os.path.exists(project) and not os.access(project, os.W_OK) or \
       not os.path.exists(project) and not os.access(os.path.dirname(project), os.W_OK):
        print("Error: you don't have write access to save this project there.")
        return False

    ####################################################################################################################
    # Save to zip

    if zip:
        # project = os.path.join(
        #     os.path.dirname(project),
        #     "_" + os.path.basename(project)
        # )

        zf = zipfile.ZipFile(project, mode="w")

        for filename, content in files:
            zf.writestr(filename, content, compress_type=compression)

        zf.close()
        return True

    ####################################################################################################################
    # Save to plain text

    else:

        global cache

        # Project path
        dir = os.path.dirname(project)

        # Folder containing file: name of the project file (without .msk extension)
        folder = os.path.splitext(os.path.basename(project))[0]

        # Debug
        log("\nSaving to folder", folder)

        # If cache is empty (meaning we haven't loaded from disk), we wipe folder, just to be sure.
        if not cache:
            if os.path.exists(os.path.join(dir, folder)):
                shutil.rmtree(os.path.join(dir, folder))

        # Moving files that have been renamed
        for old, new in moves:

            # Get full path
            oldPath = os.path.join(dir, folder, old)
            newPath = os.path.join(dir, folder, new)

            # Move the old file to the new place
            try:
                os.replace(oldPath, newPath)
                log("* Renaming/moving {} to {}".format(old, new))
            except FileNotFoundError:
                # Maybe parent folder has been renamed
                pass

            # Update cache
            cache2 = {}
            for f in cache:
                f2 = f.replace(old, new)
                if f2 != f:
                    log("  * Updating cache:", f, f2)
                cache2[f2] = cache[f]
            cache = cache2

        # Writing files
        for path, content in files:
            filename = os.path.join(dir, folder, path)
            os.makedirs(os.path.dirname(filename), exist_ok=True)

            # Check if content is in cache, and write if necessary
            if path not in cache or cache[path] != content:
                log("* Writing file {} ({})".format(path, "not in cache" if path not in cache else "different"))
                # mode = "w" + ("b" if type(content) == bytes else "")
                if type(content) == bytes:
                    with open(filename, "wb") as f:
                        f.write(content)
                else:
                    with open(filename, "w", encoding='utf8') as f:
                        f.write(content)

                cache[path] = content

        # Removing phantoms
        for path in [p for p in cache if p not in [p for p, c in files]]:
            filename = os.path.join(dir, folder, path)
            log("* Removing", path)

            if os.path.isdir(filename):
                shutil.rmtree(filename)

            else:  # elif os.path.exists(filename)
                os.remove(filename)

            # Clear cache
            cache.pop(path, 0)

        # Removing empty directories
        for root, dirs, files in os.walk(os.path.join(dir, folder, "outline")):
            for dir in dirs:
                newDir = os.path.join(root, dir)
                try:
                    os.removedirs(newDir)
                    log("* Removing empty directory:", newDir)
                except:
                    # Directory not empty, we don't remove.
                    pass

        # Write the project file's content
        with open(project, "w", encoding='utf8') as f:
            f.write("1")  # Format number

        return True
Exemplo n.º 15
0
def saveProject(zip=None):
    """
    Saves the project. If zip is False, the project is saved as a multitude of plain-text files for the most parts
    and some XML or zip? for settings and stuff.
    If zip is True, everything is saved as a single zipped file. Easier to carry around, but does not allow
    collaborative work, versionning, or third-party editing.
    @param zip: if True, saves as a single file. If False, saves as plain-text. If None, tries to determine based on
    settings.
    @return: Nothing
    """
    if zip is None:
        zip = settings.saveToZip

    log("\n\nSaving to:", "zip" if zip else "folder")

    # List of files to be written
    files = []
    # List of files to be removed
    removes = []
    # List of files to be moved
    moves = []

    mw = mainWindow()

    # File format version
    files.append(("MANUSKRIPT", "1"))

    # General infos (book and author)
    # Saved in plain text, in infos.txt

    path = "infos.txt"
    content = ""
    for name, col in [
            ("Title", 0),
            ("Subtitle", 1),
            ("Serie", 2),
            ("Volume", 3),
            ("Genre", 4),
            ("License", 5),
            ("Author", 6),
            ("Email", 7),
            ]:
        item = mw.mdlFlatData.item(0, col)
        if item:
            val = item.text().strip()
        else:
            val = ""

        if val:
            content += "{name}:{spaces}{value}\n".format(
                name=name,
                spaces=" " * (15 - len(name)),
                value=val
            )
    files.append((path, content))

    ####################################################################################################################
    # Summary
    # In plain text, in summary.txt

    path = "summary.txt"
    content = ""
    for name, col in [
            ("Situation", 0),
            ("Sentence", 1),
            ("Paragraph", 2),
            ("Page", 3),
            ("Full", 4),
            ]:
        item = mw.mdlFlatData.item(1, col)
        if item:
            val = item.text().strip()
        else:
            val = ""

        if val:
            content += formatMetaData(name, val, 12)

    files.append((path, content))

    ####################################################################################################################
    # Label & Status
    # In plain text

    for mdl, path in [
        (mw.mdlStatus, "status.txt"),
        (mw.mdlLabels, "labels.txt")
    ]:

        content = ""

        # We skip the first row, which is empty and transparent
        for i in range(1, mdl.rowCount()):
            color = ""
            if mdl.data(mdl.index(i, 0), Qt.DecorationRole) is not None:
                color = iconColor(mdl.data(mdl.index(i, 0), Qt.DecorationRole)).name(QColor.HexRgb)
                color = color if color != "#ff000000" else "#00000000"

            text = mdl.data(mdl.index(i, 0))

            if text:
                content += "{name}{color}\n".format(
                    name=text,
                    color="" if color == "" else ":" + " " * (20 - len(text)) + color
                )

        files.append((path, content))

    ####################################################################################################################
    # Characters
    # In a character folder

    path = os.path.join("characters", "{name}.txt")
    mdl = mw.mdlCharacter

    # Review characters
    for c in mdl.characters:

        # Generates file's content
        content = ""
        for m in characterMap:
            val = mdl.data(c.index(m.value)).strip()
            if val:
                content += formatMetaData(characterMap[m], val, 20)

        # Character's color:
        content += formatMetaData("Color", c.color().name(QColor.HexRgb), 20)

        # Character's infos
        for info in c.infos:
            content += formatMetaData(info.description, info.value, 20)

        # generate file's path
        cpath = path.format(name="{ID}-{slugName}".format(
            ID=c.ID(),
            slugName=slugify(c.name())
        ))

        # Has the character been renamed?
        if c.lastPath and cpath != c.lastPath:
            moves.append((c.lastPath, cpath))

        # Update character's path
        c.lastPath = cpath

        files.append((cpath, content))

    ####################################################################################################################
    # Texts
    # In an outline folder

    mdl = mw.mdlOutline

    # Go through the tree
    f, m, r = exportOutlineItem(mdl.rootItem)
    files += f
    moves += m
    removes += r

    # Writes revisions (if asked for)
    if settings.revisions["keep"]:
        files.append(("revisions.xml", mdl.saveToXML()))

    ####################################################################################################################
    # World
    # Either in an XML file, or in lots of plain texts?
    # More probably text, since there might be writing done in third-party.

    path = "world.opml"
    mdl = mw.mdlWorld

    root = ET.Element("opml")
    root.attrib["version"] = "1.0"
    body = ET.SubElement(root, "body")
    addWorldItem(body, mdl)
    content = ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
    files.append((path, content))

    ####################################################################################################################
    # Plots (mw.mdlPlots)
    # Either in XML or lots of plain texts?
    # More probably XML since there is not really a lot if writing to do (third-party)

    path = "plots.xml"
    mdl = mw.mdlPlots

    root = ET.Element("root")
    addPlotItem(root, mdl)
    content = ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
    files.append((path, content))

    ####################################################################################################################
    # Settings
    # Saved in readable text (json) for easier versionning. But they mustn't be shared, it seems.
    # Maybe include them only if zipped?
    # Well, for now, we keep them here...

    files.append(("settings.txt", settings.save(protocol=0)))

    project = mw.currentProject

    ####################################################################################################################
    # Save to zip

    if zip:
        # project = os.path.join(
        #     os.path.dirname(project),
        #     "_" + os.path.basename(project)
        # )

        zf = zipfile.ZipFile(project, mode="w")

        for filename, content in files:
            zf.writestr(filename, content, compress_type=compression)

        zf.close()

    ####################################################################################################################
    # Save to plain text

    else:

        global cache

        # Project path
        dir = os.path.dirname(project)

        # Folder containing file: name of the project file (without .msk extension)
        folder = os.path.splitext(os.path.basename(project))[0]

        # Debug
        log("\nSaving to folder", folder)

        # If cache is empty (meaning we haven't loaded from disk), we wipe folder, just to be sure.
        if not cache:
            if os.path.exists(os.path.join(dir, folder)):
                shutil.rmtree(os.path.join(dir, folder))

        # Moving files that have been renamed
        for old, new in moves:

            # Get full path
            oldPath = os.path.join(dir, folder, old)
            newPath = os.path.join(dir, folder, new)

            # Move the old file to the new place
            try:
                os.replace(oldPath, newPath)
                log("* Renaming/moving {} to {}".format(old, new))
            except FileNotFoundError:
                # Maybe parent folder has been renamed
                pass

            # Update cache
            cache2 = {}
            for f in cache:
                f2 = f.replace(old, new)
                if f2 != f:
                    log("  * Updating cache:", f, f2)
                cache2[f2] = cache[f]
            cache = cache2

        # Writing files
        for path, content in files:
            filename = os.path.join(dir, folder, path)
            os.makedirs(os.path.dirname(filename), exist_ok=True)

            # Check if content is in cache, and write if necessary
            if path not in cache or cache[path] != content:
                log("* Writing file {} ({})".format(path, "not in cache" if path not in cache else "different"))
                # mode = "w" + ("b" if type(content) == bytes else "")
                if type(content) == bytes:
                    with open(filename, "wb") as f:
                        f.write(content)
                else:
                    with open(filename, "w", encoding='utf8') as f:
                        f.write(content)

                cache[path] = content

        # Removing phantoms
        for path in [p for p in cache if p not in [p for p, c in files]]:
            filename = os.path.join(dir, folder, path)
            log("* Removing", path)

            if os.path.isdir(filename):
                shutil.rmtree(filename)

            else:  # elif os.path.exists(filename)
                os.remove(filename)

            # Clear cache
            cache.pop(path, 0)

        # Removing empty directories
        for root, dirs, files in os.walk(os.path.join(dir, folder, "outline")):
            for dir in dirs:
                newDir = os.path.join(root, dir)
                try:
                    os.removedirs(newDir)
                    log("* Removing empty directory:", newDir)
                except:
                    # Directory not empty, we don't remove.
                    pass

        # Write the project file's content
        with open(project, "w", encoding='utf8') as f:
            f.write("1")  # Format number
Exemplo n.º 16
0
 def color(self):
     """
     Returns character's color in QColor
     @return: QColor
     """
     return iconColor(self.icon)