chore: make yuzu REUSE compliant
[REUSE] is a specification that aims at making file copyright
information consistent, so that it can be both human and machine
readable. It basically requires that all files have a header containing
copyright and licensing information. When this isn't possible, like
when dealing with binary assets, generated files or embedded third-party
dependencies, it is permitted to insert copyright information in the
`.reuse/dep5` file.
Oh, and it also requires that all the licenses used in the project are
present in the `LICENSES` folder, that's why the diff is so huge.
This can be done automatically with `reuse download --all`.
The `reuse` tool also contains a handy subcommand that analyzes the
project and tells whether or not the project is (still) compliant,
`reuse lint`.
Following REUSE has a few advantages over the current approach:
- Copyright information is easy to access for users / downstream
- Files like `dist/license.md` do not need to exist anymore, as
`.reuse/dep5` is used instead
- `reuse lint` makes it easy to ensure that copyright information of
files like binary assets / images is always accurate and up to date
To add copyright information of files that didn't have it I looked up
who committed what and when, for each file. As yuzu contributors do not
have to sign a CLA or similar I couldn't assume that copyright ownership
was of the "yuzu Emulator Project", so I used the name and/or email of
the commit author instead.
[REUSE]: https://reuse.software
Follow-up to 01cf05bc75b1e47beb08937439f3ed9339e7b254
2022-05-15 01:06:02 +01:00
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2015-09-01 05:35:33 +01:00
# pragma once
2018-08-10 23:12:26 +01:00
# include <array>
2018-08-21 01:36:36 +01:00
# include <map>
2018-09-02 15:53:06 +01:00
# include <string>
2018-08-06 18:36:05 +01:00
# include <utility>
2018-09-02 15:53:06 +01:00
2018-08-29 14:42:53 +01:00
# include <QCoreApplication>
2019-05-01 22:21:04 +01:00
# include <QFileInfo>
2018-08-29 14:42:53 +01:00
# include <QObject>
2015-09-01 05:35:33 +01:00
# include <QStandardItem>
# include <QString>
2018-07-23 11:43:34 +01:00
# include <QWidget>
2018-09-02 15:53:06 +01:00
# include "common/common_types.h"
2018-08-29 14:42:53 +01:00
# include "common/logging/log.h"
2016-09-18 01:38:01 +01:00
# include "common/string_util.h"
2023-08-27 23:41:42 +01:00
# include "yuzu/play_time_manager.h"
2019-07-29 21:06:33 +01:00
# include "yuzu/uisettings.h"
2018-01-16 18:05:21 +00:00
# include "yuzu/util/util.h"
2016-04-13 22:04:05 +01:00
2019-05-01 22:21:04 +01:00
enum class GameListItemType {
Game = QStandardItem : : UserType + 1 ,
CustomDir = QStandardItem : : UserType + 2 ,
2019-05-05 02:07:09 +01:00
SdmcDir = QStandardItem : : UserType + 3 ,
UserNandDir = QStandardItem : : UserType + 4 ,
SysNandDir = QStandardItem : : UserType + 5 ,
2021-04-10 10:09:01 +01:00
AddDir = QStandardItem : : UserType + 6 ,
Favorites = QStandardItem : : UserType + 7 ,
2019-05-01 22:21:04 +01:00
} ;
Q_DECLARE_METATYPE ( GameListItemType ) ;
2016-04-13 22:04:05 +01:00
/**
2019-05-20 20:04:32 +01:00
* Gets the default icon ( for games without valid title metadata )
* @ param size The desired width and height of the default icon .
2016-04-13 22:04:05 +01:00
* @ return QPixmap default icon
*/
2018-07-28 17:32:16 +01:00
static QPixmap GetDefaultIcon ( u32 size ) {
2016-04-13 22:04:05 +01:00
QPixmap icon ( size , size ) ;
icon . fill ( Qt : : transparent ) ;
return icon ;
}
2015-09-01 05:35:33 +01:00
class GameListItem : public QStandardItem {
public :
2019-05-01 22:21:04 +01:00
// used to access type from item index
2020-08-29 19:23:35 +01:00
static constexpr int TypeRole = Qt : : UserRole + 1 ;
static constexpr int SortRole = Qt : : UserRole + 2 ;
2018-08-06 17:58:46 +01:00
GameListItem ( ) = default ;
2020-08-29 19:23:35 +01:00
explicit GameListItem ( const QString & string ) : QStandardItem ( string ) {
2019-05-01 22:21:04 +01:00
setData ( string , SortRole ) ;
}
2015-09-01 05:35:33 +01:00
} ;
/**
* A specialization of GameListItem for path values .
* This class ensures that for every full path value it holds , a correct string representation
* of just the filename ( with no extension ) will be displayed to the user .
2019-05-20 20:04:32 +01:00
* If this class receives valid title metadata , it will also display game icons and titles .
2015-09-01 05:35:33 +01:00
*/
class GameListItemPath : public GameListItem {
public :
2020-08-29 19:23:35 +01:00
static constexpr int TitleRole = SortRole + 1 ;
static constexpr int FullPathRole = SortRole + 2 ;
static constexpr int ProgramIdRole = SortRole + 3 ;
static constexpr int FileTypeRole = SortRole + 4 ;
2015-09-01 05:35:33 +01:00
2018-08-06 17:58:46 +01:00
GameListItemPath ( ) = default ;
2018-07-28 17:32:16 +01:00
GameListItemPath ( const QString & game_path , const std : : vector < u8 > & picture_data ,
2018-08-10 23:07:43 +01:00
const QString & game_name , const QString & game_type , u64 program_id ) {
2019-05-01 22:21:04 +01:00
setData ( type ( ) , TypeRole ) ;
2015-09-01 05:35:33 +01:00
setData ( game_path , FullPathRole ) ;
2018-07-28 17:32:16 +01:00
setData ( game_name , TitleRole ) ;
2016-12-15 09:55:03 +00:00
setData ( qulonglong ( program_id ) , ProgramIdRole ) ;
2018-07-28 17:32:16 +01:00
setData ( game_type , FileTypeRole ) ;
2021-08-01 17:59:36 +01:00
const u32 size = UISettings : : values . game_icon_size . GetValue ( ) ;
2018-08-10 23:15:06 +01:00
2018-07-28 17:32:16 +01:00
QPixmap picture ;
2018-08-10 23:15:06 +01:00
if ( ! picture . loadFromData ( picture_data . data ( ) , static_cast < u32 > ( picture_data . size ( ) ) ) ) {
2018-07-28 17:32:16 +01:00
picture = GetDefaultIcon ( size ) ;
2018-08-10 23:15:06 +01:00
}
2018-09-22 02:34:46 +01:00
picture = picture . scaled ( size , size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ;
2018-07-28 17:32:16 +01:00
setData ( picture , Qt : : DecorationRole ) ;
2015-09-01 05:35:33 +01:00
}
2019-05-01 22:21:04 +01:00
int type ( ) const override {
return static_cast < int > ( GameListItemType : : Game ) ;
}
2016-04-13 22:04:05 +01:00
QVariant data ( int role ) const override {
2020-04-06 02:12:17 +01:00
if ( role = = Qt : : DisplayRole | | role = = SortRole ) {
2015-09-01 05:35:33 +01:00
std : : string filename ;
2016-09-18 01:38:01 +01:00
Common : : SplitPath ( data ( FullPathRole ) . toString ( ) . toStdString ( ) , nullptr , & filename ,
nullptr ) ;
2018-07-28 17:32:16 +01:00
2018-08-10 23:12:26 +01:00
const std : : array < QString , 4 > row_data { {
2018-07-28 17:32:16 +01:00
QString : : fromStdString ( filename ) ,
data ( FileTypeRole ) . toString ( ) ,
QString : : fromStdString ( fmt : : format ( " 0x{:016X} " , data ( ProgramIdRole ) . toULongLong ( ) ) ) ,
data ( TitleRole ) . toString ( ) ,
2018-08-10 23:12:26 +01:00
} } ;
2018-07-28 17:32:16 +01:00
2021-06-28 22:32:24 +01:00
const auto & row1 = row_data . at ( UISettings : : values . row_1_text_id . GetValue ( ) ) ;
const int row2_id = UISettings : : values . row_2_text_id . GetValue ( ) ;
2018-07-28 17:32:16 +01:00
2020-08-29 19:30:49 +01:00
if ( role = = SortRole ) {
2020-04-06 02:12:17 +01:00
return row1 . toLower ( ) ;
2020-08-29 19:30:49 +01:00
}
2020-04-06 02:12:17 +01:00
2020-08-29 19:30:49 +01:00
// None
if ( row2_id = = 4 ) {
2020-01-19 20:56:49 +00:00
return row1 ;
2020-08-29 19:30:49 +01:00
}
2020-01-19 20:56:49 +00:00
const auto & row2 = row_data . at ( row2_id ) ;
2020-08-29 19:30:49 +01:00
if ( row1 = = row2 ) {
2018-07-28 17:32:16 +01:00
return row1 ;
2020-08-29 19:30:49 +01:00
}
2018-07-28 17:32:16 +01:00
2020-08-29 19:30:49 +01:00
return QStringLiteral ( " %1 \n %2 " ) . arg ( row1 , row2 ) ;
2015-09-01 05:35:33 +01:00
}
2018-08-10 23:12:26 +01:00
return GameListItem : : data ( role ) ;
2015-09-01 05:35:33 +01:00
}
} ;
2018-08-29 14:42:53 +01:00
class GameListItemCompat : public GameListItem {
Q_DECLARE_TR_FUNCTIONS ( GameListItemCompat )
public :
2020-08-29 19:23:35 +01:00
static constexpr int CompatNumberRole = SortRole ;
2018-08-29 14:42:53 +01:00
GameListItemCompat ( ) = default ;
2018-09-17 10:31:27 +01:00
explicit GameListItemCompat ( const QString & compatibility ) {
2019-05-01 22:21:04 +01:00
setData ( type ( ) , TypeRole ) ;
2018-08-29 14:42:53 +01:00
struct CompatStatus {
QString color ;
const char * text ;
const char * tooltip ;
} ;
// clang-format off
2022-10-26 14:03:55 +01:00
const auto ingame_status =
CompatStatus { QStringLiteral ( " #f2d624 " ) , QT_TR_NOOP ( " Ingame " ) , QT_TR_NOOP ( " Game starts, but crashes or major glitches prevent it from being completed. " ) } ;
2018-08-29 14:42:53 +01:00
static const std : : map < QString , CompatStatus > status_data = {
2022-10-26 14:03:55 +01:00
{ QStringLiteral ( " 0 " ) , { QStringLiteral ( " #5c93ed " ) , QT_TR_NOOP ( " Perfect " ) , QT_TR_NOOP ( " Game can be played without issues. " ) } } ,
{ QStringLiteral ( " 1 " ) , { QStringLiteral ( " #47d35c " ) , QT_TR_NOOP ( " Playable " ) , QT_TR_NOOP ( " Game functions with minor graphical or audio glitches and is playable from start to finish. " ) } } ,
{ QStringLiteral ( " 2 " ) , ingame_status } ,
{ QStringLiteral ( " 3 " ) , ingame_status } , // Fallback for the removed "Okay" category
{ QStringLiteral ( " 4 " ) , { QStringLiteral ( " #FF0000 " ) , QT_TR_NOOP ( " Intro/Menu " ) , QT_TR_NOOP ( " Game loads, but is unable to progress past the Start Screen. " ) } } ,
2019-05-20 20:02:30 +01:00
{ QStringLiteral ( " 5 " ) , { QStringLiteral ( " #828282 " ) , QT_TR_NOOP ( " Won't Boot " ) , QT_TR_NOOP ( " The game crashes when attempting to startup. " ) } } ,
{ QStringLiteral ( " 99 " ) , { QStringLiteral ( " #000000 " ) , QT_TR_NOOP ( " Not Tested " ) , QT_TR_NOOP ( " The game has not yet been tested. " ) } } ,
} ;
2018-08-29 14:42:53 +01:00
// clang-format on
2018-09-17 10:31:27 +01:00
auto iterator = status_data . find ( compatibility ) ;
2018-08-29 14:42:53 +01:00
if ( iterator = = status_data . end ( ) ) {
2018-09-17 10:31:27 +01:00
LOG_WARNING ( Frontend , " Invalid compatibility number {} " , compatibility . toStdString ( ) ) ;
2018-08-29 14:42:53 +01:00
return ;
}
2018-09-17 10:30:09 +01:00
const CompatStatus & status = iterator - > second ;
2018-09-17 10:31:27 +01:00
setData ( compatibility , CompatNumberRole ) ;
2022-04-13 21:29:59 +01:00
setText ( tr ( status . text ) ) ;
setToolTip ( tr ( status . tooltip ) ) ;
2018-08-29 14:42:53 +01:00
setData ( CreateCirclePixmapFromColor ( status . color ) , Qt : : DecorationRole ) ;
}
2019-05-01 22:21:04 +01:00
int type ( ) const override {
return static_cast < int > ( GameListItemType : : Game ) ;
}
2018-08-29 14:42:53 +01:00
bool operator < ( const QStandardItem & other ) const override {
2020-12-05 20:38:55 +00:00
return data ( CompatNumberRole ) . value < QString > ( ) <
other . data ( CompatNumberRole ) . value < QString > ( ) ;
2018-08-29 14:42:53 +01:00
}
} ;
2015-09-01 05:35:33 +01:00
/**
* A specialization of GameListItem for size values .
* This class ensures that for every numerical size value it holds ( in bytes ) , a correct
* human - readable string representation will be displayed to the user .
*/
class GameListItemSize : public GameListItem {
public :
2020-08-29 19:23:35 +01:00
static constexpr int SizeRole = SortRole ;
2015-09-01 05:35:33 +01:00
2018-08-06 17:58:46 +01:00
GameListItemSize ( ) = default ;
explicit GameListItemSize ( const qulonglong size_bytes ) {
2019-05-01 22:21:04 +01:00
setData ( type ( ) , TypeRole ) ;
2015-09-01 05:35:33 +01:00
setData ( size_bytes , SizeRole ) ;
}
2016-09-18 01:38:01 +01:00
void setData ( const QVariant & value , int role ) override {
2015-09-01 05:35:33 +01:00
// By specializing setData for SizeRole, we can ensure that the numerical and string
// representations of the data are always accurate and in the correct format.
if ( role = = SizeRole ) {
qulonglong size_bytes = value . toULongLong ( ) ;
GameListItem : : setData ( ReadableByteSize ( size_bytes ) , Qt : : DisplayRole ) ;
GameListItem : : setData ( value , SizeRole ) ;
} else {
GameListItem : : setData ( value , role ) ;
}
}
2019-05-01 22:21:04 +01:00
int type ( ) const override {
return static_cast < int > ( GameListItemType : : Game ) ;
}
2015-09-01 05:35:33 +01:00
/**
* This operator is , in practice , only used by the TreeView sorting systems .
2016-09-18 01:38:01 +01:00
* Override it so that it will correctly sort by numerical value instead of by string
* representation .
2015-09-01 05:35:33 +01:00
*/
2016-09-18 01:38:01 +01:00
bool operator < ( const QStandardItem & other ) const override {
2015-09-01 05:35:33 +01:00
return data ( SizeRole ) . toULongLong ( ) < other . data ( SizeRole ) . toULongLong ( ) ;
}
} ;
2018-07-23 11:43:34 +01:00
2023-08-27 02:19:00 +01:00
/**
* GameListItem for Play Time values .
* This object stores the play time of a game in seconds , and its readable
* representation in minutes / hours
*/
class GameListItemPlayTime : public GameListItem {
public :
static constexpr int PlayTimeRole = SortRole ;
GameListItemPlayTime ( ) = default ;
explicit GameListItemPlayTime ( const qulonglong time_seconds ) {
setData ( time_seconds , PlayTimeRole ) ;
}
void setData ( const QVariant & value , int role ) override {
qulonglong time_seconds = value . toULongLong ( ) ;
GameListItem : : setData ( PlayTime : : ReadablePlayTime ( time_seconds ) , Qt : : DisplayRole ) ;
GameListItem : : setData ( value , PlayTimeRole ) ;
}
bool operator < ( const QStandardItem & other ) const override {
return data ( PlayTimeRole ) . toULongLong ( ) < other . data ( PlayTimeRole ) . toULongLong ( ) ;
}
} ;
2019-05-01 22:21:04 +01:00
class GameListDir : public GameListItem {
public :
2020-08-29 19:23:35 +01:00
static constexpr int GameDirRole = Qt : : UserRole + 2 ;
2019-05-01 22:21:04 +01:00
explicit GameListDir ( UISettings : : GameDir & directory ,
2022-06-13 21:52:19 +01:00
GameListItemType dir_type_ = GameListItemType : : CustomDir )
: dir_type { dir_type_ } {
2019-05-01 22:21:04 +01:00
setData ( type ( ) , TypeRole ) ;
UISettings : : GameDir * game_dir = & directory ;
2021-01-18 00:22:54 +00:00
setData ( QVariant ( UISettings : : values . game_dirs . indexOf ( directory ) ) , GameDirRole ) ;
2019-05-01 22:21:04 +01:00
2021-08-01 17:59:36 +01:00
const int icon_size = UISettings : : values . folder_icon_size . GetValue ( ) ;
2019-05-01 22:21:04 +01:00
switch ( dir_type ) {
2019-05-05 02:07:09 +01:00
case GameListItemType : : SdmcDir :
2019-05-03 18:21:57 +01:00
setData (
QIcon : : fromTheme ( QStringLiteral ( " sd_card " ) )
. pixmap ( icon_size )
. scaled ( icon_size , icon_size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ,
Qt : : DecorationRole ) ;
2019-05-05 02:07:09 +01:00
setData ( QObject : : tr ( " Installed SD Titles " ) , Qt : : DisplayRole ) ;
2019-05-01 22:21:04 +01:00
break ;
2019-05-05 02:07:09 +01:00
case GameListItemType : : UserNandDir :
setData (
QIcon : : fromTheme ( QStringLiteral ( " chip " ) )
. pixmap ( icon_size )
. scaled ( icon_size , icon_size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ,
Qt : : DecorationRole ) ;
setData ( QObject : : tr ( " Installed NAND Titles " ) , Qt : : DisplayRole ) ;
break ;
case GameListItemType : : SysNandDir :
setData (
QIcon : : fromTheme ( QStringLiteral ( " chip " ) )
. pixmap ( icon_size )
. scaled ( icon_size , icon_size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ,
Qt : : DecorationRole ) ;
2019-05-05 00:52:17 +01:00
setData ( QObject : : tr ( " System Titles " ) , Qt : : DisplayRole ) ;
2019-05-01 22:21:04 +01:00
break ;
2019-10-05 00:35:06 +01:00
case GameListItemType : : CustomDir : {
2023-11-12 07:03:01 +00:00
const QString path = QString : : fromStdString ( game_dir - > path ) ;
const QString icon_name =
QFileInfo : : exists ( path ) ? QStringLiteral ( " folder " ) : QStringLiteral ( " bad_folder " ) ;
2019-05-01 22:21:04 +01:00
setData ( QIcon : : fromTheme ( icon_name ) . pixmap ( icon_size ) . scaled (
icon_size , icon_size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ,
Qt : : DecorationRole ) ;
2023-11-12 07:03:01 +00:00
setData ( path , Qt : : DisplayRole ) ;
2019-05-01 22:21:04 +01:00
break ;
2019-10-05 00:35:06 +01:00
}
default :
break ;
}
}
2019-05-01 22:21:04 +01:00
int type ( ) const override {
return static_cast < int > ( dir_type ) ;
}
2020-04-25 19:01:20 +01:00
/**
* Override to prevent automatic sorting between folders and the addDir button .
*/
bool operator < ( const QStandardItem & other ) const override {
return false ;
}
2019-05-01 22:21:04 +01:00
private :
GameListItemType dir_type ;
} ;
class GameListAddDir : public GameListItem {
public :
explicit GameListAddDir ( ) {
setData ( type ( ) , TypeRole ) ;
2021-08-01 17:59:36 +01:00
const int icon_size = UISettings : : values . folder_icon_size . GetValue ( ) ;
2022-07-28 15:50:20 +01:00
setData ( QIcon : : fromTheme ( QStringLiteral ( " list-add " ) )
2019-05-03 18:21:57 +01:00
. pixmap ( icon_size )
. scaled ( icon_size , icon_size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ,
2019-05-01 22:21:04 +01:00
Qt : : DecorationRole ) ;
2019-05-05 00:52:17 +01:00
setData ( QObject : : tr ( " Add New Game Directory " ) , Qt : : DisplayRole ) ;
2019-05-01 22:21:04 +01:00
}
int type ( ) const override {
return static_cast < int > ( GameListItemType : : AddDir ) ;
}
2020-04-06 02:12:17 +01:00
bool operator < ( const QStandardItem & other ) const override {
return false ;
}
2019-05-01 22:21:04 +01:00
} ;
2021-04-10 10:09:01 +01:00
class GameListFavorites : public GameListItem {
public :
explicit GameListFavorites ( ) {
setData ( type ( ) , TypeRole ) ;
2021-08-01 17:59:36 +01:00
const int icon_size = UISettings : : values . folder_icon_size . GetValue ( ) ;
2021-04-10 10:09:01 +01:00
setData ( QIcon : : fromTheme ( QStringLiteral ( " star " ) )
. pixmap ( icon_size )
. scaled ( icon_size , icon_size , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ,
Qt : : DecorationRole ) ;
setData ( QObject : : tr ( " Favorites " ) , Qt : : DisplayRole ) ;
}
int type ( ) const override {
return static_cast < int > ( GameListItemType : : Favorites ) ;
}
bool operator < ( const QStandardItem & other ) const override {
return false ;
}
} ;
2018-07-23 11:43:34 +01:00
class GameList ;
class QHBoxLayout ;
class QTreeView ;
class QLabel ;
class QLineEdit ;
class QToolButton ;
class GameListSearchField : public QWidget {
Q_OBJECT
public :
explicit GameListSearchField ( GameList * parent = nullptr ) ;
2021-04-29 22:56:30 +01:00
QString filterText ( ) const ;
2022-05-27 00:57:35 +01:00
void setFilterResult ( int visible_ , int total_ ) ;
2018-07-23 11:43:34 +01:00
void clear ( ) ;
void setFocus ( ) ;
private :
2022-08-20 15:49:29 +01:00
void changeEvent ( QEvent * ) override ;
void RetranslateUI ( ) ;
2018-07-23 11:43:34 +01:00
class KeyReleaseEater : public QObject {
public :
2022-06-13 21:52:19 +01:00
explicit KeyReleaseEater ( GameList * gamelist_ , QObject * parent = nullptr ) ;
2018-07-23 11:43:34 +01:00
private :
GameList * gamelist = nullptr ;
QString edit_filter_text_old ;
protected :
// EventFilter in order to process systemkeys while editing the searchfield
bool eventFilter ( QObject * obj , QEvent * event ) override ;
} ;
2019-05-05 00:52:17 +01:00
int visible ;
int total ;
2018-07-23 11:43:34 +01:00
QHBoxLayout * layout_filter = nullptr ;
QTreeView * tree_view = nullptr ;
QLabel * label_filter = nullptr ;
QLineEdit * edit_filter = nullptr ;
QLabel * label_filter_result = nullptr ;
QToolButton * button_filter_close = nullptr ;
} ;