5

I have created a drop down menu in QGIS. The code is mainly from the "Layers menu from project" plugin. I have cleaned it so it only have the drop down.

My problem is that I will like to add an extra item to the drop down (a "Info" item, or "about the plugin"), but I can't figure out where to add it to the code.

I added the following just above return yaLayer, but it resulted in a 'Extra item' for each other item in the drop down.

menu.addSeparator()
menu.addMenuitem('Extra item')

Does anyone know where to add it or give a hint?

Entire code:

from __future__ import unicode_literals
# Import the PyQt and QGIS libraries
import os
import sys
from qgis.core import *

from PyQt4 import QtWebKit
from PyQt4.QtCore import * 
from PyQt4.QtGui import *
from PyQt4 import QtXml

from menu_conf_dlg import menu_conf_dlg

# Initialize Qt resources from file resources.py
import resources


def getFirstChildByTagNameValue(elt, tagName, key, value):
    nodes = elt.elementsByTagName(tagName)
    for node in (nodes.at(i) for i in range(nodes.size())):
        idNode = node.namedItem(key)
        if idNode and value == idNode.firstChild().toText().data():
            # layer founds
            return node

    return None

class menu_from_project: 

    def __init__(self, iface):
        self.path = QFileInfo(os.path.realpath(__file__)).path()
        self.iface = iface
        self.toolBar = None

        # new multi projects var
        self.projects = []
        self.menubarActions = []
        self.canvas = self.iface.mapCanvas()
        self.optionTooltip = (False)
        self.optionCreateGroup = (False)
        self.optionLoadAll = (False)
        self.read()       

        # default lang
        locale = QSettings().value("locale/userLocale")
        self.myLocale = locale[0:2]


    def store(self):
        s = QSettings()
        s.remove("menu_from_project/projectFilePath")

        index = 0

        s.setValue("menu_from_project/optionTooltip", (self.optionTooltip))
        s.setValue("menu_from_project/optionCreateGroup", (self.optionCreateGroup))
        s.setValue("menu_from_project/optionLoadAll", (self.optionLoadAll))

        s.beginWriteArray("menu_from_project/projects")
        for project in self.projects:
            s.setArrayIndex(index)
            s.setValue("file", project["file"])
            s.setValue("name", project["name"])
            index = index + 1

        s.endArray()

    def read(self):
        s = QSettings()
        try:
            # old single project conf         
            filePath = s.value("menu_from_project/projectFilePath", "")

            if filePath:
                title = str(filePath).split('/')[-1]
                title = str(title).split('.')[0]
                self.projects.append({"file":filePath, "name":title})
                self.store()
            else:
                # patch : lecture ancienne conf
                size = s.beginReadArray("projects")
                for i in range(size):
                    s.setArrayIndex(i)
                    file = ((s.value("file").toString()))
                    name = ((s.value("name").toString()))
                    if file:
                        self.projects.append({"file":file, "name":(name)})
                s.endArray()

                size = s.beginReadArray("menu_from_project/projects")
                for i in range(size):
                    s.setArrayIndex(i)
                    file = s.value("file", "")
                    name = s.value("name", "")
                    if file != "":
                        self.projects.append({"file":file, "name":name})

                s.endArray()

            self.optionTooltip = s.value("menu_from_project/optionTooltip", (True), type=bool)

            # create group option only since 1.9
            self.optionCreateGroup = s.value("menu_from_project/optionCreateGroup", (False), type=bool)
            self.optionLoadAll = s.value("menu_from_project/optionLoadAll", (False), type=bool)

        except:
            pass

    def isAbsolute(self, doc):
        absolute = False
        try:
            props = doc.elementsByTagName("properties")
            if props.count()==1:
                node = props.at(0)
                pathNode = node.namedItem("Paths")
                absoluteNode = pathNode.namedItem("Absolute")
                absolute = ("true" == absoluteNode.firstChild().toText().data())
        except:
            pass

        return  absolute

    def _actionHovered(self, action): 
        tip = action.toolTip() 
        if (tip != "-"):
            QToolTip.showText(QCursor.pos(), tip)
        else: 
            QToolTip.hideText()

    def getMaplayerDomFromQgs(self, fileName, layerId):
        xml = file(unicode(fileName)).read()
        doc = QtXml.QDomDocument()
        doc.setContent(xml)

        maplayers = doc.elementsByTagName("maplayer")
        for ml in (maplayers.item(i) for i in range(maplayers.size())):
            idelt = ml.namedItem("id")
            id = ""

            if idelt and layerId == idelt.firstChild().toText().data():
                return ml

        return None

    def addMenuItem(self, filename, node, menu, domdoc):
        yaLayer = False
        initialFilename = filename

        if node == None:
            return yaLayer

        element = node.toElement()

        # if legendlayer tag
        if node.nodeName() == "legendlayer":
            try:
                legendlayerfileElt = element.firstChild().firstChildElement("legendlayerfile")
                layerId = legendlayerfileElt.attribute("layerid")
                action = QAction(element.attribute("name"), self.iface.mainWindow())

                if (self.optionTooltip == (True)): 
                    try:
                        maplayers = domdoc.elementsByTagName("maplayer")
                        for ml in (maplayers.item(i) for i in range(maplayers.size())):
                            idelt = ml.namedItem("id")
                            id = ""

                            if (idelt != None):
                                id = idelt.firstChild().toText().data()

                            attrEmbedded = ml.toElement().attribute("embedded", "0")
                            if (attrEmbedded == "1"):
                                id = ml.toElement().attribute("id", "")

                            if (id == layerId):
                                # embedded layers ?
                                embeddedFilename = ""
                                if (attrEmbedded == "1"):
                                    try:
                                        embeddedFilename = ml.toElement().attribute("project", "")
                                        # read embedded project
                                        if not self.absolute and (embeddedFilename.find(".")==0):
                                            embeddedFilename = self.projectpath + "/" + embeddedFilename

                                        ml = self.getMaplayerDomFromQgs(embeddedFilename, id)
                                        filename = embeddedFilename
                                    except:
                                        pass

                                if ml != None:
                                    try:
                                        title = ml.namedItem("title").firstChild().toText().data()
                                        abstract = ml.namedItem("abstract").firstChild().toText().data()

                                        action.setStatusTip(title)
                                        if (abstract != "") and (title == ""):
                                            action.setToolTip("<p>%s</p>" % (abstract))
                                        else:
                                            if (abstract != "" or title != ""):
                                                action.setToolTip("<b>%s</b><br/>%s" % (title, abstract))
                                            else:
                                                action.setToolTip("-")
                                    except:
                                        pass
                                else:
                                    QgsMessageLog.logMessage(id+" not found in project "+embeddedFilename, 'Extensions')

                                break
                    except:
                        pass

                menu.addAction(action)
                yaLayer = True
                helper = lambda _filename,_who,_menu: (lambda: self.do_aeag_menu(_filename, _who, _menu))
                action.triggered.connect(helper(filename, layerId, menu))
            except:
                pass

            nextNode = node.nextSibling()
            if (nextNode != None):
                # ! recursion
                self.addMenuItem(initialFilename, nextNode, menu, domdoc)
        # / if element.tagName() == "legendlayer":

        # if legendgroup tag
        if node.nodeName() == "legendgroup":
            name = element.attribute("name")
            if name == "-":
                menu.addSeparator()
                nextNode = node.nextSibling()
                if (nextNode != None):
                    # ! recursion
                    self.addMenuItem(initialFilename, nextNode, menu, domdoc)

            elif name.startswith("-"):
                action = QAction(name[1:], self.iface.mainWindow())
                font = QFont()
                font.setBold(True)
                action.setFont(font)
                menu.addAction(action) 

                nextNode = node.nextSibling()
                if (nextNode != None):
                    # ! recursion
                    self.addMenuItem(initialFilename, nextNode, menu, domdoc)

            else:
                #messageLog("Group %s" % (element.attribute("name")))

                # construire sous-menu
                sousmenu = menu.addMenu('&'+element.attribute("name"))
                sousmenu.menuAction().setToolTip("-")

                childNode = node.firstChild()

                #  ! recursion
                r = self.addMenuItem(initialFilename, childNode, sousmenu, domdoc)

                if r and self.optionLoadAll and (len(sousmenu.actions()) > 1):
                    action = QAction(QApplication.translate("menu_from_project", "&Load all", None, QApplication.UnicodeUTF8), self.iface.mainWindow())
                    font = QFont()
                    font.setBold(True)
                    action.setFont(font)
                    sousmenu.addAction(action) 
                    helper = lambda _filename,_who,_menu: (lambda: self.do_aeag_menu(_filename, _who, _menu))
                    action.triggered.connect(helper(None, None, sousmenu))

                nextNode = node.nextSibling()
                if (nextNode != None):
                    # ! recursion
                    self.addMenuItem(initialFilename, nextNode, menu, domdoc)
        # / if element.tagName() == "legendgroup":
        #below works but add a lot
        #menu.addSeparator()
        #menu.addMenuitem('actiontest')
        return yaLayer


    def addMenu(self, name, filename, domdoc):
        # main project menu
        menuBar = self.iface.editMenu().parentWidget()
        projectMenu = QMenu('&'+name, menuBar)

        if (self.optionTooltip == (True)): 
            projectMenu.hovered.connect(self._actionHovered)

        projectAction = menuBar.addMenu(projectMenu)
        self.menubarActions.append(projectAction);

        self.absolute = self.isAbsolute(domdoc)
        self.projectpath = QFileInfo(os.path.realpath(filename)).path()

        # build menu on legend schema
        legends = domdoc.elementsByTagName("legend")
        if (legends.length() > 0):
            node = legends.item(0)
            if node:
                node = node.firstChild()
                self.addMenuItem(filename, node, projectMenu, domdoc)

        # Seperate settings from actual content

    def initMenus(self):
        menuBar = self.iface.editMenu().parentWidget()
        for action in self.menubarActions:
            menuBar.removeAction(action)
            del(action)

        self.menubarActions = []

        QgsApplication.setOverrideCursor(Qt.WaitCursor)
        for project in self.projects:
            try:
                xml = file(unicode(project["file"])).read()
                doc = QtXml.QDomDocument()
                doc.setContent(xml)

                self.addMenu(project["name"], project["file"], doc)
            except:
                QgsMessageLog.logMessage('Menu from layer : invalid ' + str(project["file"]), 'Extensions')
                pass

        QgsApplication.restoreOverrideCursor()



    def initGui(self):          
        # build menu
    self.initMenus()




    # run method that performs all the real work
    def do_aeag_menu(self, filename, who, menu=None):
        self.canvas.freeze(True)
        self.canvas.setRenderFlag(False)
        idxGroup = None
        theLayer = None
        groupName = None
        QgsApplication.setOverrideCursor(Qt.WaitCursor)

        try:
            if type(menu.parentWidget()) == QMenu and self.optionCreateGroup:
                groupName = menu.title().replace("&", "")

                idxGroup = self.iface.legendInterface().groups().index(groupName) if groupName in self.iface.legendInterface().groups() else -1

                if idxGroup < 0:
                    idxGroup = self.iface.legendInterface().addGroup(groupName, True)

            # load all layers
            if filename == None and who == None and self.optionLoadAll:
                i = 0
                for action in reversed(menu.actions()):
                    if action.text() != QApplication.translate("menu_from_project", "&Load all", None, QApplication.UnicodeUTF8):
                        action.trigger()
            else:
                # read QGis project
                xml = file(unicode(filename)).read()
                doc = QtXml.QDomDocument()
                doc.setContent(xml)

                # is project in relative path ?                
                absolute = self.isAbsolute(doc)

                node = getFirstChildByTagNameValue(doc.documentElement(), "maplayer", "id", who)
                if node:
                    idNode = node.namedItem("id")
                    # give it a new id (for multiple import)
                    try:
                        import uuid
                        import re
                        newLayerId = "L%s" % re.sub("[{}-]", "", QUuid.createUuid().toString())
                        idNode.firstChild().toText().setData(newLayerId)
                    except:
                        pass

                    # if relative path, adapt datasource
                    if not absolute:
                        try:
                            datasourceNode = node.namedItem("datasource")
                            datasource = datasourceNode.firstChild().toText().data()
                            providerNode = node.namedItem("provider")
                            provider = providerNode.firstChild().toText().data()

                            if provider == "ogr" and (datasource.find(".")==0):
                                projectpath = QFileInfo(os.path.realpath(filename)).path()
                                newlayerpath = projectpath + "/" + datasource 
                                datasourceNode.firstChild().toText().setData(newlayerpath)
                        except:
                            pass

                    # read modified layer node
                    QgsProject.instance().read(node)

                    if self.optionCreateGroup:
                        theLayer = QgsMapLayerRegistry.instance().mapLayer(newLayerId)

                        if idxGroup >= 0 and theLayer != None:
                            self.iface.mainWindow().statusBar().showMessage("Move to group "+str(idxGroup))
                            self.iface.legendInterface().refreshLayerSymbology(theLayer)
                            self.iface.legendInterface().moveLayer(theLayer, idxGroup)
                            self.iface.legendInterface().refreshLayerSymbology(theLayer)


        except:
            QgsMessageLog.logMessage('Menu from layer : invalid ' + filename, 'Extensions')
            pass

        self.canvas.freeze(False)    
        self.canvas.setRenderFlag(True)
        self.canvas.refresh()
        QgsApplication.restoreOverrideCursor()  


    def doLink( self, url ):
        if url.host() == "" :
            self.hdialog.ui.helpContent.page().currentFrame().load(url)
        else:
            QDesktopServices.openUrl( url )
1
  • 1
    You should create an action (QAction), and you can add this action to a menu. Look in the source code of any Python plug-in with menu. – Zoltan Dec 11 '16 at 13:44
2

You can copy the style used in the "Layers menu from project" for the other two items (Projects configuration and Help) and rename it slightly to fit your requirements.


initGui()

In the initGui() function (I am using the source code for the plugin), it reads the following:

def initGui(self):          
    self.act_aeag_menu_config = QAction(QApplication.translate("menu_from_project", "Projects configuration", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
    self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_config)
    # Add actions to the toolbar
    self.act_aeag_menu_config.triggered.connect(self.do_aeag_menu_config)

    self.act_aeag_menu_help = QAction(QApplication.translate("menu_from_project", "Help", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
    self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_help)
    self.act_aeag_menu_help.triggered.connect(self.do_help)

    # build menu
    self.initMenus()

As Zoltan mentioned, we can create a QAction and add it as a menu. In the above code, it shows how the other two items are being added. So we can just copy it and change the name slightly:

def initGui(self):          
    self.act_aeag_menu_config = QAction(QApplication.translate("menu_from_project", "Projects configuration", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
    self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_config)
    # Add actions to the toolbar
    self.act_aeag_menu_config.triggered.connect(self.do_aeag_menu_config)

    self.act_aeag_menu_help = QAction(QApplication.translate("menu_from_project", "Help", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
    self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_help)
    self.act_aeag_menu_help.triggered.connect(self.do_help)

    # Here we added a QAction for 'Extra item'
    self.act_aeag_menu_extraItem = QAction(QApplication.translate("menu_from_project", "Extra item", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
    self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_extraItem)
    self.act_aeag_menu_extraItem.triggered.connect(self.do_extraItem)
    
    # build menu
    self.initMenus()

do_extraItem()

We need to define a function for what happens when the "Extra item" menu has been clicked. We already connected the QAction to a function called do_extraItem() but now we have to define this new function. Here's a simple example:

def do_extraItem(self):
    print "Hopefully this works!"

unload()

Finally, to avoid creating duplicate items in the menu, we need to remove and disconnect the QAction from the menu. Here is the original source code:

def unload(self):
    menuBar = self.iface.editMenu().parentWidget()
    for action in self.menubarActions:
        menuBar.removeAction(action)

    self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_config)
    self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_help)

    self.act_aeag_menu_config.triggered.disconnect(self.do_aeag_menu_config)
    self.act_aeag_menu_help.triggered.disconnect(self.do_help)

    self.store()

Again we can repeat the similar lines of code used for our new menu item:

def unload(self):
    menuBar = self.iface.editMenu().parentWidget()
    for action in self.menubarActions:
        menuBar.removeAction(action)

    self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_config)
    self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_help)
    # New line added below
    self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_extraItem)

    self.act_aeag_menu_config.triggered.disconnect(self.do_aeag_menu_config)
    self.act_aeag_menu_help.triggered.disconnect(self.do_help)
    # New line added below
    self.act_aeag_menu_extraItem.triggered.disconnect(self.do_extraItem)

    self.store()

And hopefully, that should help get you started:

Result


Edit:

This is the complete script for the menu_from_project.py file that I edited to show the extra item. Copy/paste the whole code into the said file, reload the plugin (or QGIS) and you should see the extra menu option. Make sure to back up your original file!

# -*- coding: utf-8 -*-

from __future__ import unicode_literals
# Import the PyQt and QGIS libraries
import os
import sys
from qgis.core import *

from PyQt4 import QtWebKit
from PyQt4.QtCore import * 
from PyQt4.QtGui import *
from PyQt4 import QtXml
from ui_browser import Ui_browser

from menu_conf_dlg import menu_conf_dlg

# Initialize Qt resources from file resources.py
import resources


def getFirstChildByTagNameValue(elt, tagName, key, value):
    nodes = elt.elementsByTagName(tagName)
    for node in (nodes.at(i) for i in range(nodes.size())):
        idNode = node.namedItem(key)
        if idNode and value == idNode.firstChild().toText().data():
            # layer founds
            return node
            
    return None

class menu_from_project: 

    def __init__(self, iface):
        self.path = QFileInfo(os.path.realpath(__file__)).path()
        self.iface = iface
        self.toolBar = None
        
        # new multi projects var
        self.projects = []
        self.menubarActions = []
        self.canvas = self.iface.mapCanvas()
        self.optionTooltip = (False)
        self.optionCreateGroup = (False)
        self.optionLoadAll = (False)
        self.read()       
        
        # default lang
        locale = QSettings().value("locale/userLocale")
        self.myLocale = locale[0:2]
        # dictionnary
        localePath = self.path+"/i18n/menu_from_project_" + self.myLocale + ".qm"
        # translator
        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

    def store(self):
        s = QSettings()
        s.remove("menu_from_project/projectFilePath")

        index = 0
        
        s.setValue("menu_from_project/optionTooltip", (self.optionTooltip))
        s.setValue("menu_from_project/optionCreateGroup", (self.optionCreateGroup))
        s.setValue("menu_from_project/optionLoadAll", (self.optionLoadAll))
        
        s.beginWriteArray("menu_from_project/projects")
        for project in self.projects:
            s.setArrayIndex(index)
            s.setValue("file", project["file"])
            s.setValue("name", project["name"])
            index = index + 1
            
        s.endArray()

    def read(self):
        s = QSettings()
        try:
            # old single project conf         
            filePath = s.value("menu_from_project/projectFilePath", "")
            
            if filePath:
                title = str(filePath).split('/')[-1]
                title = str(title).split('.')[0]
                self.projects.append({"file":filePath, "name":title})
                self.store()
            else:
                # patch : lecture ancienne conf
                size = s.beginReadArray("projects")
                for i in range(size):
                    s.setArrayIndex(i)
                    file = ((s.value("file").toString()))
                    name = ((s.value("name").toString()))
                    if file:
                        self.projects.append({"file":file, "name":(name)})
                s.endArray()

                size = s.beginReadArray("menu_from_project/projects")
                for i in range(size):
                    s.setArrayIndex(i)
                    file = s.value("file", "")
                    name = s.value("name", "")
                    if file != "":
                        self.projects.append({"file":file, "name":name})
                        
                s.endArray()
            
            self.optionTooltip = s.value("menu_from_project/optionTooltip", (True), type=bool)
            
            # create group option only since 1.9
            self.optionCreateGroup = s.value("menu_from_project/optionCreateGroup", (False), type=bool)
            self.optionLoadAll = s.value("menu_from_project/optionLoadAll", (False), type=bool)
            
        except:
            pass
        
    def isAbsolute(self, doc):
        absolute = False
        try:
            props = doc.elementsByTagName("properties")
            if props.count()==1:
                node = props.at(0)
                pathNode = node.namedItem("Paths")
                absoluteNode = pathNode.namedItem("Absolute")
                absolute = ("true" == absoluteNode.firstChild().toText().data())
        except:
            pass
        
        return  absolute

    def _actionHovered(self, action): 
        tip = action.toolTip() 
        if (tip != "-"):
            QToolTip.showText(QCursor.pos(), tip)
        else: 
            QToolTip.hideText()
      
    def getMaplayerDomFromQgs(self, fileName, layerId):
        xml = file(unicode(fileName)).read()
        doc = QtXml.QDomDocument()
        doc.setContent(xml)
        
        maplayers = doc.elementsByTagName("maplayer")
        for ml in (maplayers.item(i) for i in range(maplayers.size())):
            idelt = ml.namedItem("id")
            id = ""
            
            if idelt and layerId == idelt.firstChild().toText().data():
                return ml
            
        return None
        
    def addMenuItem(self, filename, node, menu, domdoc):
        yaLayer = False
        initialFilename = filename
        
        if node == None:
            return yaLayer
            
        element = node.toElement()
        
        # if legendlayer tag
        if node.nodeName() == "legendlayer":
            try:
                legendlayerfileElt = element.firstChild().firstChildElement("legendlayerfile")
                layerId = legendlayerfileElt.attribute("layerid")
                action = QAction(element.attribute("name"), self.iface.mainWindow())
                
                if (self.optionTooltip == (True)): 
                    try:
                        maplayers = domdoc.elementsByTagName("maplayer")
                        for ml in (maplayers.item(i) for i in range(maplayers.size())):
                            idelt = ml.namedItem("id")
                            id = ""
                            
                            if (idelt != None):
                                id = idelt.firstChild().toText().data()
                            
                            attrEmbedded = ml.toElement().attribute("embedded", "0")
                            if (attrEmbedded == "1"):
                                id = ml.toElement().attribute("id", "")
                                
                            if (id == layerId):
                                # embedded layers ?
                                embeddedFilename = ""
                                if (attrEmbedded == "1"):
                                    try:
                                        embeddedFilename = ml.toElement().attribute("project", "")
                                        # read embedded project
                                        if not self.absolute and (embeddedFilename.find(".")==0):
                                            embeddedFilename = self.projectpath + "/" + embeddedFilename

                                        ml = self.getMaplayerDomFromQgs(embeddedFilename, id)
                                        filename = embeddedFilename
                                    except:
                                        pass
                            
                                if ml != None:
                                    try:
                                        title = ml.namedItem("title").firstChild().toText().data()
                                        abstract = ml.namedItem("abstract").firstChild().toText().data()
                                        
                                        action.setStatusTip(title)
                                        if (abstract != "") and (title == ""):
                                            action.setToolTip("<p>%s</p>" % (abstract))
                                        else:
                                            if (abstract != "" or title != ""):
                                                action.setToolTip("<b>%s</b><br/>%s" % (title, abstract))
                                            else:
                                                action.setToolTip("-")
                                    except:
                                        pass
                                else:
                                    QgsMessageLog.logMessage(id+" not found in project "+embeddedFilename, 'Extensions')
                                    
                                break
                    except:
                        pass
                
                menu.addAction(action)
                yaLayer = True
                helper = lambda _filename,_who,_menu: (lambda: self.do_aeag_menu(_filename, _who, _menu))
                action.triggered.connect(helper(filename, layerId, menu))
            except:
                pass
            
            nextNode = node.nextSibling()
            if (nextNode != None):
                # ! recursion
                self.addMenuItem(initialFilename, nextNode, menu, domdoc)
        # / if element.tagName() == "legendlayer":
                
        # if legendgroup tag
        if node.nodeName() == "legendgroup":
            name = element.attribute("name")
            if name == "-":
                menu.addSeparator()
                nextNode = node.nextSibling()
                if (nextNode != None):
                    # ! recursion
                    self.addMenuItem(initialFilename, nextNode, menu, domdoc)

            elif name.startswith("-"):
                action = QAction(name[1:], self.iface.mainWindow())
                font = QFont()
                font.setBold(True)
                action.setFont(font)
                menu.addAction(action) 

                nextNode = node.nextSibling()
                if (nextNode != None):
                    # ! recursion
                    self.addMenuItem(initialFilename, nextNode, menu, domdoc)
                    
            else:
                #messageLog("Group %s" % (element.attribute("name")))
                
                # construire sous-menu
                sousmenu = menu.addMenu('&'+element.attribute("name"))
                sousmenu.menuAction().setToolTip("-")

                childNode = node.firstChild()

                #  ! recursion
                r = self.addMenuItem(initialFilename, childNode, sousmenu, domdoc)

                if r and self.optionLoadAll and (len(sousmenu.actions()) > 1):
                    action = QAction(QApplication.translate("menu_from_project", "&Load all", None, QApplication.UnicodeUTF8), self.iface.mainWindow())
                    font = QFont()
                    font.setBold(True)
                    action.setFont(font)
                    sousmenu.addAction(action) 
                    helper = lambda _filename,_who,_menu: (lambda: self.do_aeag_menu(_filename, _who, _menu))
                    action.triggered.connect(helper(None, None, sousmenu))
                
                nextNode = node.nextSibling()
                if (nextNode != None):
                    # ! recursion
                    self.addMenuItem(initialFilename, nextNode, menu, domdoc)
        # / if element.tagName() == "legendgroup":
                   
        return yaLayer
    
    def addMenu(self, name, filename, domdoc):
        # main project menu
        menuBar = self.iface.editMenu().parentWidget()
        projectMenu = QMenu('&'+name, menuBar)
        
        if (self.optionTooltip == (True)): 
            projectMenu.hovered.connect(self._actionHovered)

        projectAction = menuBar.addMenu(projectMenu)
        self.menubarActions.append(projectAction);

        self.absolute = self.isAbsolute(domdoc)
        self.projectpath = QFileInfo(os.path.realpath(filename)).path()

        # build menu on legend schema
        legends = domdoc.elementsByTagName("legend")
        if (legends.length() > 0):
            node = legends.item(0)
            if node:
                node = node.firstChild()
                self.addMenuItem(filename, node, projectMenu, domdoc)
    
    def initMenus(self):
        menuBar = self.iface.editMenu().parentWidget()
        for action in self.menubarActions:
            menuBar.removeAction(action)
            del(action)
            
        self.menubarActions = []

        QgsApplication.setOverrideCursor(Qt.WaitCursor)
        for project in self.projects:
            try:
                xml = file(unicode(project["file"])).read()
                doc = QtXml.QDomDocument()
                doc.setContent(xml)
                
                self.addMenu(project["name"], project["file"], doc)
            except:
                QgsMessageLog.logMessage('Menu from layer : invalid ' + str(project["file"]), 'Extensions')
                pass
            
        QgsApplication.restoreOverrideCursor()
        
    def initGui(self):          
        self.act_aeag_menu_config = QAction(QApplication.translate("menu_from_project", "Projects configuration", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
        self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_config)
        # Add actions to the toolbar
        self.act_aeag_menu_config.triggered.connect(self.do_aeag_menu_config)

        self.act_aeag_menu_help = QAction(QApplication.translate("menu_from_project", "Help", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
        self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_help)
        self.act_aeag_menu_help.triggered.connect(self.do_help)

        # Here we added a QAction for 'Extra item'
        self.act_aeag_menu_extraItem = QAction(QApplication.translate("menu_from_project", "Extra item", None, QApplication.UnicodeUTF8)+"...", self.iface.mainWindow())
        self.iface.addPluginToMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_extraItem)
        self.act_aeag_menu_extraItem.triggered.connect(self.do_extraItem)

        # build menu
        self.initMenus()


    def do_extraItem(self):
        # Extra item function
        # Print following in the python console as a test to see if it successfully connects with the menu option
        print "Hopefully this works!"

    def unload(self):
        menuBar = self.iface.editMenu().parentWidget()
        for action in self.menubarActions:
            menuBar.removeAction(action)

        self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_config)
        self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_help)
        # New line added below
        self.iface.removePluginMenu(QApplication.translate("menu_from_project", "&Layers menu from project", None, QApplication.UnicodeUTF8), self.act_aeag_menu_extraItem)

        self.act_aeag_menu_config.triggered.disconnect(self.do_aeag_menu_config)
        self.act_aeag_menu_help.triggered.disconnect(self.do_help)
        # New line added below
        self.act_aeag_menu_extraItem.triggered.disconnect(self.do_extraItem)

        self.store()

    def do_aeag_menu_config(self):
        dlg = menu_conf_dlg(self.iface.mainWindow(), self)
        dlg.setModal(True)
        
        dlg.show()
        result = dlg.exec_()
        del dlg
        
        if result != 0:
            self.initMenus()

    # run method that performs all the real work
    def do_aeag_menu(self, filename, who, menu=None):
        self.canvas.freeze(True)
        self.canvas.setRenderFlag(False)
        idxGroup = None
        theLayer = None
        groupName = None
        QgsApplication.setOverrideCursor(Qt.WaitCursor)

        try:
            if type(menu.parentWidget()) == QMenu and self.optionCreateGroup:
                groupName = menu.title().replace("&", "")

                idxGroup = self.iface.legendInterface().groups().index(groupName) if groupName in self.iface.legendInterface().groups() else -1
                
                if idxGroup < 0:
                    idxGroup = self.iface.legendInterface().addGroup(groupName, True)
    
            # load all layers
            if filename == None and who == None and self.optionLoadAll:
                i = 0
                for action in reversed(menu.actions()):
                    if action.text() != QApplication.translate("menu_from_project", "&Load all", None, QApplication.UnicodeUTF8):
                        action.trigger()
            else:
                # read QGis project
                xml = file(unicode(filename)).read()
                doc = QtXml.QDomDocument()
                doc.setContent(xml)

                # is project in relative path ?                
                absolute = self.isAbsolute(doc)

                node = getFirstChildByTagNameValue(doc.documentElement(), "maplayer", "id", who)
                if node:
                    idNode = node.namedItem("id")
                    # give it a new id (for multiple import)
                    try:
                        import uuid
                        import re
                        newLayerId = "L%s" % re.sub("[{}-]", "", QUuid.createUuid().toString())
                        idNode.firstChild().toText().setData(newLayerId)
                    except:
                        pass

                    # if relative path, adapt datasource
                    if not absolute:
                        try:
                            datasourceNode = node.namedItem("datasource")
                            datasource = datasourceNode.firstChild().toText().data()
                            providerNode = node.namedItem("provider")
                            provider = providerNode.firstChild().toText().data()
                        
                            if provider == "ogr" and (datasource.find(".")==0):
                                projectpath = QFileInfo(os.path.realpath(filename)).path()
                                newlayerpath = projectpath + "/" + datasource 
                                datasourceNode.firstChild().toText().setData(newlayerpath)
                        except:
                            pass
                    
                    # read modified layer node
                    QgsProject.instance().read(node)
                            
                    if self.optionCreateGroup:
                        theLayer = QgsMapLayerRegistry.instance().mapLayer(newLayerId)
                        
                        if idxGroup >= 0 and theLayer != None:
                            self.iface.mainWindow().statusBar().showMessage("Move to group "+str(idxGroup))
                            self.iface.legendInterface().refreshLayerSymbology(theLayer)
                            self.iface.legendInterface().moveLayer(theLayer, idxGroup)
                            self.iface.legendInterface().refreshLayerSymbology(theLayer)
                    
                            
        except:
            QgsMessageLog.logMessage('Menu from layer : invalid ' + filename, 'Extensions')
            pass
        
        self.canvas.freeze(False)    
        self.canvas.setRenderFlag(True)
        self.canvas.refresh()
        QgsApplication.restoreOverrideCursor()
      
       
    def do_help(self):
        try:
            self.hdialog = QDialog()
            self.hdialog.setModal(True)
            self.hdialog.ui = Ui_browser()
            self.hdialog.ui.setupUi(self.hdialog)
            
            if os.path.isfile(self.path+"/help_"+self.myLocale+".html"):
                self.hdialog.ui.helpContent.setUrl(QUrl(self.path+"/help_"+self.myLocale+".html"))
            else:
                self.hdialog.ui.helpContent.setUrl(QUrl(self.path+"/help.html"))

            self.hdialog.ui.helpContent.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateExternalLinks) # Handle link clicks by yourself
            self.hdialog.ui.helpContent.linkClicked.connect(self.doLink)
            
            self.hdialog.ui.helpContent.page().currentFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOn)
            
            self.hdialog.show()
            result = self.hdialog.exec_()
            del self.hdialog
        except:
            QgsMessageLog.logMessage(sys.exc_info()[0], 'Extensions')
            pass
        
    def doLink( self, url ):
        if url.host() == "" :
            self.hdialog.ui.helpContent.page().currentFrame().load(url)
        else:
            QDesktopServices.openUrl( url )
4
  • Thank you so much for your answer. I think the anser it righ. i think it works with that plugin as you show. But i cant add it to my code, i dont now where to put the extra stuff. Du you have any inputs if you take a look at the code i have in my question? Thanks – student Dec 22 '16 at 10:38
  • @student - Most welcome, I've edited the post to include the complete script I used. Back up your original file and replace the code with the one above and test it out :) – Joseph Dec 22 '16 at 10:54
  • 1
    Thank again. I just marked it at correct. My next problem is to add the extra item the correct place. But i might come back to that. – student Jan 28 '17 at 12:11
  • @student - Most welcome! Glad it was helpful =) – Joseph Jan 30 '17 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.