Skip to content

Commit

Permalink
Merge pull request #35008 from suricactus/plugins_sort_by_date
Browse files Browse the repository at this point in the history
Adds support to sort the plugins by update date; Show the plugin version update time
  • Loading branch information
m-kuhn committed Apr 11, 2020
2 parents e525b1e + e090036 commit 7a9c3c6
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 7 deletions.
6 changes: 6 additions & 0 deletions python/pyplugin_installer/installer.py
Expand Up @@ -223,6 +223,12 @@ def exportPluginsToManager(self):
"status_exp": plugin["status_exp"],
"error": plugin["error"],
"error_details": plugin["error_details"],
"create_date": plugin["create_date"],
"update_date": plugin["update_date"],
"create_date_stable": plugin["create_date_stable"],
"update_date_stable": plugin["update_date_stable"],
"create_date_experimental": plugin["create_date_experimental"],
"update_date_experimental": plugin["update_date_experimental"],
"experimental": plugin["experimental"] and "true" or "false",
"deprecated": plugin["deprecated"] and "true" or "false",
"trusted": plugin["trusted"] and "true" or "false",
Expand Down
17 changes: 16 additions & 1 deletion python/pyplugin_installer/installer_data.py
Expand Up @@ -85,6 +85,8 @@
"downloads" unicode, # number of downloads
"average_vote" unicode, # average vote
"rating_votes" unicode, # number of votes
"create_date" unicode, # ISO datetime when the plugin has been created
"update_date" unicode, # ISO datetime when the plugin has been last updated
"plugin_dependencies" unicode, # PIP-style comma separated list of plugin dependencies
}}
"""
Expand Down Expand Up @@ -444,6 +446,12 @@ def xmlDownloaded(self):
"downloads": pluginNodes.item(i).firstChildElement("downloads").text().strip(),
"average_vote": pluginNodes.item(i).firstChildElement("average_vote").text().strip(),
"rating_votes": pluginNodes.item(i).firstChildElement("rating_votes").text().strip(),
"create_date": pluginNodes.item(i).firstChildElement("create_date").text().strip(),
"update_date": pluginNodes.item(i).firstChildElement("update_date").text().strip(),
"create_date_stable": pluginNodes.item(i).firstChildElement("create_date").text().strip() if not experimental else "",
"update_date_stable": pluginNodes.item(i).firstChildElement("update_date").text().strip() if not experimental else "",
"create_date_experimental": pluginNodes.item(i).firstChildElement("create_date").text().strip() if experimental else "",
"update_date_experimental": pluginNodes.item(i).firstChildElement("update_date").text().strip() if experimental else "",
"icon": icon,
"experimental": experimental,
"deprecated": deprecated,
Expand Down Expand Up @@ -686,6 +694,12 @@ def pluginMetadata(fct):
"downloads": "",
"average_vote": "",
"rating_votes": "",
"create_date": pluginMetadata("create_date"),
"update_date": pluginMetadata("update_date"),
"create_date_stable": pluginMetadata("create_date_stable"),
"update_date_stable": pluginMetadata("update_date_stable"),
"create_date_experimental": pluginMetadata("create_date_experimental"),
"update_date_experimental": pluginMetadata("update_date_experimental"),
"available": False, # Will be overwritten, if any available version found.
"installed": True,
"status": "orphan", # Will be overwritten, if any available version found.
Expand Down Expand Up @@ -771,8 +785,9 @@ def rebuild(self):
# other remote metadata is preferred:
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", "trusted", "plugin_dependencies",
"version_available_stable", "version_available_experimental", "download_url_stable", "download_url_experimental",
"download_url", "filename", "downloads", "average_vote", "rating_votes", "trusted", "plugin_dependencies"]:
"create_date", "update_date", "create_date_stable", "update_date_stable", "create_date_experimental", "update_date_experimental"]:
if attrib not in translatableAttributes or attrib == "name": # include name!
if plugin.get(attrib, False):
self.mPlugins[key][attrib] = plugin[attrib]
Expand Down
65 changes: 61 additions & 4 deletions src/app/pluginmanager/qgspluginmanager.cpp
Expand Up @@ -196,25 +196,36 @@ void QgsPluginManager::setPythonUtils( QgsPythonUtils *pythonUtils )
QAction *actionSortByDownloads = new QAction( tr( "Sort by Downloads" ), vwPlugins );
QAction *actionSortByVote = new QAction( tr( "Sort by Vote" ), vwPlugins );
QAction *actionSortByStatus = new QAction( tr( "Sort by Status" ), vwPlugins );
QAction *actionSortByDateCreated = new QAction( tr( "Sort by Date Created" ), vwPlugins );
QAction *actionSortByDateUpdated = new QAction( tr( "Sort by Date Updated" ), vwPlugins );
actionSortByName->setCheckable( true );
actionSortByDownloads->setCheckable( true );
actionSortByVote->setCheckable( true );
actionSortByStatus->setCheckable( true );
actionSortByDateCreated->setCheckable( true );
actionSortByDateUpdated->setCheckable( true );
QActionGroup *group = new QActionGroup( vwPlugins );
actionSortByName->setActionGroup( group );
actionSortByDownloads->setActionGroup( group );
actionSortByVote->setActionGroup( group );
actionSortByStatus->setActionGroup( group );
actionSortByDateCreated->setActionGroup( group );
actionSortByDateUpdated->setActionGroup( group );
actionSortByName->setChecked( true );
vwPlugins->addAction( actionSortByName );
vwPlugins->addAction( actionSortByDownloads );
vwPlugins->addAction( actionSortByVote );
vwPlugins->addAction( actionSortByStatus );
// TODO "create_date" and "update_date" are actually both representing "update_date" from the server side. Blocked by https://github.com/qgis/QGIS-Django/issues/69
// vwPlugins->addAction( actionSortByDateCreated );
vwPlugins->addAction( actionSortByDateUpdated );
vwPlugins->setContextMenuPolicy( Qt::ActionsContextMenu );
connect( actionSortByName, &QAction::triggered, mModelProxy, &QgsPluginSortFilterProxyModel::sortPluginsByName );
connect( actionSortByDownloads, &QAction::triggered, mModelProxy, &QgsPluginSortFilterProxyModel::sortPluginsByDownloads );
connect( actionSortByVote, &QAction::triggered, mModelProxy, &QgsPluginSortFilterProxyModel::sortPluginsByVote );
connect( actionSortByStatus, &QAction::triggered, mModelProxy, &QgsPluginSortFilterProxyModel::sortPluginsByStatus );
connect( actionSortByDateCreated, &QAction::triggered, mModelProxy, &QgsPluginSortFilterProxyModel::sortPluginsByDateCreated );
connect( actionSortByDateUpdated, &QAction::triggered, mModelProxy, &QgsPluginSortFilterProxyModel::sortPluginsByDateUpdated );

// get the QgsSettings group from the installer
QString settingsGroup;
Expand Down Expand Up @@ -422,6 +433,8 @@ void QgsPluginManager::getCppPluginsMetadata()
version_t *pVersion = ( version_t * ) cast_to_fptr( myLib->resolve( "version" ) );
icon_t *pIcon = ( icon_t * ) cast_to_fptr( myLib->resolve( "icon" ) );
experimental_t *pExperimental = ( experimental_t * ) cast_to_fptr( myLib->resolve( "experimental" ) );
create_date_t *pCreateDate = ( create_date_t * ) cast_to_fptr( myLib->resolve( "create_date" ) );
update_date_t *pUpdateDate = ( update_date_t * ) cast_to_fptr( myLib->resolve( "update_date" ) );

// show the values (or lack of) for each function
if ( pName )
Expand Down Expand Up @@ -460,6 +473,26 @@ void QgsPluginManager::getCppPluginsMetadata()
{
QgsDebugMsg( "Plugin icon: " + pIcon() );
}
else
{
QgsDebugMsg( QStringLiteral( "Plugin icon not returned when queried" ) );
}
if ( pCreateDate )
{
QgsDebugMsg( "Plugin create date: " + pCreateDate() );
}
else
{
QgsDebugMsg( QStringLiteral( "Plugin create date not returned when queried" ) );
}
if ( pUpdateDate )
{
QgsDebugMsg( "Plugin update date: " + pUpdateDate() );
}
else
{
QgsDebugMsg( QStringLiteral( "Plugin update date not returned when queried" ) );
}

if ( !pName || !pDesc || !pVersion )
{
Expand All @@ -484,6 +517,8 @@ void QgsPluginManager::getCppPluginsMetadata()
metadata[QStringLiteral( "readonly" )] = QStringLiteral( "true" );
metadata[QStringLiteral( "status" )] = QStringLiteral( "orphan" );
metadata[QStringLiteral( "experimental" )] = ( pExperimental ? pExperimental() : QString() );
metadata[QStringLiteral( "create_date" )] = ( pCreateDate ? pCreateDate() : QString() );
metadata[QStringLiteral( "update_date" )] = ( pUpdateDate ? pUpdateDate() : QString() );
mPlugins.insert( baseName, metadata );

delete myLib;
Expand Down Expand Up @@ -530,6 +565,8 @@ void QgsPluginManager::reloadModelData()
QString pluginName = it->value( QStringLiteral( "name" ) );
QString description = it->value( QStringLiteral( "description" ) );
QString author = it->value( QStringLiteral( "author_name" ) );
QString createDate = it->value( QStringLiteral( "create_date" ) );
QString updateDate = it->value( QStringLiteral( "update_date" ) );
QString iconPath = it->value( QStringLiteral( "icon" ) );
QString status = it->value( QStringLiteral( "status" ) );
QString status_exp = it->value( QStringLiteral( "status_exp" ) );
Expand All @@ -543,6 +580,8 @@ void QgsPluginManager::reloadModelData()
mypDetailItem->setData( error, PLUGIN_ERROR_ROLE );
mypDetailItem->setData( description, PLUGIN_DESCRIPTION_ROLE );
mypDetailItem->setData( author, PLUGIN_AUTHOR_ROLE );
mypDetailItem->setData( createDate, PLUGIN_CREATE_DATE );
mypDetailItem->setData( updateDate, PLUGIN_UPDATE_DATE );
mypDetailItem->setData( it->value( QStringLiteral( "tags" ) ), PLUGIN_TAGS_ROLE );
mypDetailItem->setData( it->value( QStringLiteral( "downloads" ) ).rightJustified( 10, '0' ), PLUGIN_DOWNLOADS_ROLE );
mypDetailItem->setData( it->value( QStringLiteral( "average_vote" ) ), PLUGIN_VOTE_ROLE );
Expand Down Expand Up @@ -986,10 +1025,19 @@ void QgsPluginManager::showPluginDetails( QStandardItem *item )
downloadUrl = downloadUrl.replace( QStringLiteral( "download/" ), QString() );
}

html += QStringLiteral( "<tr><td class='key'>%1 </td><td title='%2'><a href='%2'>%3</a></td></tr>"
QString dateUpdatedStr;
if ( ! metadata->value( QStringLiteral( "update_date" ) ).isEmpty() )
{
const QDateTime dateUpdated = QDateTime::fromString( metadata->value( QStringLiteral( "update_date_stable" ) ).trimmed(), Qt::ISODate );
if ( dateUpdated.isValid() )
dateUpdatedStr += QStringLiteral( "%1 %2" ).arg( tr( "updated at" ), dateUpdated.toString() );
}

html += QStringLiteral( "<tr><td class='key'>%1 </td><td title='%2'><a href='%2'>%3</a> %4</td></tr>"
).arg( tr( "Available version (stable)" ),
downloadUrl,
metadata->value( QStringLiteral( "version_available_stable" ) ) );
metadata->value( QStringLiteral( "version_available_stable" ) ),
dateUpdatedStr );
}

if ( ! metadata->value( QStringLiteral( "version_available_experimental" ) ).isEmpty() )
Expand All @@ -1001,10 +1049,19 @@ void QgsPluginManager::showPluginDetails( QStandardItem *item )
downloadUrl = downloadUrl.replace( QStringLiteral( "download/" ), QString() );
}

html += QStringLiteral( "<tr><td class='key'>%1 </td><td title='%2'><a href='%2'>%3</a></td></tr>"
QString dateUpdatedStr;
if ( !metadata->value( QStringLiteral( "update_date_experimental" ) ).isEmpty() )
{
const QDateTime dateUpdated = QDateTime::fromString( metadata->value( QStringLiteral( "update_date_experimental" ) ).trimmed(), Qt::ISODate );
if ( dateUpdated.isValid() )
dateUpdatedStr += QStringLiteral( "%1 %2" ).arg( tr( "updated at" ), dateUpdated.toString() );
}

html += QStringLiteral( "<tr><td class='key'>%1 </td><td title='%2'><a href='%2'>%3</a> %4</td></tr>"
).arg( tr( "Available version (experimental)" ),
downloadUrl,
metadata->value( QStringLiteral( "version_available_experimental" ) ) );
metadata->value( QStringLiteral( "version_available_experimental" ) ),
dateUpdatedStr );
}

if ( ! metadata->value( QStringLiteral( "changelog" ) ).isEmpty() )
Expand Down
16 changes: 16 additions & 0 deletions src/app/pluginmanager/qgspluginsortfilterproxymodel.cpp
Expand Up @@ -155,6 +155,22 @@ void QgsPluginSortFilterProxyModel::sortPluginsByStatus()



void QgsPluginSortFilterProxyModel::sortPluginsByDateCreated()
{
setAcceptedSpacers();
sort( 0, Qt::DescendingOrder );
setSortRole( PLUGIN_CREATE_DATE );
}


void QgsPluginSortFilterProxyModel::sortPluginsByDateUpdated()
{
setAcceptedSpacers();
sort( 0, Qt::DescendingOrder );
setSortRole( PLUGIN_UPDATE_DATE );
}


bool QgsPluginSortFilterProxyModel::lessThan( const QModelIndex &source_left, const QModelIndex &source_right ) const
{
// Always move deprecated plugins to bottom, regardless of the sort order.
Expand Down
8 changes: 6 additions & 2 deletions src/app/pluginmanager/qgspluginsortfilterproxymodel.h
Expand Up @@ -30,8 +30,10 @@ const int PLUGIN_STATUS_ROLE = Qt::UserRole + 6; // for filtering and sort
const int PLUGIN_DOWNLOADS_ROLE = Qt::UserRole + 7; // for sorting
const int PLUGIN_VOTE_ROLE = Qt::UserRole + 8; // for sorting
const int PLUGIN_ISDEPRECATED_ROLE = Qt::UserRole + 9; // for styling
const int PLUGIN_STATUSEXP_ROLE = Qt::UserRole + 10; // for filtering and sorting
const int SPACER_ROLE = Qt::UserRole + 20; // for sorting
const int PLUGIN_STATUSEXP_ROLE = Qt::UserRole + 10; // for filtering and sorting
const int PLUGIN_CREATE_DATE = Qt::UserRole + 11; // for sorting
const int PLUGIN_UPDATE_DATE = Qt::UserRole + 12; // for sorting
const int SPACER_ROLE = Qt::UserRole + 20; // for sorting



Expand Down Expand Up @@ -59,6 +61,8 @@ class QgsPluginSortFilterProxyModel : public QSortFilterProxyModel
void sortPluginsByDownloads();
void sortPluginsByVote();
void sortPluginsByStatus();
void sortPluginsByDateCreated();
void sortPluginsByDateUpdated();

protected:
//! Filter by status: this method is used in both filterAcceptsRow and countWithCurrentStatus.
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/qgisplugin.h
Expand Up @@ -214,4 +214,10 @@ typedef QString icon_t();
//! Typedef for getting the experimental status without instantiating the plugin
typedef QString experimental_t();

//! Typedef for getting the create date without instantiating the plugin
typedef QString create_date_t();

//! Typedef for getting the update date status without instantiating the plugin
typedef QString update_date_t();

#endif // QGISPLUGIN_H

0 comments on commit 7a9c3c6

Please sign in to comment.