Skip to content

Commit

Permalink
[FEATURE] [Plugin Manager] Voting for plugins from Plugin Manager
Browse files Browse the repository at this point in the history
  • Loading branch information
borysiasty committed Apr 1, 2014
1 parent 298b1d5 commit 3b198d9
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 8 deletions.
15 changes: 15 additions & 0 deletions python/pyplugin_installer/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ def exportPluginsToManager(self):
plugin = plugins.all()[key]
iface.pluginManagerInterface().addPluginMetadata({
"id" : key,
"plugin_id" : plugin["plugin_id"] or "",
"name" : plugin["name"],
"description" : plugin["description"],
"about" : plugin["about"],
Expand Down Expand Up @@ -512,3 +513,17 @@ def setRepositoryInspectionFilter(self, reposName = None):
reposName = reposName.decode("utf-8")
repositories.setInspectionFilter(reposName)
self.reloadAndExportData()


# ----------------------------------------- #
def sendVote(self, plugin_id, vote):
""" send vote via the RPC """

if not plugin_id or not vote:
return False
url = "http://plugins.qgis.org/plugins/RPC2/"
params = "{\"id\":\"djangorpc\",\"method\":\"plugin.vote\",\"params\":[%s,%s]}" % (str(plugin_id), str(vote))
req = QNetworkRequest(QUrl(url))
req.setRawHeader("Content-Type", "application/json");
reply = QgsNetworkAccessManager.instance().post(req, params)
return True
9 changes: 8 additions & 1 deletion python/pyplugin_installer/installer_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,14 @@ def xmlDownloaded(self):
if icon and not icon.startswith("http"):
icon = "http://%s/%s" % ( QUrl(self.mRepositories[reposName]["url"]).host() , icon )

if pluginNodes.item(i).toElement().hasAttribute("plugin_id"):
plugin_id = pluginNodes.item(i).toElement().attribute("plugin_id")
else:
plugin_id = None

plugin = {
"id" : name,
"plugin_id" : plugin_id,
"name" : pluginNodes.item(i).toElement().attribute("name"),
"version_available" : pluginNodes.item(i).toElement().attribute("version"),
"description" : pluginNodes.item(i).firstChildElement("description").text().strip(),
Expand Down Expand Up @@ -647,6 +653,7 @@ def pluginMetadata(fct):

plugin = {
"id" : key,
"plugin_id" : None,
"name" : pluginMetadata("name") or key,
"description" : pluginMetadata("description"),
"about" : pluginMetadata("about"),
Expand Down Expand Up @@ -749,7 +756,7 @@ def rebuild(self):
if not self.mPlugins[key][attrib] and plugin[attrib]:
self.mPlugins[key][attrib] = plugin[attrib]
# other remote metadata is preffered:
for attrib in ["name", "description", "about", "category", "tags", "changelog", "author_name", "author_email", "homepage",
for attrib in ["name", "plugin_id", "description", "about", "category", "tags", "changelog", "author_name", "author_email", "homepage",
"tracker", "code_repository", "experimental", "deprecated", "version_available", "zip_repository",
"download_url", "filename", "downloads", "average_vote", "rating_votes"]:
if ( not attrib in translatableAttributes ) or ( attrib == "name" ): # include name!
Expand Down
1 change: 1 addition & 0 deletions src/app/pluginmanager/README
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
PLUGIN METADATA TAGS
=======================================================
id the key; C++ library base name or Python module name
plugin_id for the official repository: an integer id. At the time, used for voting only.
name human readable plugin name
description short description of the plugin purpose only
about longer description: how does it work, where does it install, how to run it?
Expand Down
81 changes: 75 additions & 6 deletions src/app/pluginmanager/qgspluginmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,11 +612,13 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
" width:360px;"
" margin-left:98px;"
" padding-top:3px;"
" }";
" }"
"</style>";

if ( ! metadata->value( "average_vote" ).isEmpty() )
if ( ! metadata->value( "plugin_id" ).isEmpty() )
{
html += QString(
"<style>"
" div#stars_bg {"
" background-image: url('file:///home/borys/Pobrane/stars_empty.png');"
" width:92px;"
Expand All @@ -626,9 +628,52 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
" background-image: url('file:///home/borys/Pobrane/stars_full.png');"
" width:%1px;"
" height:16px;"
" }").arg( metadata->value( "average_vote" ).toFloat() / 5 * 92 );
" }"
"</style>").arg( metadata->value( "average_vote" ).toFloat() / 5 * 92 );
html += QString(
"<script>"
" var plugin_id=%1;"
" var vote=0;"
" function ready()"
" {"
" document.getElementById('stars_bg').onmouseover=save_vote;"
" document.getElementById('stars_bg').onmouseout=restore_vote;"
" document.getElementById('stars_bg').onmousemove=change_vote;"
" document.getElementById('stars_bg').onclick=send_vote;"
" };"
" "
" function save_vote(e)"
" {"
" vote = document.getElementById('stars').style.width"
" }"
" "
" function restore_vote(e)"
" {"
" document.getElementById('stars').style.width = vote;"
" }"
" "
" function change_vote(e)"
" {"
" var length = e.x - document.getElementById('stars').getBoundingClientRect().left;"
" max = document.getElementById('stars_bg').getBoundingClientRect().right;"
" if ( length <= max ) document.getElementById('stars').style.width = length + 'px';"
" }"
" "
" function send_vote(e)"
" {"
" save_vote();"
" result = Number(vote.replace('px',''));"
" if (!result) return;"
" result = Math.floor(result/92*5)+1;"
" document.getElementById('send_vote_trigger').href='rpc2://plugin.vote/'+plugin_id+'/'+result;"
" ev=document.createEvent('MouseEvents');"
" ev.initEvent('click', false, true);"
" document.getElementById('send_vote_trigger').dispatchEvent(ev);"
" }"
"</script>").arg( metadata->value( "plugin_id" ) );
}
html += "</style>";

html += "<body onload='ready()'>";

// First prepare message box(es)
if ( ! metadata->value( "error" ).isEmpty() )
Expand Down Expand Up @@ -713,7 +758,7 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
}

html += "<br/><br/>";
html += "<div id='stars_bg'><div/><div id='stars'><div/>";
html += "<div id='stars_bg'/><div id='stars'/>";
html += "<div id='votes'>";
if ( ! metadata->value( "rating_votes" ).isEmpty() )
{
Expand All @@ -727,8 +772,9 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
{
html += tr( "%1 downloads" ).arg( metadata->value( "downloads" ) );
}

html += "</div>";
html += "<div><a id='send_vote_trigger'/></div>";

html += "</td></tr><tr><td>";
html += "<br/>";

Expand Down Expand Up @@ -790,6 +836,8 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )

html += "</td></tr></table>";

html += "</body>";

wvDetails->setHtml( html );

// Set buttonInstall text (and sometimes focus)
Expand Down Expand Up @@ -1105,7 +1153,28 @@ void QgsPluginManager::on_vwPlugins_doubleClicked( const QModelIndex & theIndex

void QgsPluginManager::on_wvDetails_linkClicked( const QUrl & url )
{
if ( url.scheme() == "rpc2" )
{
if ( url.host() == "plugin.vote" )
{
QString params = url.path();
QString response;
QgsPythonRunner::eval( QString( "pyplugin_installer.instance().sendVote('%1', '%2')" ).arg( params.split( "/" )[1] )
.arg( params.split( "/" )[2] ), response );
if ( response == "True" )
{
pushMessage( tr( "Vote sent successfully" ), QgsMessageBar::INFO );
}
else
{
pushMessage( tr( "Sending vote to the plugin repository failed." ), QgsMessageBar::WARNING );
}
}
}
else
{
QDesktopServices::openUrl( url );
}
}


Expand Down
2 changes: 1 addition & 1 deletion src/app/pluginmanager/qgspluginmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
void clearRepositoryFilter( );

//! show the given message in the Plugin Manager internal message bar
void pushMessage( const QString &text, QgsMessageBar::MessageLevel level, int duration );
void pushMessage( const QString &text, QgsMessageBar::MessageLevel level, int duration = -1 );

protected:
//! Reimplement QgsOptionsDialogBase method as we have a custom window title what would be overwritten by this method
Expand Down

0 comments on commit 3b198d9

Please sign in to comment.