Compare commits
243 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2770384f1f | ||
|
|
f4e5b83039 | ||
|
|
124681605b | ||
|
|
a217faae7c | ||
|
|
184c39bbb7 | ||
|
|
508e2a70bb | ||
|
|
5aac56fe96 | ||
|
|
dab7dad966 | ||
|
|
25e48d6cae | ||
|
|
9b743e55d1 | ||
|
|
dc1f9edfaf | ||
|
|
b6b68edf1e | ||
|
|
a2320b99ae | ||
|
|
be01e28068 | ||
|
|
d6084083a5 | ||
|
|
019bf5102c | ||
|
|
a1633224d1 | ||
|
|
e62bd26cb9 | ||
|
|
c29f517292 | ||
|
|
d80144f80c | ||
|
|
4733c84a86 | ||
|
|
23f3d2095b | ||
|
|
4f1f2b6fc6 | ||
|
|
1ea70b085f | ||
|
|
6c0b395f4a | ||
|
|
0ee67f186f | ||
|
|
d133addbaa | ||
|
|
683991b1c9 | ||
|
|
32ac02007b | ||
|
|
d716617ae0 | ||
|
|
26e1f015d2 | ||
|
|
1c94093a4b | ||
|
|
27eccd456a | ||
|
|
eed4447560 | ||
|
|
3c8d0ebd52 | ||
|
|
7ec0d2f2cc | ||
|
|
35da91a997 | ||
|
|
788747c071 | ||
|
|
36eb131289 | ||
|
|
f231f28818 | ||
|
|
aebdc89f77 | ||
|
|
4a3a379871 | ||
|
|
a7f27add2d | ||
|
|
cd1d4247cf | ||
|
|
6d618c4b78 | ||
|
|
ad469531ff | ||
|
|
cf9b4b1246 | ||
|
|
18a2692dc1 | ||
|
|
a2dad982f8 | ||
|
|
8f27b6a4c9 | ||
|
|
21c4022fca | ||
|
|
237933855a | ||
|
|
dff7068a03 | ||
|
|
8f28a85a6d | ||
|
|
2414eb2598 | ||
|
|
4851f6bffd | ||
|
|
948be36d3c | ||
|
|
edd088927d | ||
|
|
4cfe8dd95e | ||
|
|
e1ce81c5bf | ||
|
|
0f40b5f022 | ||
|
|
94c5ffa92e | ||
|
|
3c9bf56767 | ||
|
|
9024acb16e | ||
|
|
7732402122 | ||
|
|
2059bce6a7 | ||
|
|
499c86a8b8 | ||
|
|
ef084eb145 | ||
|
|
3f3ae7c38f | ||
|
|
83d762287f | ||
|
|
5af0acf147 | ||
|
|
907dfee6f7 | ||
|
|
d587d24603 | ||
|
|
c246b8f164 | ||
|
|
deecafa053 | ||
|
|
f8810106a2 | ||
|
|
8e35fbe532 | ||
|
|
b1fdccde6e | ||
|
|
6741f100a1 | ||
|
|
e05e9ea1b2 | ||
|
|
197341de5e | ||
|
|
2933482be3 | ||
|
|
c7ce23239f | ||
|
|
79115f7439 | ||
|
|
4457103672 | ||
|
|
d204875f72 | ||
|
|
c690e73b1a | ||
|
|
b5d39c5f21 | ||
|
|
7f8834cb04 | ||
|
|
0dab7e293c | ||
|
|
8f016880af | ||
|
|
f471462a84 | ||
|
|
58eec8df1e | ||
|
|
2655b8b43a | ||
|
|
ea86c043a4 | ||
|
|
c1faa616bc | ||
|
|
a68bf5a30d | ||
|
|
9568b8e0e5 | ||
|
|
b34321ef87 | ||
|
|
4971f1c5bf | ||
|
|
962b52bd5b | ||
|
|
9449bfa414 | ||
|
|
5b8e9066c6 | ||
|
|
8690be7fd2 | ||
|
|
497267016b | ||
|
|
0468f850c2 | ||
|
|
b9e7d4e30c | ||
|
|
0e7734b555 | ||
|
|
e81dcce5b3 | ||
|
|
38bd1f7e1c | ||
|
|
36ad9704a2 | ||
|
|
a6c05df362 | ||
|
|
f6b70fda71 | ||
|
|
8cb4e75f70 | ||
|
|
da1815ac2b | ||
|
|
f7357f2d10 | ||
|
|
d9c92c5ddd | ||
|
|
c82bdb6405 | ||
|
|
eec8ee5830 | ||
|
|
e67eb3c0d8 | ||
|
|
9c101759f6 | ||
|
|
a55ee92590 | ||
|
|
5ccfc97dab | ||
|
|
d6dd88ec3d | ||
|
|
8557d83599 | ||
|
|
94cf1f8698 | ||
|
|
9ada35c3a3 | ||
|
|
79b0c906fa | ||
|
|
a0688f1dba | ||
|
|
f91e8fecee | ||
|
|
1b363babe2 | ||
|
|
73843cb54d | ||
|
|
a2ccfc2116 | ||
|
|
fe104e2bad | ||
|
|
35e3e9f4ff | ||
|
|
b2a1cd9716 | ||
|
|
14f58eae4b | ||
|
|
5cec000618 | ||
|
|
4805a5287d | ||
|
|
4789dc5b30 | ||
|
|
5a35099043 | ||
|
|
4cd0128919 | ||
|
|
61e9b80f67 | ||
|
|
dcd881ba6c | ||
|
|
d40a67ce68 | ||
|
|
1c1e7ca62a | ||
|
|
d3831d511b | ||
|
|
0942e93144 | ||
|
|
98d3eba8e8 | ||
|
|
ff3db03696 | ||
|
|
3608c31d22 | ||
|
|
8d504d9cee | ||
|
|
782921f6e0 | ||
|
|
0694aabb45 | ||
|
|
604b35dfde | ||
|
|
4c308bf5d0 | ||
|
|
7a53ca7f8e | ||
|
|
7c51f04140 | ||
|
|
488b326e0f | ||
|
|
1e0c0a35ba | ||
|
|
bf044c1ccc | ||
|
|
c9caa7f034 | ||
|
|
1b8966b3a4 | ||
|
|
01d4d404c0 | ||
|
|
354bbf820f | ||
|
|
7620f9ebbe | ||
|
|
9c2c668a04 | ||
|
|
b6f5a5712b | ||
|
|
9e9df6eb16 | ||
|
|
f510c993a6 | ||
|
|
8ddcbaac27 | ||
|
|
3fcab72900 | ||
|
|
70aa2233e2 | ||
|
|
8123a2924d | ||
|
|
dd3c308b09 | ||
|
|
e56ca2ffd6 | ||
|
|
57c98c363c | ||
|
|
2211508061 | ||
|
|
848e41919d | ||
|
|
dac613a8bb | ||
|
|
a1735278df | ||
|
|
3730bd04a4 | ||
|
|
eee3445d2f | ||
|
|
8bf473dc3a | ||
|
|
e106dda794 | ||
|
|
fc35d2a35c | ||
|
|
aef9ff0d38 | ||
|
|
192fb46d1d | ||
|
|
1dd4eb05f2 | ||
|
|
79f0c494fa | ||
|
|
7caeb47637 | ||
|
|
ffef339ebd | ||
|
|
817153b20b | ||
|
|
686eb2e786 | ||
|
|
53d5192477 | ||
|
|
a172f5fe85 | ||
|
|
288408795b | ||
|
|
4b5a811b08 | ||
|
|
c1259d8b6e | ||
|
|
3acbe431f7 | ||
|
|
40f381257d | ||
|
|
beec983f21 | ||
|
|
d20750012e | ||
|
|
e31c9d74fa | ||
|
|
78adc388df | ||
|
|
609413cda4 | ||
|
|
63e5d6a94a | ||
|
|
fd5970b647 | ||
|
|
af38b8f92b | ||
|
|
e676e65f9e | ||
|
|
4c479301ff | ||
|
|
98178947ae | ||
|
|
0dbf3b462b | ||
|
|
cd9f8b569b | ||
|
|
6b23728efa | ||
|
|
ff0f7ee483 | ||
|
|
74498c3ac9 | ||
|
|
7a61e740e8 | ||
|
|
81e6b55c39 | ||
|
|
e439ac0e0e | ||
|
|
7b9d784a64 | ||
|
|
56b2630a1c | ||
|
|
6d5597a732 | ||
|
|
c0a9345358 | ||
|
|
2e4ad81fff | ||
|
|
1aad85a4f9 | ||
|
|
fbd2993239 | ||
|
|
203228bd05 | ||
|
|
da7edebe90 | ||
|
|
c7444a189e | ||
|
|
29235c5fa6 | ||
|
|
bf8374ff9f | ||
|
|
ba05e85e48 | ||
|
|
a9aab0702c | ||
|
|
b5cf83d501 | ||
|
|
1cc2e6303a | ||
|
|
4509a07fff | ||
|
|
ea419f6d40 | ||
|
|
c9b6707468 | ||
|
|
cf512a35a7 | ||
|
|
bdd3e5343d | ||
|
|
80fd8cd338 | ||
|
|
eb48592083 |
3
.github/ISSUE_TEMPLATE.md
vendored
3
.github/ISSUE_TEMPLATE.md
vendored
@@ -7,7 +7,8 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
For technical issues, questions and feature suggestions/requests please use the forum on https://forum.strawberrymusicplayer.org/
|
For technical issues, questions and discussion please use the forum on https://forum.strawberrymusicplayer.org/
|
||||||
|
Any issues related to feature requests will be closed. See the README for more details.
|
||||||
|
|
||||||
Check the Changelog to see if the issue is already fixed:
|
Check the Changelog to see if the issue is already fixed:
|
||||||
https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog
|
https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog
|
||||||
|
|||||||
1535
.github/workflows/ccpp.yml
vendored
1535
.github/workflows/ccpp.yml
vendored
File diff suppressed because it is too large
Load Diff
6
.gitignore
vendored
6
.gitignore
vendored
@@ -105,7 +105,6 @@ Thumbs.db
|
|||||||
# Stuff in dist
|
# Stuff in dist
|
||||||
maketarball.sh
|
maketarball.sh
|
||||||
changelog
|
changelog
|
||||||
PKGBUILD
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
translations.pot
|
translations.pot
|
||||||
@@ -119,3 +118,8 @@ stage/
|
|||||||
*.snap
|
*.snap
|
||||||
/snap/.snapcraft/
|
/snap/.snapcraft/
|
||||||
/*_source.tar.bz2
|
/*_source.tar.bz2
|
||||||
|
|
||||||
|
# MSVC
|
||||||
|
CMakeSettings.json
|
||||||
|
/.vs/
|
||||||
|
/out/
|
||||||
|
|||||||
5
3rdparty/README.md
vendored
5
3rdparty/README.md
vendored
@@ -23,3 +23,8 @@ macdeployqt
|
|||||||
A modified version of Qt's official macdeployqt utility that fixes some issues,
|
A modified version of Qt's official macdeployqt utility that fixes some issues,
|
||||||
this version also deploys gstreamer plugins.
|
this version also deploys gstreamer plugins.
|
||||||
Can safely be deleted on other platforms.
|
Can safely be deleted on other platforms.
|
||||||
|
|
||||||
|
|
||||||
|
getopt
|
||||||
|
------
|
||||||
|
getopt included only when compiling with MSVC on Windows.
|
||||||
|
|||||||
2
3rdparty/getopt/CMakeLists.txt
vendored
Normal file
2
3rdparty/getopt/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
add_library(getopt STATIC getopt.c)
|
||||||
|
target_include_directories(getopt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
562
3rdparty/getopt/getopt.c
vendored
Normal file
562
3rdparty/getopt/getopt.c
vendored
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
|
||||||
|
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*/
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Dieter Baron and Thomas Klausner.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
|
||||||
|
|
||||||
|
#ifdef REPLACE_GETOPT
|
||||||
|
int opterr = 1; /* if error message should be printed */
|
||||||
|
int optind = 1; /* index into parent argv vector */
|
||||||
|
int optopt = '?'; /* character checked for validity */
|
||||||
|
#undef optreset /* see getopt.h */
|
||||||
|
#define optreset __mingw_optreset
|
||||||
|
int optreset; /* reset getopt */
|
||||||
|
char *optarg; /* argument associated with option */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRINT_ERROR ((opterr) && (*options != ':'))
|
||||||
|
|
||||||
|
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
|
||||||
|
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
|
||||||
|
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
|
||||||
|
|
||||||
|
/* return values */
|
||||||
|
#define BADCH (int)'?'
|
||||||
|
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
|
||||||
|
#define INORDER (int)1
|
||||||
|
|
||||||
|
#ifndef __CYGWIN__
|
||||||
|
#define __progname __argv[0]
|
||||||
|
#else
|
||||||
|
extern char __declspec(dllimport) *__progname;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
static char EMSG[] = "";
|
||||||
|
#else
|
||||||
|
#define EMSG ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int getopt_internal(int, char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int parse_long_options(char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int gcd(int, int);
|
||||||
|
static void permute_args(int, int, int, char * const *);
|
||||||
|
|
||||||
|
static char *place = EMSG; /* option letter processing */
|
||||||
|
|
||||||
|
/* XXX: set optreset to 1 rather than these two */
|
||||||
|
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||||
|
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||||
|
|
||||||
|
/* Error messages */
|
||||||
|
static const char recargchar[] = "option requires an argument -- %c";
|
||||||
|
static const char recargstring[] = "option requires an argument -- %s";
|
||||||
|
static const char ambig[] = "ambiguous option -- %.*s";
|
||||||
|
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||||
|
static const char illoptchar[] = "unknown option -- %c";
|
||||||
|
static const char illoptstring[] = "unknown option -- %s";
|
||||||
|
|
||||||
|
static void
|
||||||
|
_vwarnx(const char *fmt,va_list ap)
|
||||||
|
{
|
||||||
|
(void)fprintf(stderr,"%s: ",__progname);
|
||||||
|
if (fmt != NULL)
|
||||||
|
(void)vfprintf(stderr,fmt,ap);
|
||||||
|
(void)fprintf(stderr,"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
warnx(const char *fmt,...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,fmt);
|
||||||
|
_vwarnx(fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the greatest common divisor of a and b.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
gcd(int a, int b)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = a % b;
|
||||||
|
while (c != 0) {
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
c = a % b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||||
|
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||||
|
* in each block).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
permute_args(int panonopt_start, int panonopt_end, int opt_end,
|
||||||
|
char * const *nargv)
|
||||||
|
{
|
||||||
|
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||||
|
char *swap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute lengths of blocks and number and size of cycles
|
||||||
|
*/
|
||||||
|
nnonopts = panonopt_end - panonopt_start;
|
||||||
|
nopts = opt_end - panonopt_end;
|
||||||
|
ncycle = gcd(nnonopts, nopts);
|
||||||
|
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||||
|
|
||||||
|
for (i = 0; i < ncycle; i++) {
|
||||||
|
cstart = panonopt_end+i;
|
||||||
|
pos = cstart;
|
||||||
|
for (j = 0; j < cyclelen; j++) {
|
||||||
|
if (pos >= panonopt_end)
|
||||||
|
pos -= nnonopts;
|
||||||
|
else
|
||||||
|
pos += nopts;
|
||||||
|
swap = nargv[pos];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **) nargv)[pos] = nargv[cstart];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **)nargv)[cstart] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse_long_options --
|
||||||
|
* Parse long options in argc/argv argument vector.
|
||||||
|
* Returns -1 if short_too is set and the option does not match long_options.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_long_options(char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int short_too)
|
||||||
|
{
|
||||||
|
char *current_argv, *has_equal;
|
||||||
|
size_t current_argv_len;
|
||||||
|
int i, ambiguous, match;
|
||||||
|
|
||||||
|
#define IDENTICAL_INTERPRETATION(_x, _y) \
|
||||||
|
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
|
||||||
|
long_options[(_x)].flag == long_options[(_y)].flag && \
|
||||||
|
long_options[(_x)].val == long_options[(_y)].val)
|
||||||
|
|
||||||
|
current_argv = place;
|
||||||
|
match = -1;
|
||||||
|
ambiguous = 0;
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||||
|
/* argument found (--option=arg) */
|
||||||
|
current_argv_len = has_equal - current_argv;
|
||||||
|
has_equal++;
|
||||||
|
} else
|
||||||
|
current_argv_len = strlen(current_argv);
|
||||||
|
|
||||||
|
for (i = 0; long_options[i].name; i++) {
|
||||||
|
/* find matching long option */
|
||||||
|
if (strncmp(current_argv, long_options[i].name,
|
||||||
|
current_argv_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(long_options[i].name) == current_argv_len) {
|
||||||
|
/* exact match */
|
||||||
|
match = i;
|
||||||
|
ambiguous = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If this is a known short option, don't allow
|
||||||
|
* a partial match of a single character.
|
||||||
|
*/
|
||||||
|
if (short_too && current_argv_len == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (match == -1) /* partial match */
|
||||||
|
match = i;
|
||||||
|
else if (!IDENTICAL_INTERPRETATION(i, match))
|
||||||
|
ambiguous = 1;
|
||||||
|
}
|
||||||
|
if (ambiguous) {
|
||||||
|
/* ambiguous abbreviation */
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(ambig, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (match != -1) { /* option found */
|
||||||
|
if (long_options[match].has_arg == no_argument
|
||||||
|
&& has_equal) {
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(noarg, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
if (long_options[match].has_arg == required_argument ||
|
||||||
|
long_options[match].has_arg == optional_argument) {
|
||||||
|
if (has_equal)
|
||||||
|
optarg = has_equal;
|
||||||
|
else if (long_options[match].has_arg ==
|
||||||
|
required_argument) {
|
||||||
|
/*
|
||||||
|
* optional argument doesn't use next nargv
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((long_options[match].has_arg == required_argument)
|
||||||
|
&& (optarg == NULL)) {
|
||||||
|
/*
|
||||||
|
* Missing argument; leading ':' indicates no error
|
||||||
|
* should be generated.
|
||||||
|
*/
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargstring,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
--optind;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
} else { /* unknown option */
|
||||||
|
if (short_too) {
|
||||||
|
--optind;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptstring, current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (idx)
|
||||||
|
*idx = match;
|
||||||
|
if (long_options[match].flag) {
|
||||||
|
*long_options[match].flag = long_options[match].val;
|
||||||
|
return (0);
|
||||||
|
} else
|
||||||
|
return (long_options[match].val);
|
||||||
|
#undef IDENTICAL_INTERPRETATION
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_internal --
|
||||||
|
* Parse argc/argv argument vector. Called by user level routines.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int flags)
|
||||||
|
{
|
||||||
|
char *oli; /* option letter list index */
|
||||||
|
int optchar, short_too;
|
||||||
|
static int posixly_correct = -1;
|
||||||
|
|
||||||
|
if (options == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Some GNU programs (like cvs) set optind to 0 instead of
|
||||||
|
* XXX using optreset. Work around this braindamage.
|
||||||
|
*/
|
||||||
|
if (optind == 0)
|
||||||
|
optind = optreset = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable GNU extensions if POSIXLY_CORRECT is set or options
|
||||||
|
* string begins with a '+'.
|
||||||
|
*
|
||||||
|
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
|
||||||
|
* optreset != 0 for GNU compatibility.
|
||||||
|
*/
|
||||||
|
if (posixly_correct == -1 || optreset != 0)
|
||||||
|
posixly_correct = (GetEnvironmentVariableW(L"POSIXLY_CORRECT", NULL, 0) != 0);
|
||||||
|
if (*options == '-')
|
||||||
|
flags |= FLAG_ALLARGS;
|
||||||
|
else if (posixly_correct || *options == '+')
|
||||||
|
flags &= ~FLAG_PERMUTE;
|
||||||
|
if (*options == '+' || *options == '-')
|
||||||
|
options++;
|
||||||
|
|
||||||
|
optarg = NULL;
|
||||||
|
if (optreset)
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
start:
|
||||||
|
if (optreset || !*place) { /* update scanning pointer */
|
||||||
|
optreset = 0;
|
||||||
|
if (optind >= nargc) { /* end of argument vector */
|
||||||
|
place = EMSG;
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
/* do permutation, if we have to */
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
else if (nonopt_start != -1) {
|
||||||
|
/*
|
||||||
|
* If we skipped non-options, set optind
|
||||||
|
* to the first of them.
|
||||||
|
*/
|
||||||
|
optind = nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (*(place = nargv[optind]) != '-' ||
|
||||||
|
(place[1] == '\0' && strchr(options, '-') == NULL)) {
|
||||||
|
place = EMSG; /* found non-option */
|
||||||
|
if (flags & FLAG_ALLARGS) {
|
||||||
|
/*
|
||||||
|
* GNU extension:
|
||||||
|
* return non-option as argument to option 1
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
return (INORDER);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAG_PERMUTE)) {
|
||||||
|
/*
|
||||||
|
* If no permutation wanted, stop parsing
|
||||||
|
* at first non-option.
|
||||||
|
*/
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
/* do permutation */
|
||||||
|
if (nonopt_start == -1)
|
||||||
|
nonopt_start = optind;
|
||||||
|
else if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
nonopt_start = optind -
|
||||||
|
(nonopt_end - nonopt_start);
|
||||||
|
nonopt_end = -1;
|
||||||
|
}
|
||||||
|
optind++;
|
||||||
|
/* process next argument */
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
if (nonopt_start != -1 && nonopt_end == -1)
|
||||||
|
nonopt_end = optind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have "-" do nothing, if "--" we are done.
|
||||||
|
*/
|
||||||
|
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
|
||||||
|
optind++;
|
||||||
|
place = EMSG;
|
||||||
|
/*
|
||||||
|
* We found an option (--), so if we skipped
|
||||||
|
* non-options, we have to permute.
|
||||||
|
*/
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check long options if:
|
||||||
|
* 1) we were passed some
|
||||||
|
* 2) the arg is not just "-"
|
||||||
|
* 3) either the arg starts with -- we are getopt_long_only()
|
||||||
|
*/
|
||||||
|
if (long_options != NULL && place != nargv[optind] &&
|
||||||
|
(*place == '-' || (flags & FLAG_LONGONLY))) {
|
||||||
|
short_too = 0;
|
||||||
|
if (*place == '-')
|
||||||
|
place++; /* --foo long option */
|
||||||
|
else if (*place != ':' && strchr(options, *place) != NULL)
|
||||||
|
short_too = 1; /* could be short option too */
|
||||||
|
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, short_too);
|
||||||
|
if (optchar != -1) {
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optchar = (int)*place++) == (int)':' ||
|
||||||
|
(optchar == (int)'-' && *place != '\0') ||
|
||||||
|
(oli = strchr(options, optchar)) == NULL) {
|
||||||
|
/*
|
||||||
|
* If the user specified "-" and '-' isn't listed in
|
||||||
|
* options, return -1 (non-option) as per POSIX.
|
||||||
|
* Otherwise, it is an unknown option character (or ':').
|
||||||
|
*/
|
||||||
|
if (optchar == (int)'-' && *place == '\0')
|
||||||
|
return (-1);
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
|
||||||
|
/* -W long-option */
|
||||||
|
if (*place) /* no space */
|
||||||
|
/* NOTHING */;
|
||||||
|
else if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else /* white space */
|
||||||
|
place = nargv[optind];
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, 0);
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
if (*++oli != ':') { /* doesn't take argument */
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
} else { /* takes (optional) argument */
|
||||||
|
optarg = NULL;
|
||||||
|
if (*place) /* no white space */
|
||||||
|
optarg = place;
|
||||||
|
else if (oli[1] != ':') { /* arg not optional */
|
||||||
|
if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else
|
||||||
|
optarg = nargv[optind];
|
||||||
|
}
|
||||||
|
place = EMSG;
|
||||||
|
++optind;
|
||||||
|
}
|
||||||
|
/* dump back option letter */
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REPLACE_GETOPT
|
||||||
|
/*
|
||||||
|
* getopt --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*
|
||||||
|
* [eventually this will replace the BSD getopt]
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt(int nargc, char * const *nargv, const char *options)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't pass FLAG_PERMUTE to getopt_internal() since
|
||||||
|
* the BSD getopt(3) (unlike GNU) has never done this.
|
||||||
|
*
|
||||||
|
* Furthermore, since many privileged programs call getopt()
|
||||||
|
* before dropping privileges it makes sense to keep things
|
||||||
|
* as simple (and bug-free) as possible.
|
||||||
|
*/
|
||||||
|
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
|
||||||
|
}
|
||||||
|
#endif /* REPLACE_GETOPT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_long --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_long_only --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE|FLAG_LONGONLY));
|
||||||
|
}
|
||||||
95
3rdparty/getopt/getopt.h
vendored
Normal file
95
3rdparty/getopt/getopt.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#ifndef __GETOPT_H__
|
||||||
|
/**
|
||||||
|
* DISCLAIMER
|
||||||
|
* This file has no copyright assigned and is placed in the Public Domain.
|
||||||
|
* This file is part of the mingw-w64 runtime package.
|
||||||
|
*
|
||||||
|
* The mingw-w64 runtime package and its code is distributed in the hope that it
|
||||||
|
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
|
||||||
|
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
|
||||||
|
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __GETOPT_H__
|
||||||
|
|
||||||
|
/* All the headers include this file. */
|
||||||
|
#include <crtdefs.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int optind; /* index of first non-option in argv */
|
||||||
|
extern int optopt; /* single option character, as parsed */
|
||||||
|
extern int opterr; /* flag to enable built-in diagnostics... */
|
||||||
|
/* (user may set to zero, to suppress) */
|
||||||
|
|
||||||
|
extern char *optarg; /* pointer to argument of current option */
|
||||||
|
|
||||||
|
extern int getopt(int nargc, char * const *nargv, const char *options);
|
||||||
|
|
||||||
|
#ifdef _BSD_SOURCE
|
||||||
|
/*
|
||||||
|
* BSD adds the non-standard `optreset' feature, for reinitialisation
|
||||||
|
* of `getopt' parsing. We support this feature, for applications which
|
||||||
|
* proclaim their BSD heritage, before including this header; however,
|
||||||
|
* to maintain portability, developers are advised to avoid it.
|
||||||
|
*/
|
||||||
|
# define optreset __mingw_optreset
|
||||||
|
extern int optreset;
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* POSIX requires the `getopt' API to be specified in `unistd.h';
|
||||||
|
* thus, `unistd.h' includes this header. However, we do not want
|
||||||
|
* to expose the `getopt_long' or `getopt_long_only' APIs, when
|
||||||
|
* included in this manner. Thus, close the standard __GETOPT_H__
|
||||||
|
* declarations block, and open an additional __GETOPT_LONG_H__
|
||||||
|
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
|
||||||
|
* to declare the extended API.
|
||||||
|
*/
|
||||||
|
#endif /* !defined(__GETOPT_H__) */
|
||||||
|
|
||||||
|
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
|
||||||
|
#define __GETOPT_LONG_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct option /* specification for a long form option... */
|
||||||
|
{
|
||||||
|
const char *name; /* option name, without leading hyphens */
|
||||||
|
int has_arg; /* does it take an argument? */
|
||||||
|
int *flag; /* where to save its status, or NULL */
|
||||||
|
int val; /* its associated status value */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum /* permitted values for its `has_arg' field... */
|
||||||
|
{
|
||||||
|
no_argument = 0, /* option never takes an argument */
|
||||||
|
required_argument, /* option always requires an argument */
|
||||||
|
optional_argument /* option may take an argument */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int getopt_long(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx);
|
||||||
|
extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx);
|
||||||
|
/*
|
||||||
|
* Previous MinGW implementation had...
|
||||||
|
*/
|
||||||
|
#ifndef HAVE_DECL_GETOPT
|
||||||
|
/*
|
||||||
|
* ...for the long form API only; keep this for compatibility.
|
||||||
|
*/
|
||||||
|
# define HAVE_DECL_GETOPT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
|
||||||
127
3rdparty/macdeployqt/shared.cpp
vendored
127
3rdparty/macdeployqt/shared.cpp
vendored
@@ -1214,28 +1214,42 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
|
|
||||||
// GIO modules
|
// GIO modules
|
||||||
{
|
{
|
||||||
QString sourcePath = qgetenv("GIO_EXTRA_MODULES");
|
QString giomodule_path = qgetenv("GIO_EXTRA_MODULES");
|
||||||
if (sourcePath.isEmpty()) {
|
if (giomodule_path.isEmpty()) {
|
||||||
if (QFileInfo::exists("/usr/local/lib/gio/modules/libgiognutls.so")) {
|
if (QDir().exists("/usr/local/lib/gio/modules")) {
|
||||||
sourcePath = "/usr/local/lib/gio/modules/libgiognutls.so";
|
giomodule_path = "/usr/local/lib/gio/modules";
|
||||||
}
|
}
|
||||||
else if (QFileInfo::exists("/opt/local/lib/gio/modules/libgiognutls.so")) {
|
else if (QDir().exists("/opt/local/lib/gio/modules")) {
|
||||||
sourcePath = "/opt/local/lib/gio/modules/libgiognutls.so";
|
giomodule_path = "/opt/local/lib/gio/modules";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qFatal("Missing GIO_EXTRA_MODULES");
|
qFatal("Missing GIO_EXTRA_MODULES");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
sourcePath = sourcePath + "/libgiognutls.so";
|
const QStringList giomodules = QStringList() << "libgiognutls.so" << "libgioopenssl.so";
|
||||||
|
bool have_giomodule = false;
|
||||||
|
for (const QString &giomodule : giomodules) {
|
||||||
|
const QString sourcePath = giomodule_path + "/" + giomodule;
|
||||||
|
QFileInfo fileinfo(sourcePath);
|
||||||
|
if (!fileinfo.exists()) {
|
||||||
|
LogError() << "Missing GIO module" << fileinfo.baseName();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
have_giomodule = true;
|
||||||
|
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/" + giomodule;
|
||||||
|
QDir dir;
|
||||||
|
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
|
||||||
|
runStrip(destinationPath);
|
||||||
|
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
|
||||||
|
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gio-modules/libgiognutls.so";
|
|
||||||
QDir dir;
|
if (!have_giomodule) {
|
||||||
if (dir.mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
|
qFatal("Missing GIO modules.");
|
||||||
runStrip(destinationPath);
|
|
||||||
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
|
|
||||||
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gst-plugin-scanner
|
// gst-plugin-scanner
|
||||||
@@ -1262,8 +1276,12 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GStreamer plugins.
|
// GStreamer plugins.
|
||||||
QStringList gstreamer_plugins = QStringList() << "libgstapetag.dylib"
|
QStringList gstreamer_plugins = QStringList()
|
||||||
|
<< "libgstaiff.dylib"
|
||||||
|
<< "libgstapetag.dylib"
|
||||||
<< "libgstapp.dylib"
|
<< "libgstapp.dylib"
|
||||||
|
<< "libgstasf.dylib"
|
||||||
|
<< "libgstasfmux.dylib"
|
||||||
<< "libgstaudioconvert.dylib"
|
<< "libgstaudioconvert.dylib"
|
||||||
<< "libgstaudiofx.dylib"
|
<< "libgstaudiofx.dylib"
|
||||||
<< "libgstaudiomixer.dylib"
|
<< "libgstaudiomixer.dylib"
|
||||||
@@ -1271,48 +1289,46 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
<< "libgstaudiorate.dylib"
|
<< "libgstaudiorate.dylib"
|
||||||
<< "libgstaudioresample.dylib"
|
<< "libgstaudioresample.dylib"
|
||||||
<< "libgstaudiotestsrc.dylib"
|
<< "libgstaudiotestsrc.dylib"
|
||||||
<< "libgstaudiovisualizers.dylib"
|
|
||||||
<< "libgstauparse.dylib"
|
|
||||||
<< "libgstautoconvert.dylib"
|
|
||||||
<< "libgstautodetect.dylib"
|
<< "libgstautodetect.dylib"
|
||||||
|
<< "libgstbs2b.dylib"
|
||||||
|
<< "libgstcdio.dylib"
|
||||||
<< "libgstcoreelements.dylib"
|
<< "libgstcoreelements.dylib"
|
||||||
|
<< "libgstdash.dylib"
|
||||||
<< "libgstequalizer.dylib"
|
<< "libgstequalizer.dylib"
|
||||||
|
<< "libgstflac.dylib"
|
||||||
|
<< "libgstfaac.dylib"
|
||||||
|
<< "libgstfaad.dylib"
|
||||||
|
<< "libgstfdkaac.dylib"
|
||||||
<< "libgstgio.dylib"
|
<< "libgstgio.dylib"
|
||||||
<< "libgsticydemux.dylib"
|
<< "libgsticydemux.dylib"
|
||||||
<< "libgstid3demux.dylib"
|
<< "libgstid3demux.dylib"
|
||||||
<< "libgstlevel.dylib"
|
<< "libgstisomp4.dylib"
|
||||||
|
<< "libgstlame.dylib"
|
||||||
|
<< "libgstlibav.dylib"
|
||||||
|
<< "libgstmpg123.dylib"
|
||||||
|
<< "libgstmusepack.dylib"
|
||||||
|
<< "libgstogg.dylib"
|
||||||
|
<< "libgstopenmpt.dylib"
|
||||||
|
<< "libgstopus.dylib"
|
||||||
|
<< "libgstopusparse.dylib"
|
||||||
<< "libgstosxaudio.dylib"
|
<< "libgstosxaudio.dylib"
|
||||||
<< "libgstplayback.dylib"
|
|
||||||
<< "libgstrawparse.dylib"
|
|
||||||
<< "libgstreplaygain.dylib"
|
|
||||||
<< "libgstsoup.dylib"
|
|
||||||
<< "libgstspectrum.dylib"
|
|
||||||
<< "libgsttypefindfunctions.dylib"
|
|
||||||
<< "libgstvolume.dylib"
|
|
||||||
<< "libgstxingmux.dylib"
|
|
||||||
<< "libgsttcp.dylib"
|
|
||||||
<< "libgstudp.dylib"
|
|
||||||
<< "libgstpbtypes.dylib"
|
<< "libgstpbtypes.dylib"
|
||||||
|
<< "libgstplayback.dylib"
|
||||||
|
<< "libgstreplaygain.dylib"
|
||||||
<< "libgstrtp.dylib"
|
<< "libgstrtp.dylib"
|
||||||
<< "libgstrtsp.dylib"
|
<< "libgstrtsp.dylib"
|
||||||
<< "libgstflac.dylib"
|
<< "libgstsoup.dylib"
|
||||||
<< "libgstwavparse.dylib"
|
<< "libgstspectrum.dylib"
|
||||||
<< "libgstfaad.dylib"
|
|
||||||
<< "libgstogg.dylib"
|
|
||||||
<< "libgstopus.dylib"
|
|
||||||
<< "libgstasf.dylib"
|
|
||||||
<< "libgstspeex.dylib"
|
<< "libgstspeex.dylib"
|
||||||
<< "libgsttaglib.dylib"
|
<< "libgsttaglib.dylib"
|
||||||
|
<< "libgsttcp.dylib"
|
||||||
|
<< "libgsttypefindfunctions.dylib"
|
||||||
|
<< "libgstudp.dylib"
|
||||||
|
<< "libgstvolume.dylib"
|
||||||
<< "libgstvorbis.dylib"
|
<< "libgstvorbis.dylib"
|
||||||
<< "libgstisomp4.dylib"
|
<< "libgstwavpack.dylib"
|
||||||
<< "libgstlibav.dylib"
|
<< "libgstwavparse.dylib"
|
||||||
<< "libgstaiff.dylib"
|
<< "libgstxingmux.dylib";
|
||||||
<< "libgstlame.dylib";
|
|
||||||
|
|
||||||
// macports does not have these.
|
|
||||||
QStringList gstreamer_plugins_optional = QStringList() << "libgstopusparse.dylib"
|
|
||||||
<< "libgstfaac.dylib"
|
|
||||||
<< "libgstmusepack.dylib";
|
|
||||||
|
|
||||||
QString gstreamer_plugins_dir = qgetenv("GST_PLUGIN_PATH");
|
QString gstreamer_plugins_dir = qgetenv("GST_PLUGIN_PATH");
|
||||||
if (gstreamer_plugins_dir.isEmpty()) {
|
if (gstreamer_plugins_dir.isEmpty()) {
|
||||||
@@ -1327,13 +1343,16 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList missing_gst_plugins;
|
||||||
|
|
||||||
for (const QString &plugin : gstreamer_plugins) {
|
for (const QString &plugin : gstreamer_plugins) {
|
||||||
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
|
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
|
||||||
if (!info.exists()) {
|
if (!info.exists()) {
|
||||||
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
|
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
|
||||||
if (!info.exists()) {
|
if (!info.exists()) {
|
||||||
LogError() << "Missing gstreamer plugin" << info.baseName();
|
LogError() << "Missing gstreamer plugin" << info.baseName();
|
||||||
qFatal("Missing %s", info.baseName().toUtf8().constData());
|
missing_gst_plugins << info.baseName();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const QString &sourcePath = info.filePath();
|
const QString &sourcePath = info.filePath();
|
||||||
@@ -1345,22 +1364,8 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString &plugin : gstreamer_plugins_optional) {
|
if (!missing_gst_plugins.isEmpty()) {
|
||||||
QFileInfo info(gstreamer_plugins_dir + "/" + plugin);
|
LogError() << "Missing gstreamer plugins" << missing_gst_plugins;
|
||||||
if (!info.exists()) {
|
|
||||||
info.setFile(gstreamer_plugins_dir + "/" + info.baseName() + QString(".so"));
|
|
||||||
if (!info.exists()) {
|
|
||||||
LogWarning() << "Skip missing gstreamer plugin" << info.baseName();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const QString &sourcePath = info.filePath();
|
|
||||||
const QString destinationPath = appBundleInfo.path + "/Contents/PlugIns/gstreamer/" + info.fileName();
|
|
||||||
if (QDir().mkpath(QFileInfo(destinationPath).path()) && copyFilePrintStatus(sourcePath, destinationPath)) {
|
|
||||||
runStrip(destinationPath);
|
|
||||||
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
|
|
||||||
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
2
3rdparty/singleapplication/LICENSE
vendored
2
3rdparty/singleapplication/LICENSE
vendored
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) Itay Grudev 2015 - 2016
|
Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
86
3rdparty/singleapplication/README.md
vendored
86
3rdparty/singleapplication/README.md
vendored
@@ -1,7 +1,8 @@
|
|||||||
SingleApplication
|
SingleApplication
|
||||||
=================
|
=================
|
||||||
|
[](https://github.com/itay-grudev/SingleApplication/actions)
|
||||||
|
|
||||||
This is a replacement of the QtSingleApplication for `Qt5`.
|
This is a replacement of the QtSingleApplication for `Qt5` and `Qt6`.
|
||||||
|
|
||||||
Keeps the Primary Instance of your Application and kills each subsequent
|
Keeps the Primary Instance of your Application and kills each subsequent
|
||||||
instances. It can (if enabled) spawn secondary (non-related to the primary)
|
instances. It can (if enabled) spawn secondary (non-related to the primary)
|
||||||
@@ -15,18 +16,6 @@ class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
|
|||||||
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
||||||
classes.
|
classes.
|
||||||
|
|
||||||
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
|
||||||
instance of your Application is your Primary Instance. It would check if the
|
|
||||||
shared memory block exists and if not it will start a `QLocalServer` and listen
|
|
||||||
for connections. Each subsequent instance of your application would check if the
|
|
||||||
shared memory block exists and if it does, it will connect to the QLocalServer
|
|
||||||
to notify the primary instance that a new instance had been started, after which
|
|
||||||
it would terminate with status code `0`. In the Primary Instance
|
|
||||||
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
|
||||||
that a new instance had been started.
|
|
||||||
|
|
||||||
The library uses `stdlib` to terminate the program with the `exit()` function.
|
|
||||||
|
|
||||||
You can use the library as if you use any other `QCoreApplication` derived
|
You can use the library as if you use any other `QCoreApplication` derived
|
||||||
class:
|
class:
|
||||||
|
|
||||||
@@ -43,24 +32,49 @@ int main( int argc, char* argv[] )
|
|||||||
```
|
```
|
||||||
|
|
||||||
To include the library files I would recommend that you add it as a git
|
To include the library files I would recommend that you add it as a git
|
||||||
submodule to your project and include it's contents with a `.pri` file. Here is
|
submodule to your project. Here is how:
|
||||||
how:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
|
git submodule add https://github.com/itay-grudev/SingleApplication.git singleapplication
|
||||||
```
|
```
|
||||||
|
|
||||||
Then include the `singleapplication.pri` file in your `.pro` project file. Also
|
**Qmake:**
|
||||||
don't forget to specify which `QCoreApplication` class your app is using if it
|
|
||||||
is not `QCoreApplication`.
|
Then include the `singleapplication.pri` file in your `.pro` project file.
|
||||||
|
|
||||||
```qmake
|
```qmake
|
||||||
include(singleapplication/singleapplication.pri)
|
include(singleapplication/singleapplication.pri)
|
||||||
DEFINES += QAPPLICATION_CLASS=QApplication
|
DEFINES += QAPPLICATION_CLASS=QApplication
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**CMake:**
|
||||||
|
|
||||||
|
Then include the subdirectory in your `CMakeLists.txt` project file.
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
||||||
|
add_subdirectory(src/third-party/singleapplication)
|
||||||
|
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
||||||
|
instance of your Application is your Primary Instance. It would check if the
|
||||||
|
shared memory block exists and if not it will start a `QLocalServer` and listen
|
||||||
|
for connections. Each subsequent instance of your application would check if the
|
||||||
|
shared memory block exists and if it does, it will connect to the QLocalServer
|
||||||
|
to notify the primary instance that a new instance had been started, after which
|
||||||
|
it would terminate with status code `0`. In the Primary Instance
|
||||||
|
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
||||||
|
that a new instance had been started.
|
||||||
|
|
||||||
|
The library uses `stdlib` to terminate the program with the `exit()` function.
|
||||||
|
|
||||||
|
Also don't forget to specify which `QCoreApplication` class your app is using if it
|
||||||
|
is not `QCoreApplication` as in examples above.
|
||||||
|
|
||||||
The `Instance Started` signal
|
The `Instance Started` signal
|
||||||
------------------------
|
-----------------------------
|
||||||
|
|
||||||
The SingleApplication class implements a `instanceStarted()` signal. You can
|
The SingleApplication class implements a `instanceStarted()` signal. You can
|
||||||
bind to that signal to raise your application's window when a new instance had
|
bind to that signal to raise your application's window when a new instance had
|
||||||
@@ -125,13 +139,22 @@ app.isSecondary();
|
|||||||
*__Note:__ If your Primary Instance is terminated a newly launched instance
|
*__Note:__ If your Primary Instance is terminated a newly launched instance
|
||||||
will replace the Primary one even if the Secondary flag has been set.*
|
will replace the Primary one even if the Secondary flag has been set.*
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
There are three examples provided in this repository:
|
||||||
|
|
||||||
|
* Basic example that prevents a secondary instance from starting [`examples/basic`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/basic)
|
||||||
|
* An example of a graphical application raising it's parent window [`examples/calculator`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/calculator)
|
||||||
|
* A console application sending the primary instance it's command line parameters [`examples/sending_arguments`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/sending_arguments)
|
||||||
|
|
||||||
API
|
API
|
||||||
---
|
---
|
||||||
|
|
||||||
### Members
|
### Members
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
|
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100, QString userData = QString() )
|
||||||
```
|
```
|
||||||
|
|
||||||
Depending on whether `allowSecondary` is set, this constructor may terminate
|
Depending on whether `allowSecondary` is set, this constructor may terminate
|
||||||
@@ -140,7 +163,7 @@ can be specified to set whether the SingleApplication block should work
|
|||||||
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
|
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
|
||||||
used to notify the primary instance whenever a secondary instance had been
|
used to notify the primary instance whenever a secondary instance had been
|
||||||
started (disabled by default). `timeout` specifies the maximum time in
|
started (disabled by default). `timeout` specifies the maximum time in
|
||||||
milliseconds to wait for blocking operations.
|
milliseconds to wait for blocking operations. Setting `userData` provides additional data that will isolate this instance from other instances that do not have the same (or any) user data set.
|
||||||
|
|
||||||
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
|
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
|
||||||
recognizes.*
|
recognizes.*
|
||||||
@@ -159,7 +182,8 @@ bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
|
|||||||
```
|
```
|
||||||
|
|
||||||
Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
|
Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
|
||||||
in milliseconds for blocking functions
|
in milliseconds for blocking functions. Returns `true` if the message has been sent
|
||||||
|
successfully. If the message can't be sent or the function timeouts - returns `false`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -192,6 +216,22 @@ qint64 SingleApplication::primaryPid()
|
|||||||
|
|
||||||
Returns the process ID (PID) of the primary instance.
|
Returns the process ID (PID) of the primary instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QString SingleApplication::primaryUser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the username the primary instance is running as.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QString SingleApplication::currentUser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the username the current instance is running as.
|
||||||
|
|
||||||
### Signals
|
### Signals
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|||||||
44
3rdparty/singleapplication/singleapplication.cpp
vendored
44
3rdparty/singleapplication/singleapplication.cpp
vendored
@@ -54,7 +54,7 @@
|
|||||||
* @param options Optional flags to toggle specific behaviour
|
* @param options Optional flags to toggle specific behaviour
|
||||||
* @param timeout Maximum time blocking functions are allowed during app load
|
* @param timeout Maximum time blocking functions are allowed during app load
|
||||||
*/
|
*/
|
||||||
SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondary, Options options, int timeout)
|
SingleApplication::SingleApplication(int &argc, char *argv[], const bool allowSecondary, const Options options, const int timeout)
|
||||||
: app_t(argc, argv),
|
: app_t(argc, argv),
|
||||||
d_ptr(new SingleApplicationPrivate(this)) {
|
d_ptr(new SingleApplicationPrivate(this)) {
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondar
|
|||||||
d->genBlockServerName();
|
d->genBlockServerName();
|
||||||
|
|
||||||
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
||||||
d->randomSleep();
|
SingleApplicationPrivate::randomSleep();
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
||||||
@@ -106,14 +106,14 @@ SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(d->memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(d->memory_->data());
|
||||||
QElapsedTimer time;
|
QElapsedTimer time;
|
||||||
time.start();
|
time.start();
|
||||||
|
|
||||||
// Make sure the shared memory block is initialised and in consistent state
|
// Make sure the shared memory block is initialised and in consistent state
|
||||||
forever {
|
forever {
|
||||||
// If the shared memory block's checksum is valid continue
|
// If the shared memory block's checksum is valid continue
|
||||||
if (d->blockChecksum() == inst->checksum) break;
|
if (d->blockChecksum() == instance->checksum) break;
|
||||||
|
|
||||||
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
||||||
if (time.elapsed() > 5000) {
|
if (time.elapsed() > 5000) {
|
||||||
@@ -127,14 +127,14 @@ SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondar
|
|||||||
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
|
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
|
||||||
qDebug() << d->memory_->errorString();
|
qDebug() << d->memory_->errorString();
|
||||||
}
|
}
|
||||||
d->randomSleep();
|
SingleApplicationPrivate::randomSleep();
|
||||||
if (!d->memory_->lock()) {
|
if (!d->memory_->lock()) {
|
||||||
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
|
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
|
||||||
abortSafely();
|
abortSafely();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inst->primary) {
|
if (!instance->primary) {
|
||||||
d->startPrimary();
|
d->startPrimary();
|
||||||
if (!d->memory_->unlock()) {
|
if (!d->memory_->unlock()) {
|
||||||
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
|
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
|
||||||
@@ -178,8 +178,8 @@ SingleApplication::~SingleApplication() {
|
|||||||
* Checks if the current application instance is primary.
|
* Checks if the current application instance is primary.
|
||||||
* @return Returns true if the instance is primary, false otherwise.
|
* @return Returns true if the instance is primary, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool SingleApplication::isPrimary() {
|
bool SingleApplication::isPrimary() const {
|
||||||
Q_D(SingleApplication);
|
Q_D(const SingleApplication);
|
||||||
return d->server_ != nullptr;
|
return d->server_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +187,8 @@ bool SingleApplication::isPrimary() {
|
|||||||
* Checks if the current application instance is secondary.
|
* Checks if the current application instance is secondary.
|
||||||
* @return Returns true if the instance is secondary, false otherwise.
|
* @return Returns true if the instance is secondary, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool SingleApplication::isSecondary() {
|
bool SingleApplication::isSecondary() const {
|
||||||
Q_D(SingleApplication);
|
Q_D(const SingleApplication);
|
||||||
return d->server_ == nullptr;
|
return d->server_ == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +197,8 @@ bool SingleApplication::isSecondary() {
|
|||||||
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
||||||
* @return Returns a unique instance id.
|
* @return Returns a unique instance id.
|
||||||
*/
|
*/
|
||||||
quint32 SingleApplication::instanceId() {
|
quint32 SingleApplication::instanceId() const {
|
||||||
Q_D(SingleApplication);
|
Q_D(const SingleApplication);
|
||||||
return d->instanceNumber_;
|
return d->instanceNumber_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,8 +207,8 @@ quint32 SingleApplication::instanceId() {
|
|||||||
* Especially useful when SingleApplication is coupled with OS. specific APIs.
|
* Especially useful when SingleApplication is coupled with OS. specific APIs.
|
||||||
* @return Returns the primary instance PID.
|
* @return Returns the primary instance PID.
|
||||||
*/
|
*/
|
||||||
qint64 SingleApplication::primaryPid() {
|
qint64 SingleApplication::primaryPid() const {
|
||||||
Q_D(SingleApplication);
|
Q_D(const SingleApplication);
|
||||||
return d->primaryPid();
|
return d->primaryPid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +216,8 @@ qint64 SingleApplication::primaryPid() {
|
|||||||
* Returns the username the primary instance is running as.
|
* Returns the username the primary instance is running as.
|
||||||
* @return Returns the username the primary instance is running as.
|
* @return Returns the username the primary instance is running as.
|
||||||
*/
|
*/
|
||||||
QString SingleApplication::primaryUser() {
|
QString SingleApplication::primaryUser() const {
|
||||||
Q_D(SingleApplication);
|
Q_D(const SingleApplication);
|
||||||
return d->primaryUser();
|
return d->primaryUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,9 +225,8 @@ QString SingleApplication::primaryUser() {
|
|||||||
* Returns the username the current instance is running as.
|
* Returns the username the current instance is running as.
|
||||||
* @return Returns the username the current instance is running as.
|
* @return Returns the username the current instance is running as.
|
||||||
*/
|
*/
|
||||||
QString SingleApplication::currentUser() {
|
QString SingleApplication::currentUser() const {
|
||||||
Q_D(SingleApplication);
|
return SingleApplicationPrivate::getUsername();
|
||||||
return d->getUsername();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,11 +247,7 @@ bool SingleApplication::sendMessage(const QByteArray &message, const int timeout
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
d->socket_->write(message);
|
return d->writeConfirmedMessage(timeout, message);
|
||||||
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
|
|
||||||
d->socket_->flush();
|
|
||||||
return dataWritten;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -265,6 +260,7 @@ void SingleApplication::abortSafely() {
|
|||||||
|
|
||||||
qCritical() << "SingleApplication: " << d->memory_->error() << d->memory_->errorString();
|
qCritical() << "SingleApplication: " << d->memory_->error() << d->memory_->errorString();
|
||||||
delete d;
|
delete d;
|
||||||
|
|
||||||
::exit(EXIT_FAILURE);
|
::exit(EXIT_FAILURE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
17
3rdparty/singleapplication/singleapplication.h
vendored
17
3rdparty/singleapplication/singleapplication.h
vendored
@@ -48,7 +48,7 @@ class SingleApplicationPrivate;
|
|||||||
class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-parent-argument
|
class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-parent-argument
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
typedef QApplication app_t;
|
using app_t = QApplication;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -88,46 +88,45 @@ class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-p
|
|||||||
* operations. It does not guarantee that the SingleApplication
|
* operations. It does not guarantee that the SingleApplication
|
||||||
* initialisation will be completed in given time, though is a good hint.
|
* initialisation will be completed in given time, though is a good hint.
|
||||||
* Usually 4*timeout would be the worst case (fail) scenario.
|
* Usually 4*timeout would be the worst case (fail) scenario.
|
||||||
* @see See the corresponding QAPPLICATION_CLASS constructor for reference
|
|
||||||
*/
|
*/
|
||||||
explicit SingleApplication(int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000);
|
explicit SingleApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
|
||||||
~SingleApplication() override;
|
~SingleApplication() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns if the instance is the primary instance
|
* @brief Returns if the instance is the primary instance
|
||||||
* @returns {bool}
|
* @returns {bool}
|
||||||
*/
|
*/
|
||||||
bool isPrimary();
|
bool isPrimary() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns if the instance is a secondary instance
|
* @brief Returns if the instance is a secondary instance
|
||||||
* @returns {bool}
|
* @returns {bool}
|
||||||
*/
|
*/
|
||||||
bool isSecondary();
|
bool isSecondary() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a unique identifier for the current instance
|
* @brief Returns a unique identifier for the current instance
|
||||||
* @returns {qint32}
|
* @returns {qint32}
|
||||||
*/
|
*/
|
||||||
quint32 instanceId();
|
quint32 instanceId() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the process ID (PID) of the primary instance
|
* @brief Returns the process ID (PID) of the primary instance
|
||||||
* @returns {qint64}
|
* @returns {qint64}
|
||||||
*/
|
*/
|
||||||
qint64 primaryPid();
|
qint64 primaryPid() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the username of the user running the primary instance
|
* @brief Returns the username of the user running the primary instance
|
||||||
* @returns {QString}
|
* @returns {QString}
|
||||||
*/
|
*/
|
||||||
QString primaryUser();
|
QString primaryUser() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the username of the current user
|
* @brief Returns the username of the current user
|
||||||
* @returns {QString}
|
* @returns {QString}
|
||||||
*/
|
*/
|
||||||
QString currentUser();
|
QString currentUser() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a message to the primary instance. Returns true on success.
|
* @brief Sends a message to the primary instance. Returns true on success.
|
||||||
|
|||||||
191
3rdparty/singleapplication/singleapplication_p.cpp
vendored
191
3rdparty/singleapplication/singleapplication_p.cpp
vendored
@@ -44,6 +44,14 @@
|
|||||||
# include <pwd.h>
|
# include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX 1
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
# include <lmcons.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
@@ -53,7 +61,6 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QDir>
|
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
# include <QRandomGenerator>
|
# include <QRandomGenerator>
|
||||||
@@ -64,11 +71,6 @@
|
|||||||
#include "singleapplication.h"
|
#include "singleapplication.h"
|
||||||
#include "singleapplication_p.h"
|
#include "singleapplication_p.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
# include <windows.h>
|
|
||||||
# include <lmcons.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SingleApplicationPrivate::SingleApplicationPrivate(SingleApplication *ptr)
|
SingleApplicationPrivate::SingleApplicationPrivate(SingleApplication *ptr)
|
||||||
: q_ptr(ptr),
|
: q_ptr(ptr),
|
||||||
memory_(nullptr),
|
memory_(nullptr),
|
||||||
@@ -86,14 +88,14 @@ SingleApplicationPrivate::~SingleApplicationPrivate() {
|
|||||||
|
|
||||||
if (memory_ != nullptr) {
|
if (memory_ != nullptr) {
|
||||||
memory_->lock();
|
memory_->lock();
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
if (server_ != nullptr) {
|
if (server_ != nullptr) {
|
||||||
server_->close();
|
server_->close();
|
||||||
delete server_;
|
delete server_;
|
||||||
inst->primary = false;
|
instance->primary = false;
|
||||||
inst->primaryPid = -1;
|
instance->primaryPid = -1;
|
||||||
inst->primaryUser[0] = '\0';
|
instance->primaryUser[0] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
}
|
}
|
||||||
memory_->unlock();
|
memory_->unlock();
|
||||||
|
|
||||||
@@ -142,7 +144,7 @@ QString SingleApplicationPrivate::getUsername() {
|
|||||||
void SingleApplicationPrivate::genBlockServerName() {
|
void SingleApplicationPrivate::genBlockServerName() {
|
||||||
|
|
||||||
QCryptographicHash appData(QCryptographicHash::Sha256);
|
QCryptographicHash appData(QCryptographicHash::Sha256);
|
||||||
appData.addData("SingleApplication", 17);
|
appData.addData("SingleApplication");
|
||||||
appData.addData(SingleApplication::app_t::applicationName().toUtf8());
|
appData.addData(SingleApplication::app_t::applicationName().toUtf8());
|
||||||
appData.addData(SingleApplication::app_t::organizationName().toUtf8());
|
appData.addData(SingleApplication::app_t::organizationName().toUtf8());
|
||||||
appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
|
appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
|
||||||
@@ -152,7 +154,15 @@ void SingleApplicationPrivate::genBlockServerName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(options_ & SingleApplication::Mode::ExcludeAppPath)) {
|
if (!(options_ & SingleApplication::Mode::ExcludeAppPath)) {
|
||||||
#ifdef Q_OS_WIN
|
#if defined(Q_OS_UNIX)
|
||||||
|
const QByteArray appImagePath = qgetenv("APPIMAGE");
|
||||||
|
if (appImagePath.isEmpty()) {
|
||||||
|
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appData.addData(appImagePath);
|
||||||
|
};
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
appData.addData(SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
|
appData.addData(SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
|
||||||
#else
|
#else
|
||||||
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
|
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
|
||||||
@@ -171,26 +181,24 @@ void SingleApplicationPrivate::genBlockServerName() {
|
|||||||
|
|
||||||
void SingleApplicationPrivate::initializeMemoryBlock() const {
|
void SingleApplicationPrivate::initializeMemoryBlock() const {
|
||||||
|
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
inst->primary = false;
|
instance->primary = false;
|
||||||
inst->secondary = 0;
|
instance->secondary = 0;
|
||||||
inst->primaryPid = -1;
|
instance->primaryPid = -1;
|
||||||
inst->primaryUser[0] = '\0';
|
instance->primaryUser[0] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleApplicationPrivate::startPrimary() {
|
void SingleApplicationPrivate::startPrimary() {
|
||||||
|
|
||||||
Q_Q(SingleApplication);
|
|
||||||
|
|
||||||
// Reset the number of connections
|
// Reset the number of connections
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
inst->primary = true;
|
instance->primary = true;
|
||||||
inst->primaryPid = q->applicationPid();
|
instance->primaryPid = QCoreApplication::applicationPid();
|
||||||
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
|
qstrncpy(instance->primaryUser, getUsername().toUtf8().data(), sizeof(instance->primaryUser));
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
instanceNumber_ = 0;
|
instanceNumber_ = 0;
|
||||||
// Successful creation means that no main process exists
|
// Successful creation means that no main process exists
|
||||||
// So we start a QLocalServer to listen for connections
|
// So we start a QLocalServer to listen for connections
|
||||||
@@ -212,11 +220,11 @@ void SingleApplicationPrivate::startPrimary() {
|
|||||||
|
|
||||||
void SingleApplicationPrivate::startSecondary() {
|
void SingleApplicationPrivate::startSecondary() {
|
||||||
|
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
inst->secondary += 1;
|
instance->secondary += 1;
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
instanceNumber_ = inst->secondary;
|
instanceNumber_ = instance->secondary;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,25 +271,53 @@ bool SingleApplicationPrivate::connectToPrimary(const int timeout, const Connect
|
|||||||
writeStream << instanceNumber_;
|
writeStream << instanceNumber_;
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||||
#else
|
#else
|
||||||
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
writeStream << checksum;
|
writeStream << checksum;
|
||||||
|
|
||||||
// The header indicates the message length that follows
|
return writeConfirmedMessage(static_cast<int>(timeout - time.elapsed()), initMsg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleApplicationPrivate::writeAck(QLocalSocket *sock) {
|
||||||
|
sock->putChar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::writeConfirmedMessage(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Frame 1: The header indicates the message length that follows
|
||||||
QByteArray header;
|
QByteArray header;
|
||||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||||
headerStream.setVersion(QDataStream::Qt_5_8);
|
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||||
headerStream << static_cast<quint64>(initMsg.length());
|
headerStream << static_cast<quint64>(msg.length());
|
||||||
|
|
||||||
socket_->write(header);
|
if (!writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), header)) {
|
||||||
socket_->write(initMsg);
|
return false;
|
||||||
bool result = socket_->waitForBytesWritten(static_cast<int>(timeout - time.elapsed()));
|
}
|
||||||
|
|
||||||
|
// Frame 2: The message
|
||||||
|
return writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::writeConfirmedFrame(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
socket_->write(msg);
|
||||||
socket_->flush();
|
socket_->flush();
|
||||||
|
|
||||||
return result;
|
bool result = socket_->waitForReadyRead(timeout);
|
||||||
|
if (result) {
|
||||||
|
socket_->read(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,8 +336,8 @@ quint16 SingleApplicationPrivate::blockChecksum() const {
|
|||||||
qint64 SingleApplicationPrivate::primaryPid() const {
|
qint64 SingleApplicationPrivate::primaryPid() const {
|
||||||
|
|
||||||
memory_->lock();
|
memory_->lock();
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
qint64 pid = inst->primaryPid;
|
qint64 pid = instance->primaryPid;
|
||||||
memory_->unlock();
|
memory_->unlock();
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
@@ -311,8 +347,8 @@ qint64 SingleApplicationPrivate::primaryPid() const {
|
|||||||
QString SingleApplicationPrivate::primaryUser() const {
|
QString SingleApplicationPrivate::primaryUser() const {
|
||||||
|
|
||||||
memory_->lock();
|
memory_->lock();
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
QByteArray username = inst->primaryUser;
|
QByteArray username = instance->primaryUser;
|
||||||
memory_->unlock();
|
memory_->unlock();
|
||||||
|
|
||||||
return QString::fromUtf8(username);
|
return QString::fromUtf8(username);
|
||||||
@@ -328,26 +364,30 @@ void SingleApplicationPrivate::slotConnectionEstablished() {
|
|||||||
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
||||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
|
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this, [nextConnSocket, this]() {
|
||||||
connectionMap_.remove(nextConnSocket);
|
connectionMap_.remove(nextConnSocket);
|
||||||
nextConnSocket->deleteLater();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
||||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
switch (info.stage) {
|
switch (info.stage) {
|
||||||
case StageHeader:
|
case StageInitHeader:
|
||||||
readInitMessageHeader(nextConnSocket);
|
readMessageHeader(nextConnSocket, StageInitBody);
|
||||||
break;
|
break;
|
||||||
case StageBody:
|
case StageInitBody:
|
||||||
readInitMessageBody(nextConnSocket);
|
readInitMessageBody(nextConnSocket);
|
||||||
break;
|
break;
|
||||||
case StageConnected:
|
case StageConnectedHeader:
|
||||||
slotDataAvailable(nextConnSocket, info.instanceId);
|
readMessageHeader(nextConnSocket, StageConnectedBody);
|
||||||
|
break;
|
||||||
|
case StageConnectedBody:
|
||||||
|
this->slotDataAvailable(nextConnSocket, info.instanceId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -356,7 +396,7 @@ void SingleApplicationPrivate::slotConnectionEstablished() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
|
void SingleApplicationPrivate::readMessageHeader(QLocalSocket *sock, const SingleApplicationPrivate::ConnectionStage nextStage) {
|
||||||
|
|
||||||
if (!connectionMap_.contains(sock)) {
|
if (!connectionMap_.contains(sock)) {
|
||||||
return;
|
return;
|
||||||
@@ -373,30 +413,34 @@ void SingleApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
|
|||||||
quint64 msgLen = 0;
|
quint64 msgLen = 0;
|
||||||
headerStream >> msgLen;
|
headerStream >> msgLen;
|
||||||
ConnectionInfo &info = connectionMap_[sock];
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
info.stage = StageBody;
|
info.stage = nextStage;
|
||||||
info.msgLen = msgLen;
|
info.msgLen = msgLen;
|
||||||
|
|
||||||
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
|
writeAck(sock);
|
||||||
readInitMessageBody(sock);
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplicationPrivate::isFrameComplete(QLocalSocket *sock) {
|
||||||
|
|
||||||
|
if (!connectionMap_.contains(sock)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
return (sock->bytesAvailable() >= static_cast<qint64>(info.msgLen));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
||||||
|
|
||||||
Q_Q(SingleApplication);
|
Q_Q(SingleApplication);
|
||||||
|
|
||||||
if (!connectionMap_.contains(sock)) {
|
if (!isFrameComplete(sock)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionInfo &info = connectionMap_[sock];
|
|
||||||
if (sock->bytesAvailable() < static_cast<qint64>(info.msgLen)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the message body
|
// Read the message body
|
||||||
QByteArray msgBytes = sock->read(static_cast<qint64>(info.msgLen));
|
QByteArray msgBytes = sock->readAll();
|
||||||
QDataStream readStream(msgBytes);
|
QDataStream readStream(msgBytes);
|
||||||
readStream.setVersion(QDataStream::Qt_5_8);
|
readStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
@@ -431,23 +475,34 @@ void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
info.instanceId = instanceId;
|
info.instanceId = instanceId;
|
||||||
info.stage = StageConnected;
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleApplication::Mode::SecondaryNotification)) {
|
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleApplication::Mode::SecondaryNotification)) {
|
||||||
Q_EMIT q->instanceStarted();
|
emit q->instanceStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sock->bytesAvailable() > 0) {
|
writeAck(sock);
|
||||||
slotDataAvailable(sock, instanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
||||||
|
|
||||||
Q_Q(SingleApplication);
|
Q_Q(SingleApplication);
|
||||||
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
|
|
||||||
|
if (!isFrameComplete(dataSocket)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray message = dataSocket->readAll();
|
||||||
|
|
||||||
|
writeAck(dataSocket);
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[dataSocket];
|
||||||
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
|
emit q->receivedMessage(instanceId, message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +520,7 @@ void SingleApplicationPrivate::randomSleep() {
|
|||||||
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
||||||
#else
|
#else
|
||||||
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
||||||
QThread::msleep(8 + static_cast<unsigned long>(static_cast<float>(qrand()) / RAND_MAX * 10));
|
QThread::msleep(qrand() % 11 + 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
13
3rdparty/singleapplication/singleapplication_p.h
vendored
13
3rdparty/singleapplication/singleapplication_p.h
vendored
@@ -71,9 +71,10 @@ class SingleApplicationPrivate : public QObject {
|
|||||||
Reconnect = 3
|
Reconnect = 3
|
||||||
};
|
};
|
||||||
enum ConnectionStage : quint8 {
|
enum ConnectionStage : quint8 {
|
||||||
StageHeader = 0,
|
StageInitHeader = 0,
|
||||||
StageBody = 1,
|
StageInitBody = 1,
|
||||||
StageConnected = 2,
|
StageConnectedHeader = 2,
|
||||||
|
StageConnectedBody = 3,
|
||||||
};
|
};
|
||||||
Q_DECLARE_PUBLIC(SingleApplication)
|
Q_DECLARE_PUBLIC(SingleApplication)
|
||||||
|
|
||||||
@@ -89,8 +90,12 @@ class SingleApplicationPrivate : public QObject {
|
|||||||
quint16 blockChecksum() const;
|
quint16 blockChecksum() const;
|
||||||
qint64 primaryPid() const;
|
qint64 primaryPid() const;
|
||||||
QString primaryUser() const;
|
QString primaryUser() const;
|
||||||
void readInitMessageHeader(QLocalSocket *socket);
|
bool isFrameComplete(QLocalSocket *sock);
|
||||||
|
void readMessageHeader(QLocalSocket *socket, const ConnectionStage nextStage);
|
||||||
void readInitMessageBody(QLocalSocket *socket);
|
void readInitMessageBody(QLocalSocket *socket);
|
||||||
|
void writeAck(QLocalSocket *sock);
|
||||||
|
bool writeConfirmedFrame(const int timeout, const QByteArray &msg) const;
|
||||||
|
bool writeConfirmedMessage(const int timeout, const QByteArray &msg) const;
|
||||||
static void randomSleep();
|
static void randomSleep();
|
||||||
|
|
||||||
SingleApplication *q_ptr;
|
SingleApplication *q_ptr;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
* @param options Optional flags to toggle specific behaviour
|
* @param options Optional flags to toggle specific behaviour
|
||||||
* @param timeout Maximum time blocking functions are allowed during app load
|
* @param timeout Maximum time blocking functions are allowed during app load
|
||||||
*/
|
*/
|
||||||
SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allowSecondary, Options options, int timeout)
|
SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary, const Options options, const int timeout)
|
||||||
: app_t(argc, argv),
|
: app_t(argc, argv),
|
||||||
d_ptr(new SingleCoreApplicationPrivate(this)) {
|
d_ptr(new SingleCoreApplicationPrivate(this)) {
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allow
|
|||||||
d->genBlockServerName();
|
d->genBlockServerName();
|
||||||
|
|
||||||
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
||||||
d->randomSleep();
|
SingleCoreApplicationPrivate::randomSleep();
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
||||||
@@ -106,14 +106,14 @@ SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(d->memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(d->memory_->data());
|
||||||
QElapsedTimer time;
|
QElapsedTimer time;
|
||||||
time.start();
|
time.start();
|
||||||
|
|
||||||
// Make sure the shared memory block is initialised and in consistent state
|
// Make sure the shared memory block is initialised and in consistent state
|
||||||
forever {
|
forever {
|
||||||
// If the shared memory block's checksum is valid continue
|
// If the shared memory block's checksum is valid continue
|
||||||
if (d->blockChecksum() == inst->checksum) break;
|
if (d->blockChecksum() == instance->checksum) break;
|
||||||
|
|
||||||
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
||||||
if (time.elapsed() > 5000) {
|
if (time.elapsed() > 5000) {
|
||||||
@@ -127,14 +127,14 @@ SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allow
|
|||||||
qDebug() << "SingleCoreApplication: Unable to unlock memory for random wait.";
|
qDebug() << "SingleCoreApplication: Unable to unlock memory for random wait.";
|
||||||
qDebug() << d->memory_->errorString();
|
qDebug() << d->memory_->errorString();
|
||||||
}
|
}
|
||||||
d->randomSleep();
|
SingleCoreApplicationPrivate::randomSleep();
|
||||||
if (!d->memory_->lock()) {
|
if (!d->memory_->lock()) {
|
||||||
qCritical() << "SingleCoreApplication: Unable to lock memory after random wait.";
|
qCritical() << "SingleCoreApplication: Unable to lock memory after random wait.";
|
||||||
abortSafely();
|
abortSafely();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inst->primary) {
|
if (!instance->primary) {
|
||||||
d->startPrimary();
|
d->startPrimary();
|
||||||
if (!d->memory_->unlock()) {
|
if (!d->memory_->unlock()) {
|
||||||
qDebug() << "SingleCoreApplication: Unable to unlock memory after primary start.";
|
qDebug() << "SingleCoreApplication: Unable to unlock memory after primary start.";
|
||||||
@@ -178,8 +178,8 @@ SingleCoreApplication::~SingleCoreApplication() {
|
|||||||
* Checks if the current application instance is primary.
|
* Checks if the current application instance is primary.
|
||||||
* @return Returns true if the instance is primary, false otherwise.
|
* @return Returns true if the instance is primary, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool SingleCoreApplication::isPrimary() {
|
bool SingleCoreApplication::isPrimary() const {
|
||||||
Q_D(SingleCoreApplication);
|
Q_D(const SingleCoreApplication);
|
||||||
return d->server_ != nullptr;
|
return d->server_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +187,8 @@ bool SingleCoreApplication::isPrimary() {
|
|||||||
* Checks if the current application instance is secondary.
|
* Checks if the current application instance is secondary.
|
||||||
* @return Returns true if the instance is secondary, false otherwise.
|
* @return Returns true if the instance is secondary, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool SingleCoreApplication::isSecondary() {
|
bool SingleCoreApplication::isSecondary() const {
|
||||||
Q_D(SingleCoreApplication);
|
Q_D(const SingleCoreApplication);
|
||||||
return d->server_ == nullptr;
|
return d->server_ == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +197,8 @@ bool SingleCoreApplication::isSecondary() {
|
|||||||
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
||||||
* @return Returns a unique instance id.
|
* @return Returns a unique instance id.
|
||||||
*/
|
*/
|
||||||
quint32 SingleCoreApplication::instanceId() {
|
quint32 SingleCoreApplication::instanceId() const {
|
||||||
Q_D(SingleCoreApplication);
|
Q_D(const SingleCoreApplication);
|
||||||
return d->instanceNumber_;
|
return d->instanceNumber_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,8 +207,8 @@ quint32 SingleCoreApplication::instanceId() {
|
|||||||
* Especially useful when SingleCoreApplication is coupled with OS. specific APIs.
|
* Especially useful when SingleCoreApplication is coupled with OS. specific APIs.
|
||||||
* @return Returns the primary instance PID.
|
* @return Returns the primary instance PID.
|
||||||
*/
|
*/
|
||||||
qint64 SingleCoreApplication::primaryPid() {
|
qint64 SingleCoreApplication::primaryPid() const {
|
||||||
Q_D(SingleCoreApplication);
|
Q_D(const SingleCoreApplication);
|
||||||
return d->primaryPid();
|
return d->primaryPid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +216,8 @@ qint64 SingleCoreApplication::primaryPid() {
|
|||||||
* Returns the username the primary instance is running as.
|
* Returns the username the primary instance is running as.
|
||||||
* @return Returns the username the primary instance is running as.
|
* @return Returns the username the primary instance is running as.
|
||||||
*/
|
*/
|
||||||
QString SingleCoreApplication::primaryUser() {
|
QString SingleCoreApplication::primaryUser() const {
|
||||||
Q_D(SingleCoreApplication);
|
Q_D(const SingleCoreApplication);
|
||||||
return d->primaryUser();
|
return d->primaryUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,9 +225,8 @@ QString SingleCoreApplication::primaryUser() {
|
|||||||
* Returns the username the current instance is running as.
|
* Returns the username the current instance is running as.
|
||||||
* @return Returns the username the current instance is running as.
|
* @return Returns the username the current instance is running as.
|
||||||
*/
|
*/
|
||||||
QString SingleCoreApplication::currentUser() {
|
QString SingleCoreApplication::currentUser() const {
|
||||||
Q_D(SingleCoreApplication);
|
return SingleCoreApplicationPrivate::getUsername();
|
||||||
return d->getUsername();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,11 +247,7 @@ bool SingleCoreApplication::sendMessage(const QByteArray &message, const int tim
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
d->socket_->write(message);
|
return d->writeConfirmedMessage(timeout, message);
|
||||||
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
|
|
||||||
d->socket_->flush();
|
|
||||||
return dataWritten;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -265,6 +260,7 @@ void SingleCoreApplication::abortSafely() {
|
|||||||
|
|
||||||
qCritical() << "SingleCoreApplication: " << d->memory_->error() << d->memory_->errorString();
|
qCritical() << "SingleCoreApplication: " << d->memory_->error() << d->memory_->errorString();
|
||||||
delete d;
|
delete d;
|
||||||
|
|
||||||
::exit(EXIT_FAILURE);
|
::exit(EXIT_FAILURE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ class SingleCoreApplicationPrivate;
|
|||||||
* @brief The SingleCoreApplication class handles multiple instances of the same Application
|
* @brief The SingleCoreApplication class handles multiple instances of the same Application
|
||||||
* @see QCoreApplication
|
* @see QCoreApplication
|
||||||
*/
|
*/
|
||||||
class SingleCoreApplication : public QCoreApplication {
|
class SingleCoreApplication : public QCoreApplication { // clazy:exclude=ctor-missing-parent-argument
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
typedef QCoreApplication app_t;
|
using app_t = QCoreApplication;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -96,37 +96,37 @@ class SingleCoreApplication : public QCoreApplication {
|
|||||||
* @brief Returns if the instance is the primary instance
|
* @brief Returns if the instance is the primary instance
|
||||||
* @returns {bool}
|
* @returns {bool}
|
||||||
*/
|
*/
|
||||||
bool isPrimary();
|
bool isPrimary() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns if the instance is a secondary instance
|
* @brief Returns if the instance is a secondary instance
|
||||||
* @returns {bool}
|
* @returns {bool}
|
||||||
*/
|
*/
|
||||||
bool isSecondary();
|
bool isSecondary() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a unique identifier for the current instance
|
* @brief Returns a unique identifier for the current instance
|
||||||
* @returns {qint32}
|
* @returns {qint32}
|
||||||
*/
|
*/
|
||||||
quint32 instanceId();
|
quint32 instanceId() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the process ID (PID) of the primary instance
|
* @brief Returns the process ID (PID) of the primary instance
|
||||||
* @returns {qint64}
|
* @returns {qint64}
|
||||||
*/
|
*/
|
||||||
qint64 primaryPid();
|
qint64 primaryPid() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the username of the user running the primary instance
|
* @brief Returns the username of the user running the primary instance
|
||||||
* @returns {QString}
|
* @returns {QString}
|
||||||
*/
|
*/
|
||||||
QString primaryUser();
|
QString primaryUser() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the username of the current user
|
* @brief Returns the username of the current user
|
||||||
* @returns {QString}
|
* @returns {QString}
|
||||||
*/
|
*/
|
||||||
QString currentUser();
|
QString currentUser() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a message to the primary instance. Returns true on success.
|
* @brief Sends a message to the primary instance. Returns true on success.
|
||||||
|
|||||||
@@ -44,6 +44,14 @@
|
|||||||
# include <pwd.h>
|
# include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX 1
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
# include <lmcons.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
@@ -53,7 +61,6 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QDir>
|
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||||
# include <QRandomGenerator>
|
# include <QRandomGenerator>
|
||||||
@@ -64,11 +71,6 @@
|
|||||||
#include "singlecoreapplication.h"
|
#include "singlecoreapplication.h"
|
||||||
#include "singlecoreapplication_p.h"
|
#include "singlecoreapplication_p.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
# include <windows.h>
|
|
||||||
# include <lmcons.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SingleCoreApplicationPrivate::SingleCoreApplicationPrivate(SingleCoreApplication *ptr)
|
SingleCoreApplicationPrivate::SingleCoreApplicationPrivate(SingleCoreApplication *ptr)
|
||||||
: q_ptr(ptr),
|
: q_ptr(ptr),
|
||||||
memory_(nullptr),
|
memory_(nullptr),
|
||||||
@@ -86,14 +88,14 @@ SingleCoreApplicationPrivate::~SingleCoreApplicationPrivate() {
|
|||||||
|
|
||||||
if (memory_ != nullptr) {
|
if (memory_ != nullptr) {
|
||||||
memory_->lock();
|
memory_->lock();
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
if (server_ != nullptr) {
|
if (server_ != nullptr) {
|
||||||
server_->close();
|
server_->close();
|
||||||
delete server_;
|
delete server_;
|
||||||
inst->primary = false;
|
instance->primary = false;
|
||||||
inst->primaryPid = -1;
|
instance->primaryPid = -1;
|
||||||
inst->primaryUser[0] = '\0';
|
instance->primaryUser[0] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
}
|
}
|
||||||
memory_->unlock();
|
memory_->unlock();
|
||||||
|
|
||||||
@@ -142,7 +144,7 @@ QString SingleCoreApplicationPrivate::getUsername() {
|
|||||||
void SingleCoreApplicationPrivate::genBlockServerName() {
|
void SingleCoreApplicationPrivate::genBlockServerName() {
|
||||||
|
|
||||||
QCryptographicHash appData(QCryptographicHash::Sha256);
|
QCryptographicHash appData(QCryptographicHash::Sha256);
|
||||||
appData.addData("SingleApplication", 17);
|
appData.addData("SingleApplication");
|
||||||
appData.addData(SingleCoreApplication::app_t::applicationName().toUtf8());
|
appData.addData(SingleCoreApplication::app_t::applicationName().toUtf8());
|
||||||
appData.addData(SingleCoreApplication::app_t::organizationName().toUtf8());
|
appData.addData(SingleCoreApplication::app_t::organizationName().toUtf8());
|
||||||
appData.addData(SingleCoreApplication::app_t::organizationDomain().toUtf8());
|
appData.addData(SingleCoreApplication::app_t::organizationDomain().toUtf8());
|
||||||
@@ -152,7 +154,15 @@ void SingleCoreApplicationPrivate::genBlockServerName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppPath)) {
|
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppPath)) {
|
||||||
#ifdef Q_OS_WIN
|
#if defined(Q_OS_UNIX)
|
||||||
|
const QByteArray appImagePath = qgetenv("APPIMAGE");
|
||||||
|
if (appImagePath.isEmpty()) {
|
||||||
|
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appData.addData(appImagePath);
|
||||||
|
};
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toLower().toUtf8());
|
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toLower().toUtf8());
|
||||||
#else
|
#else
|
||||||
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
|
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
|
||||||
@@ -171,26 +181,24 @@ void SingleCoreApplicationPrivate::genBlockServerName() {
|
|||||||
|
|
||||||
void SingleCoreApplicationPrivate::initializeMemoryBlock() const {
|
void SingleCoreApplicationPrivate::initializeMemoryBlock() const {
|
||||||
|
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
inst->primary = false;
|
instance->primary = false;
|
||||||
inst->secondary = 0;
|
instance->secondary = 0;
|
||||||
inst->primaryPid = -1;
|
instance->primaryPid = -1;
|
||||||
inst->primaryUser[0] = '\0';
|
instance->primaryUser[0] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCoreApplicationPrivate::startPrimary() {
|
void SingleCoreApplicationPrivate::startPrimary() {
|
||||||
|
|
||||||
Q_Q(SingleCoreApplication);
|
|
||||||
|
|
||||||
// Reset the number of connections
|
// Reset the number of connections
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
inst->primary = true;
|
instance->primary = true;
|
||||||
inst->primaryPid = q->applicationPid();
|
instance->primaryPid = QCoreApplication::applicationPid();
|
||||||
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
|
qstrncpy(instance->primaryUser, getUsername().toUtf8().data(), sizeof(instance->primaryUser));
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
instanceNumber_ = 0;
|
instanceNumber_ = 0;
|
||||||
// Successful creation means that no main process exists
|
// Successful creation means that no main process exists
|
||||||
// So we start a QLocalServer to listen for connections
|
// So we start a QLocalServer to listen for connections
|
||||||
@@ -212,11 +220,11 @@ void SingleCoreApplicationPrivate::startPrimary() {
|
|||||||
|
|
||||||
void SingleCoreApplicationPrivate::startSecondary() {
|
void SingleCoreApplicationPrivate::startSecondary() {
|
||||||
|
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
|
|
||||||
inst->secondary += 1;
|
instance->secondary += 1;
|
||||||
inst->checksum = blockChecksum();
|
instance->checksum = blockChecksum();
|
||||||
instanceNumber_ = inst->secondary;
|
instanceNumber_ = instance->secondary;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,25 +271,53 @@ bool SingleCoreApplicationPrivate::connectToPrimary(const int timeout, const Con
|
|||||||
writeStream << instanceNumber_;
|
writeStream << instanceNumber_;
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||||
#else
|
#else
|
||||||
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
writeStream << checksum;
|
writeStream << checksum;
|
||||||
|
|
||||||
// The header indicates the message length that follows
|
return writeConfirmedMessage(static_cast<int>(timeout - time.elapsed()), initMsg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCoreApplicationPrivate::writeAck(QLocalSocket *sock) {
|
||||||
|
sock->putChar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::writeConfirmedMessage(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
QElapsedTimer time;
|
||||||
|
time.start();
|
||||||
|
|
||||||
|
// Frame 1: The header indicates the message length that follows
|
||||||
QByteArray header;
|
QByteArray header;
|
||||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||||
headerStream.setVersion(QDataStream::Qt_5_8);
|
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||||
headerStream << static_cast<quint64>(initMsg.length());
|
headerStream << static_cast<quint64>(msg.length());
|
||||||
|
|
||||||
socket_->write(header);
|
if (!writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), header)) {
|
||||||
socket_->write(initMsg);
|
return false;
|
||||||
bool result = socket_->waitForBytesWritten(timeout - static_cast<int>(time.elapsed()));
|
}
|
||||||
|
|
||||||
|
// Frame 2: The message
|
||||||
|
return writeConfirmedFrame(static_cast<int>(timeout - time.elapsed()), msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::writeConfirmedFrame(const int timeout, const QByteArray &msg) const {
|
||||||
|
|
||||||
|
socket_->write(msg);
|
||||||
socket_->flush();
|
socket_->flush();
|
||||||
|
|
||||||
return result;
|
bool result = socket_->waitForReadyRead(timeout);
|
||||||
|
if (result) {
|
||||||
|
socket_->read(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,8 +336,8 @@ quint16 SingleCoreApplicationPrivate::blockChecksum() const {
|
|||||||
qint64 SingleCoreApplicationPrivate::primaryPid() const {
|
qint64 SingleCoreApplicationPrivate::primaryPid() const {
|
||||||
|
|
||||||
memory_->lock();
|
memory_->lock();
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
qint64 pid = inst->primaryPid;
|
qint64 pid = instance->primaryPid;
|
||||||
memory_->unlock();
|
memory_->unlock();
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
@@ -311,8 +347,8 @@ qint64 SingleCoreApplicationPrivate::primaryPid() const {
|
|||||||
QString SingleCoreApplicationPrivate::primaryUser() const {
|
QString SingleCoreApplicationPrivate::primaryUser() const {
|
||||||
|
|
||||||
memory_->lock();
|
memory_->lock();
|
||||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
InstancesInfo *instance = static_cast<InstancesInfo*>(memory_->data());
|
||||||
QByteArray username = inst->primaryUser;
|
QByteArray username = instance->primaryUser;
|
||||||
memory_->unlock();
|
memory_->unlock();
|
||||||
|
|
||||||
return QString::fromUtf8(username);
|
return QString::fromUtf8(username);
|
||||||
@@ -328,26 +364,30 @@ void SingleCoreApplicationPrivate::slotConnectionEstablished() {
|
|||||||
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
||||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
|
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
|
||||||
|
|
||||||
|
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this, [nextConnSocket, this]() {
|
||||||
connectionMap_.remove(nextConnSocket);
|
connectionMap_.remove(nextConnSocket);
|
||||||
nextConnSocket->deleteLater();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
||||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
const ConnectionInfo &info = connectionMap_[nextConnSocket];
|
||||||
switch (info.stage) {
|
switch (info.stage) {
|
||||||
case StageHeader:
|
case StageInitHeader:
|
||||||
readInitMessageHeader(nextConnSocket);
|
readMessageHeader(nextConnSocket, StageInitBody);
|
||||||
break;
|
break;
|
||||||
case StageBody:
|
case StageInitBody:
|
||||||
readInitMessageBody(nextConnSocket);
|
readInitMessageBody(nextConnSocket);
|
||||||
break;
|
break;
|
||||||
case StageConnected:
|
case StageConnectedHeader:
|
||||||
slotDataAvailable(nextConnSocket, info.instanceId);
|
readMessageHeader(nextConnSocket, StageConnectedBody);
|
||||||
|
break;
|
||||||
|
case StageConnectedBody:
|
||||||
|
this->slotDataAvailable(nextConnSocket, info.instanceId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -356,7 +396,7 @@ void SingleCoreApplicationPrivate::slotConnectionEstablished() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCoreApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
|
void SingleCoreApplicationPrivate::readMessageHeader(QLocalSocket *sock, SingleCoreApplicationPrivate::ConnectionStage nextStage) {
|
||||||
|
|
||||||
if (!connectionMap_.contains(sock)) {
|
if (!connectionMap_.contains(sock)) {
|
||||||
return;
|
return;
|
||||||
@@ -373,30 +413,34 @@ void SingleCoreApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
|
|||||||
quint64 msgLen = 0;
|
quint64 msgLen = 0;
|
||||||
headerStream >> msgLen;
|
headerStream >> msgLen;
|
||||||
ConnectionInfo &info = connectionMap_[sock];
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
info.stage = StageBody;
|
info.stage = nextStage;
|
||||||
info.msgLen = msgLen;
|
info.msgLen = msgLen;
|
||||||
|
|
||||||
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
|
writeAck(sock);
|
||||||
readInitMessageBody(sock);
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleCoreApplicationPrivate::isFrameComplete(QLocalSocket *sock) {
|
||||||
|
|
||||||
|
if (!connectionMap_.contains(sock)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
|
return (sock->bytesAvailable() >= static_cast<qint64>(info.msgLen));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
||||||
|
|
||||||
Q_Q(SingleCoreApplication);
|
Q_Q(SingleCoreApplication);
|
||||||
|
|
||||||
if (!connectionMap_.contains(sock)) {
|
if (!isFrameComplete(sock)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionInfo &info = connectionMap_[sock];
|
|
||||||
if (sock->bytesAvailable() < static_cast<qint64>(info.msgLen)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the message body
|
// Read the message body
|
||||||
QByteArray msgBytes = sock->read(static_cast<qint64>(info.msgLen));
|
QByteArray msgBytes = sock->readAll();
|
||||||
QDataStream readStream(msgBytes);
|
QDataStream readStream(msgBytes);
|
||||||
readStream.setVersion(QDataStream::Qt_5_8);
|
readStream.setVersion(QDataStream::Qt_5_8);
|
||||||
|
|
||||||
@@ -431,23 +475,34 @@ void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[sock];
|
||||||
info.instanceId = instanceId;
|
info.instanceId = instanceId;
|
||||||
info.stage = StageConnected;
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleCoreApplication::Mode::SecondaryNotification)) {
|
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleCoreApplication::Mode::SecondaryNotification)) {
|
||||||
Q_EMIT q->instanceStarted();
|
emit q->instanceStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sock->bytesAvailable() > 0) {
|
writeAck(sock);
|
||||||
slotDataAvailable(sock, instanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
||||||
|
|
||||||
Q_Q(SingleCoreApplication);
|
Q_Q(SingleCoreApplication);
|
||||||
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
|
|
||||||
|
if (!isFrameComplete(dataSocket)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray message = dataSocket->readAll();
|
||||||
|
|
||||||
|
writeAck(dataSocket);
|
||||||
|
|
||||||
|
ConnectionInfo &info = connectionMap_[dataSocket];
|
||||||
|
info.stage = StageConnectedHeader;
|
||||||
|
|
||||||
|
emit q->receivedMessage(instanceId, message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +520,7 @@ void SingleCoreApplicationPrivate::randomSleep() {
|
|||||||
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
||||||
#else
|
#else
|
||||||
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
||||||
QThread::msleep(8 + static_cast<unsigned long>(static_cast<float>(qrand()) / RAND_MAX * 10));
|
QThread::msleep(qrand() % 11 + 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,10 @@ class SingleCoreApplicationPrivate : public QObject {
|
|||||||
Reconnect = 3
|
Reconnect = 3
|
||||||
};
|
};
|
||||||
enum ConnectionStage : quint8 {
|
enum ConnectionStage : quint8 {
|
||||||
StageHeader = 0,
|
StageInitHeader = 0,
|
||||||
StageBody = 1,
|
StageInitBody = 1,
|
||||||
StageConnected = 2,
|
StageConnectedHeader = 2,
|
||||||
|
StageConnectedBody = 3,
|
||||||
};
|
};
|
||||||
Q_DECLARE_PUBLIC(SingleCoreApplication)
|
Q_DECLARE_PUBLIC(SingleCoreApplication)
|
||||||
|
|
||||||
@@ -89,8 +90,12 @@ class SingleCoreApplicationPrivate : public QObject {
|
|||||||
quint16 blockChecksum() const;
|
quint16 blockChecksum() const;
|
||||||
qint64 primaryPid() const;
|
qint64 primaryPid() const;
|
||||||
QString primaryUser() const;
|
QString primaryUser() const;
|
||||||
void readInitMessageHeader(QLocalSocket *socket);
|
bool isFrameComplete(QLocalSocket *sock);
|
||||||
|
void readMessageHeader(QLocalSocket *socket, const ConnectionStage nextStage);
|
||||||
void readInitMessageBody(QLocalSocket *socket);
|
void readInitMessageBody(QLocalSocket *socket);
|
||||||
|
void writeAck(QLocalSocket *sock);
|
||||||
|
bool writeConfirmedFrame(const int timeout, const QByteArray &msg) const;
|
||||||
|
bool writeConfirmedMessage(const int timeout, const QByteArray &msg) const;
|
||||||
static void randomSleep();
|
static void randomSleep();
|
||||||
|
|
||||||
SingleCoreApplication *q_ptr;
|
SingleCoreApplication *q_ptr;
|
||||||
|
|||||||
@@ -58,8 +58,7 @@ else()
|
|||||||
-Wformat=2
|
-Wformat=2
|
||||||
-Wdisabled-optimization
|
-Wdisabled-optimization
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
|
$<$<COMPILE_LANGUAGE:CXX>:-Woverloaded-virtual>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-Wno-old-style-cast>
|
$<$<COMPILE_LANGUAGE:CXX>:-Wold-style-cast>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -117,6 +116,9 @@ endif()
|
|||||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||||
pkg_check_modules(GOBJECT REQUIRED gobject-2.0)
|
pkg_check_modules(GOBJECT REQUIRED gobject-2.0)
|
||||||
pkg_check_modules(GIO REQUIRED gio-2.0)
|
pkg_check_modules(GIO REQUIRED gio-2.0)
|
||||||
|
if(UNIX)
|
||||||
|
pkg_check_modules(GIO_UNIX gio-unix-2.0)
|
||||||
|
endif()
|
||||||
pkg_check_modules(LIBCDIO libcdio)
|
pkg_check_modules(LIBCDIO libcdio)
|
||||||
pkg_check_modules(GSTREAMER gstreamer-1.0)
|
pkg_check_modules(GSTREAMER gstreamer-1.0)
|
||||||
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
|
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
|
||||||
@@ -155,7 +157,7 @@ if(DBUS_FOUND AND NOT WIN32)
|
|||||||
list(APPEND QT_COMPONENTS DBus)
|
list(APPEND QT_COMPONENTS DBus)
|
||||||
endif()
|
endif()
|
||||||
set(QT_OPTIONAL_COMPONENTS Test)
|
set(QT_OPTIONAL_COMPONENTS Test)
|
||||||
set(QT_MIN_VERSION 5.8)
|
set(QT_MIN_VERSION 5.9)
|
||||||
|
|
||||||
if(BUILD_WITH_QT6 OR QT_VERSION_MAJOR EQUAL 6)
|
if(BUILD_WITH_QT6 OR QT_VERSION_MAJOR EQUAL 6)
|
||||||
set(QT_VERSION_MAJOR 6 CACHE STRING "" FORCE)
|
set(QT_VERSION_MAJOR 6 CACHE STRING "" FORCE)
|
||||||
@@ -292,7 +294,6 @@ set(SINGLEAPPLICATION_LIBRARIES singleapplication)
|
|||||||
set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication)
|
set(SINGLECOREAPPLICATION_LIBRARIES singlecoreapplication)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
find_library(SPARKLE Sparkle PATHS "/usr/local/opt/sparkle")
|
|
||||||
add_subdirectory(3rdparty/SPMediaKeyTap)
|
add_subdirectory(3rdparty/SPMediaKeyTap)
|
||||||
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
|
set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
|
||||||
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
|
set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
|
||||||
@@ -300,7 +301,7 @@ if(APPLE)
|
|||||||
add_subdirectory(ext/macdeploycheck)
|
add_subdirectory(ext/macdeploycheck)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT SPARKLE AND (APPLE OR WIN32))
|
if(WIN32)
|
||||||
if(BUILD_WITH_QT6)
|
if(BUILD_WITH_QT6)
|
||||||
pkg_check_modules(QTSPARKLE qtsparkle-qt6)
|
pkg_check_modules(QTSPARKLE qtsparkle-qt6)
|
||||||
else()
|
else()
|
||||||
@@ -311,6 +312,12 @@ if(NOT SPARKLE AND (APPLE OR WIN32))
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WIN32 AND MSVC)
|
||||||
|
add_subdirectory(3rdparty/getopt)
|
||||||
|
set(GETOPT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/getopt)
|
||||||
|
set(GETOPT_LIBRARIES getopt)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32 AND NOT MSVC)
|
if(WIN32 AND NOT MSVC)
|
||||||
# RC compiler
|
# RC compiler
|
||||||
string(REPLACE "gcc" "windres" CMAKE_RC_COMPILER_INIT ${CMAKE_C_COMPILER})
|
string(REPLACE "gcc" "windres" CMAKE_RC_COMPILER_INIT ${CMAKE_C_COMPILER})
|
||||||
@@ -391,6 +398,11 @@ optional_component(GIO ON "Devices: GIO device backend"
|
|||||||
DEPENDS "Unix or Windows" "NOT APPLE"
|
DEPENDS "Unix or Windows" "NOT APPLE"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
optional_component(GIO_UNIX ON "Devices: GIO device backend (Unix support)"
|
||||||
|
DEPENDS "libgio-unix" GIO_UNIX_FOUND
|
||||||
|
DEPENDS "Unix" "UNIX"
|
||||||
|
)
|
||||||
|
|
||||||
optional_component(LIBGPOD ON "Devices: iPod classic support"
|
optional_component(LIBGPOD ON "Devices: iPod classic support"
|
||||||
DEPENDS "libgpod" LIBGPOD_FOUND
|
DEPENDS "libgpod" LIBGPOD_FOUND
|
||||||
DEPENDS "gdk-pixbuf" GDK_PIXBUF_FOUND
|
DEPENDS "gdk-pixbuf" GDK_PIXBUF_FOUND
|
||||||
@@ -400,11 +412,6 @@ optional_component(LIBMTP ON "Devices: MTP support"
|
|||||||
DEPENDS "libmtp" LIBMTP_FOUND
|
DEPENDS "libmtp" LIBMTP_FOUND
|
||||||
)
|
)
|
||||||
|
|
||||||
optional_component(SPARKLE ON "Sparkle integration"
|
|
||||||
DEPENDS "macOS" APPLE
|
|
||||||
DEPENDS "Sparkle" SPARKLE
|
|
||||||
)
|
|
||||||
|
|
||||||
if(BUILD_WITH_QT6)
|
if(BUILD_WITH_QT6)
|
||||||
optional_component(TRANSLATIONS ON "Translations"
|
optional_component(TRANSLATIONS ON "Translations"
|
||||||
DEPENDS "gettext" GETTEXT_FOUND
|
DEPENDS "gettext" GETTEXT_FOUND
|
||||||
@@ -419,9 +426,9 @@ endif()
|
|||||||
|
|
||||||
option(INSTALL_TRANSLATIONS "Install translations" OFF)
|
option(INSTALL_TRANSLATIONS "Install translations" OFF)
|
||||||
|
|
||||||
optional_component(SUBSONIC ON "Subsonic support")
|
optional_component(SUBSONIC ON "Streaming: Subsonic")
|
||||||
optional_component(TIDAL ON "Tidal support")
|
optional_component(TIDAL ON "Streaming: Tidal")
|
||||||
optional_component(QOBUZ ON "Qobuz support")
|
optional_component(QOBUZ ON "Streaming: Qobuz")
|
||||||
|
|
||||||
optional_component(MOODBAR ON "Moodbar"
|
optional_component(MOODBAR ON "Moodbar"
|
||||||
DEPENDS "fftw3" FFTW3_FOUND
|
DEPENDS "fftw3" FFTW3_FOUND
|
||||||
@@ -482,12 +489,13 @@ endif()
|
|||||||
|
|
||||||
# Set up definitions
|
# Set up definitions
|
||||||
|
|
||||||
add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS)
|
add_definitions(
|
||||||
add_definitions(${QT_DEFINITIONS})
|
-DBOOST_BIND_NO_PLACEHOLDERS
|
||||||
add_definitions(-DQT_STRICT_ITERATORS)
|
-DQT_STRICT_ITERATORS
|
||||||
add_definitions(-DQT_USE_QSTRINGBUILDER)
|
-DQT_USE_QSTRINGBUILDER
|
||||||
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
|
-DQT_NO_URL_CAST_FROM_STRING
|
||||||
add_definitions(-DQT_NO_CAST_TO_ASCII)
|
-DQT_NO_CAST_TO_ASCII
|
||||||
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_definitions(-DUNICODE)
|
add_definitions(-DUNICODE)
|
||||||
@@ -510,6 +518,10 @@ if(GTest_FOUND AND GMOCK_LIBRARY AND QtTest_LIBRARIES)
|
|||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LINUX AND LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||||
|
add_subdirectory(debian)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Uninstall support
|
# Uninstall support
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
||||||
|
|
||||||
@@ -518,7 +530,7 @@ add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/c
|
|||||||
# Show a summary of what we have enabled
|
# Show a summary of what we have enabled
|
||||||
summary_show()
|
summary_show()
|
||||||
if(NOT HAVE_GSTREAMER AND NOT HAVE_VLC)
|
if(NOT HAVE_GSTREAMER AND NOT HAVE_VLC)
|
||||||
message(FATAL_ERROR "You need to have either GStreamer or VLC to compile!")
|
message(FATAL_ERROR "You need to have either GStreamer or libvlc to compile!")
|
||||||
elseif(NOT HAVE_GSTREAMER)
|
elseif(NOT HAVE_GSTREAMER)
|
||||||
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
82
Changelog
82
Changelog
@@ -2,6 +2,88 @@ Strawberry Music Player
|
|||||||
=======================
|
=======================
|
||||||
ChangeLog
|
ChangeLog
|
||||||
|
|
||||||
|
Version 1.0.5 (2022.06.10)
|
||||||
|
|
||||||
|
BugFixes:
|
||||||
|
* Fixed smart playlist filetype search.
|
||||||
|
* Fixed Radio Paradise URLs to use HTTPS instead of HTTP.
|
||||||
|
* Fixed horizontal scrolling not affecting currently playing track (#952).
|
||||||
|
* Fixed keep running in the background when window is closed with Wayland (#964).
|
||||||
|
* Fixed percent-encoding of URLs when loading and saving XSPF playlists (#821).
|
||||||
|
* Fixed fancy tabbar context menu showing on right clicks outside of tabbar when a song is playing.
|
||||||
|
* Fixed possible duplicating songs in the database when moving songs to the collection using the organize feature.
|
||||||
|
* (Windows|MSVC) Fixed moodbar fftw3 crash with (older) CPU's that does not support AVX2 (#944).
|
||||||
|
* (Windows|MSVC) Fixed using libiconv for converting characters when organizing files like with MinGW.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
* Show more details in error dialog on GStreamer errors (#958).
|
||||||
|
* Allow setting blur amount of playlist background image up to 100px (#939).
|
||||||
|
* Include 128x128 icon sizes (#954).
|
||||||
|
* Show right click copy context menu in context view on top text and lyrics (#965).
|
||||||
|
* Improve fading between album covers in context view.
|
||||||
|
* Added option for overwriting database playcounts in collection settings (#962).
|
||||||
|
* Added option for disabling bar on currently playing track (#972).
|
||||||
|
* (Debian) Added Qt 6 support to debian files and build with Qt 6 for Debian Bookworm, Ubuntu Jammy and newer.
|
||||||
|
* (Windows|MSVC) Added libav/ffmpeg plugin.
|
||||||
|
|
||||||
|
Version 1.0.4 (2022.04.10)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed use-after-free memory in ALSA PCM device finder.
|
||||||
|
* Translate global shortcuts.
|
||||||
|
* (Windows) Fixed registering 0-9 numpad keys in global shortcuts.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
* Added save all playlists action.
|
||||||
|
* (Windows) Made updater support both MSVC and MinGW.
|
||||||
|
* (Windows) Added HLS support.
|
||||||
|
|
||||||
|
Other:
|
||||||
|
* Removed use of custom font in context.
|
||||||
|
|
||||||
|
Version 1.0.3 (2022.03.24)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Remove slash and backslash from filenames when saving album covers using album directory cover filenames (#903).
|
||||||
|
* Remove playlist file-extensions from accepted audio file extensions (#909).
|
||||||
|
* Fixed Qobuz requests only receiving the first 50 albums (#922).
|
||||||
|
* (Windows|MinGW) Fixed streaming stopping at the end of each track. libsoup downgraded from 3.0 to 2.74.
|
||||||
|
* (Windows|MSVC) Fixed initial database schema failure caused by CRLF line-endings in schema files.
|
||||||
|
|
||||||
|
New features
|
||||||
|
* Added support for bs2b (Improved headphone listening of stereo audio records using Bauer stereophonic-to-binaural DSP) (#249).
|
||||||
|
|
||||||
|
Version 1.0.2 (2022.02.20)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed showing menu when clicking icon for collection and internet search tool buttons
|
||||||
|
* Fixed ignoring devices with system mounts as defined by GIO (#410).
|
||||||
|
* Fixed updating database when deleting songs from filesystem devices.
|
||||||
|
* Fixed unregistered metatype when listing songs from MTP devices with Qt 6.
|
||||||
|
* Fixed using entered password when testing Subsonic settings before pressing save (#879).
|
||||||
|
* Fixed downloading Subsonic album covers.
|
||||||
|
* Fixed subsonic album covers downloaded several times for each album when MD5 authentication was enabled (#885).
|
||||||
|
* Fixed volume going to 100% when pressing volume down with MRPIS2 and global shortcuts (#884).
|
||||||
|
* Fixed incorrect rounding when setting volume through MPRIS2 (#894).
|
||||||
|
* Fixed delete from disk not showing up in the menu when one or more CUE songs were selected.
|
||||||
|
* Fixed possible crashes when switching songs when fading is enabled (#890).
|
||||||
|
* Fixed X11 global shortcuts not working unless window was in focus with Qt 6.2 and higher (#893).
|
||||||
|
* Fixed scrobbler re-sending scrobbles to fast on error (#898).
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
* Log Qt version on startup.
|
||||||
|
* Added button for deleting existing Subsonic songs (#883).
|
||||||
|
* Make collection watcher ignore files with "qt_temp" filename and tmp extension.
|
||||||
|
* Require Qt 5.9 or higher.
|
||||||
|
* Added scrollbars to edit tag dialog (#888).
|
||||||
|
* Added advanced settings for configuring collection watcher.
|
||||||
|
* Disable open audio CD menu when compiled without audio CD support.
|
||||||
|
* Replaced use of deprecated QMouseEvent constructor as of Qt 6.4.
|
||||||
|
* Replaced use of deprecated QCryptographicHash::addData overload as of Qt 6.4.
|
||||||
|
|
||||||
|
Removed features:
|
||||||
|
* Removed broken "nomedia" / "nomusic" file handling.
|
||||||
|
|
||||||
Version 1.0.1 (2022.01.08)
|
Version 1.0.1 (2022.01.08)
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -23,7 +23,8 @@ Resources:
|
|||||||
### :bangbang: Opening an issue:
|
### :bangbang: Opening an issue:
|
||||||
|
|
||||||
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
|
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
|
||||||
* For technical problems, questions and feature requests please use our forum on https://forum.strawberrymusicplayer.org/ that is better suited for discussion. It also better allows answers from the community instead of just the developers on GitHub.
|
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
|
||||||
|
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
|
||||||
|
|
||||||
### :moneybag: Sponsoring:
|
### :moneybag: Sponsoring:
|
||||||
|
|
||||||
@@ -66,15 +67,14 @@ It has so far been tested to work on Linux, OpenBSD, FreeBSD, macOS and Windows.
|
|||||||
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
||||||
|
|
||||||
* [CMake](https://cmake.org/)
|
* [CMake](https://cmake.org/)
|
||||||
* [GNU Make](https://www.gnu.org/software/make/)
|
* [GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/) compiler
|
||||||
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
|
|
||||||
* [Boost](https://www.boost.org/)
|
* [Boost](https://www.boost.org/)
|
||||||
* [GLib](https://developer.gnome.org/glib/)
|
* [GLib](https://developer.gnome.org/glib/)
|
||||||
* [Protobuf](https://developers.google.com/protocol-buffers/)
|
* [Qt 5.9 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
||||||
* [Qt 5.8 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
|
||||||
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
|
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
|
||||||
* [ALSA (Linux required)](https://www.alsa-project.org/)
|
* [Protobuf](https://developers.google.com/protocol-buffers/)
|
||||||
* [D-Bus (Linux required)](https://www.freedesktop.org/wiki/Software/dbus/)
|
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
|
||||||
|
* [D-Bus (Required on Linux)](https://www.freedesktop.org/wiki/Software/dbus/)
|
||||||
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
|
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
|
||||||
* [GnuTLS](https://www.gnutls.org/)
|
* [GnuTLS](https://www.gnutls.org/)
|
||||||
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
|
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
|
||||||
@@ -88,8 +88,7 @@ Optional dependencies:
|
|||||||
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
||||||
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
||||||
|
|
||||||
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented, and works best, it is therefore recommended to use GStreamer.
|
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav to support all audio formats.
|
||||||
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav.
|
|
||||||
|
|
||||||
### :wrench: Compiling from source
|
### :wrench: Compiling from source
|
||||||
|
|
||||||
@@ -101,13 +100,13 @@ You should also install the gstreamer plugins base and good, and optionally bad,
|
|||||||
|
|
||||||
cd strawberry
|
cd strawberry
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake ..
|
cmake .. -DBUILD_WITH_QT6=ON
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
To compile with Qt 6 use:
|
Strawberry is backwards compatible with Qt 5, to compile with Qt 5 use:
|
||||||
|
|
||||||
cmake .. -DBUILD_WITH_QT6=ON
|
cmake .. -DBUILD_WITH_QT5=ON
|
||||||
|
|
||||||
### :penguin: Packaging status
|
### :penguin: Packaging status
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,5 @@ find_program(LSB_RELEASE_EXEC lsb_release)
|
|||||||
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
|
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
|
||||||
|
|
||||||
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||||
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
add_custom_target(deb WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us)
|
||||||
|
|
||||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs"
|
|
||||||
OUTPUT_VARIABLE DEB_CODENAME
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
|
|
||||||
if (DEB_CODENAME AND DEB_DATE)
|
|
||||||
add_custom_target(deb
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ if(MACDEPLOYQT_EXECUTABLE)
|
|||||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/{Frameworks,Resources}
|
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/{Frameworks,Resources}
|
||||||
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/
|
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/
|
||||||
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/strawberry.icns ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources/
|
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/strawberry.icns ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources/
|
||||||
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3
|
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
|
||||||
-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
|
|
||||||
-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gio-modules/libgiognutls.so
|
|
||||||
#-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner
|
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
DEPENDS strawberry strawberry-tagreader copy_gstreamer_plugins macdeployqt
|
DEPENDS strawberry strawberry-tagreader copy_gstreamer_plugins macdeployqt
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,10 +12,17 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
|
|||||||
OUTPUT_VARIABLE DIST_RELEASE
|
OUTPUT_VARIABLE DIST_RELEASE
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
)
|
)
|
||||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
|
if (${DIST_NAME} STREQUAL "openmandrivalinux")
|
||||||
OUTPUT_VARIABLE DIST_VERSION
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\./0/g' | cut -d' ' -f3"
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_VARIABLE DIST_VERSION
|
||||||
)
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
|
||||||
|
OUTPUT_VARIABLE DIST_VERSION
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
if (DIST_NAME)
|
if (DIST_NAME)
|
||||||
|
|
||||||
message(STATUS "Distro Name: ${DIST_NAME}")
|
message(STATUS "Distro Name: ${DIST_NAME}")
|
||||||
@@ -44,6 +51,8 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
|
|||||||
set(RPM_DISTRO "el${DIST_VERSION}")
|
set(RPM_DISTRO "el${DIST_VERSION}")
|
||||||
elseif (${DIST_NAME} STREQUAL "mageia" AND DIST_RELEASE)
|
elseif (${DIST_NAME} STREQUAL "mageia" AND DIST_RELEASE)
|
||||||
set(RPM_DISTRO "mga${DIST_RELEASE}")
|
set(RPM_DISTRO "mga${DIST_RELEASE}")
|
||||||
|
elseif (${DIST_NAME} STREQUAL "openmandrivalinux" AND DIST_VERSION)
|
||||||
|
set(RPM_DISTRO "omv${DIST_VERSION}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT RPM_DISTRO)
|
if(NOT RPM_DISTRO)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set(STRAWBERRY_VERSION_MAJOR 1)
|
set(STRAWBERRY_VERSION_MAJOR 1)
|
||||||
set(STRAWBERRY_VERSION_MINOR 0)
|
set(STRAWBERRY_VERSION_MINOR 0)
|
||||||
set(STRAWBERRY_VERSION_PATCH 1)
|
set(STRAWBERRY_VERSION_PATCH 5)
|
||||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||||
|
|
||||||
set(INCLUDE_GIT_REVISION OFF)
|
set(INCLUDE_GIT_REVISION OFF)
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
<file>pictures/rainbowdash.png</file>
|
<file>pictures/rainbowdash.png</file>
|
||||||
<file>pictures/star-on.png</file>
|
<file>pictures/star-on.png</file>
|
||||||
<file>pictures/star-off.png</file>
|
<file>pictures/star-off.png</file>
|
||||||
<file>fonts/HumongousofEternitySt.ttf</file>
|
|
||||||
<file>mood/sample.mood</file>
|
<file>mood/sample.mood</file>
|
||||||
<file>text/ghosts.txt</file>
|
<file>text/ghosts.txt</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
|||||||
Binary file not shown.
@@ -24,6 +24,7 @@
|
|||||||
<file>icons/128x128/document-open-folder.png</file>
|
<file>icons/128x128/document-open-folder.png</file>
|
||||||
<file>icons/128x128/document-open.png</file>
|
<file>icons/128x128/document-open.png</file>
|
||||||
<file>icons/128x128/document-save.png</file>
|
<file>icons/128x128/document-save.png</file>
|
||||||
|
<file>icons/128x128/document-save-all.png</file>
|
||||||
<file>icons/128x128/document-search.png</file>
|
<file>icons/128x128/document-search.png</file>
|
||||||
<file>icons/128x128/download.png</file>
|
<file>icons/128x128/download.png</file>
|
||||||
<file>icons/128x128/edit-clear-list.png</file>
|
<file>icons/128x128/edit-clear-list.png</file>
|
||||||
@@ -120,6 +121,7 @@
|
|||||||
<file>icons/64x64/document-open-folder.png</file>
|
<file>icons/64x64/document-open-folder.png</file>
|
||||||
<file>icons/64x64/document-open.png</file>
|
<file>icons/64x64/document-open.png</file>
|
||||||
<file>icons/64x64/document-save.png</file>
|
<file>icons/64x64/document-save.png</file>
|
||||||
|
<file>icons/64x64/document-save-all.png</file>
|
||||||
<file>icons/64x64/document-search.png</file>
|
<file>icons/64x64/document-search.png</file>
|
||||||
<file>icons/64x64/download.png</file>
|
<file>icons/64x64/download.png</file>
|
||||||
<file>icons/64x64/edit-clear-list.png</file>
|
<file>icons/64x64/edit-clear-list.png</file>
|
||||||
@@ -218,6 +220,7 @@
|
|||||||
<file>icons/48x48/document-open-remote.png</file>
|
<file>icons/48x48/document-open-remote.png</file>
|
||||||
<file>icons/48x48/document-open.png</file>
|
<file>icons/48x48/document-open.png</file>
|
||||||
<file>icons/48x48/document-save.png</file>
|
<file>icons/48x48/document-save.png</file>
|
||||||
|
<file>icons/48x48/document-save-all.png</file>
|
||||||
<file>icons/48x48/document-search.png</file>
|
<file>icons/48x48/document-search.png</file>
|
||||||
<file>icons/48x48/download.png</file>
|
<file>icons/48x48/download.png</file>
|
||||||
<file>icons/48x48/edit-clear-list.png</file>
|
<file>icons/48x48/edit-clear-list.png</file>
|
||||||
@@ -319,6 +322,7 @@
|
|||||||
<file>icons/32x32/document-open-remote.png</file>
|
<file>icons/32x32/document-open-remote.png</file>
|
||||||
<file>icons/32x32/document-open.png</file>
|
<file>icons/32x32/document-open.png</file>
|
||||||
<file>icons/32x32/document-save.png</file>
|
<file>icons/32x32/document-save.png</file>
|
||||||
|
<file>icons/32x32/document-save-all.png</file>
|
||||||
<file>icons/32x32/document-search.png</file>
|
<file>icons/32x32/document-search.png</file>
|
||||||
<file>icons/32x32/download.png</file>
|
<file>icons/32x32/download.png</file>
|
||||||
<file>icons/32x32/edit-clear-list.png</file>
|
<file>icons/32x32/edit-clear-list.png</file>
|
||||||
@@ -420,6 +424,7 @@
|
|||||||
<file>icons/22x22/document-open-remote.png</file>
|
<file>icons/22x22/document-open-remote.png</file>
|
||||||
<file>icons/22x22/document-open.png</file>
|
<file>icons/22x22/document-open.png</file>
|
||||||
<file>icons/22x22/document-save.png</file>
|
<file>icons/22x22/document-save.png</file>
|
||||||
|
<file>icons/22x22/document-save-all.png</file>
|
||||||
<file>icons/22x22/document-search.png</file>
|
<file>icons/22x22/document-search.png</file>
|
||||||
<file>icons/22x22/download.png</file>
|
<file>icons/22x22/download.png</file>
|
||||||
<file>icons/22x22/edit-clear-list.png</file>
|
<file>icons/22x22/edit-clear-list.png</file>
|
||||||
|
|||||||
BIN
data/icons/128x128/document-save-all.png
Normal file
BIN
data/icons/128x128/document-save-all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
data/icons/22x22/document-save-all.png
Normal file
BIN
data/icons/22x22/document-save-all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 921 B |
BIN
data/icons/32x32/document-save-all.png
Normal file
BIN
data/icons/32x32/document-save-all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
data/icons/48x48/document-save-all.png
Normal file
BIN
data/icons/48x48/document-save-all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
BIN
data/icons/64x64/document-save-all.png
Normal file
BIN
data/icons/64x64/document-save-all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
data/icons/full/document-save-all.png
Normal file
BIN
data/icons/full/document-save-all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
@@ -31,39 +31,40 @@
|
|||||||
background-color: %palette-base;
|
background-color: %palette-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#context-scrollarea {
|
||||||
|
background-color: %palette-base;
|
||||||
|
}
|
||||||
|
|
||||||
QToolButton {
|
QToolButton {
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton::menu-button {
|
|
||||||
width: 16px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
QToolButton[popupMode="1"] {
|
|
||||||
padding-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QToolButton:hover {
|
QToolButton:hover {
|
||||||
border: 2px solid %palette-highlight;
|
border: 2px solid %palette-highlight;
|
||||||
background-color: %palette-highlight-lighter;
|
background-color: %palette-highlight-lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton:hover[popupMode="1"] {
|
|
||||||
padding-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QToolButton:pressed {
|
QToolButton:pressed {
|
||||||
border: 2px solid %palette-highlight-darker;
|
border: 2px solid %palette-highlight-darker;
|
||||||
background-color: %palette-highlight-lighter;
|
background-color: %palette-highlight-lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton:pressed[popupMode="1"] {
|
QToolButton[popupMode="MenuButtonPopup"], QToolButton:hover[popupMode="MenuButtonPopup"], QToolButton:pressed[popupMode="MenuButtonPopup"] {
|
||||||
padding-right: 16px;
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For backwards compatibility with Qt 5 as it does not support property name */
|
||||||
|
QToolButton[popupMode="1"], QToolButton:hover[popupMode="1"], QToolButton:pressed[popupMode="1"] {
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolButton::menu-button {
|
||||||
|
width: 16px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
macos {
|
macos {
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
}
|
}
|
||||||
@@ -71,4 +72,3 @@ macos {
|
|||||||
macos QMenu {
|
macos QMenu {
|
||||||
font-size: 13pt;
|
font-size: 13pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
debian/CMakeLists.txt
vendored
Normal file
22
debian/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
if(LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||||
|
|
||||||
|
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs" OUTPUT_VARIABLE DEB_CODENAME OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
if(DEB_CODENAME AND DEB_DATE)
|
||||||
|
|
||||||
|
if(BUILD_WITH_QT5)
|
||||||
|
set(DEBIAN_BUILD_DEPENDS_QT_PACKAGES qtbase5-dev,qtbase5-dev-tools,qttools5-dev,qttools5-dev-tools,libqt5x11extras5-dev)
|
||||||
|
set(DEBIAN_DEPENDS_QT_PACKAGES libqt5sql5-sqlite)
|
||||||
|
endif()
|
||||||
|
if(BUILD_WITH_QT6)
|
||||||
|
set(DEBIAN_BUILD_DEPENDS_QT_PACKAGES qt6-base-dev,qt6-base-dev-tools,qt6-tools-dev,qt6-tools-dev-tools,qt6-l10n-tools)
|
||||||
|
set(DEBIAN_DEPENDS_QT_PACKAGES libqt6sql6-sqlite,qt6-qpa-plugins)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.in ${CMAKE_CURRENT_SOURCE_DIR}/control @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/changelog)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
19
debian/control → debian/control.in
vendored
19
debian/control → debian/control.in
vendored
@@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 11),
|
|||||||
make,
|
make,
|
||||||
cmake,
|
cmake,
|
||||||
gcc,
|
gcc,
|
||||||
|
g++,
|
||||||
protobuf-compiler,
|
protobuf-compiler,
|
||||||
libglib2.0-dev,
|
libglib2.0-dev,
|
||||||
libdbus-1-dev,
|
libdbus-1-dev,
|
||||||
@@ -16,11 +17,7 @@ Build-Depends: debhelper (>= 11),
|
|||||||
libasound2-dev,
|
libasound2-dev,
|
||||||
libpulse-dev,
|
libpulse-dev,
|
||||||
libtag1-dev,
|
libtag1-dev,
|
||||||
qtbase5-dev,
|
@DEBIAN_BUILD_DEPENDS_QT_PACKAGES@,
|
||||||
qtbase5-private-dev,
|
|
||||||
qtbase5-dev-tools,
|
|
||||||
qttools5-dev,
|
|
||||||
libqt5x11extras5-dev,
|
|
||||||
libgstreamer1.0-dev,
|
libgstreamer1.0-dev,
|
||||||
libgstreamer-plugins-base1.0-dev,
|
libgstreamer-plugins-base1.0-dev,
|
||||||
libcdio-dev,
|
libcdio-dev,
|
||||||
@@ -28,20 +25,19 @@ Build-Depends: debhelper (>= 11),
|
|||||||
libmtp-dev,
|
libmtp-dev,
|
||||||
libchromaprint-dev,
|
libchromaprint-dev,
|
||||||
libfftw3-dev
|
libfftw3-dev
|
||||||
Standards-Version: 4.2.1
|
Standards-Version: 4.6.1
|
||||||
|
|
||||||
Package: strawberry
|
Package: strawberry
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends},
|
Depends: ${shlibs:Depends},
|
||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
libsqlite3-0,
|
@DEBIAN_DEPENDS_QT_PACKAGES@,
|
||||||
libqt5sql5-sqlite,
|
|
||||||
gstreamer1.0-plugins-base,
|
gstreamer1.0-plugins-base,
|
||||||
gstreamer1.0-plugins-good,
|
gstreamer1.0-plugins-good,
|
||||||
gstreamer1.0-alsa,
|
gstreamer1.0-alsa,
|
||||||
gstreamer1.0-pulseaudio
|
gstreamer1.0-pulseaudio
|
||||||
Homepage: http://www.strawberrymusicplayer.org/
|
Homepage: http://www.strawberrymusicplayer.org/
|
||||||
Description: Audio player and music collection organizer
|
Description: music player and music collection organizer
|
||||||
Strawberry is a music player aimed at music collectors and audiophiles.
|
Strawberry is a music player aimed at music collectors and audiophiles.
|
||||||
.
|
.
|
||||||
Features:
|
Features:
|
||||||
@@ -49,14 +45,13 @@ Description: Audio player and music collection organizer
|
|||||||
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
|
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
|
||||||
- Audio CD playback
|
- Audio CD playback
|
||||||
- Native desktop notifications
|
- Native desktop notifications
|
||||||
- Playlist management
|
- Playlist management and playlists in multiple formats
|
||||||
- Playlists in multiple formats
|
- Smart and dynamic playlists
|
||||||
- Advanced audio output and device configuration for bit-perfect playback on Linux
|
- Advanced audio output and device configuration for bit-perfect playback on Linux
|
||||||
- Edit tags on audio files
|
- Edit tags on audio files
|
||||||
- Automatically retrieve tags from MusicBrainz
|
- Automatically retrieve tags from MusicBrainz
|
||||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
||||||
- Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
|
- Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||||
- Support for multiple backends
|
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
- Audio equalizer
|
- Audio equalizer
|
||||||
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||||
183
debian/copyright
vendored
183
debian/copyright
vendored
@@ -1,10 +1,11 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Upstream-Name: strawberry
|
Upstream-Name: strawberry
|
||||||
Upstream-Contact: Jonas Kvinge <jonas@jkvinge.net>
|
Upstream-Contact: Jonas Kvinge <jonas@jkvinge.net>
|
||||||
Source: https://www.strawberrymusicplayer.org/
|
Source: https://github.com/strawberrymusicplayer/strawberry
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
|
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
|
||||||
|
2012-2014, 2017-2022 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/timeconstants.h
|
Files: src/core/timeconstants.h
|
||||||
@@ -13,14 +14,13 @@ Files: src/core/timeconstants.h
|
|||||||
ext/libstrawberry-common/core/messagehandler.cpp
|
ext/libstrawberry-common/core/messagehandler.cpp
|
||||||
ext/libstrawberry-common/core/messagehandler.h
|
ext/libstrawberry-common/core/messagehandler.h
|
||||||
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
|
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
|
||||||
|
2018-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: Apache-2.0
|
License: Apache-2.0
|
||||||
|
|
||||||
Files: src/core/main.h
|
Files: src/core/main.h
|
||||||
src/core/iconloader.cpp
|
src/core/iconloader.cpp
|
||||||
src/core/iconloader.h
|
src/core/iconloader.h
|
||||||
src/core/iconmapper.h
|
src/core/iconmapper.h
|
||||||
src/config.h.in
|
|
||||||
src/version.h.in
|
|
||||||
src/context/contextview.cpp
|
src/context/contextview.cpp
|
||||||
src/context/contextview.h
|
src/context/contextview.h
|
||||||
src/context/contextalbum.cpp
|
src/context/contextalbum.cpp
|
||||||
@@ -29,6 +29,8 @@ Files: src/core/main.h
|
|||||||
src/engine/enginetype.h
|
src/engine/enginetype.h
|
||||||
src/engine/alsadevicefinder.cpp
|
src/engine/alsadevicefinder.cpp
|
||||||
src/engine/alsadevicefinder.h
|
src/engine/alsadevicefinder.h
|
||||||
|
src/engine/alsapcmdevicefinder.cpp
|
||||||
|
src/engine/alsapcmdevicefinder.h
|
||||||
src/engine/mmdevicefinder.cpp
|
src/engine/mmdevicefinder.cpp
|
||||||
src/engine/mmdevicefinder.h
|
src/engine/mmdevicefinder.h
|
||||||
src/engine/devicefinder.cpp
|
src/engine/devicefinder.cpp
|
||||||
@@ -69,11 +71,17 @@ Files: src/core/main.h
|
|||||||
src/covermanager/spotifycoverprovider.h
|
src/covermanager/spotifycoverprovider.h
|
||||||
src/covermanager/musixmatchcoverprovider.cpp
|
src/covermanager/musixmatchcoverprovider.cpp
|
||||||
src/covermanager/musixmatchcoverprovider.h
|
src/covermanager/musixmatchcoverprovider.h
|
||||||
src/globalshortcuts/globalshortcutsbackend-system.cpp
|
src/globalshortcuts/globalshortcutsbackend-kde.cpp
|
||||||
src/globalshortcuts/globalshortcutsbackend-system.h
|
src/globalshortcuts/globalshortcutsbackend-kde.h
|
||||||
|
src/globalshortcuts/globalshortcutsbackend-mate.cpp
|
||||||
|
src/globalshortcuts/globalshortcutsbackend-mate.h
|
||||||
|
src/globalshortcuts/globalshortcutsbackend-x11.cpp
|
||||||
|
src/globalshortcuts/globalshortcutsbackend-x11.h
|
||||||
|
src/globalshortcuts/globalshortcutsbackend-win.cpp
|
||||||
|
src/globalshortcuts/globalshortcutsbackend-win.h
|
||||||
src/globalshortcuts/globalshortcut.cpp
|
src/globalshortcuts/globalshortcut.cpp
|
||||||
src/globalshortcuts/globalshortcut.h
|
src/globalshortcuts/globalshortcut.h
|
||||||
src/globalshortcuts/globalshortcut-X11.cpp
|
src/globalshortcuts/globalshortcut-x11.cpp
|
||||||
src/globalshortcuts/globalshortcut-win.cpp
|
src/globalshortcuts/globalshortcut-win.cpp
|
||||||
src/globalshortcuts/keymapper_x11.h
|
src/globalshortcuts/keymapper_x11.h
|
||||||
src/globalshortcuts/keymapper_win.h
|
src/globalshortcuts/keymapper_win.h
|
||||||
@@ -81,132 +89,21 @@ Files: src/core/main.h
|
|||||||
src/scrobbler/*
|
src/scrobbler/*
|
||||||
src/subsonic/*
|
src/subsonic/*
|
||||||
src/tidal/*
|
src/tidal/*
|
||||||
|
src/qobuz/*
|
||||||
|
src/radios/*
|
||||||
src/transcoder/transcoderoptionswavpack.cpp
|
src/transcoder/transcoderoptionswavpack.cpp
|
||||||
src/transcoder/transcoderoptionswavpack.h
|
src/transcoder/transcoderoptionswavpack.h
|
||||||
Copyright: 2012-2014, 2017-2020, Jonas Kvinge <jonas@jkvinge.net>
|
ext/libstrawberry-tagreader/tagreadertagparser.cpp
|
||||||
License: GPL-3+
|
ext/libstrawberry-tagreader/tagreadertagparser.h
|
||||||
|
ext/macdeploycheck/*
|
||||||
Files: src/core/main.cpp
|
widgets/resizabletextedit.cpp
|
||||||
src/core/mainwindow.cpp
|
widgets/resizabletextedit.h
|
||||||
src/core/mainwindow.h
|
Copyright: 2012-2014, 2017-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
src/core/player.cpp
|
|
||||||
src/core/player.h
|
|
||||||
src/core/song.cpp
|
|
||||||
src/core/song.h
|
|
||||||
src/core/songloader.cpp
|
|
||||||
src/core/songloader.h
|
|
||||||
src/core/urlhandler.cpp
|
|
||||||
src/core/urlhandler.h
|
|
||||||
src/core/utilities.cpp
|
|
||||||
src/core/utilities.h
|
|
||||||
src/core/networkaccessmanager.cpp
|
|
||||||
src/core/networkaccessmanager.h
|
|
||||||
src/core/threadsafenetworkdiskcache.cpp
|
|
||||||
src/core/threadsafenetworkdiskcache.h
|
|
||||||
src/core/filesystemmusicstorage.cpp
|
|
||||||
src/core/filesystemmusicstorage.h
|
|
||||||
src/core/stylesheetloader.cpp
|
|
||||||
src/core/stylesheetloader.h
|
|
||||||
src/engine/gstenginepipeline.cpp
|
|
||||||
src/engine/gstenginepipeline.h
|
|
||||||
src/engine/vlcengine.cpp
|
|
||||||
src/engine/vlcengine.h
|
|
||||||
src/collection/collectionwatcher.cpp
|
|
||||||
src/collection/collectionwatcher.h
|
|
||||||
src/collection/collectionbackend.cpp
|
|
||||||
src/collection/collectionbackend.h
|
|
||||||
src/collection/collectionmodel.cpp
|
|
||||||
src/collection/collectionmodel.h
|
|
||||||
src/context/contextalbumsmodel.cpp
|
|
||||||
src/context/contextalbumsview.cpp
|
|
||||||
src/context/contextalbumsmodel.h
|
|
||||||
src/context/contextalbumsview.h
|
|
||||||
src/widgets/playingwidget.cpp
|
|
||||||
src/widgets/playingwidget.h
|
|
||||||
src/osd/osdbase.cpp
|
|
||||||
src/osd/osdbase.h
|
|
||||||
src/osd/osdpretty.cpp
|
|
||||||
src/osd/osdpretty.h
|
|
||||||
src/osd/osddbus.cpp
|
|
||||||
src/osd/osddbus.h
|
|
||||||
src/osd/osdmac.cpp
|
|
||||||
src/osd/osdmac.h
|
|
||||||
src/dialogs/about.cpp
|
|
||||||
src/dialogs/about.h
|
|
||||||
src/playlist/playlist.cpp
|
|
||||||
src/playlist/playlist.h
|
|
||||||
src/playlist/playlistitem.cpp
|
|
||||||
src/playlist/playlistitem.h
|
|
||||||
src/playlist/playlistdelegates.cpp
|
|
||||||
src/playlist/playlistdelegates.h
|
|
||||||
src/playlist/playlistbackend.cpp
|
|
||||||
src/playlist/playlistbackend.h
|
|
||||||
src/playlist/playlistview.cpp
|
|
||||||
src/playlist/playlistview.h
|
|
||||||
src/playlist/songplaylistitem.cpp
|
|
||||||
src/playlist/songplaylistitem.h
|
|
||||||
src/internet/internetplaylistitem.cpp
|
|
||||||
src/internet/internetsearch.cpp
|
|
||||||
src/internet/internetsearch.h
|
|
||||||
src/internet/internetsearchview.cpp
|
|
||||||
src/internet/internetsearchview.h
|
|
||||||
src/internet/internetservices.cpp
|
|
||||||
src/internet/internetservices.h
|
|
||||||
src/internet/internetsongsview.cpp
|
|
||||||
src/internet/internetsongsview.h
|
|
||||||
src/internet/internetcollectionview.cpp
|
|
||||||
src/internet/internetcollectionview.h
|
|
||||||
ext/libstrawberry-tagreader/tagreader.cpp
|
|
||||||
ext/libstrawberry-tagreader/tagreader.h
|
|
||||||
src/device/devicemanager.cpp
|
|
||||||
src/device/devicemanager.h
|
|
||||||
src/device/deviceinfo.cpp
|
|
||||||
src/device/deviceinfo.h
|
|
||||||
src/device/deviceproperties.cpp
|
|
||||||
src/device/deviceproperties.h
|
|
||||||
src/device/deviceview.cpp
|
|
||||||
src/device/deviceview.h
|
|
||||||
src/device/connecteddevice.cpp
|
|
||||||
src/device/connecteddevice.h
|
|
||||||
src/device/mtpconnection.cpp
|
|
||||||
src/device/mtpconnection.h
|
|
||||||
src/device/mtpdevice.cpp
|
|
||||||
src/device/mtpdevice.h
|
|
||||||
src/globalshortcuts/globalshortcutsmanager.cpp
|
|
||||||
src/globalshortcuts/globalshortcutsmanager.h
|
|
||||||
src/settings/shortcutssettingspage.cpp
|
|
||||||
src/settings/shortcutssettingspage.h
|
|
||||||
src/settings/appearancesettingspage.cpp
|
|
||||||
src/settings/appearancesettingspage.h
|
|
||||||
src/organize/organize.cpp
|
|
||||||
src/organize/organize.h
|
|
||||||
src/organize/organizedialog.cpp
|
|
||||||
src/organize/organizedialog.h
|
|
||||||
src/organize/organizeerrordialog.cpp
|
|
||||||
src/organize/organizeerrordialog.h
|
|
||||||
src/transcoder/transcoder.cpp
|
|
||||||
src/transcoder/transcoder.h
|
|
||||||
src/musicbrainz/musicbrainzclient.cpp
|
|
||||||
src/musicbrainz/musicbrainzclient.h
|
|
||||||
src/covermanager/albumcoverloader.cpp
|
|
||||||
src/covermanager/albumcoverloader.h
|
|
||||||
src/covermanager/currentalbumcoverloader.cpp
|
|
||||||
src/covermanager/currentalbumcoverloader.h
|
|
||||||
src/covermanager/albumcoverchoicecontroller.cpp
|
|
||||||
src/covermanager/albumcoverchoicecontroller.h
|
|
||||||
src/covermanager/albumcoverfetchersearch.cpp
|
|
||||||
src/covermanager/albumcoverfetchersearch.h
|
|
||||||
src/covermanager/coverproviders.cpp
|
|
||||||
src/covermanager/coverproviders.h
|
|
||||||
src/covermanager/coverprovider.cpp
|
|
||||||
src/covermanager/coverprovider.h
|
|
||||||
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
|
|
||||||
2012-2014, 2017-2020 Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/engine/enginebase.cpp
|
Files: src/engine/enginebase.cpp
|
||||||
src/engine/enginebase.h
|
src/engine/enginebase.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2010, David Sansome <me@davidsansome.com>
|
2010, David Sansome <me@davidsansome.com>
|
||||||
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
||||||
2003, Mark Kretschmann <markey@web.de>
|
2003, Mark Kretschmann <markey@web.de>
|
||||||
@@ -214,7 +111,7 @@ License: GPL-3+
|
|||||||
|
|
||||||
Files: src/engine/gstengine.cpp
|
Files: src/engine/gstengine.cpp
|
||||||
src/engine/gstengine.h
|
src/engine/gstengine.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2006, Paul Cifarelli <paul@cifarelli.net>
|
2006, Paul Cifarelli <paul@cifarelli.net>
|
||||||
2005, Jakub Stachowski <qbast@go2.pl>
|
2005, Jakub Stachowski <qbast@go2.pl>
|
||||||
2003-2005, Mark Kretschmann <markey@web.de>
|
2003-2005, Mark Kretschmann <markey@web.de>
|
||||||
@@ -230,7 +127,7 @@ Files: src/core/application.cpp
|
|||||||
src/core/application.h
|
src/core/application.h
|
||||||
Copyright: 2012, David Sansome <me@davidsansome.com>
|
Copyright: 2012, David Sansome <me@davidsansome.com>
|
||||||
2012, 2014, John Maguire <john.maguire@gmail.com>
|
2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2018, Jonas Kvinge <jonas@jkvinge.net>
|
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/appearance.cpp
|
Files: src/core/appearance.cpp
|
||||||
@@ -244,13 +141,7 @@ Copyright: 2012, Martin Björklund <mbj4668@gmail.com>
|
|||||||
2016, Jonas Kvinge <jonas@jkvinge.net>
|
2016, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: ext/libstrawberry-common/core/arraysize.h
|
Files: src/core/lazy.h
|
||||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.h
|
|
||||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.mm
|
|
||||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
|
||||||
License: BSD-style
|
|
||||||
|
|
||||||
Files: ext/libstrawberry-common/core/lazy.h
|
|
||||||
Copyright: 2016, John Maguire <john.maguire@gmail.com>
|
Copyright: 2016, John Maguire <john.maguire@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
@@ -298,12 +189,17 @@ Copyright: 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
|||||||
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/collection/savedgroupingmanager.h
|
Files: src/collection/savedgroupingmanager.*
|
||||||
Copyright: 2015, Nick Lanham <nick@afternight.org>
|
Copyright: 2015, Nick Lanham <nick@afternight.org>
|
||||||
|
2019-2021 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/scoped_cftyperef.h
|
Files:
|
||||||
|
src/core/arraysize.h
|
||||||
|
src/core/scoped_cftyperef.h
|
||||||
src/core/scoped_nsobject.h
|
src/core/scoped_nsobject.h
|
||||||
|
src/core/scoped_nsautorelease_pool.h
|
||||||
|
src/core/scoped_nsautorelease_pool.mm
|
||||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
||||||
License: BSD-style
|
License: BSD-style
|
||||||
|
|
||||||
@@ -322,7 +218,7 @@ Files: src/internet/localredirectserver.cpp
|
|||||||
src/internet/localredirectserver.h
|
src/internet/localredirectserver.h
|
||||||
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/transcoder/transcoderoptionsopus.cpp
|
Files: src/transcoder/transcoderoptionsopus.cpp
|
||||||
@@ -337,12 +233,16 @@ Files: src/widgets/clickablelabel.cpp
|
|||||||
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/widgets/sliderwidget.cpp
|
Files: src/widgets/volumeslider.cpp
|
||||||
src/widgets/sliderwidget.h
|
src/widgets/volumeslider.h
|
||||||
Copyright: 2005, Gábor Lehel
|
Copyright: 2005, Gábor Lehel
|
||||||
2003, Mark Kretschmann <markey@web.de>
|
2003, Mark Kretschmann <markey@web.de>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
|
Files: src/scrobbler/subsonicscrobbler.*
|
||||||
|
Copyright: 2018-2021 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
2020 Pascal Below <spezifisch@below.fr>
|
||||||
|
|
||||||
Files: src/core/stylehelper.cpp
|
Files: src/core/stylehelper.cpp
|
||||||
src/core/stylehelper.h
|
src/core/stylehelper.h
|
||||||
Copyright: 2016 The Qt Company Ltd.
|
Copyright: 2016 The Qt Company Ltd.
|
||||||
@@ -358,6 +258,7 @@ License: GPL-2+
|
|||||||
Files: src/widgets/qsearchfield_nonmac.cpp
|
Files: src/widgets/qsearchfield_nonmac.cpp
|
||||||
src/widgets/qsearchfield_mac.mm
|
src/widgets/qsearchfield_mac.mm
|
||||||
src/widgets/qsearchfield.h
|
src/widgets/qsearchfield.h
|
||||||
|
src/widgets/qocoa_mac.h
|
||||||
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
|
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
@@ -367,7 +268,7 @@ Copyright: 2010, Spotify AB
|
|||||||
License: BSD-3-clause
|
License: BSD-3-clause
|
||||||
|
|
||||||
Files: 3rdparty/singleapplication/*
|
Files: 3rdparty/singleapplication/*
|
||||||
Copyright: 2015-2018, Itay Grudev
|
Copyright: 2015-2022, Itay Grudev
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
debian/copyright-scan-patterns.yml
vendored
6
debian/copyright-scan-patterns.yml
vendored
@@ -4,14 +4,14 @@ ignore:
|
|||||||
- Changelog
|
- Changelog
|
||||||
- COPYING
|
- COPYING
|
||||||
- CMakeLists.txt
|
- CMakeLists.txt
|
||||||
- Dockerfile
|
- cmake_uninstall.cmake.in
|
||||||
|
- .clang-format
|
||||||
- .gitignore
|
- .gitignore
|
||||||
- .travis.yml
|
- .github
|
||||||
- /debian/
|
- /debian/
|
||||||
- /cmake/
|
- /cmake/
|
||||||
- /data/
|
- /data/
|
||||||
- /dist/
|
- /dist/
|
||||||
- /snap/
|
|
||||||
|
|
||||||
suffixes:
|
suffixes:
|
||||||
- jpg
|
- jpg
|
||||||
|
|||||||
1
debian/rules
vendored
1
debian/rules
vendored
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
rm -f dist/macos/Info.plist
|
rm -f dist/macos/Info.plist
|
||||||
rm -f dist/unix/PKGBUILD
|
|
||||||
rm -f dist/unix/strawberry.spec
|
rm -f dist/unix/strawberry.spec
|
||||||
rm -f dist/scripts/maketarball.sh
|
rm -f dist/scripts/maketarball.sh
|
||||||
rm -f dist/windows/strawberry.nsi
|
rm -f dist/windows/strawberry.nsi
|
||||||
|
|||||||
4
dist/CMakeLists.txt
vendored
4
dist/CMakeLists.txt
vendored
@@ -2,10 +2,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CUR
|
|||||||
if(RPM_DISTRO AND RPM_DATE)
|
if(RPM_DISTRO AND RPM_DATE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
|
||||||
endif(RPM_DISTRO AND RPM_DATE)
|
endif(RPM_DISTRO AND RPM_DATE)
|
||||||
if(DEB_CODENAME AND DEB_DATE)
|
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/debian/changelog.in ${CMAKE_SOURCE_DIR}/debian/changelog)
|
|
||||||
endif(DEB_CODENAME AND DEB_DATE)
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD @ONLY)
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||||
|
|||||||
58
dist/macos/macgstcopy.sh
vendored
58
dist/macos/macgstcopy.sh
vendored
@@ -39,8 +39,12 @@ fi
|
|||||||
cp -v -f "${GST_PLUGIN_SCANNER}" "${bundledir}/Contents/PlugIns/" || exit 1
|
cp -v -f "${GST_PLUGIN_SCANNER}" "${bundledir}/Contents/PlugIns/" || exit 1
|
||||||
|
|
||||||
gst_plugins="
|
gst_plugins="
|
||||||
|
libgstaes.dylib
|
||||||
|
libgstaiff.dylib
|
||||||
libgstapetag.dylib
|
libgstapetag.dylib
|
||||||
libgstapp.dylib
|
libgstapp.dylib
|
||||||
|
libgstasf.dylib
|
||||||
|
libgstasfmux.dylib
|
||||||
libgstaudioconvert.dylib
|
libgstaudioconvert.dylib
|
||||||
libgstaudiofx.dylib
|
libgstaudiofx.dylib
|
||||||
libgstaudiomixer.dylib
|
libgstaudiomixer.dylib
|
||||||
@@ -48,46 +52,46 @@ libgstaudioparsers.dylib
|
|||||||
libgstaudiorate.dylib
|
libgstaudiorate.dylib
|
||||||
libgstaudioresample.dylib
|
libgstaudioresample.dylib
|
||||||
libgstaudiotestsrc.dylib
|
libgstaudiotestsrc.dylib
|
||||||
libgstaudiovisualizers.dylib
|
|
||||||
libgstauparse.dylib
|
|
||||||
libgstautoconvert.dylib
|
|
||||||
libgstautodetect.dylib
|
libgstautodetect.dylib
|
||||||
|
libgstbs2b.dylib
|
||||||
|
libgstcdio.dylib
|
||||||
libgstcoreelements.dylib
|
libgstcoreelements.dylib
|
||||||
|
libgstdash.dylib
|
||||||
libgstequalizer.dylib
|
libgstequalizer.dylib
|
||||||
|
libgstflac.dylib
|
||||||
|
libgstfaac.dylib
|
||||||
|
libgstfaad.dylib
|
||||||
|
libgstfdkaac.dylib
|
||||||
libgstgio.dylib
|
libgstgio.dylib
|
||||||
libgsticydemux.dylib
|
libgsticydemux.dylib
|
||||||
libgstid3demux.dylib
|
libgstid3demux.dylib
|
||||||
libgstlevel.dylib
|
libgstisomp4.dylib
|
||||||
|
libgstlame.dylib
|
||||||
|
libgstlibav.dylib
|
||||||
|
libgstmpg123.dylib
|
||||||
|
libgstmusepack.dylib
|
||||||
|
libgstogg.dylib
|
||||||
|
libgstopenmpt.dylib
|
||||||
|
libgstopus.dylib
|
||||||
|
libgstopusparse.dylib
|
||||||
libgstosxaudio.dylib
|
libgstosxaudio.dylib
|
||||||
libgstplayback.dylib
|
|
||||||
libgstrawparse.dylib
|
|
||||||
libgstreplaygain.dylib
|
|
||||||
libgstsoup.dylib
|
|
||||||
libgstspectrum.dylib
|
|
||||||
libgsttypefindfunctions.dylib
|
|
||||||
libgstvolume.dylib
|
|
||||||
libgstxingmux.dylib
|
|
||||||
libgsttcp.dylib
|
|
||||||
libgstudp.dylib
|
|
||||||
libgstpbtypes.dylib
|
libgstpbtypes.dylib
|
||||||
|
libgstplayback.dylib
|
||||||
|
libgstreplaygain.dylib
|
||||||
libgstrtp.dylib
|
libgstrtp.dylib
|
||||||
libgstrtsp.dylib
|
libgstrtsp.dylib
|
||||||
libgstflac.dylib
|
libgstsoup.dylib
|
||||||
libgstwavparse.dylib
|
libgstspectrum.dylib
|
||||||
libgstfaad.dylib
|
|
||||||
libgstogg.dylib
|
|
||||||
libgstopus.dylib
|
|
||||||
libgstasf.dylib
|
|
||||||
libgstspeex.dylib
|
libgstspeex.dylib
|
||||||
libgsttaglib.dylib
|
libgsttaglib.dylib
|
||||||
|
libgsttcp.dylib
|
||||||
|
libgsttypefindfunctions.dylib
|
||||||
|
libgstudp.dylib
|
||||||
|
libgstvolume.dylib
|
||||||
libgstvorbis.dylib
|
libgstvorbis.dylib
|
||||||
libgstisomp4.dylib
|
libgstwavpack.dylib
|
||||||
libgstlibav.dylib
|
libgstwavparse.dylib
|
||||||
libgstaiff.dylib
|
libgstxingmux.dylib;
|
||||||
libgstlame.dylib
|
|
||||||
libgstopusparse.dylib
|
|
||||||
libgstfaac.dylib
|
|
||||||
libgstmusepack.dylib
|
|
||||||
"
|
"
|
||||||
|
|
||||||
gst_plugins=$(echo "$gst_plugins" | tr '\n' ' ' | sed -e 's/^ //g' | sed -e 's/ / /g')
|
gst_plugins=$(echo "$gst_plugins" | tr '\n' ' ' | sed -e 's/^ //g' | sed -e 's/ / /g')
|
||||||
|
|||||||
26
dist/scripts/maketarball.sh.in
vendored
26
dist/scripts/maketarball.sh.in
vendored
@@ -11,10 +11,33 @@ if ! [ "$gitrev" = "ON" ]; then
|
|||||||
exclude_vcs="--exclude-vcs"
|
exclude_vcs="--exclude-vcs"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
cmds="gtar tar"
|
||||||
|
for cmd in $cmds
|
||||||
|
do
|
||||||
|
which $cmd >/dev/null 2>&1
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
result=$($cmd --version 2>&1 | head -n1)
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "$result" | grep "^.* (GNU tar) .*$" >/dev/null 2>&1
|
||||||
|
if [ ! $? -eq 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
TAR=$cmd
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$TAR" = "" ]; then
|
||||||
|
echo "ERROR: Missing GNU Tar"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Creating $name-$version.tar.xz..."
|
echo "Creating $name-$version.tar.xz..."
|
||||||
|
|
||||||
rm -f "$name-$version.tar.xz"
|
rm -f "$name-$version.tar.xz"
|
||||||
tar -cJf $name-$version.tar.xz \
|
${TAR} -cJf $name-$version.tar.xz \
|
||||||
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
||||||
--exclude=".directory" \
|
--exclude=".directory" \
|
||||||
--exclude="*.tar" \
|
--exclude="*.tar" \
|
||||||
@@ -37,7 +60,6 @@ tar -cJf $name-$version.tar.xz \
|
|||||||
--exclude="$root/.zanata-cache" \
|
--exclude="$root/.zanata-cache" \
|
||||||
--exclude="$root/debian/changelog" \
|
--exclude="$root/debian/changelog" \
|
||||||
--exclude="$root/dist/scripts/maketarball.sh" \
|
--exclude="$root/dist/scripts/maketarball.sh" \
|
||||||
--exclude="$root/dist/unix/PKGBUILD" \
|
|
||||||
--exclude="$root/dist/macos/Info.plist" \
|
--exclude="$root/dist/macos/Info.plist" \
|
||||||
--exclude="$root/dist/windows/windres.rc" \
|
--exclude="$root/dist/windows/windres.rc" \
|
||||||
--exclude="$root/src/translations/translations.pot" \
|
--exclude="$root/src/translations/translations.pot" \
|
||||||
|
|||||||
56
dist/unix/PKGBUILD.in
vendored
56
dist/unix/PKGBUILD.in
vendored
@@ -1,56 +0,0 @@
|
|||||||
# Maintainer: Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
pkgname=strawberry
|
|
||||||
pkgver=@STRAWBERRY_VERSION_PAC_V@
|
|
||||||
pkgrel=@STRAWBERRY_VERSION_PAC_R@
|
|
||||||
pkgdesc="A music player aimed at audio enthusiasts and music collectors"
|
|
||||||
arch=(x86_64)
|
|
||||||
url="https://www.strawberrymusicplayer.org/"
|
|
||||||
license=(GPL3)
|
|
||||||
makedepends=(git cmake make gcc boost gettext qt5-tools)
|
|
||||||
depends=(
|
|
||||||
desktop-file-utils
|
|
||||||
hicolor-icon-theme
|
|
||||||
gnutls
|
|
||||||
udisks2
|
|
||||||
protobuf
|
|
||||||
qt5-base
|
|
||||||
qt5-x11extras
|
|
||||||
sqlite3
|
|
||||||
alsa-lib
|
|
||||||
libpulse
|
|
||||||
dbus
|
|
||||||
taglib
|
|
||||||
gstreamer
|
|
||||||
gst-plugins-base
|
|
||||||
gst-plugins-good
|
|
||||||
vlc
|
|
||||||
chromaprint
|
|
||||||
libgpod
|
|
||||||
libcdio
|
|
||||||
libmtp
|
|
||||||
fftw
|
|
||||||
)
|
|
||||||
optdepends=(
|
|
||||||
gst-plugins-bad
|
|
||||||
gst-plugins-ugly
|
|
||||||
gst-libav
|
|
||||||
)
|
|
||||||
provides=(strawberry)
|
|
||||||
conflicts=(strawberry)
|
|
||||||
source=("strawberry-@STRAWBERRY_VERSION_PACKAGE@.tar.xz")
|
|
||||||
sha256sums=('SKIP')
|
|
||||||
|
|
||||||
prepare() {
|
|
||||||
mkdir -p build
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
cd build
|
|
||||||
cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j$(nproc)
|
|
||||||
}
|
|
||||||
|
|
||||||
package() {
|
|
||||||
cd build
|
|
||||||
make DESTDIR="${pkgdir}" install
|
|
||||||
}
|
|
||||||
6
dist/unix/strawberry.spec.in
vendored
6
dist/unix/strawberry.spec.in
vendored
@@ -1,6 +1,6 @@
|
|||||||
Name: strawberry
|
Name: strawberry
|
||||||
Version: @STRAWBERRY_VERSION_RPM_V@
|
Version: @STRAWBERRY_VERSION_RPM_V@
|
||||||
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos}
|
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos} || "%{?_vendor}" == "openmandriva"
|
||||||
Release: @STRAWBERRY_VERSION_RPM_R@%{?dist}
|
Release: @STRAWBERRY_VERSION_RPM_R@%{?dist}
|
||||||
%else
|
%else
|
||||||
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
||||||
@@ -138,7 +138,7 @@ Features:
|
|||||||
export CXXFLAGS="-fPIC $RPM_OPT_FLAGS"
|
export CXXFLAGS="-fPIC $RPM_OPT_FLAGS"
|
||||||
%endif
|
%endif
|
||||||
%{cmake} -DQT_VERSION_MAJOR=@QT_VERSION_MAJOR@
|
%{cmake} -DQT_VERSION_MAJOR=@QT_VERSION_MAJOR@
|
||||||
%if 0%{?centos} || (0%{?mageia} && 0%{?mageia} <= 7)
|
%if 0%{?centos} || (0%{?mageia} && 0%{?mageia} <= 7) || "%{?_vendor}" == "openmandriva"
|
||||||
%make_build
|
%make_build
|
||||||
%else
|
%else
|
||||||
%cmake_build
|
%cmake_build
|
||||||
@@ -148,7 +148,7 @@ Features:
|
|||||||
%if 0%{?centos}
|
%if 0%{?centos}
|
||||||
%make_install
|
%make_install
|
||||||
%else
|
%else
|
||||||
%if 0%{?mageia}
|
%if 0%{?mageia} || "%{?_vendor}" == "openmandriva"
|
||||||
%make_install -C build
|
%make_install -C build
|
||||||
%else
|
%else
|
||||||
%cmake_install
|
%cmake_install
|
||||||
|
|||||||
186
dist/windows/Registry.nsh
vendored
Normal file
186
dist/windows/Registry.nsh
vendored
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
!define registry::Open `!insertmacro registry::Open`
|
||||||
|
|
||||||
|
!macro registry::Open _PATH _OPTIONS _HANDLE
|
||||||
|
registry::_Open /NOUNLOAD `${_PATH}` `${_OPTIONS}`
|
||||||
|
Pop ${_HANDLE}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::Find `!insertmacro registry::Find`
|
||||||
|
|
||||||
|
!macro registry::Find _HANDLE _PATH _VALUEORKEY _STRING _TYPE
|
||||||
|
registry::_Find /NOUNLOAD `${_HANDLE}`
|
||||||
|
Pop ${_PATH}
|
||||||
|
Pop ${_VALUEORKEY}
|
||||||
|
Pop ${_STRING}
|
||||||
|
Pop ${_TYPE}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::Close `!insertmacro registry::Close`
|
||||||
|
|
||||||
|
!macro registry::Close _HANDLE
|
||||||
|
registry::_Close /NOUNLOAD `${_HANDLE}`
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::KeyExists `!insertmacro registry::KeyExists`
|
||||||
|
|
||||||
|
!macro registry::KeyExists _PATH _ERR
|
||||||
|
registry::_KeyExists /NOUNLOAD `${_PATH}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::Read `!insertmacro registry::Read`
|
||||||
|
|
||||||
|
!macro registry::Read _PATH _VALUE _STRING _TYPE
|
||||||
|
registry::_Read /NOUNLOAD `${_PATH}` `${_VALUE}`
|
||||||
|
Pop ${_STRING}
|
||||||
|
Pop ${_TYPE}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::Write `!insertmacro registry::Write`
|
||||||
|
|
||||||
|
!macro registry::Write _PATH _VALUE _STRING _TYPE _ERR
|
||||||
|
registry::_Write /NOUNLOAD `${_PATH}` `${_VALUE}` `${_STRING}` `${_TYPE}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::ReadExtra `!insertmacro registry::ReadExtra`
|
||||||
|
|
||||||
|
!macro registry::ReadExtra _PATH _VALUE _NUMBER _STRING _TYPE
|
||||||
|
registry::_ReadExtra /NOUNLOAD `${_PATH}` `${_VALUE}` `${_NUMBER}`
|
||||||
|
Pop ${_STRING}
|
||||||
|
Pop ${_TYPE}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::WriteExtra `!insertmacro registry::WriteExtra`
|
||||||
|
|
||||||
|
!macro registry::WriteExtra _PATH _VALUE _STRING _ERR
|
||||||
|
registry::_WriteExtra /NOUNLOAD `${_PATH}` `${_VALUE}` `${_STRING}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::CreateKey `!insertmacro registry::CreateKey`
|
||||||
|
|
||||||
|
!macro registry::CreateKey _PATH _ERR
|
||||||
|
registry::_CreateKey /NOUNLOAD `${_PATH}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::DeleteValue `!insertmacro registry::DeleteValue`
|
||||||
|
|
||||||
|
!macro registry::DeleteValue _PATH _VALUE _ERR
|
||||||
|
registry::_DeleteValue /NOUNLOAD `${_PATH}` `${_VALUE}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::DeleteKey `!insertmacro registry::DeleteKey`
|
||||||
|
|
||||||
|
!macro registry::DeleteKey _PATH _ERR
|
||||||
|
registry::_DeleteKey /NOUNLOAD `${_PATH}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::DeleteKeyEmpty `!insertmacro registry::DeleteKeyEmpty`
|
||||||
|
|
||||||
|
!macro registry::DeleteKeyEmpty _PATH _ERR
|
||||||
|
registry::_DeleteKeyEmpty /NOUNLOAD `${_PATH}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::CopyValue `!insertmacro registry::CopyValue`
|
||||||
|
|
||||||
|
!macro registry::CopyValue _PATH_SOURCE _VALUE_SOURCE _PATH_TARGET _VALUE_TARGET _ERR
|
||||||
|
registry::_CopyValue /NOUNLOAD `${_PATH_SOURCE}` `${_VALUE_SOURCE}` `${_PATH_TARGET}` `${_VALUE_TARGET}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::MoveValue `!insertmacro registry::MoveValue`
|
||||||
|
|
||||||
|
!macro registry::MoveValue _PATH_SOURCE _VALUE_SOURCE _PATH_TARGET _VALUE_TARGET _ERR
|
||||||
|
registry::_MoveValue /NOUNLOAD `${_PATH_SOURCE}` `${_VALUE_SOURCE}` `${_PATH_TARGET}` `${_VALUE_TARGET}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::CopyKey `!insertmacro registry::CopyKey`
|
||||||
|
|
||||||
|
!macro registry::CopyKey _PATH_SOURCE _PATH_TARGET _ERR
|
||||||
|
registry::_CopyKey /NOUNLOAD `${_PATH_SOURCE}` `${_PATH_TARGET}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::MoveKey `!insertmacro registry::MoveKey`
|
||||||
|
|
||||||
|
!macro registry::MoveKey _PATH_SOURCE _PATH_TARGET _ERR
|
||||||
|
registry::_MoveKey /NOUNLOAD `${_PATH_SOURCE}` `${_PATH_TARGET}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::SaveKey `!insertmacro registry::SaveKey`
|
||||||
|
|
||||||
|
!macro registry::SaveKey _PATH _FILE _OPTIONS _ERR
|
||||||
|
registry::_SaveKey /NOUNLOAD `${_PATH}` `${_FILE}` `${_OPTIONS}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::RestoreKey `!insertmacro registry::RestoreKey`
|
||||||
|
|
||||||
|
!macro registry::RestoreKey _FILE _ERR
|
||||||
|
registry::_RestoreKey /NOUNLOAD `${_FILE}`
|
||||||
|
Pop ${_ERR}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::StrToHex `!insertmacro registry::StrToHexA`
|
||||||
|
!define registry::StrToHexA `!insertmacro registry::StrToHexA`
|
||||||
|
|
||||||
|
!macro registry::StrToHexA _STRING _HEX_STRING
|
||||||
|
registry::_StrToHexA /NOUNLOAD `${_STRING}`
|
||||||
|
Pop ${_HEX_STRING}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::StrToHexW `!insertmacro registry::StrToHexW`
|
||||||
|
|
||||||
|
!macro registry::StrToHexW _STRING _HEX_STRING
|
||||||
|
registry::_StrToHexW /NOUNLOAD `${_STRING}`
|
||||||
|
Pop ${_HEX_STRING}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::HexToStr `!insertmacro registry::HexToStrA`
|
||||||
|
!define registry::HexToStrA `!insertmacro registry::HexToStrA`
|
||||||
|
|
||||||
|
!macro registry::HexToStrA _HEX_STRING _STRING
|
||||||
|
registry::_HexToStrA /NOUNLOAD `${_HEX_STRING}`
|
||||||
|
Pop ${_STRING}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
!define registry::HexToStrW `!insertmacro registry::HexToStrW`
|
||||||
|
|
||||||
|
!macro registry::HexToStrW _HEX_STRING _STRING
|
||||||
|
registry::_HexToStrW /NOUNLOAD `${_HEX_STRING}`
|
||||||
|
Pop ${_STRING}
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
|
||||||
|
!define registry::Unload `!insertmacro registry::Unload`
|
||||||
|
|
||||||
|
!macro registry::Unload
|
||||||
|
registry::_Unload
|
||||||
|
!macroend
|
||||||
657
dist/windows/strawberry.nsi.in
vendored
657
dist/windows/strawberry.nsi.in
vendored
@@ -1,21 +1,51 @@
|
|||||||
!if "@ARCH@" == x86
|
!define build_type ""
|
||||||
|
!define compiler "unknown"
|
||||||
|
!define arch "unknown"
|
||||||
|
|
||||||
|
!if "@ARCH@" == "x86"
|
||||||
!define arch_x86
|
!define arch_x86
|
||||||
|
!undef arch
|
||||||
|
!define arch "x86"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!if "@ARCH@" == i686-w64-mingw32.shared
|
!if "@ARCH@" == "i686-w64-mingw32.shared"
|
||||||
!define arch_x86
|
!define arch_x86
|
||||||
|
!undef arch
|
||||||
|
!define arch "x86"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!if "@ARCH@" == x86_64
|
!if "@ARCH@" == "x86_64"
|
||||||
!define arch_x64
|
!define arch_x64
|
||||||
|
!undef arch
|
||||||
|
!define arch "x64"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!if "@ARCH@" == x86_64-w64-mingw32.shared
|
!if "@ARCH@" == "x86_64-w64-mingw32.shared"
|
||||||
!define arch_x64
|
!define arch_x64
|
||||||
|
!undef arch
|
||||||
|
!define arch "x64"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!if "@CMAKE_BUILD_TYPE@" == Debug
|
!if "@MINGW@" == "1"
|
||||||
|
!define mingw
|
||||||
|
!undef compiler
|
||||||
|
!define compiler "mingw"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!if "@MSVC@" == "1"
|
||||||
|
!define msvc
|
||||||
|
!undef compiler
|
||||||
|
!define compiler "msvc"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!if "@CMAKE_BUILD_TYPE@" == "Release"
|
||||||
|
!define release
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!if "@CMAKE_BUILD_TYPE@" == "Debug"
|
||||||
!define debug
|
!define debug
|
||||||
|
!undef build_type
|
||||||
|
!define build_type "-Debug"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
@@ -70,14 +100,27 @@ SetCompressor /SOLID lzma
|
|||||||
!include "FileAssociation.nsh"
|
!include "FileAssociation.nsh"
|
||||||
!include "Capabilities.nsh"
|
!include "Capabilities.nsh"
|
||||||
!include LogicLib.nsh
|
!include LogicLib.nsh
|
||||||
|
!include Registry.nsh
|
||||||
!include x64.nsh
|
!include x64.nsh
|
||||||
|
|
||||||
!define MUI_ICON "strawberry.ico"
|
!define MUI_ICON "strawberry.ico"
|
||||||
|
|
||||||
!define MUI_COMPONENTSPAGE_SMALLDESC
|
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||||
|
|
||||||
ReserveFile "${NSISDIR}/Plugins/x86-unicode/LockedList.dll"
|
!ifdef mingw
|
||||||
ReserveFile "${NSISDIR}/Plugins/LockedList64.dll"
|
ReserveFile "${NSISDIR}/Plugins/x86-unicode/LockedList.dll"
|
||||||
|
ReserveFile "${NSISDIR}/Plugins/LockedList64.dll"
|
||||||
|
ReserveFile "${NSISDIR}/Plugins/registry.dll"
|
||||||
|
ReserveFile "${NSISDIR}/Plugins/x86-unicode/INetC.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef msvc
|
||||||
|
ReserveFile "${NSISDIR}\Plugins\x86-unicode\LockedList.dll"
|
||||||
|
ReserveFile "${NSISDIR}\Plugins\LockedList64.dll"
|
||||||
|
ReserveFile "${NSISDIR}\Plugins\registry.dll"
|
||||||
|
ReserveFile "${NSISDIR}\Plugins\x86-unicode\INetC.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
!define LockedListPATH $InstallDir
|
!define LockedListPATH $InstallDir
|
||||||
|
|
||||||
; Installer pages
|
; Installer pages
|
||||||
@@ -97,21 +140,8 @@ UninstPage custom un.LockedListPageShow
|
|||||||
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||||
|
|
||||||
Name "${PRODUCT_NAME}"
|
Name "${PRODUCT_NAME}"
|
||||||
!ifdef arch_x86
|
|
||||||
!ifdef debug
|
|
||||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x86.exe"
|
|
||||||
!else
|
|
||||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x86.exe"
|
|
||||||
!endif
|
|
||||||
!endif
|
|
||||||
|
|
||||||
!ifdef arch_x64
|
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}${build_type}-${compiler}-${arch}.exe"
|
||||||
!ifdef debug
|
|
||||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x64.exe"
|
|
||||||
!else
|
|
||||||
OutFile "${PRODUCT_NAME_SHORT}Setup-${PRODUCT_DISPLAY_VERSION}-x64.exe"
|
|
||||||
!endif
|
|
||||||
!endif
|
|
||||||
|
|
||||||
InstallDir "${PRODUCT_INSTALL_DIR}"
|
InstallDir "${PRODUCT_INSTALL_DIR}"
|
||||||
|
|
||||||
@@ -166,6 +196,8 @@ SectionEnd
|
|||||||
Section "Strawberry" Strawberry
|
Section "Strawberry" Strawberry
|
||||||
SetOutPath "$INSTDIR"
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
; Common executables
|
||||||
|
|
||||||
File "strawberry.exe"
|
File "strawberry.exe"
|
||||||
File "strawberry-tagreader.exe"
|
File "strawberry-tagreader.exe"
|
||||||
File "strawberry.ico"
|
File "strawberry.ico"
|
||||||
@@ -173,30 +205,35 @@ Section "Strawberry" Strawberry
|
|||||||
File "gst-launch-1.0.exe"
|
File "gst-launch-1.0.exe"
|
||||||
File "gst-discoverer-1.0.exe"
|
File "gst-discoverer-1.0.exe"
|
||||||
|
|
||||||
|
; MinGW specific files
|
||||||
|
|
||||||
|
!ifdef mingw
|
||||||
|
|
||||||
!ifdef arch_x86
|
!ifdef arch_x86
|
||||||
File "libgcc_s_sjlj-1.dll"
|
File "libgcc_s_sjlj-1.dll"
|
||||||
File "libcrypto-3.dll"
|
File "libcrypto-3.dll"
|
||||||
File "libssl-3.dll"
|
File "libssl-3.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
!ifdef arch_x64
|
!ifdef arch_x64
|
||||||
File "libgcc_s_seh-1.dll"
|
File "libgcc_s_seh-1.dll"
|
||||||
File "libcrypto-3-x64.dll"
|
File "libcrypto-3-x64.dll"
|
||||||
File "libssl-3-x64.dll"
|
File "libssl-3-x64.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
File "avcodec-58.dll"
|
File "avcodec-59.dll"
|
||||||
File "avfilter-7.dll"
|
File "avfilter-8.dll"
|
||||||
File "avformat-58.dll"
|
File "avformat-59.dll"
|
||||||
File "avutil-56.dll"
|
File "avutil-57.dll"
|
||||||
File "libbrotlicommon.dll"
|
File "libbrotlicommon.dll"
|
||||||
File "libbrotlidec.dll"
|
File "libbrotlidec.dll"
|
||||||
|
File "libbrotlienc.dll"
|
||||||
|
File "libbs2b-0.dll"
|
||||||
File "libbz2.dll"
|
File "libbz2.dll"
|
||||||
File "libcdio-19.dll"
|
File "libcdio-19.dll"
|
||||||
File "libchromaprint.dll"
|
File "libchromaprint.dll"
|
||||||
File "libdl.dll"
|
File "libdl.dll"
|
||||||
|
File "libfdk-aac-2.dll"
|
||||||
File "libffi-8.dll"
|
File "libffi-8.dll"
|
||||||
File "libfftw3-3.dll"
|
|
||||||
File "libFLAC-8.dll"
|
File "libFLAC-8.dll"
|
||||||
File "libfreetype-6.dll"
|
File "libfreetype-6.dll"
|
||||||
File "libfaac-0.dll"
|
File "libfaac-0.dll"
|
||||||
@@ -232,22 +269,24 @@ Section "Strawberry" Strawberry
|
|||||||
File "libjpeg-9.dll"
|
File "libjpeg-9.dll"
|
||||||
File "liblzma-5.dll"
|
File "liblzma-5.dll"
|
||||||
File "libmp3lame-0.dll"
|
File "libmp3lame-0.dll"
|
||||||
|
File "libmpcdec.dll"
|
||||||
|
File "libmpg123-0.dll"
|
||||||
File "libnettle-8.dll"
|
File "libnettle-8.dll"
|
||||||
|
File "libnghttp2.dll"
|
||||||
File "libogg-0.dll"
|
File "libogg-0.dll"
|
||||||
File "libopenmpt-0.dll"
|
File "libopenmpt-0.dll"
|
||||||
File "libopus-0.dll"
|
File "libopus-0.dll"
|
||||||
File "liborc-0.4-0.dll"
|
File "liborc-0.4-0.dll"
|
||||||
File "libpcre-1.dll"
|
File "libpcre-1.dll"
|
||||||
File "libpcre2-16-0.dll"
|
|
||||||
File "libpng16-16.dll"
|
File "libpng16-16.dll"
|
||||||
|
File "libprotobuf-32.dll"
|
||||||
File "libpsl-5.dll"
|
File "libpsl-5.dll"
|
||||||
File "libprotobuf-30.dll"
|
|
||||||
File "libqtsparkle-qt6.dll"
|
File "libqtsparkle-qt6.dll"
|
||||||
|
File "libsoup-2.4-1.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3-0.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssp-0.dll"
|
File "libssp-0.dll"
|
||||||
File "libstdc++-6.dll"
|
File "libstdc++-6.dll"
|
||||||
File "libsoup-2.4-1.dll"
|
|
||||||
File "libtag.dll"
|
File "libtag.dll"
|
||||||
File "libtasn1-6.dll"
|
File "libtasn1-6.dll"
|
||||||
File "libunistring-2.dll"
|
File "libunistring-2.dll"
|
||||||
@@ -258,15 +297,9 @@ Section "Strawberry" Strawberry
|
|||||||
File "libwinpthread-1.dll"
|
File "libwinpthread-1.dll"
|
||||||
File "libxml2-2.dll"
|
File "libxml2-2.dll"
|
||||||
File "libzstd.dll"
|
File "libzstd.dll"
|
||||||
File "postproc-55.dll"
|
File "postproc-56.dll"
|
||||||
File "Qt6Concurrent.dll"
|
File "swresample-4.dll"
|
||||||
File "Qt6Core.dll"
|
File "swscale-6.dll"
|
||||||
File "Qt6Gui.dll"
|
|
||||||
File "Qt6Network.dll"
|
|
||||||
File "Qt6Sql.dll"
|
|
||||||
File "Qt6Widgets.dll"
|
|
||||||
File "swresample-3.dll"
|
|
||||||
File "swscale-5.dll"
|
|
||||||
File "zlib1.dll"
|
File "zlib1.dll"
|
||||||
|
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
@@ -274,8 +307,122 @@ Section "Strawberry" Strawberry
|
|||||||
File "libexpat-1.dll"
|
File "libexpat-1.dll"
|
||||||
File "libmman.dll"
|
File "libmman.dll"
|
||||||
File "libmpfr-6.dll"
|
File "libmpfr-6.dll"
|
||||||
|
File "libpcre2-16d.dll"
|
||||||
File "libreadline8.dll"
|
File "libreadline8.dll"
|
||||||
File "libtermcap.dll"
|
File "libtermcap.dll"
|
||||||
|
!else
|
||||||
|
File "libpcre2-16.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!endif ; MinGW
|
||||||
|
|
||||||
|
; MSVC specific files
|
||||||
|
|
||||||
|
!ifdef msvc
|
||||||
|
|
||||||
|
!ifdef arch_x86
|
||||||
|
File "libcrypto-3.dll"
|
||||||
|
File "libssl-3.dll"
|
||||||
|
!endif
|
||||||
|
!ifdef arch_x64
|
||||||
|
File "libcrypto-3-x64.dll"
|
||||||
|
File "libssl-3-x64.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
File "avcodec-58.dll"
|
||||||
|
File "avfilter-7.dll"
|
||||||
|
File "avformat-58.dll"
|
||||||
|
File "avresample-4.dll"
|
||||||
|
File "avutil-56.dll"
|
||||||
|
File "brotlicommon.dll"
|
||||||
|
File "brotlidec.dll"
|
||||||
|
File "chromaprint.dll"
|
||||||
|
File "faad.dll"
|
||||||
|
File "fdk-aac.dll"
|
||||||
|
File "ffi-7.dll"
|
||||||
|
File "FLAC.dll"
|
||||||
|
File "gio-2.0-0.dll"
|
||||||
|
File "glib-2.0-0.dll"
|
||||||
|
File "gmodule-2.0-0.dll"
|
||||||
|
File "gnutls.dll"
|
||||||
|
File "gobject-2.0-0.dll"
|
||||||
|
File "gstadaptivedemux-1.0-0.dll"
|
||||||
|
File "gstapp-1.0-0.dll"
|
||||||
|
File "gstaudio-1.0-0.dll"
|
||||||
|
File "gstbadaudio-1.0-0.dll"
|
||||||
|
File "gstbase-1.0-0.dll"
|
||||||
|
File "gstfft-1.0-0.dll"
|
||||||
|
File "gstisoff-1.0-0.dll"
|
||||||
|
File "gstnet-1.0-0.dll"
|
||||||
|
File "gstpbutils-1.0-0.dll"
|
||||||
|
File "gstreamer-1.0-0.dll"
|
||||||
|
File "gstriff-1.0-0.dll"
|
||||||
|
File "gstrtp-1.0-0.dll"
|
||||||
|
File "gstrtsp-1.0-0.dll"
|
||||||
|
File "gstsdp-1.0-0.dll"
|
||||||
|
File "gsttag-1.0-0.dll"
|
||||||
|
File "gsturidownloader-1.0-0.dll"
|
||||||
|
File "gstvideo-1.0-0.dll"
|
||||||
|
File "gstwinrt-1.0-0.dll"
|
||||||
|
File "intl-8.dll"
|
||||||
|
File "libbs2b.dll"
|
||||||
|
File "libfaac_dll.dll"
|
||||||
|
File "libiconv.dll"
|
||||||
|
File "liblzma.dll"
|
||||||
|
File "libmp3lame.dll"
|
||||||
|
File "libopenmpt.dll"
|
||||||
|
File "libspeex.dll"
|
||||||
|
File "mpcdec.dll"
|
||||||
|
File "mpg123.dll"
|
||||||
|
File "ogg.dll"
|
||||||
|
File "opus.dll"
|
||||||
|
File "orc-0.4-0.dll"
|
||||||
|
File "postproc-55.dll"
|
||||||
|
File "psl-5.dll"
|
||||||
|
File "qtsparkle-qt6.dll"
|
||||||
|
File "soup-2.4-1.dll"
|
||||||
|
File "sqlite3.dll"
|
||||||
|
File "swresample-3.dll"
|
||||||
|
File "swscale-5.dll"
|
||||||
|
File "tag.dll"
|
||||||
|
File "vorbis.dll"
|
||||||
|
File "vorbisfile.dll"
|
||||||
|
File "wavpackdll.dll"
|
||||||
|
|
||||||
|
!ifdef release
|
||||||
|
File "libpng16.dll"
|
||||||
|
File "libprotobuf.dll"
|
||||||
|
File "libxml2.dll"
|
||||||
|
File "pcre2-16.dll"
|
||||||
|
File "zlib.dll"
|
||||||
|
!endif
|
||||||
|
!ifdef debug
|
||||||
|
File "libpng16d.dll"
|
||||||
|
File "libprotobufd.dll"
|
||||||
|
File "libxml2d.dll"
|
||||||
|
File "pcre2-16d.dll"
|
||||||
|
File "zlibd.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!endif ; MSVC
|
||||||
|
|
||||||
|
; Common files
|
||||||
|
|
||||||
|
File "libfftw3-3.dll"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
File "Qt6Concurrentd.dll"
|
||||||
|
File "Qt6Cored.dll"
|
||||||
|
File "Qt6Guid.dll"
|
||||||
|
File "Qt6Networkd.dll"
|
||||||
|
File "Qt6Sqld.dll"
|
||||||
|
File "Qt6Widgetsd.dll"
|
||||||
|
!else
|
||||||
|
File "Qt6Concurrent.dll"
|
||||||
|
File "Qt6Core.dll"
|
||||||
|
File "Qt6Gui.dll"
|
||||||
|
File "Qt6Network.dll"
|
||||||
|
File "Qt6Sql.dll"
|
||||||
|
File "Qt6Widgets.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
@@ -312,39 +459,72 @@ SectionEnd
|
|||||||
|
|
||||||
Section "GIO modules" gio-modules
|
Section "GIO modules" gio-modules
|
||||||
SetOutPath "$INSTDIR\gio-modules"
|
SetOutPath "$INSTDIR\gio-modules"
|
||||||
|
!ifdef mingw
|
||||||
File "/oname=libgiognutls.dll" "gio-modules\libgiognutls.dll"
|
File "/oname=libgiognutls.dll" "gio-modules\libgiognutls.dll"
|
||||||
|
File "/oname=libgioopenssl.dll" "gio-modules\libgioopenssl.dll"
|
||||||
|
!endif
|
||||||
|
!ifdef msvc
|
||||||
|
File "/oname=giognutls.dll" "gio-modules\giognutls.dll"
|
||||||
|
File "/oname=gioopenssl.dll" "gio-modules\gioopenssl.dll"
|
||||||
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Qt Platform plugins" platforms
|
Section "Qt Platform plugins" platforms
|
||||||
SetOutPath "$INSTDIR\platforms"
|
SetOutPath "$INSTDIR\platforms"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
File "/oname=qwindowsd.dll" "platforms\qwindowsd.dll"
|
||||||
|
!else
|
||||||
File "/oname=qwindows.dll" "platforms\qwindows.dll"
|
File "/oname=qwindows.dll" "platforms\qwindows.dll"
|
||||||
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Qt styles" styles
|
Section "Qt styles" styles
|
||||||
SetOutPath "$INSTDIR\styles"
|
SetOutPath "$INSTDIR\styles"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
File "/oname=qwindowsvistastyled.dll" "styles\qwindowsvistastyled.dll"
|
||||||
|
!else
|
||||||
File "/oname=qwindowsvistastyle.dll" "styles\qwindowsvistastyle.dll"
|
File "/oname=qwindowsvistastyle.dll" "styles\qwindowsvistastyle.dll"
|
||||||
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Qt TLS plugins" tls
|
Section "Qt TLS plugins" tls
|
||||||
SetOutPath "$INSTDIR\tls"
|
SetOutPath "$INSTDIR\tls"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
File "/oname=qschannelbackendd.dll" "tls\qschannelbackendd.dll"
|
||||||
|
File "/oname=qopensslbackendd.dll" "tls\qopensslbackendd.dll"
|
||||||
|
!else
|
||||||
|
File "/oname=qschannelbackend.dll" "tls\qschannelbackend.dll"
|
||||||
File "/oname=qopensslbackend.dll" "tls\qopensslbackend.dll"
|
File "/oname=qopensslbackend.dll" "tls\qopensslbackend.dll"
|
||||||
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Qt SQL Drivers" sqldrivers
|
Section "Qt SQL Drivers" sqldrivers
|
||||||
SetOutPath "$INSTDIR\sqldrivers"
|
SetOutPath "$INSTDIR\sqldrivers"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
File "/oname=qsqlited.dll" "sqldrivers\qsqlited.dll"
|
||||||
|
!else
|
||||||
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
|
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
|
||||||
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Qt imageformats" imageformats
|
Section "Qt imageformats" imageformats
|
||||||
SetOutPath "$INSTDIR\imageformats"
|
SetOutPath "$INSTDIR\imageformats"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
File "/oname=qgifd.dll" "imageformats\qgifd.dll"
|
||||||
|
File "/oname=qicod.dll" "imageformats\qicod.dll"
|
||||||
|
File "/oname=qjpegd.dll" "imageformats\qjpegd.dll"
|
||||||
|
!else
|
||||||
File "/oname=qgif.dll" "imageformats\qgif.dll"
|
File "/oname=qgif.dll" "imageformats\qgif.dll"
|
||||||
File "/oname=qico.dll" "imageformats\qico.dll"
|
File "/oname=qico.dll" "imageformats\qico.dll"
|
||||||
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
|
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
|
||||||
|
!endif
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Gstreamer plugins" gstreamer-plugins
|
Section "Gstreamer plugins" gstreamer-plugins
|
||||||
SetOutPath "$INSTDIR\gstreamer-plugins"
|
SetOutPath "$INSTDIR\gstreamer-plugins"
|
||||||
|
|
||||||
|
!ifdef mingw
|
||||||
|
File "/oname=libgstaes.dll" "gstreamer-plugins\libgstaes.dll"
|
||||||
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
|
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
|
||||||
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
|
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
|
||||||
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
|
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
|
||||||
@@ -358,20 +538,25 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
|
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
|
||||||
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
||||||
|
File "/oname=libgstbs2b.dll" "gstreamer-plugins\libgstbs2b.dll"
|
||||||
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
|
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
|
||||||
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
||||||
File "/oname=libgstdash.dll" "gstreamer-plugins\libgstdash.dll"
|
File "/oname=libgstdash.dll" "gstreamer-plugins\libgstdash.dll"
|
||||||
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
||||||
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
|
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
|
||||||
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
|
||||||
File "/oname=libgstfaac.dll" "gstreamer-plugins\libgstfaac.dll"
|
File "/oname=libgstfaac.dll" "gstreamer-plugins\libgstfaac.dll"
|
||||||
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
|
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
|
||||||
|
File "/oname=libgstfdkaac.dll" "gstreamer-plugins\libgstfdkaac.dll"
|
||||||
|
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
||||||
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
||||||
|
File "/oname=libgsthls.dll" "gstreamer-plugins\libgsthls.dll"
|
||||||
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
||||||
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
||||||
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
||||||
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
||||||
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
|
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
|
||||||
|
File "/oname=libgstmpg123.dll" "gstreamer-plugins\libgstmpg123.dll"
|
||||||
|
File "/oname=libgstmusepack.dll" "gstreamer-plugins\libgstmusepack.dll"
|
||||||
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
|
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
|
||||||
File "/oname=libgstopenmpt.dll" "gstreamer-plugins\libgstopenmpt.dll"
|
File "/oname=libgstopenmpt.dll" "gstreamer-plugins\libgstopenmpt.dll"
|
||||||
File "/oname=libgstopus.dll" "gstreamer-plugins\libgstopus.dll"
|
File "/oname=libgstopus.dll" "gstreamer-plugins\libgstopus.dll"
|
||||||
@@ -394,6 +579,62 @@ Section "Gstreamer plugins" gstreamer-plugins
|
|||||||
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
||||||
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
||||||
File "/oname=libgstxingmux.dll" "gstreamer-plugins\libgstxingmux.dll"
|
File "/oname=libgstxingmux.dll" "gstreamer-plugins\libgstxingmux.dll"
|
||||||
|
!endif ; MinGW
|
||||||
|
|
||||||
|
!ifdef msvc
|
||||||
|
File "/oname=gstaiff.dll" "gstreamer-plugins\gstaiff.dll"
|
||||||
|
File "/oname=gstapetag.dll" "gstreamer-plugins\gstapetag.dll"
|
||||||
|
File "/oname=gstapp.dll" "gstreamer-plugins\gstapp.dll"
|
||||||
|
File "/oname=gstasf.dll" "gstreamer-plugins\gstasf.dll"
|
||||||
|
File "/oname=gstasfmux.dll" "gstreamer-plugins\gstasfmux.dll"
|
||||||
|
File "/oname=gstaudioconvert.dll" "gstreamer-plugins\gstaudioconvert.dll"
|
||||||
|
File "/oname=gstaudiofx.dll" "gstreamer-plugins\gstaudiofx.dll"
|
||||||
|
File "/oname=gstaudiomixer.dll" "gstreamer-plugins\gstaudiomixer.dll"
|
||||||
|
File "/oname=gstaudioparsers.dll" "gstreamer-plugins\gstaudioparsers.dll"
|
||||||
|
File "/oname=gstaudiorate.dll" "gstreamer-plugins\gstaudiorate.dll"
|
||||||
|
File "/oname=gstaudioresample.dll" "gstreamer-plugins\gstaudioresample.dll"
|
||||||
|
File "/oname=gstaudiotestsrc.dll" "gstreamer-plugins\gstaudiotestsrc.dll"
|
||||||
|
File "/oname=gstautodetect.dll" "gstreamer-plugins\gstautodetect.dll"
|
||||||
|
File "/oname=gstbs2b.dll" "gstreamer-plugins\gstbs2b.dll"
|
||||||
|
File "/oname=gstcoreelements.dll" "gstreamer-plugins\gstcoreelements.dll"
|
||||||
|
File "/oname=gstdash.dll" "gstreamer-plugins\gstdash.dll"
|
||||||
|
File "/oname=gstdirectsound.dll" "gstreamer-plugins\gstdirectsound.dll"
|
||||||
|
File "/oname=gstequalizer.dll" "gstreamer-plugins\gstequalizer.dll"
|
||||||
|
File "/oname=gstfaac.dll" "gstreamer-plugins\gstfaac.dll"
|
||||||
|
File "/oname=gstfaad.dll" "gstreamer-plugins\gstfaad.dll"
|
||||||
|
File "/oname=gstfdkaac.dll" "gstreamer-plugins\gstfdkaac.dll"
|
||||||
|
File "/oname=gstflac.dll" "gstreamer-plugins\gstflac.dll"
|
||||||
|
File "/oname=gstgio.dll" "gstreamer-plugins\gstgio.dll"
|
||||||
|
File "/oname=gsthls.dll" "gstreamer-plugins\gsthls.dll"
|
||||||
|
File "/oname=gsticydemux.dll" "gstreamer-plugins\gsticydemux.dll"
|
||||||
|
File "/oname=gstid3demux.dll" "gstreamer-plugins\gstid3demux.dll"
|
||||||
|
File "/oname=gstisomp4.dll" "gstreamer-plugins\gstisomp4.dll"
|
||||||
|
File "/oname=gstlame.dll" "gstreamer-plugins\gstlame.dll"
|
||||||
|
File "/oname=gstlibav.dll" "gstreamer-plugins\gstlibav.dll"
|
||||||
|
File "/oname=gstmpg123.dll" "gstreamer-plugins\gstmpg123.dll"
|
||||||
|
File "/oname=gstmusepack.dll" "gstreamer-plugins\gstmusepack.dll"
|
||||||
|
File "/oname=gstogg.dll" "gstreamer-plugins\gstogg.dll"
|
||||||
|
File "/oname=gstopenmpt.dll" "gstreamer-plugins\gstopenmpt.dll"
|
||||||
|
File "/oname=gstopus.dll" "gstreamer-plugins\gstopus.dll"
|
||||||
|
File "/oname=gstopusparse.dll" "gstreamer-plugins\gstopusparse.dll"
|
||||||
|
File "/oname=gstplayback.dll" "gstreamer-plugins\gstplayback.dll"
|
||||||
|
File "/oname=gstreplaygain.dll" "gstreamer-plugins\gstreplaygain.dll"
|
||||||
|
File "/oname=gstrtp.dll" "gstreamer-plugins\gstrtp.dll"
|
||||||
|
File "/oname=gstrtsp.dll" "gstreamer-plugins\gstrtsp.dll"
|
||||||
|
File "/oname=gstspeex.dll" "gstreamer-plugins\gstspeex.dll"
|
||||||
|
File "/oname=gstsoup.dll" "gstreamer-plugins\gstsoup.dll"
|
||||||
|
File "/oname=gstspectrum.dll" "gstreamer-plugins\gstspectrum.dll"
|
||||||
|
File "/oname=gsttcp.dll" "gstreamer-plugins\gsttcp.dll"
|
||||||
|
File "/oname=gsttypefindfunctions.dll" "gstreamer-plugins\gsttypefindfunctions.dll"
|
||||||
|
File "/oname=gstudp.dll" "gstreamer-plugins\gstudp.dll"
|
||||||
|
File "/oname=gstvolume.dll" "gstreamer-plugins\gstvolume.dll"
|
||||||
|
File "/oname=gstvorbis.dll" "gstreamer-plugins\gstvorbis.dll"
|
||||||
|
File "/oname=gstwasapi.dll" "gstreamer-plugins\gstwasapi.dll"
|
||||||
|
;File "/oname=gstwasapi2.dll" "gstreamer-plugins\gstwasapi2.dll"
|
||||||
|
File "/oname=gstwavpack.dll" "gstreamer-plugins\gstwavpack.dll"
|
||||||
|
File "/oname=gstwavparse.dll" "gstreamer-plugins\gstwavparse.dll"
|
||||||
|
File "/oname=gstxingmux.dll" "gstreamer-plugins\gstxingmux.dll"
|
||||||
|
!endif ; MSVC
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
@@ -439,6 +680,10 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\gst-launch-1.0.exe"
|
Delete "$INSTDIR\gst-launch-1.0.exe"
|
||||||
Delete "$INSTDIR\gst-discoverer-1.0.exe"
|
Delete "$INSTDIR\gst-discoverer-1.0.exe"
|
||||||
|
|
||||||
|
; MinGW specific files
|
||||||
|
|
||||||
|
!ifdef mingw
|
||||||
|
|
||||||
!ifdef arch_x86
|
!ifdef arch_x86
|
||||||
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
||||||
Delete "$INSTDIR\libcrypto-3.dll"
|
Delete "$INSTDIR\libcrypto-3.dll"
|
||||||
@@ -451,18 +696,20 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libssl-3-x64.dll"
|
Delete "$INSTDIR\libssl-3-x64.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
Delete "$INSTDIR\avcodec-58.dll"
|
Delete "$INSTDIR\avcodec-59.dll"
|
||||||
Delete "$INSTDIR\avfilter-7.dll"
|
Delete "$INSTDIR\avfilter-8.dll"
|
||||||
Delete "$INSTDIR\avformat-58.dll"
|
Delete "$INSTDIR\avformat-59.dll"
|
||||||
Delete "$INSTDIR\avutil-56.dll"
|
Delete "$INSTDIR\avutil-57.dll"
|
||||||
Delete "$INSTDIR\libbrotlicommon.dll"
|
Delete "$INSTDIR\libbrotlicommon.dll"
|
||||||
Delete "$INSTDIR\libbrotlidec.dll"
|
Delete "$INSTDIR\libbrotlidec.dll"
|
||||||
|
Delete "$INSTDIR\libbrotlienc.dll"
|
||||||
|
Delete "$INSTDIR\libbs2b-0.dll"
|
||||||
Delete "$INSTDIR\libbz2.dll"
|
Delete "$INSTDIR\libbz2.dll"
|
||||||
Delete "$INSTDIR\libcdio-19.dll"
|
Delete "$INSTDIR\libcdio-19.dll"
|
||||||
Delete "$INSTDIR\libchromaprint.dll"
|
Delete "$INSTDIR\libchromaprint.dll"
|
||||||
Delete "$INSTDIR\libdl.dll"
|
Delete "$INSTDIR\libdl.dll"
|
||||||
|
Delete "$INSTDIR\libfdk-aac-2.dll"
|
||||||
Delete "$INSTDIR\libffi-8.dll"
|
Delete "$INSTDIR\libffi-8.dll"
|
||||||
Delete "$INSTDIR\libfftw3-3.dll"
|
|
||||||
Delete "$INSTDIR\libFLAC-8.dll"
|
Delete "$INSTDIR\libFLAC-8.dll"
|
||||||
Delete "$INSTDIR\libfreetype-6.dll"
|
Delete "$INSTDIR\libfreetype-6.dll"
|
||||||
Delete "$INSTDIR\libfaac-0.dll"
|
Delete "$INSTDIR\libfaac-0.dll"
|
||||||
@@ -498,22 +745,24 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libjpeg-9.dll"
|
Delete "$INSTDIR\libjpeg-9.dll"
|
||||||
Delete "$INSTDIR\liblzma-5.dll"
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
Delete "$INSTDIR\libmp3lame-0.dll"
|
Delete "$INSTDIR\libmp3lame-0.dll"
|
||||||
|
Delete "$INSTDIR\libmpcdec.dll"
|
||||||
|
Delete "$INSTDIR\libmpg123-0.dll"
|
||||||
Delete "$INSTDIR\libnettle-8.dll"
|
Delete "$INSTDIR\libnettle-8.dll"
|
||||||
|
Delete "$INSTDIR\libnghttp2.dll"
|
||||||
Delete "$INSTDIR\libogg-0.dll"
|
Delete "$INSTDIR\libogg-0.dll"
|
||||||
Delete "$INSTDIR\libopenmpt-0.dll"
|
Delete "$INSTDIR\libopenmpt-0.dll"
|
||||||
Delete "$INSTDIR\libopus-0.dll"
|
Delete "$INSTDIR\libopus-0.dll"
|
||||||
Delete "$INSTDIR\liborc-0.4-0.dll"
|
Delete "$INSTDIR\liborc-0.4-0.dll"
|
||||||
Delete "$INSTDIR\libpcre-1.dll"
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
|
||||||
Delete "$INSTDIR\libpng16-16.dll"
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
|
Delete "$INSTDIR\libprotobuf-32.dll"
|
||||||
Delete "$INSTDIR\libpsl-5.dll"
|
Delete "$INSTDIR\libpsl-5.dll"
|
||||||
Delete "$INSTDIR\libprotobuf-30.dll"
|
|
||||||
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
Delete "$INSTDIR\libqtsparkle-qt6.dll"
|
||||||
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssp-0.dll"
|
Delete "$INSTDIR\libssp-0.dll"
|
||||||
Delete "$INSTDIR\libstdc++-6.dll"
|
Delete "$INSTDIR\libstdc++-6.dll"
|
||||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
|
||||||
Delete "$INSTDIR\libtag.dll"
|
Delete "$INSTDIR\libtag.dll"
|
||||||
Delete "$INSTDIR\libtasn1-6.dll"
|
Delete "$INSTDIR\libtasn1-6.dll"
|
||||||
Delete "$INSTDIR\libunistring-2.dll"
|
Delete "$INSTDIR\libunistring-2.dll"
|
||||||
@@ -524,15 +773,9 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libwinpthread-1.dll"
|
Delete "$INSTDIR\libwinpthread-1.dll"
|
||||||
Delete "$INSTDIR\libxml2-2.dll"
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
Delete "$INSTDIR\libzstd.dll"
|
Delete "$INSTDIR\libzstd.dll"
|
||||||
Delete "$INSTDIR\postproc-55.dll"
|
Delete "$INSTDIR\postproc-56.dll"
|
||||||
Delete "$INSTDIR\Qt6Concurrent.dll"
|
Delete "$INSTDIR\swresample-4.dll"
|
||||||
Delete "$INSTDIR\Qt6Core.dll"
|
Delete "$INSTDIR\swscale-6.dll"
|
||||||
Delete "$INSTDIR\Qt6Gui.dll"
|
|
||||||
Delete "$INSTDIR\Qt6Network.dll"
|
|
||||||
Delete "$INSTDIR\Qt6Sql.dll"
|
|
||||||
Delete "$INSTDIR\Qt6Widgets.dll"
|
|
||||||
Delete "$INSTDIR\swresample-3.dll"
|
|
||||||
Delete "$INSTDIR\swscale-5.dll"
|
|
||||||
Delete "$INSTDIR\zlib1.dll"
|
Delete "$INSTDIR\zlib1.dll"
|
||||||
|
|
||||||
!ifdef debug
|
!ifdef debug
|
||||||
@@ -540,69 +783,269 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libexpat-1.dll"
|
Delete "$INSTDIR\libexpat-1.dll"
|
||||||
Delete "$INSTDIR\libmman.dll"
|
Delete "$INSTDIR\libmman.dll"
|
||||||
Delete "$INSTDIR\libmpfr-6.dll"
|
Delete "$INSTDIR\libmpfr-6.dll"
|
||||||
|
Delete "$INSTDIR\libpcre2-16d.dll"
|
||||||
Delete "$INSTDIR\libreadline8.dll"
|
Delete "$INSTDIR\libreadline8.dll"
|
||||||
Delete "$INSTDIR\libtermcap.dll"
|
Delete "$INSTDIR\libtermcap.dll"
|
||||||
|
!else
|
||||||
|
Delete "$INSTDIR\libpcre2-16.dll"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
|
!endif ; MinGW
|
||||||
|
|
||||||
|
; MSVC specific files
|
||||||
|
|
||||||
|
!ifdef msvc
|
||||||
|
|
||||||
|
!ifdef arch_x86
|
||||||
|
Delete "$INSTDIR\libcrypto-3.dll"
|
||||||
|
Delete "$INSTDIR\libssl-3.dll"
|
||||||
|
!endif
|
||||||
|
!ifdef arch_x64
|
||||||
|
Delete "$INSTDIR\libcrypto-3-x64.dll"
|
||||||
|
Delete "$INSTDIR\libssl-3-x64.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
Delete "$INSTDIR\avcodec-58.dll"
|
||||||
|
Delete "$INSTDIR\avfilter-7.dll"
|
||||||
|
Delete "$INSTDIR\avformat-58.dll"
|
||||||
|
Delete "$INSTDIR\avresample-4.dll"
|
||||||
|
Delete "$INSTDIR\avutil-56.dll"
|
||||||
|
Delete "$INSTDIR\brotlicommon.dll"
|
||||||
|
Delete "$INSTDIR\brotlidec.dll"
|
||||||
|
Delete "$INSTDIR\chromaprint.dll"
|
||||||
|
Delete "$INSTDIR\faad.dll"
|
||||||
|
Delete "$INSTDIR\fdk-aac.dll"
|
||||||
|
Delete "$INSTDIR\ffi-7.dll"
|
||||||
|
Delete "$INSTDIR\FLAC.dll"
|
||||||
|
Delete "$INSTDIR\gio-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\glib-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gmodule-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gnutls.dll"
|
||||||
|
Delete "$INSTDIR\gobject-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstadaptivedemux-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstapp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstaudio-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstbadaudio-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstbase-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstfft-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstisoff-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstnet-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstpbutils-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstriff-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstrtp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstrtsp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstsdp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gsttag-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gsturidownloader-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstvideo-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\gstwinrt-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\intl-8.dll"
|
||||||
|
Delete "$INSTDIR\libbs2b.dll"
|
||||||
|
Delete "$INSTDIR\libfaac_dll.dll"
|
||||||
|
Delete "$INSTDIR\libiconv.dll"
|
||||||
|
Delete "$INSTDIR\liblzma.dll"
|
||||||
|
Delete "$INSTDIR\libmp3lame.dll"
|
||||||
|
Delete "$INSTDIR\libopenmpt.dll"
|
||||||
|
Delete "$INSTDIR\libspeex.dll"
|
||||||
|
Delete "$INSTDIR\mpcdec.dll"
|
||||||
|
Delete "$INSTDIR\mpg123.dll"
|
||||||
|
Delete "$INSTDIR\ogg.dll"
|
||||||
|
Delete "$INSTDIR\opus.dll"
|
||||||
|
Delete "$INSTDIR\orc-0.4-0.dll"
|
||||||
|
Delete "$INSTDIR\postproc-55.dll"
|
||||||
|
Delete "$INSTDIR\psl-5.dll"
|
||||||
|
Delete "$INSTDIR\qtsparkle-qt6.dll"
|
||||||
|
Delete "$INSTDIR\soup-2.4-1.dll"
|
||||||
|
Delete "$INSTDIR\sqlite3.dll"
|
||||||
|
Delete "$INSTDIR\swresample-3.dll"
|
||||||
|
Delete "$INSTDIR\swscale-5.dll"
|
||||||
|
Delete "$INSTDIR\tag.dll"
|
||||||
|
Delete "$INSTDIR\vorbis.dll"
|
||||||
|
Delete "$INSTDIR\vorbisfile.dll"
|
||||||
|
Delete "$INSTDIR\wavpackdll.dll"
|
||||||
|
|
||||||
|
!ifdef release
|
||||||
|
Delete "$INSTDIR\libpng16.dll"
|
||||||
|
Delete "$INSTDIR\libprotobuf.dll"
|
||||||
|
Delete "$INSTDIR\libxml2.dll"
|
||||||
|
Delete "$INSTDIR\pcre2-16.dll"
|
||||||
|
Delete "$INSTDIR\zlib.dll"
|
||||||
|
!endif
|
||||||
|
!ifdef debug
|
||||||
|
Delete "$INSTDIR\libpng16d.dll"
|
||||||
|
Delete "$INSTDIR\libprotobufd.dll"
|
||||||
|
Delete "$INSTDIR\libxml2d.dll"
|
||||||
|
Delete "$INSTDIR\pcre2-16d.dll"
|
||||||
|
Delete "$INSTDIR\zlibd.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!endif ; MSVC
|
||||||
|
|
||||||
|
; Common files
|
||||||
|
|
||||||
|
Delete "$INSTDIR\libfftw3-3.dll"
|
||||||
|
!ifdef msvc && debug
|
||||||
|
Delete "$INSTDIR\Qt6Concurrentd.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Cored.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Guid.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Networkd.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Sqld.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Widgetsd.dll"
|
||||||
|
!else
|
||||||
|
Delete "$INSTDIR\Qt6Concurrent.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Core.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Gui.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Network.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Sql.dll"
|
||||||
|
Delete "$INSTDIR\Qt6Widgets.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef mingw
|
||||||
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
|
Delete "$INSTDIR\gio-modules\libgiognutls.dll"
|
||||||
|
Delete "$INSTDIR\gio-modules\libgioopenssl.dll"
|
||||||
|
!endif
|
||||||
|
!ifdef msvc
|
||||||
|
Delete "$INSTDIR\gio-modules\giognutls.dll"
|
||||||
|
Delete "$INSTDIR\gio-modules\gioopenssl.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef msvc && debug
|
||||||
|
Delete "$INSTDIR\platforms\qwindowsd.dll"
|
||||||
|
Delete "$INSTDIR\styles\qwindowsvistastyled.dll"
|
||||||
|
Delete "$INSTDIR\tls\qschannelbackendd.dll"
|
||||||
|
Delete "$INSTDIR\tls\qopensslbackendd.dll"
|
||||||
|
Delete "$INSTDIR\sqldrivers\qsqlited.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qgifd.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qicod.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qjpegd.dll"
|
||||||
|
!else
|
||||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
|
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
|
||||||
|
Delete "$INSTDIR\tls\qschannelbackend.dll"
|
||||||
Delete "$INSTDIR\tls\qopensslbackend.dll"
|
Delete "$INSTDIR\tls\qopensslbackend.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|
||||||
Delete "$INSTDIR\imageformats\qgif.dll"
|
Delete "$INSTDIR\imageformats\qgif.dll"
|
||||||
Delete "$INSTDIR\imageformats\qico.dll"
|
Delete "$INSTDIR\imageformats\qico.dll"
|
||||||
Delete "$INSTDIR\imageformats\qjpeg.dll"
|
Delete "$INSTDIR\imageformats\qjpeg.dll"
|
||||||
|
!endif
|
||||||
|
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaiff.dll"
|
; MinGW GStreamer plugins
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstapetag.dll"
|
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstapp.dll"
|
!ifdef mingw
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstasf.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaes.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstasfmux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudiomixer.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstasfmux.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudiorate.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiomixer.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstcdio.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiorate.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstdash.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstequalizer.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstbs2b.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstflac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstfaac.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstfaad.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstdash.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstgio.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstfaac.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstlame.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstfdkaac.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstlibav.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstogg.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstopenmpt.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsthls.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstopus.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstopusparse.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstpbtypes.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstplayback.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstrtp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstmpg123.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstrtsp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstmusepack.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstsoup.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstspectrum.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstopenmpt.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstopus.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgsttcp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstpbtypes.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstudp.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstrtp.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstrtsp.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
||||||
Delete $INSTDIR\gstreamer-plugins\libgstxingmux.dll"
|
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwasapi.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstxingmux.dll"
|
||||||
|
!endif ; mingw
|
||||||
|
|
||||||
|
; MSVC GStreamer plugins
|
||||||
|
|
||||||
|
!ifdef msvc
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaiff.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstapetag.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstapp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstasf.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstasfmux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudioconvert.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudiofx.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudiomixer.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudioparsers.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudiorate.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudioresample.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstaudiotestsrc.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstautodetect.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstbs2b.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstcoreelements.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstdash.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstdirectsound.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstequalizer.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstfaac.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstfaad.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstfdkaac.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstflac.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstgio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsthls.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsticydemux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstid3demux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstisomp4.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstlame.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstlibav.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstmpg123.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstmusepack.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstogg.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstopenmpt.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstopus.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstopusparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstplayback.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstreplaygain.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstrtp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstrtsp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstspeex.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstsoup.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstspectrum.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsttcp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gsttypefindfunctions.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstudp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstvolume.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstvorbis.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstwasapi.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstwasapi2.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstwavpack.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstwavparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\gstxingmux.dll"
|
||||||
|
!endif ; msvc
|
||||||
|
|
||||||
Delete $INSTDIR\Uninstall.exe"
|
Delete $INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ enum {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#define gst_fastspectrum_parent_class parent_class
|
#define gst_fastspectrum_parent_class parent_class
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||||
G_DEFINE_TYPE(GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER)
|
G_DEFINE_TYPE(GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
static void gst_fastspectrum_finalize(GObject *object);
|
static void gst_fastspectrum_finalize(GObject *object);
|
||||||
static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ static const char *kMessageHandlerMagic = "__logging_message__";
|
|||||||
static const size_t kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);
|
static const size_t kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);
|
||||||
static QtMessageHandler sOriginalMessageHandler = nullptr;
|
static QtMessageHandler sOriginalMessageHandler = nullptr;
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
static T CreateLogger(Level level, const QString &class_name, int line, const char *category);
|
static T CreateLogger(Level level, const QString &class_name, int line, const char *category);
|
||||||
|
|
||||||
void GLog(const char *domain, int level, const char *message, void*) {
|
void GLog(const char *domain, int level, const char *message, void*) {
|
||||||
@@ -88,7 +88,7 @@ void GLog(const char *domain, int level, const char *message, void*) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
class DebugBase : public QDebug {
|
class DebugBase : public QDebug {
|
||||||
public:
|
public:
|
||||||
DebugBase() : QDebug(sNullDevice) {}
|
DebugBase() : QDebug(sNullDevice) {}
|
||||||
@@ -314,11 +314,11 @@ QString LinuxDemangle(const QString &symbol) {
|
|||||||
QString DarwinDemangle(const QString &symbol);
|
QString DarwinDemangle(const QString &symbol);
|
||||||
QString DarwinDemangle(const QString &symbol) {
|
QString DarwinDemangle(const QString &symbol) {
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
# if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
QStringList split = symbol.split(' ', Qt::SkipEmptyParts);
|
QStringList split = symbol.split(' ', Qt::SkipEmptyParts);
|
||||||
#else
|
# else
|
||||||
QStringList split = symbol.split(' ', QString::SkipEmptyParts);
|
QStringList split = symbol.split(' ', QString::SkipEmptyParts);
|
||||||
#endif
|
# endif
|
||||||
QString mangled_function = split[3];
|
QString mangled_function = split[3];
|
||||||
return CXXDemangle(mangled_function);
|
return CXXDemangle(mangled_function);
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ QDebug CreateLoggerError(int line, const char *pretty_function, const char *cate
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
QString print_duration(T duration, const std::string &unit) {
|
QString print_duration(T duration, const std::string &unit) {
|
||||||
return QString("%1%2").arg(duration.count()).arg(unit.c_str());
|
return QString("%1%2").arg(duration.count()).arg(unit.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class _MessageHandlerBase : public QObject {
|
|||||||
|
|
||||||
// Reads and writes uint32 length encoded MessageType messages to a socket.
|
// Reads and writes uint32 length encoded MessageType messages to a socket.
|
||||||
// You should subclass this and implement the MessageArrived(MessageType) method.
|
// You should subclass this and implement the MessageArrived(MessageType) method.
|
||||||
template <typename MT>
|
template<typename MT>
|
||||||
class AbstractMessageHandler : public _MessageHandlerBase {
|
class AbstractMessageHandler : public _MessageHandlerBase {
|
||||||
public:
|
public:
|
||||||
AbstractMessageHandler(QIODevice *device, QObject *parent);
|
AbstractMessageHandler(QIODevice *device, QObject *parent);
|
||||||
@@ -115,11 +115,11 @@ class AbstractMessageHandler : public _MessageHandlerBase {
|
|||||||
QMap<int, ReplyType*> pending_replies_;
|
QMap<int, ReplyType*> pending_replies_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename MT>
|
template<typename MT>
|
||||||
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice *device, QObject *parent)
|
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice *device, QObject *parent)
|
||||||
: _MessageHandlerBase(device, parent) {}
|
: _MessageHandlerBase(device, parent) {}
|
||||||
|
|
||||||
template <typename MT>
|
template<typename MT>
|
||||||
void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
|
void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
|
|||||||
WriteMessage(QByteArray(data.data(), data.size()));
|
WriteMessage(QByteArray(data.data(), data.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename MT>
|
template<typename MT>
|
||||||
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType &message) {
|
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType &message) {
|
||||||
std::string data = message.SerializeAsString();
|
std::string data = message.SerializeAsString();
|
||||||
QMetaObject::invokeMethod(this, "WriteMessage", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray(data.data(), data.size())));
|
QMetaObject::invokeMethod(this, "WriteMessage", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray(data.data(), data.size())));
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class _MessageReplyBase : public QObject {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// A reply future class that is returned immediately for requests that will occur in the background. Similar to QNetworkReply.
|
// A reply future class that is returned immediately for requests that will occur in the background. Similar to QNetworkReply.
|
||||||
template <typename MessageType>
|
template<typename MessageType>
|
||||||
class MessageReply : public _MessageReplyBase {
|
class MessageReply : public _MessageReplyBase {
|
||||||
public:
|
public:
|
||||||
explicit MessageReply(const MessageType &request_message, QObject *parent = nullptr);
|
explicit MessageReply(const MessageType &request_message, QObject *parent = nullptr);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class _WorkerPoolBase : public QObject {
|
|||||||
// A local socket server is started for each process, and the address is passed to the process as argv[1].
|
// A local socket server is started for each process, and the address is passed to the process as argv[1].
|
||||||
// The process is expected to connect back to the socket server, and when it does a HandlerType is created for it.
|
// The process is expected to connect back to the socket server, and when it does a HandlerType is created for it.
|
||||||
// Instances of HandlerType are created in the WorkerPool's thread.
|
// Instances of HandlerType are created in the WorkerPool's thread.
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
class WorkerPool : public _WorkerPoolBase {
|
class WorkerPool : public _WorkerPoolBase {
|
||||||
public:
|
public:
|
||||||
explicit WorkerPool(QObject *parent = nullptr);
|
explicit WorkerPool(QObject *parent = nullptr);
|
||||||
@@ -121,9 +121,9 @@ class WorkerPool : public _WorkerPoolBase {
|
|||||||
// Must only ever be called on my thread.
|
// Must only ever be called on my thread.
|
||||||
void StartOneWorker(Worker *worker);
|
void StartOneWorker(Worker *worker);
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
Worker *FindWorker(T Worker::*member, T value) {
|
Worker *FindWorker(T Worker::*member, T value) {
|
||||||
for (typename QList<Worker>::iterator it = workers_.begin() ; it != workers_.end() ; ++it) {
|
for (typename QList<Worker>::iterator it = workers_.begin(); it != workers_.end(); ++it) {
|
||||||
if ((*it).*member == value) {
|
if ((*it).*member == value) {
|
||||||
return &(*it);
|
return &(*it);
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ class WorkerPool : public _WorkerPoolBase {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
void DeleteQObjectPointerLater(T **p) {
|
void DeleteQObjectPointerLater(T **p) {
|
||||||
if (*p) {
|
if (*p) {
|
||||||
(*p)->deleteLater();
|
(*p)->deleteLater();
|
||||||
@@ -158,15 +158,15 @@ class WorkerPool : public _WorkerPoolBase {
|
|||||||
QAtomicInt next_id_;
|
QAtomicInt next_id_;
|
||||||
|
|
||||||
QMutex message_queue_mutex_;
|
QMutex message_queue_mutex_;
|
||||||
QQueue<ReplyType*> message_queue_;
|
QQueue<ReplyType *> message_queue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
WorkerPool<HandlerType>::WorkerPool(QObject *parent)
|
WorkerPool<HandlerType>::WorkerPool(QObject *parent)
|
||||||
: _WorkerPoolBase(parent),
|
: _WorkerPoolBase(parent),
|
||||||
next_worker_(0),
|
next_worker_(0),
|
||||||
next_id_(0) {
|
next_id_(0) {
|
||||||
|
|
||||||
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 4);
|
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 4);
|
||||||
local_server_name_ = qApp->applicationName().toLower();
|
local_server_name_ = qApp->applicationName().toLower();
|
||||||
@@ -177,7 +177,7 @@ WorkerPool<HandlerType>::WorkerPool(QObject *parent)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
WorkerPool<HandlerType>::~WorkerPool() {
|
WorkerPool<HandlerType>::~WorkerPool() {
|
||||||
|
|
||||||
for (const Worker &worker : workers_) {
|
for (const Worker &worker : workers_) {
|
||||||
@@ -208,30 +208,30 @@ WorkerPool<HandlerType>::~WorkerPool() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::SetWorkerCount(const int count) {
|
void WorkerPool<HandlerType>::SetWorkerCount(const int count) {
|
||||||
Q_ASSERT(workers_.isEmpty());
|
Q_ASSERT(workers_.isEmpty());
|
||||||
worker_count_ = count;
|
worker_count_ = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::SetLocalServerName(const QString &local_server_name) {
|
void WorkerPool<HandlerType>::SetLocalServerName(const QString &local_server_name) {
|
||||||
Q_ASSERT(workers_.isEmpty());
|
Q_ASSERT(workers_.isEmpty());
|
||||||
local_server_name_ = local_server_name;
|
local_server_name_ = local_server_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::SetExecutableName(const QString &executable_name) {
|
void WorkerPool<HandlerType>::SetExecutableName(const QString &executable_name) {
|
||||||
Q_ASSERT(workers_.isEmpty());
|
Q_ASSERT(workers_.isEmpty());
|
||||||
executable_name_ = executable_name;
|
executable_name_ = executable_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::Start() {
|
void WorkerPool<HandlerType>::Start() {
|
||||||
QMetaObject::invokeMethod(this, "DoStart");
|
QMetaObject::invokeMethod(this, "DoStart");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::DoStart() {
|
void WorkerPool<HandlerType>::DoStart() {
|
||||||
|
|
||||||
Q_ASSERT(workers_.isEmpty());
|
Q_ASSERT(workers_.isEmpty());
|
||||||
@@ -270,7 +270,7 @@ void WorkerPool<HandlerType>::DoStart() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
|
void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
|
||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
@@ -311,10 +311,9 @@ void WorkerPool<HandlerType>::StartOneWorker(Worker *worker) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
worker->process_->start(executable_path_, QStringList() << worker->local_server_->fullServerName());
|
worker->process_->start(executable_path_, QStringList() << worker->local_server_->fullServerName());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::NewConnection() {
|
void WorkerPool<HandlerType>::NewConnection() {
|
||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
@@ -342,7 +341,7 @@ void WorkerPool<HandlerType>::NewConnection() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
|
void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
|
||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
@@ -370,7 +369,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::ProcessReadyReadStandardOutput() {
|
void WorkerPool<HandlerType>::ProcessReadyReadStandardOutput() {
|
||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
@@ -383,7 +382,7 @@ void WorkerPool<HandlerType>::ProcessReadyReadStandardOutput() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::ProcessReadyReadStandardError() {
|
void WorkerPool<HandlerType>::ProcessReadyReadStandardError() {
|
||||||
|
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
@@ -426,7 +425,7 @@ WorkerPool<HandlerType>::SendMessageWithReply(MessageType *message) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::SendQueuedMessages() {
|
void WorkerPool<HandlerType>::SendQueuedMessages() {
|
||||||
|
|
||||||
QMutexLocker l(&message_queue_mutex_);
|
QMutexLocker l(&message_queue_mutex_);
|
||||||
@@ -448,7 +447,7 @@ void WorkerPool<HandlerType>::SendQueuedMessages() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template<typename HandlerType>
|
||||||
HandlerType *WorkerPool<HandlerType>::NextHandler() const {
|
HandlerType *WorkerPool<HandlerType>::NextHandler() const {
|
||||||
|
|
||||||
for (int i = 0; i < workers_.count(); ++i) {
|
for (int i = 0; i < workers_.count(); ++i) {
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ class TagLibFileRefFactory : public FileRefFactory {
|
|||||||
return new TagLib::FileRef(QFile::encodeName(filename).constData());
|
return new TagLib::FileRef(QFile::encodeName(filename).constData());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(TagLibFileRefFactory)
|
Q_DISABLE_COPY(TagLibFileRefFactory)
|
||||||
};
|
};
|
||||||
@@ -130,11 +131,11 @@ TagLib::String QStringToTaglibString(const QString &s) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
|
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
|
||||||
const char *kMP4_FMPS_Playcount_ID = "----:com.apple.iTunes:FMPS_Playcount";
|
const char *kMP4_FMPS_Playcount_ID = "----:com.apple.iTunes:FMPS_Playcount";
|
||||||
const char *kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
|
const char *kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
|
||||||
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
|
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
|
||||||
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
|
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
@@ -265,7 +266,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
if (tag) Decode(tag->comment(), song->mutable_comment());
|
if (tag) Decode(tag->comment(), song->mutable_comment());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (TagLib::WavPack::File *file_wavpack = dynamic_cast<TagLib::WavPack::File *>(fileref->file())) {
|
else if (TagLib::WavPack::File *file_wavpack = dynamic_cast<TagLib::WavPack::File*>(fileref->file())) {
|
||||||
song->set_bitdepth(file_wavpack->audioProperties()->bitsPerSample());
|
song->set_bitdepth(file_wavpack->audioProperties()->bitsPerSample());
|
||||||
if (file_wavpack->APETag()) {
|
if (file_wavpack->APETag()) {
|
||||||
ParseAPETag(file_wavpack->APETag()->itemListMap(), &disc, &compilation, song);
|
ParseAPETag(file_wavpack->APETag()->itemListMap(), &disc, &compilation, song);
|
||||||
@@ -306,7 +307,9 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
|
|
||||||
if (!map["TCMP"].isEmpty()) compilation = TStringToQString(map["TCMP"].front()->toString()).trimmed();
|
if (!map["TCMP"].isEmpty()) compilation = TStringToQString(map["TCMP"].front()->toString()).trimmed();
|
||||||
|
|
||||||
if (!map["TDOR"].isEmpty()) { song->set_originalyear(map["TDOR"].front()->toString().substr(0, 4).toInt()); }
|
if (!map["TDOR"].isEmpty()) {
|
||||||
|
song->set_originalyear(map["TDOR"].front()->toString().substr(0, 4).toInt());
|
||||||
|
}
|
||||||
else if (!map["TORY"].isEmpty()) {
|
else if (!map["TORY"].isEmpty()) {
|
||||||
song->set_originalyear(map["TORY"].front()->toString().substr(0, 4).toInt());
|
song->set_originalyear(map["TORY"].front()->toString().substr(0, 4).toInt());
|
||||||
}
|
}
|
||||||
@@ -321,7 +324,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
||||||
|
|
||||||
// Find a suitable comment tag. For now we ignore iTunNORM comments.
|
// Find a suitable comment tag. For now we ignore iTunNORM comments.
|
||||||
for (uint i = 0 ; i < map["COMM"].size() ; ++i) {
|
for (uint i = 0; i < map["COMM"].size(); ++i) {
|
||||||
const TagLib::ID3v2::CommentsFrame *frame = dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);
|
const TagLib::ID3v2::CommentsFrame *frame = dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);
|
||||||
|
|
||||||
if (frame && TStringToQString(frame->description()) != "iTunNORM") {
|
if (frame && TStringToQString(frame->description()) != "iTunNORM") {
|
||||||
@@ -450,7 +453,7 @@ void TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMeta
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attributes_map.contains("FMPS/Rating")) {
|
if (attributes_map.contains("FMPS/Rating")) {
|
||||||
const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating"];
|
const TagLib::ASF::AttributeList &attributes = attributes_map["FMPS/Rating"];
|
||||||
if (!attributes.isEmpty()) {
|
if (!attributes.isEmpty()) {
|
||||||
float rating = TStringToQString(attributes.front().toString()).toFloat();
|
float rating = TStringToQString(attributes.front().toString()).toFloat();
|
||||||
if (song->rating() <= 0 && rating > 0) {
|
if (song->rating() <= 0 && rating > 0) {
|
||||||
@@ -679,7 +682,7 @@ bool TagReaderTagLib::SaveFile(const QString &filename, const spb::tagreader::So
|
|||||||
else if (TagLib::MP4::File *file_mp4 = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
|
else if (TagLib::MP4::File *file_mp4 = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
|
||||||
TagLib::MP4::Tag *tag = file_mp4->tag();
|
TagLib::MP4::Tag *tag = file_mp4->tag();
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0));
|
tag->setItem("disk", TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0));
|
||||||
tag->setItem("\251wrt", TagLib::StringList(TagLib::String(song.composer(), TagLib::String::UTF8)));
|
tag->setItem("\251wrt", TagLib::StringList(TagLib::String(song.composer(), TagLib::String::UTF8)));
|
||||||
tag->setItem("\251grp", TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8)));
|
tag->setItem("\251grp", TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8)));
|
||||||
tag->setItem("\251lyr", TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8)));
|
tag->setItem("\251lyr", TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8)));
|
||||||
@@ -743,7 +746,7 @@ void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, Tag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update and add the frames
|
// Update and add the frames
|
||||||
for (int i = 0 ; i < frames_buffer.size() ; ++i) {
|
for (int i = 0; i < frames_buffer.size(); ++i) {
|
||||||
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame(frames_buffer.at(i));
|
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame(frames_buffer.at(i));
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
frame->setText(StdStringToTaglibString(value));
|
frame->setText(StdStringToTaglibString(value));
|
||||||
@@ -799,7 +802,7 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update and add the frames
|
// Update and add the frames
|
||||||
for (int i = 0 ; i < frames_buffer.size() ; ++i) {
|
for (int i = 0; i < frames_buffer.size(); ++i) {
|
||||||
TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame(frames_buffer.at(i));
|
TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame(frames_buffer.at(i));
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
frame->setText(StdStringToTaglibString(value));
|
frame->setText(StdStringToTaglibString(value));
|
||||||
@@ -983,7 +986,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
|
|||||||
|
|
||||||
// Remove existing covers
|
// Remove existing covers
|
||||||
TagLib::ID3v2::FrameList apiclist = tag->frameListMap()["APIC"];
|
TagLib::ID3v2::FrameList apiclist = tag->frameListMap()["APIC"];
|
||||||
for (TagLib::ID3v2::FrameList::ConstIterator it = apiclist.begin() ; it != apiclist.end() ; ++it ) {
|
for (TagLib::ID3v2::FrameList::ConstIterator it = apiclist.begin(); it != apiclist.end(); ++it) {
|
||||||
TagLib::ID3v2::AttachedPictureFrame *frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
|
TagLib::ID3v2::AttachedPictureFrame *frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
|
||||||
tag->removeFrame(frame, false);
|
tag->removeFrame(frame, false);
|
||||||
}
|
}
|
||||||
@@ -994,7 +997,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
|
|||||||
frontcover = new TagLib::ID3v2::AttachedPictureFrame("APIC");
|
frontcover = new TagLib::ID3v2::AttachedPictureFrame("APIC");
|
||||||
frontcover->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
|
frontcover->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
|
||||||
frontcover->setMimeType("image/jpeg");
|
frontcover->setMimeType("image/jpeg");
|
||||||
frontcover->setPicture(TagLib::ByteVector(data.constData(), data.count()));
|
frontcover->setPicture(TagLib::ByteVector(data.constData(), data.size()));
|
||||||
tag->addFrame(frontcover);
|
tag->addFrame(frontcover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1008,7 +1011,7 @@ bool TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const QByteArray
|
|||||||
if (tag->contains("covr")) tag->removeItem("covr");
|
if (tag->contains("covr")) tag->removeItem("covr");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
covers.append(TagLib::MP4::CoverArt(TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector(data.constData(), data.count())));
|
covers.append(TagLib::MP4::CoverArt(TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector(data.constData(), data.size())));
|
||||||
tag->setItem("covr", covers);
|
tag->setItem("covr", covers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1040,13 +1043,13 @@ TagLib::ID3v2::PopularimeterFrame *TagReaderTagLib::GetPOPMFrameFromTag(TagLib::
|
|||||||
|
|
||||||
float TagReaderTagLib::ConvertPOPMRating(const int POPM_rating) {
|
float TagReaderTagLib::ConvertPOPMRating(const int POPM_rating) {
|
||||||
|
|
||||||
if (POPM_rating < 0x01) return 0.0;
|
if (POPM_rating < 0x01) return 0.0F;
|
||||||
else if (POPM_rating < 0x40) return 0.20;
|
else if (POPM_rating < 0x40) return 0.20F;
|
||||||
else if (POPM_rating < 0x80) return 0.40;
|
else if (POPM_rating < 0x80) return 0.40F;
|
||||||
else if (POPM_rating < 0xC0) return 0.60;
|
else if (POPM_rating < 0xC0) return 0.60F;
|
||||||
else if (POPM_rating < 0xFC) return 0.80;
|
else if (POPM_rating < 0xFC) return 0.80F;
|
||||||
|
|
||||||
return 1.0;
|
return 1.0F;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,13 +75,13 @@ class TagReaderTagLib : public TagReaderBase {
|
|||||||
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
||||||
void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const;
|
void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const;
|
||||||
void SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
void SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
||||||
void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const;
|
void SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
||||||
|
|
||||||
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
|
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
|
||||||
|
|
||||||
static float ConvertPOPMRating(const int POPM_rating);
|
static float ConvertPOPMRating(const int POPM_rating);
|
||||||
static int ConvertToPOPMRating(const float rating);
|
static int ConvertToPOPMRating(const float rating);
|
||||||
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag* tag);
|
static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileRefFactory *factory_;
|
FileRefFactory *factory_;
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
|
|||||||
|
|
||||||
const auto tracks = taginfo.tracks();
|
const auto tracks = taginfo.tracks();
|
||||||
for (const auto track : tracks) {
|
for (const auto track : tracks) {
|
||||||
switch(track->format().general) {
|
switch (track->format().general) {
|
||||||
case TagParser::GeneralMediaFormat::Flac:
|
case TagParser::GeneralMediaFormat::Flac:
|
||||||
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_FLAC);
|
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_FLAC);
|
||||||
break;
|
break;
|
||||||
@@ -174,7 +174,7 @@ void TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongM
|
|||||||
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGSPEEX);
|
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGSPEEX);
|
||||||
break;
|
break;
|
||||||
case TagParser::GeneralMediaFormat::Mpeg1Audio:
|
case TagParser::GeneralMediaFormat::Mpeg1Audio:
|
||||||
switch(track->format().sub) {
|
switch (track->format().sub) {
|
||||||
case TagParser::SubFormats::Mpeg1Layer3:
|
case TagParser::SubFormats::Mpeg1Layer3:
|
||||||
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_MPEG);
|
song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_MPEG);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ int main(int argc, char **argv) {
|
|||||||
QRegularExpressionMatch match = regexp.match(output_line);
|
QRegularExpressionMatch match = regexp.match(output_line);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
QString library = match.captured(1);
|
QString library = match.captured(1);
|
||||||
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
|
if (QFileInfo(library).fileName() == QFileInfo(filepath).fileName()) { // It's this.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (library.startsWith("@executable_path")) {
|
else if (library.startsWith("@executable_path")) {
|
||||||
@@ -113,7 +113,7 @@ int main(int argc, char **argv) {
|
|||||||
else if (library.startsWith("@rpath")) {
|
else if (library.startsWith("@rpath")) {
|
||||||
QString real_path = library;
|
QString real_path = library;
|
||||||
real_path = real_path.replace("@rpath", bundle_path + "/Contents/Frameworks");
|
real_path = real_path.replace("@rpath", bundle_path + "/Contents/Frameworks");
|
||||||
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
|
if (!QFile(real_path).exists() && !real_path.endsWith("QtSvg")) { // FIXME: Ignore broken svg image plugin.
|
||||||
qLog(Error) << real_path << "does not exist for" << filepath;
|
qLog(Error) << real_path << "does not exist for" << filepath;
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ int main(int argc, char **argv) {
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
|
else if (library.startsWith("/System/Library/") || library.startsWith("/usr/lib/")) { // System library
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (library.endsWith("libgcc_s.1.dylib")) { // fftw points to it for some reason.
|
else if (library.endsWith("libgcc_s.1.dylib")) { // fftw points to it for some reason.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||||
#include <sys/time.h>
|
# include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "tagreaderworker.h"
|
#include "tagreaderworker.h"
|
||||||
|
|
||||||
TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent)
|
TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent)
|
||||||
: AbstractMessageHandler<spb::tagreader::Message>(socket, parent) {}
|
: AbstractMessageHandler<spb::tagreader::Message>(socket, parent) {}
|
||||||
|
|
||||||
void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {
|
void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) {
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ set(SOURCES
|
|||||||
core/commandlineoptions.cpp
|
core/commandlineoptions.cpp
|
||||||
core/database.cpp
|
core/database.cpp
|
||||||
core/sqlquery.cpp
|
core/sqlquery.cpp
|
||||||
|
core/sqlrow.cpp
|
||||||
core/metatypes.cpp
|
core/metatypes.cpp
|
||||||
core/deletefiles.cpp
|
core/deletefiles.cpp
|
||||||
core/filesystemmusicstorage.cpp
|
core/filesystemmusicstorage.cpp
|
||||||
@@ -59,8 +60,6 @@ set(SOURCES
|
|||||||
|
|
||||||
context/contextview.cpp
|
context/contextview.cpp
|
||||||
context/contextalbum.cpp
|
context/contextalbum.cpp
|
||||||
context/contextalbumsmodel.cpp
|
|
||||||
context/contextalbumsview.cpp
|
|
||||||
|
|
||||||
collection/collection.cpp
|
collection/collection.cpp
|
||||||
collection/collectionmodel.cpp
|
collection/collectionmodel.cpp
|
||||||
@@ -73,7 +72,6 @@ set(SOURCES
|
|||||||
collection/collectionfilterwidget.cpp
|
collection/collectionfilterwidget.cpp
|
||||||
collection/collectionplaylistitem.cpp
|
collection/collectionplaylistitem.cpp
|
||||||
collection/collectionquery.cpp
|
collection/collectionquery.cpp
|
||||||
collection/sqlrow.cpp
|
|
||||||
collection/savedgroupingmanager.cpp
|
collection/savedgroupingmanager.cpp
|
||||||
collection/groupbydialog.cpp
|
collection/groupbydialog.cpp
|
||||||
collection/collectiontask.cpp
|
collection/collectiontask.cpp
|
||||||
@@ -212,6 +210,7 @@ set(SOURCES
|
|||||||
widgets/tracksliderslider.cpp
|
widgets/tracksliderslider.cpp
|
||||||
widgets/loginstatewidget.cpp
|
widgets/loginstatewidget.cpp
|
||||||
widgets/ratingwidget.cpp
|
widgets/ratingwidget.cpp
|
||||||
|
widgets/resizabletextedit.cpp
|
||||||
|
|
||||||
osd/osdbase.cpp
|
osd/osdbase.cpp
|
||||||
osd/osdpretty.cpp
|
osd/osdpretty.cpp
|
||||||
@@ -298,8 +297,6 @@ set(HEADERS
|
|||||||
|
|
||||||
context/contextview.h
|
context/contextview.h
|
||||||
context/contextalbum.h
|
context/contextalbum.h
|
||||||
context/contextalbumsmodel.h
|
|
||||||
context/contextalbumsview.h
|
|
||||||
|
|
||||||
collection/collection.h
|
collection/collection.h
|
||||||
collection/collectionmodel.h
|
collection/collectionmodel.h
|
||||||
@@ -445,6 +442,7 @@ set(HEADERS
|
|||||||
widgets/qsearchfield.h
|
widgets/qsearchfield.h
|
||||||
widgets/ratingwidget.h
|
widgets/ratingwidget.h
|
||||||
widgets/forcescrollperpixel.h
|
widgets/forcescrollperpixel.h
|
||||||
|
widgets/resizabletextedit.h
|
||||||
|
|
||||||
osd/osdbase.h
|
osd/osdbase.h
|
||||||
osd/osdpretty.h
|
osd/osdpretty.h
|
||||||
@@ -943,7 +941,6 @@ link_directories(
|
|||||||
${SQLITE_LIBRARY_DIRS}
|
${SQLITE_LIBRARY_DIRS}
|
||||||
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
${SINGLEAPPLICATION_LIBRARY_DIRS}
|
||||||
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
|
${SINGLECOREAPPLICATION_LIBRARY_DIRS}
|
||||||
${QTSPARKLE_LIBRARY_DIRS}
|
|
||||||
${Iconv_LIBRARY_DIRS}
|
${Iconv_LIBRARY_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -986,6 +983,10 @@ if(HAVE_GIO)
|
|||||||
link_directories(${GIO_LIBRARY_DIRS})
|
link_directories(${GIO_LIBRARY_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(HAVE_GIO_UNIX)
|
||||||
|
link_directories(${GIO_UNIX_LIBRARY_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(HAVE_AUDIOCD)
|
if(HAVE_AUDIOCD)
|
||||||
link_directories(${LIBCDIO_LIBRARY_DIRS})
|
link_directories(${LIBCDIO_LIBRARY_DIRS})
|
||||||
endif()
|
endif()
|
||||||
@@ -1006,6 +1007,10 @@ if(USE_TAGPARSER AND TAGPARSER_FOUND)
|
|||||||
link_directories(${TAGPARSER_LIBRARY_DIRS})
|
link_directories(${TAGPARSER_LIBRARY_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(HAVE_QTSPARKLE)
|
||||||
|
link_directories(${QTSPARKLE_LIBRARY_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(strawberry_lib STATIC
|
add_library(strawberry_lib STATIC
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
${MOC}
|
${MOC}
|
||||||
@@ -1022,6 +1027,7 @@ target_include_directories(strawberry_lib SYSTEM PUBLIC
|
|||||||
${GOBJECT_INCLUDE_DIRS}
|
${GOBJECT_INCLUDE_DIRS}
|
||||||
${GNUTLS_INCLUDE_DIRS}
|
${GNUTLS_INCLUDE_DIRS}
|
||||||
${SQLITE_INCLUDE_DIRS}
|
${SQLITE_INCLUDE_DIRS}
|
||||||
|
${PROTOBUF_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
|
if(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
|
||||||
@@ -1049,7 +1055,6 @@ target_link_libraries(strawberry_lib PUBLIC
|
|||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
${SINGLEAPPLICATION_LIBRARIES}
|
${SINGLEAPPLICATION_LIBRARIES}
|
||||||
${SINGLECOREAPPLICATION_LIBRARIES}
|
${SINGLECOREAPPLICATION_LIBRARIES}
|
||||||
${QTSPARKLE_LIBRARIES}
|
|
||||||
${Iconv_LIBRARIES}
|
${Iconv_LIBRARIES}
|
||||||
libstrawberry-common
|
libstrawberry-common
|
||||||
libstrawberry-tagreader
|
libstrawberry-tagreader
|
||||||
@@ -1113,6 +1118,11 @@ if(HAVE_GIO)
|
|||||||
target_link_libraries(strawberry_lib PRIVATE ${GIO_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${GIO_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(HAVE_GIO_UNIX)
|
||||||
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GIO_UNIX_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(strawberry_lib PRIVATE ${GIO_UNIX_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(HAVE_AUDIOCD)
|
if(HAVE_AUDIOCD)
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBCDIO_INCLUDE_DIRS})
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${LIBCDIO_INCLUDE_DIRS})
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${LIBCDIO_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${LIBCDIO_LIBRARIES})
|
||||||
@@ -1143,19 +1153,25 @@ if(APPLE)
|
|||||||
"-framework ScriptingBridge"
|
"-framework ScriptingBridge"
|
||||||
)
|
)
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${SPMEDIAKEYTAP_LIBRARIES})
|
target_link_libraries(strawberry_lib PRIVATE ${SPMEDIAKEYTAP_LIBRARIES})
|
||||||
if(HAVE_SPARKLE)
|
|
||||||
target_include_directories(strawberry_lib SYSTEM PRIVATE ${SPARKLE}/Headers)
|
|
||||||
target_link_libraries(strawberry_lib PRIVATE ${SPARKLE})
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(strawberry_lib PRIVATE dsound dwmapi)
|
target_link_libraries(strawberry_lib PRIVATE dsound dwmapi)
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_link_libraries(strawberry_lib PRIVATE sqlite3)
|
target_link_libraries(strawberry_lib PRIVATE sqlite3)
|
||||||
|
if (GETOPT_INCLUDE_DIRS)
|
||||||
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${GETOPT_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
if(GETOPT_LIBRARIES)
|
||||||
|
target_link_libraries(strawberry_lib PRIVATE ${GETOPT_LIBRARIES})
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(HAVE_QTSPARKLE)
|
||||||
|
target_include_directories(strawberry_lib SYSTEM PRIVATE ${QTSPARKLE_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(strawberry_lib PRIVATE ${QTSPARKLE_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -32,10 +32,11 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
#include <QBasicTimer>
|
||||||
|
#include <QShowEvent>
|
||||||
|
#include <QHideEvent>
|
||||||
#include <QTimerEvent>
|
#include <QTimerEvent>
|
||||||
#include <QtEvents>
|
|
||||||
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "engine/enginebase.h"
|
#include "engine/enginebase.h"
|
||||||
|
|
||||||
// INSTRUCTIONS Base2D
|
// INSTRUCTIONS Base2D
|
||||||
@@ -47,27 +48,38 @@
|
|||||||
//
|
//
|
||||||
// TODO:
|
// TODO:
|
||||||
// Make an INSTRUCTIONS file
|
// Make an INSTRUCTIONS file
|
||||||
// can't mod scope in analyze you have to use transform
|
// can't mod scope in analyze you have to use transform for 2D use setErasePixmap Qt function insetead of m_background
|
||||||
// for 2D use setErasePixmap Qt function insetead of m_background
|
|
||||||
|
|
||||||
// make the linker happy only for gcc < 4.0
|
|
||||||
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \
|
|
||||||
!defined(Q_OS_WIN32)
|
|
||||||
template class Analyzer::Base<QWidget>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Analyzer::Base::Base(QWidget *parent, const uint scopeSize)
|
Analyzer::Base::Base(QWidget *parent, const uint scopeSize)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
timeout_(40),
|
|
||||||
fht_(new FHT(scopeSize)),
|
fht_(new FHT(scopeSize)),
|
||||||
engine_(nullptr),
|
engine_(nullptr),
|
||||||
lastscope_(512),
|
lastscope_(512),
|
||||||
new_frame_(false),
|
new_frame_(false),
|
||||||
is_playing_(false) {}
|
is_playing_(false),
|
||||||
|
timeout_(40) {}
|
||||||
|
|
||||||
void Analyzer::Base::hideEvent(QHideEvent*) { timer_.stop(); }
|
Analyzer::Base::~Base() {
|
||||||
|
delete fht_;
|
||||||
|
}
|
||||||
|
|
||||||
void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); }
|
void Analyzer::Base::showEvent(QShowEvent*) {
|
||||||
|
timer_.start(timeout(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Analyzer::Base::hideEvent(QHideEvent*) {
|
||||||
|
timer_.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Analyzer::Base::ChangeTimeout(const int timeout) {
|
||||||
|
|
||||||
|
timeout_ = timeout;
|
||||||
|
if (timer_.isActive()) {
|
||||||
|
timer_.stop();
|
||||||
|
timer_.start(timeout_, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Analyzer::Base::transform(Scope &scope) {
|
void Analyzer::Base::transform(Scope &scope) {
|
||||||
|
|
||||||
@@ -80,7 +92,7 @@ void Analyzer::Base::transform(Scope &scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fht_->logSpectrum(scope.data(), aux.data());
|
fht_->logSpectrum(scope.data(), aux.data());
|
||||||
fht_->scale(scope.data(), 1.0 / 20);
|
fht_->scale(scope.data(), 1.0F / 20);
|
||||||
|
|
||||||
scope.resize(fht_->size() / 2); // second half of values are rubbish
|
scope.resize(fht_->size() / 2); // second half of values are rubbish
|
||||||
|
|
||||||
@@ -161,7 +173,7 @@ int Analyzer::Base::resizeForBands(const int bands) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
exp = 9;
|
exp = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeExponent(exp);
|
resizeExponent(exp);
|
||||||
return fht_->size() / 2;
|
return fht_->size() / 2;
|
||||||
@@ -193,10 +205,6 @@ void Analyzer::Base::demo(QPainter &p) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Analyzer::Base::polishEvent() {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Analyzer::interpolate(const Scope &inVec, Scope &outVec) {
|
void Analyzer::interpolate(const Scope &inVec, Scope &outVec) {
|
||||||
|
|
||||||
double pos = 0.0;
|
double pos = 0.0;
|
||||||
|
|||||||
@@ -44,8 +44,8 @@
|
|||||||
|
|
||||||
class QHideEvent;
|
class QHideEvent;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
class QTimerEvent;
|
|
||||||
class QPaintEvent;
|
class QPaintEvent;
|
||||||
|
class QTimerEvent;
|
||||||
|
|
||||||
namespace Analyzer {
|
namespace Analyzer {
|
||||||
|
|
||||||
@@ -55,19 +55,13 @@ class Base : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Base() override { delete fht_; }
|
~Base() override;
|
||||||
|
|
||||||
int timeout() const { return timeout_; }
|
int timeout() const { return timeout_; }
|
||||||
|
|
||||||
void set_engine(EngineBase *engine) { engine_ = engine; }
|
void set_engine(EngineBase *engine) { engine_ = engine; }
|
||||||
|
|
||||||
void changeTimeout(int newTimeout) {
|
void ChangeTimeout(const int timeout);
|
||||||
timeout_ = newTimeout;
|
|
||||||
if (timer_.isActive()) {
|
|
||||||
timer_.stop();
|
|
||||||
timer_.start(timeout_, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void framerateChanged() {}
|
virtual void framerateChanged() {}
|
||||||
|
|
||||||
@@ -76,10 +70,8 @@ class Base : public QWidget {
|
|||||||
|
|
||||||
void hideEvent(QHideEvent*) override;
|
void hideEvent(QHideEvent*) override;
|
||||||
void showEvent(QShowEvent*) override;
|
void showEvent(QShowEvent*) override;
|
||||||
void paintEvent(QPaintEvent*) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void timerEvent(QTimerEvent*) override;
|
void timerEvent(QTimerEvent *e) override;
|
||||||
|
|
||||||
void polishEvent();
|
|
||||||
|
|
||||||
int resizeExponent(int);
|
int resizeExponent(int);
|
||||||
int resizeForBands(const int);
|
int resizeForBands(const int);
|
||||||
@@ -90,13 +82,13 @@ class Base : public QWidget {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QBasicTimer timer_;
|
QBasicTimer timer_;
|
||||||
int timeout_;
|
|
||||||
FHT *fht_;
|
FHT *fht_;
|
||||||
EngineBase *engine_;
|
EngineBase *engine_;
|
||||||
Scope lastscope_;
|
Scope lastscope_;
|
||||||
|
|
||||||
bool new_frame_;
|
bool new_frame_;
|
||||||
bool is_playing_;
|
bool is_playing_;
|
||||||
|
int timeout_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void interpolate(const Scope&, Scope&);
|
void interpolate(const Scope&, Scope&);
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ void AnalyzerContainer::ChangeAnalyzer(const int id) {
|
|||||||
current_analyzer_->set_engine(engine_);
|
current_analyzer_->set_engine(engine_);
|
||||||
// Even if it is not supposed to happen, I don't want to get a dbz error
|
// Even if it is not supposed to happen, I don't want to get a dbz error
|
||||||
current_framerate_ = current_framerate_ == 0 ? kMediumFramerate : current_framerate_;
|
current_framerate_ = current_framerate_ == 0 ? kMediumFramerate : current_framerate_;
|
||||||
current_analyzer_->changeTimeout(1000 / current_framerate_);
|
current_analyzer_->ChangeTimeout(1000 / current_framerate_);
|
||||||
|
|
||||||
layout()->addWidget(current_analyzer_);
|
layout()->addWidget(current_analyzer_);
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ void AnalyzerContainer::ChangeFramerate(int new_framerate) {
|
|||||||
if (current_analyzer_) {
|
if (current_analyzer_) {
|
||||||
// Even if it is not supposed to happen, I don't want to get a dbz error
|
// Even if it is not supposed to happen, I don't want to get a dbz error
|
||||||
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
|
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
|
||||||
current_analyzer_->changeTimeout(1000 / new_framerate);
|
current_analyzer_->ChangeTimeout(1000 / new_framerate);
|
||||||
|
|
||||||
// notify the current analyzer that the framerate has changed
|
// notify the current analyzer that the framerate has changed
|
||||||
current_analyzer_->framerateChanged();
|
current_analyzer_->framerateChanged();
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class AnalyzerContainer : public QWidget {
|
|||||||
void Load();
|
void Load();
|
||||||
void Save();
|
void Save();
|
||||||
void SaveFramerate(const int framerate);
|
void SaveFramerate(const int framerate);
|
||||||
template <typename T>
|
template<typename T>
|
||||||
void AddAnalyzerType();
|
void AddAnalyzerType();
|
||||||
void AddFramerate(const QString &name, const int framerate);
|
void AddFramerate(const QString &name, const int framerate);
|
||||||
|
|
||||||
@@ -96,10 +96,9 @@ class AnalyzerContainer : public QWidget {
|
|||||||
|
|
||||||
Analyzer::Base *current_analyzer_;
|
Analyzer::Base *current_analyzer_;
|
||||||
EngineBase *engine_;
|
EngineBase *engine_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
void AnalyzerContainer::AddAnalyzerType() {
|
void AnalyzerContainer::AddAnalyzerType() {
|
||||||
|
|
||||||
int id = analyzer_types_.count();
|
int id = analyzer_types_.count();
|
||||||
|
|||||||
@@ -63,8 +63,7 @@ BlockAnalyzer::BlockAnalyzer(QWidget *parent)
|
|||||||
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
|
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
|
||||||
|
|
||||||
// mxcl says null pixmaps cause crashes, so let's play it safe
|
// mxcl says null pixmaps cause crashes, so let's play it safe
|
||||||
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
|
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(1, 1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
||||||
@@ -89,7 +88,7 @@ void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
|||||||
if (rows_ != oldRows) {
|
if (rows_ != oldRows) {
|
||||||
barpixmap_ = QPixmap(kWidth, rows_ * (kHeight + 1));
|
barpixmap_ = QPixmap(kWidth, rows_ * (kHeight + 1));
|
||||||
|
|
||||||
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(kWidth, rows_ * (kHeight + 1)));
|
std::fill(fade_bars_.begin(), fade_bars_.end(), QPixmap(kWidth, rows_ * (kHeight + 1)));
|
||||||
|
|
||||||
yscale_.resize(rows_ + 1);
|
yscale_.resize(rows_ + 1);
|
||||||
|
|
||||||
@@ -130,7 +129,7 @@ void BlockAnalyzer::transform(Analyzer::Scope &s) {
|
|||||||
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
|
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
|
||||||
|
|
||||||
fht_->spectrum(s.data());
|
fht_->spectrum(s.data());
|
||||||
fht_->scale(s.data(), 1.0 / 20);
|
fht_->scale(s.data(), 1.0F / 20);
|
||||||
|
|
||||||
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good!
|
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good!
|
||||||
s.resize(scope_.size() <= kMaxColumns / 2 ? kMaxColumns / 2 : scope_.size());
|
s.resize(scope_.size() <= kMaxColumns / 2 ? kMaxColumns / 2 : scope_.size());
|
||||||
|
|||||||
@@ -65,14 +65,14 @@ class BlockAnalyzer : public Analyzer::Base {
|
|||||||
private:
|
private:
|
||||||
QPixmap *bar() { return &barpixmap_; }
|
QPixmap *bar() { return &barpixmap_; }
|
||||||
|
|
||||||
int columns_, rows_; // number of rows and columns of blocks
|
int columns_, rows_; // number of rows and columns of blocks
|
||||||
int y_; // y-offset from top of widget
|
int y_; // y-offset from top of widget
|
||||||
QPixmap barpixmap_;
|
QPixmap barpixmap_;
|
||||||
QPixmap topbarpixmap_;
|
QPixmap topbarpixmap_;
|
||||||
QPixmap background_;
|
QPixmap background_;
|
||||||
QPixmap canvas_;
|
QPixmap canvas_;
|
||||||
Analyzer::Scope scope_; // so we don't create a vector every frame
|
Analyzer::Scope scope_; // so we don't create a vector every frame
|
||||||
QVector<double> store_; // current bar heights
|
QVector<double> store_; // current bar heights
|
||||||
QVector<double> yscale_;
|
QVector<double> yscale_;
|
||||||
|
|
||||||
QVector<QPixmap> fade_bars_;
|
QVector<QPixmap> fade_bars_;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ void BoomAnalyzer::resizeEvent(QResizeEvent *e) {
|
|||||||
void BoomAnalyzer::transform(Scope &s) {
|
void BoomAnalyzer::transform(Scope &s) {
|
||||||
|
|
||||||
fht_->spectrum(s.data());
|
fht_->spectrum(s.data());
|
||||||
fht_->scale(s.data(), 1.0 / 50);
|
fht_->scale(s.data(), 1.0F / 50);
|
||||||
|
|
||||||
s.resize(scope_.size() <= static_cast<quint64>(kMaxBandCount) / 2 ? kMaxBandCount / 2 : scope_.size());
|
s.resize(scope_.size() <= static_cast<quint64>(kMaxBandCount) / 2 ? kMaxBandCount / 2 : scope_.size());
|
||||||
|
|
||||||
|
|||||||
@@ -43,12 +43,12 @@
|
|||||||
|
|
||||||
using Analyzer::Scope;
|
using Analyzer::Scope;
|
||||||
|
|
||||||
const int Rainbow::RainbowAnalyzer::kHeight[] = {21, 33};
|
const int Rainbow::RainbowAnalyzer::kHeight[] = { 21, 33 };
|
||||||
const int Rainbow::RainbowAnalyzer::kWidth[] = {34, 53};
|
const int Rainbow::RainbowAnalyzer::kWidth[] = { 34, 53 };
|
||||||
const int Rainbow::RainbowAnalyzer::kFrameCount[] = {6, 16};
|
const int Rainbow::RainbowAnalyzer::kFrameCount[] = { 6, 16 };
|
||||||
const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = {21, 16};
|
const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = { 21, 16 };
|
||||||
const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = {13, 15};
|
const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = { 13, 15 };
|
||||||
const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = {24, 33};
|
const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = { 24, 33 };
|
||||||
|
|
||||||
const char *Rainbow::NyanCatAnalyzer::kName = "Nyanalyzer Cat";
|
const char *Rainbow::NyanCatAnalyzer::kName = "Nyanalyzer Cat";
|
||||||
const char *Rainbow::RainbowDashAnalyzer::kName = "Rainbow Dash";
|
const char *Rainbow::RainbowDashAnalyzer::kName = "Rainbow Dash";
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class RainbowAnalyzer : public Analyzer::Base {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// "constants" that get initialized in the constructor
|
// "constants" that get initialized in the constructor
|
||||||
float band_scale_[kRainbowBands]{};
|
float band_scale_[kRainbowBands] {};
|
||||||
QPen colors_[kRainbowBands];
|
QPen colors_[kRainbowBands];
|
||||||
|
|
||||||
// Rainbow Nyancat & Dash
|
// Rainbow Nyancat & Dash
|
||||||
@@ -104,7 +104,7 @@ class RainbowAnalyzer : public Analyzer::Base {
|
|||||||
int frame_;
|
int frame_;
|
||||||
|
|
||||||
// The y positions of each point on the rainbow.
|
// The y positions of each point on the rainbow.
|
||||||
float history_[kHistorySize * kRainbowBands]{};
|
float history_[kHistorySize * kRainbowBands] {};
|
||||||
|
|
||||||
// A cache of the last frame's rainbow,
|
// A cache of the last frame's rainbow,
|
||||||
// so it can be used in the next frame.
|
// so it can be used in the next frame.
|
||||||
@@ -142,6 +142,6 @@ class RainbowDashAnalyzer : public RainbowAnalyzer {
|
|||||||
|
|
||||||
static const char *kName;
|
static const char *kName;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Rainbow
|
||||||
|
|
||||||
#endif // RAINBOWANALYZER_H
|
#endif // RAINBOWANALYZER_H
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ SCollection::SCollection(Application *app, QObject *parent)
|
|||||||
watcher_(nullptr),
|
watcher_(nullptr),
|
||||||
watcher_thread_(nullptr),
|
watcher_thread_(nullptr),
|
||||||
original_thread_(nullptr),
|
original_thread_(nullptr),
|
||||||
|
io_priority_(Utilities::IoPriority::IOPRIO_CLASS_IDLE),
|
||||||
|
thread_priority_(QThread::Priority::IdlePriority),
|
||||||
save_playcounts_to_files_(false),
|
save_playcounts_to_files_(false),
|
||||||
save_ratings_to_files_(false) {
|
save_ratings_to_files_(false) {
|
||||||
|
|
||||||
@@ -94,11 +96,18 @@ void SCollection::Init() {
|
|||||||
|
|
||||||
watcher_ = new CollectionWatcher(Song::Source_Collection);
|
watcher_ = new CollectionWatcher(Song::Source_Collection);
|
||||||
watcher_thread_ = new Thread(this);
|
watcher_thread_ = new Thread(this);
|
||||||
watcher_thread_->SetIoPriority(Utilities::IOPRIO_CLASS_IDLE);
|
|
||||||
|
#ifndef Q_OS_WIN32
|
||||||
|
if (io_priority_ != Utilities::IoPriority::IOPRIO_CLASS_NONE) {
|
||||||
|
watcher_thread_->SetIoPriority(io_priority_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
watcher_->moveToThread(watcher_thread_);
|
watcher_->moveToThread(watcher_thread_);
|
||||||
watcher_thread_->start(QThread::IdlePriority);
|
|
||||||
qLog(Debug) << watcher_ << "moved to thread" << watcher_thread_;
|
qLog(Debug) << watcher_ << "moved to thread" << watcher_thread_ << "with I/O priority" << io_priority_ << "and thread priority" << thread_priority_;
|
||||||
|
|
||||||
|
watcher_thread_->start(thread_priority_);
|
||||||
|
|
||||||
watcher_->set_backend(backend_);
|
watcher_->set_backend(backend_);
|
||||||
watcher_->set_task_manager(app_->task_manager());
|
watcher_->set_task_manager(app_->task_manager());
|
||||||
@@ -176,6 +185,8 @@ void SCollection::ReloadSettings() {
|
|||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(CollectionSettingsPage::kSettingsGroup);
|
s.beginGroup(CollectionSettingsPage::kSettingsGroup);
|
||||||
|
io_priority_ = static_cast<Utilities::IoPriority>(s.value("io_priority", Utilities::IOPRIO_CLASS_IDLE).toInt());
|
||||||
|
thread_priority_ = static_cast<QThread::Priority>(s.value("thread_priority", QThread::Priority::IdlePriority).toInt());
|
||||||
save_playcounts_to_files_ = s.value("save_playcounts", false).toBool();
|
save_playcounts_to_files_ = s.value("save_playcounts", false).toBool();
|
||||||
save_ratings_to_files_ = s.value("save_ratings", false).toBool();
|
save_ratings_to_files_ = s.value("save_ratings", false).toBool();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|||||||
@@ -28,10 +28,10 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "core/utilities.h"
|
||||||
class QThread;
|
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
class Thread;
|
class Thread;
|
||||||
@@ -99,6 +99,8 @@ class SCollection : public QObject {
|
|||||||
|
|
||||||
QList<QObject*> wait_for_exit_;
|
QList<QObject*> wait_for_exit_;
|
||||||
|
|
||||||
|
Utilities::IoPriority io_priority_;
|
||||||
|
QThread::Priority thread_priority_;
|
||||||
bool save_playcounts_to_files_;
|
bool save_playcounts_to_files_;
|
||||||
bool save_ratings_to_files_;
|
bool save_ratings_to_files_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,10 +47,10 @@
|
|||||||
#include "core/database.h"
|
#include "core/database.h"
|
||||||
#include "core/scopedtransaction.h"
|
#include "core/scopedtransaction.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "core/sqlrow.h"
|
||||||
#include "smartplaylists/smartplaylistsearch.h"
|
#include "smartplaylists/smartplaylistsearch.h"
|
||||||
|
|
||||||
#include "directory.h"
|
#include "directory.h"
|
||||||
#include "sqlrow.h"
|
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
#include "collectiontask.h"
|
#include "collectiontask.h"
|
||||||
@@ -335,8 +335,8 @@ void CollectionBackend::AddDirectory(const QString &path) {
|
|||||||
q.prepare(QString("INSERT INTO %1 (path, subdirs) VALUES (:path, 1)").arg(dirs_table_));
|
q.prepare(QString("INSERT INTO %1 (path, subdirs) VALUES (:path, 1)").arg(dirs_table_));
|
||||||
q.BindValue(":path", db_path);
|
q.BindValue(":path", db_path);
|
||||||
if (!q.Exec()) {
|
if (!q.Exec()) {
|
||||||
db_->ReportErrors(q);
|
db_->ReportErrors(q);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory dir;
|
Directory dir;
|
||||||
@@ -634,15 +634,13 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
|
|||||||
added_songs << new_song;
|
added_songs << new_song;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new song
|
// Create new song
|
||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
{ // Insert the row and create a new ID
|
{ // Insert the row and create a new ID
|
||||||
SqlQuery q(db);
|
SqlQuery q(db);
|
||||||
q.prepare(QString("INSERT INTO %1 (" + Song::kColumnSpec + ") VALUES (" + Song::kBindSpec + ")").arg(songs_table_));
|
q.prepare(QString("INSERT INTO %1 (" + Song::kColumnSpec + ") VALUES (" + Song::kBindSpec + ")").arg(songs_table_));
|
||||||
song.BindToQuery(&q);
|
song.BindToQuery(&q);
|
||||||
@@ -656,7 +654,7 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
|
|||||||
|
|
||||||
if (id == -1) return;
|
if (id == -1) return;
|
||||||
|
|
||||||
{ // Add to the FTS index
|
{ // Add to the FTS index
|
||||||
SqlQuery q(db);
|
SqlQuery q(db);
|
||||||
q.prepare(QString("INSERT INTO %1 (ROWID, " + Song::kFtsColumnSpec + ") VALUES (:id, " + Song::kFtsBindSpec + ")").arg(fts_table_));
|
q.prepare(QString("INSERT INTO %1 (ROWID, " + Song::kFtsColumnSpec + ") VALUES (:id, " + Song::kFtsBindSpec + ")").arg(fts_table_));
|
||||||
q.BindValue(":id", id);
|
q.BindValue(":id", id);
|
||||||
@@ -1345,7 +1343,7 @@ void CollectionBackend::CompilationsNeedUpdating() {
|
|||||||
if (album.isEmpty()) continue;
|
if (album.isEmpty()) continue;
|
||||||
|
|
||||||
// Find the directory the song is in
|
// Find the directory the song is in
|
||||||
QString directory = url.toString(QUrl::PreferLocalFile|QUrl::RemoveFilename);
|
QString directory = url.toString(QUrl::PreferLocalFile | QUrl::RemoveFilename);
|
||||||
|
|
||||||
CompilationInfo &info = compilation_info[directory + album];
|
CompilationInfo &info = compilation_info[directory + album];
|
||||||
info.urls << url;
|
info.urls << url;
|
||||||
@@ -1801,6 +1799,12 @@ void CollectionBackend::ResetStatistics(const int id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionBackend::DeleteAllAsync() {
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(this, "DeleteAll", Qt::QueuedConnection);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionBackend::DeleteAll() {
|
void CollectionBackend::DeleteAll() {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void IncrementSkipCountAsync(const int id, const float progress);
|
void IncrementSkipCountAsync(const int id, const float progress);
|
||||||
void ResetStatisticsAsync(const int id);
|
void ResetStatisticsAsync(const int id);
|
||||||
|
|
||||||
void DeleteAll();
|
void DeleteAllAsync();
|
||||||
|
|
||||||
Song GetSongBySongId(const QString &song_id);
|
Song GetSongBySongId(const QString &song_id);
|
||||||
SongList GetSongsBySongId(const QStringList &song_ids);
|
SongList GetSongsBySongId(const QStringList &song_ids);
|
||||||
@@ -234,6 +234,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void IncrementPlayCount(const int id);
|
void IncrementPlayCount(const int id);
|
||||||
void IncrementSkipCount(const int id, const float progress);
|
void IncrementSkipCount(const int id, const float progress);
|
||||||
void ResetStatistics(const int id);
|
void ResetStatistics(const int id);
|
||||||
|
void DeleteAll();
|
||||||
void SongPathChanged(const Song &song, const QFileInfo &new_file, const std::optional<int> new_collection_directory_id);
|
void SongPathChanged(const Song &song, const QFileInfo &new_file, const std::optional<int> new_collection_directory_id);
|
||||||
|
|
||||||
SongList GetSongsBy(const QString &artist, const QString &album, const QString &title);
|
SongList GetSongsBy(const QString &artist, const QString &album, const QString &title);
|
||||||
|
|||||||
@@ -68,24 +68,23 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
|||||||
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegularExpression("\\bfts"), "");
|
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegularExpression("\\bfts"), "");
|
||||||
|
|
||||||
ui_->search_field->setToolTip(
|
ui_->search_field->setToolTip(
|
||||||
QString("<html><head/><body><p>") +
|
QString("<html><head/><body><p>") +
|
||||||
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
|
tr("Prefix a word with a field name to limit the search to that field, e.g.:") +
|
||||||
QString(" ") +
|
QString(" ") +
|
||||||
QString("<span style=\"font-weight:600;\">") +
|
QString("<span style=\"font-weight:600;\">") +
|
||||||
tr("artist") +
|
tr("artist") +
|
||||||
QString(":") +
|
QString(":") +
|
||||||
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
|
QString("</span><span style=\"font-style:italic;\">Strawbs</span>") +
|
||||||
QString(" ") +
|
QString(" ") +
|
||||||
tr("searches the collection for all artists that contain the word") +
|
tr("searches the collection for all artists that contain the word") +
|
||||||
QString(" Strawbs.") +
|
QString(" Strawbs.") +
|
||||||
QString("</p><p><span style=\"font-weight:600;\">") +
|
QString("</p><p><span style=\"font-weight:600;\">") +
|
||||||
tr("Available fields") +
|
tr("Available fields") +
|
||||||
QString(": ") +
|
QString(": ") +
|
||||||
"</span><span style=\"font-style:italic;\">" +
|
"</span><span style=\"font-style:italic;\">" +
|
||||||
available_fields +
|
available_fields +
|
||||||
QString("</span>.") +
|
QString("</span>.") +
|
||||||
QString("</p></body></html>")
|
QString("</p></body></html>"));
|
||||||
);
|
|
||||||
|
|
||||||
QObject::connect(ui_->search_field, &QSearchField::returnPressed, this, &CollectionFilterWidget::ReturnPressed);
|
QObject::connect(ui_->search_field, &QSearchField::returnPressed, this, &CollectionFilterWidget::ReturnPressed);
|
||||||
QObject::connect(filter_delay_, &QTimer::timeout, this, &CollectionFilterWidget::FilterDelayTimeout);
|
QObject::connect(filter_delay_, &QTimer::timeout, this, &CollectionFilterWidget::FilterDelayTimeout);
|
||||||
@@ -136,6 +135,7 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
|||||||
ui_->options->setMenu(collection_menu_);
|
ui_->options->setMenu(collection_menu_);
|
||||||
|
|
||||||
QObject::connect(ui_->search_field, &QSearchField::textChanged, this, &CollectionFilterWidget::FilterTextChanged);
|
QObject::connect(ui_->search_field, &QSearchField::textChanged, this, &CollectionFilterWidget::FilterTextChanged);
|
||||||
|
QObject::connect(ui_->options, &QToolButton::clicked, ui_->options, &QToolButton::showMenu);
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
@@ -176,16 +176,15 @@ void CollectionFilterWidget::Init(CollectionModel *model) {
|
|||||||
if (s.contains(group_by_version())) version = s.value(group_by_version(), 0).toInt();
|
if (s.contains(group_by_version())) version = s.value(group_by_version(), 0).toInt();
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
model_->SetGroupBy(CollectionModel::Grouping(
|
model_->SetGroupBy(CollectionModel::Grouping(
|
||||||
CollectionModel::GroupBy(s.value(group_by(1), static_cast<int>(CollectionModel::GroupBy_AlbumArtist)).toInt()),
|
CollectionModel::GroupBy(s.value(group_by(1), static_cast<int>(CollectionModel::GroupBy_AlbumArtist)).toInt()),
|
||||||
CollectionModel::GroupBy(s.value(group_by(2), static_cast<int>(CollectionModel::GroupBy_AlbumDisc)).toInt()),
|
CollectionModel::GroupBy(s.value(group_by(2), static_cast<int>(CollectionModel::GroupBy_AlbumDisc)).toInt()),
|
||||||
CollectionModel::GroupBy(s.value(group_by(3), static_cast<int>(CollectionModel::GroupBy_None)).toInt())));
|
CollectionModel::GroupBy(s.value(group_by(3), static_cast<int>(CollectionModel::GroupBy_None)).toInt())));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None));
|
model_->SetGroupBy(CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_AlbumDisc, CollectionModel::GroupBy_None));
|
||||||
}
|
}
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionFilterWidget::ReloadSettings() {
|
void CollectionFilterWidget::ReloadSettings() {
|
||||||
|
|||||||
@@ -38,10 +38,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="options">
|
<widget class="QToolButton" name="options">
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">padding-right: 16px;
|
|
||||||
</string>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
<property name="iconSize">
|
||||||
<size>
|
<size>
|
||||||
<width>16</width>
|
<width>16</width>
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ void CollectionItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
|||||||
// Draw the line under the item
|
// Draw the line under the item
|
||||||
QColor line_color = opt.palette.color(QPalette::Text);
|
QColor line_color = opt.palette.color(QPalette::Text);
|
||||||
QLinearGradient grad_color(opt.rect.bottomLeft(), opt.rect.bottomRight());
|
QLinearGradient grad_color(opt.rect.bottomLeft(), opt.rect.bottomRight());
|
||||||
const double fade_start_end = (opt.rect.width()/3.0)/opt.rect.width();
|
const double fade_start_end = (opt.rect.width() / 3.0) / opt.rect.width();
|
||||||
line_color.setAlphaF(0.0);
|
line_color.setAlphaF(0.0);
|
||||||
grad_color.setColorAt(0, line_color);
|
grad_color.setColorAt(0, line_color);
|
||||||
line_color.setAlphaF(0.5);
|
line_color.setAlphaF(0.5);
|
||||||
|
|||||||
@@ -59,12 +59,12 @@
|
|||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
|
#include "core/sqlrow.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
#include "collectionbackend.h"
|
#include "collectionbackend.h"
|
||||||
#include "collectiondirectorymodel.h"
|
#include "collectiondirectorymodel.h"
|
||||||
#include "collectionitem.h"
|
#include "collectionitem.h"
|
||||||
#include "collectionmodel.h"
|
#include "collectionmodel.h"
|
||||||
#include "sqlrow.h"
|
|
||||||
#include "playlist/playlistmanager.h"
|
#include "playlist/playlistmanager.h"
|
||||||
#include "playlist/songmimedata.h"
|
#include "playlist/songmimedata.h"
|
||||||
#include "covermanager/albumcoverloader.h"
|
#include "covermanager/albumcoverloader.h"
|
||||||
@@ -325,26 +325,32 @@ QString CollectionModel::ContainerKey(const GroupBy type, const Song &song) {
|
|||||||
case GroupBy_Album:
|
case GroupBy_Album:
|
||||||
key = TextOrUnknown(song.album());
|
key = TextOrUnknown(song.album());
|
||||||
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
||||||
|
if (!song.grouping().isEmpty()) key.append("-" + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_AlbumDisc:
|
case GroupBy_AlbumDisc:
|
||||||
key = PrettyAlbumDisc(song.album(), song.disc());
|
key = PrettyAlbumDisc(song.album(), song.disc());
|
||||||
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
||||||
|
if (!song.grouping().isEmpty()) key.append("-" + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_YearAlbum:
|
case GroupBy_YearAlbum:
|
||||||
key = PrettyYearAlbum(song.year(), song.album());
|
key = PrettyYearAlbum(song.year(), song.album());
|
||||||
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
||||||
|
if (!song.grouping().isEmpty()) key.append("-" + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_YearAlbumDisc:
|
case GroupBy_YearAlbumDisc:
|
||||||
key = PrettyYearAlbumDisc(song.year(), song.album(), song.disc());
|
key = PrettyYearAlbumDisc(song.year(), song.album(), song.disc());
|
||||||
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
||||||
|
if (!song.grouping().isEmpty()) key.append("-" + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_OriginalYearAlbum:
|
case GroupBy_OriginalYearAlbum:
|
||||||
key = PrettyYearAlbum(song.effective_originalyear(), song.album());
|
key = PrettyYearAlbum(song.effective_originalyear(), song.album());
|
||||||
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
||||||
|
if (!song.grouping().isEmpty()) key.append("-" + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_OriginalYearAlbumDisc:
|
case GroupBy_OriginalYearAlbumDisc:
|
||||||
key = PrettyYearAlbumDisc(song.effective_originalyear(), song.album(), song.disc());
|
key = PrettyYearAlbumDisc(song.effective_originalyear(), song.album(), song.disc());
|
||||||
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
if (!song.album_id().isEmpty()) key.append("-" + song.album_id());
|
||||||
|
if (!song.grouping().isEmpty()) key.append("-" + song.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_Disc:
|
case GroupBy_Disc:
|
||||||
key = PrettyDisc(song.disc());
|
key = PrettyDisc(song.disc());
|
||||||
@@ -476,7 +482,7 @@ QString CollectionModel::DividerDisplayText(const GroupBy type, const QString &k
|
|||||||
case GroupBy_Genre:
|
case GroupBy_Genre:
|
||||||
case GroupBy_FileType:
|
case GroupBy_FileType:
|
||||||
case GroupBy_Format:
|
case GroupBy_Format:
|
||||||
if (key == "0") return "0-9";
|
if (key == "0") return "0-9";
|
||||||
return key.toUpper();
|
return key.toUpper();
|
||||||
|
|
||||||
case GroupBy_YearAlbum:
|
case GroupBy_YearAlbum:
|
||||||
@@ -1008,22 +1014,22 @@ void CollectionModel::InitQuery(const GroupBy type, CollectionQuery *q) {
|
|||||||
q->SetColumnSpec("DISTINCT artist");
|
q->SetColumnSpec("DISTINCT artist");
|
||||||
break;
|
break;
|
||||||
case GroupBy_Album:
|
case GroupBy_Album:
|
||||||
q->SetColumnSpec("DISTINCT album, album_id");
|
q->SetColumnSpec("DISTINCT album, album_id, grouping");
|
||||||
break;
|
break;
|
||||||
case GroupBy_AlbumDisc:
|
case GroupBy_AlbumDisc:
|
||||||
q->SetColumnSpec("DISTINCT album, album_id, disc");
|
q->SetColumnSpec("DISTINCT album, album_id, disc, grouping");
|
||||||
break;
|
break;
|
||||||
case GroupBy_YearAlbum:
|
case GroupBy_YearAlbum:
|
||||||
q->SetColumnSpec("DISTINCT year, album, album_id, grouping");
|
q->SetColumnSpec("DISTINCT year, album, album_id, grouping");
|
||||||
break;
|
break;
|
||||||
case GroupBy_YearAlbumDisc:
|
case GroupBy_YearAlbumDisc:
|
||||||
q->SetColumnSpec("DISTINCT year, album, album_id, disc");
|
q->SetColumnSpec("DISTINCT year, album, album_id, disc, grouping");
|
||||||
break;
|
break;
|
||||||
case GroupBy_OriginalYearAlbum:
|
case GroupBy_OriginalYearAlbum:
|
||||||
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, grouping");
|
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, grouping");
|
||||||
break;
|
break;
|
||||||
case GroupBy_OriginalYearAlbumDisc:
|
case GroupBy_OriginalYearAlbumDisc:
|
||||||
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, disc");
|
q->SetColumnSpec("DISTINCT year, originalyear, album, album_id, disc, grouping");
|
||||||
break;
|
break;
|
||||||
case GroupBy_Disc:
|
case GroupBy_Disc:
|
||||||
q->SetColumnSpec("DISTINCT disc");
|
q->SetColumnSpec("DISTINCT disc");
|
||||||
@@ -1097,11 +1103,13 @@ void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, Coll
|
|||||||
case GroupBy_Album:
|
case GroupBy_Album:
|
||||||
q->AddWhere("album", item->metadata.album());
|
q->AddWhere("album", item->metadata.album());
|
||||||
q->AddWhere("album_id", item->metadata.album_id());
|
q->AddWhere("album_id", item->metadata.album_id());
|
||||||
|
q->AddWhere("grouping", item->metadata.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_AlbumDisc:
|
case GroupBy_AlbumDisc:
|
||||||
q->AddWhere("album", item->metadata.album());
|
q->AddWhere("album", item->metadata.album());
|
||||||
q->AddWhere("album_id", item->metadata.album_id());
|
q->AddWhere("album_id", item->metadata.album_id());
|
||||||
q->AddWhere("disc", item->metadata.disc());
|
q->AddWhere("disc", item->metadata.disc());
|
||||||
|
q->AddWhere("grouping", item->metadata.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_YearAlbum:
|
case GroupBy_YearAlbum:
|
||||||
q->AddWhere("year", item->metadata.year());
|
q->AddWhere("year", item->metadata.year());
|
||||||
@@ -1114,6 +1122,7 @@ void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, Coll
|
|||||||
q->AddWhere("album", item->metadata.album());
|
q->AddWhere("album", item->metadata.album());
|
||||||
q->AddWhere("album_id", item->metadata.album_id());
|
q->AddWhere("album_id", item->metadata.album_id());
|
||||||
q->AddWhere("disc", item->metadata.disc());
|
q->AddWhere("disc", item->metadata.disc());
|
||||||
|
q->AddWhere("grouping", item->metadata.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_OriginalYearAlbum:
|
case GroupBy_OriginalYearAlbum:
|
||||||
q->AddWhere("year", item->metadata.year());
|
q->AddWhere("year", item->metadata.year());
|
||||||
@@ -1128,6 +1137,7 @@ void CollectionModel::FilterQuery(const GroupBy type, CollectionItem *item, Coll
|
|||||||
q->AddWhere("album", item->metadata.album());
|
q->AddWhere("album", item->metadata.album());
|
||||||
q->AddWhere("album_id", item->metadata.album_id());
|
q->AddWhere("album_id", item->metadata.album_id());
|
||||||
q->AddWhere("disc", item->metadata.disc());
|
q->AddWhere("disc", item->metadata.disc());
|
||||||
|
q->AddWhere("grouping", item->metadata.grouping());
|
||||||
break;
|
break;
|
||||||
case GroupBy_Disc:
|
case GroupBy_Disc:
|
||||||
q->AddWhere("disc", item->metadata.disc());
|
q->AddWhere("disc", item->metadata.disc());
|
||||||
@@ -1216,6 +1226,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
|
|||||||
case GroupBy_Album:{
|
case GroupBy_Album:{
|
||||||
item->metadata.set_album(row.value(0).toString());
|
item->metadata.set_album(row.value(0).toString());
|
||||||
item->metadata.set_album_id(row.value(1).toString());
|
item->metadata.set_album_id(row.value(1).toString());
|
||||||
|
item->metadata.set_grouping(row.value(2).toString());
|
||||||
item->key.append(ContainerKey(type, item->metadata));
|
item->key.append(ContainerKey(type, item->metadata));
|
||||||
item->display_text = TextOrUnknown(item->metadata.album());
|
item->display_text = TextOrUnknown(item->metadata.album());
|
||||||
item->sort_text = SortTextForArtist(item->metadata.album());
|
item->sort_text = SortTextForArtist(item->metadata.album());
|
||||||
@@ -1225,6 +1236,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
|
|||||||
item->metadata.set_album(row.value(0).toString());
|
item->metadata.set_album(row.value(0).toString());
|
||||||
item->metadata.set_album_id(row.value(1).toString());
|
item->metadata.set_album_id(row.value(1).toString());
|
||||||
item->metadata.set_disc(row.value(2).toInt());
|
item->metadata.set_disc(row.value(2).toInt());
|
||||||
|
item->metadata.set_grouping(row.value(3).toString());
|
||||||
item->key.append(ContainerKey(type, item->metadata));
|
item->key.append(ContainerKey(type, item->metadata));
|
||||||
item->display_text = PrettyAlbumDisc(item->metadata.album(), item->metadata.disc());
|
item->display_text = PrettyAlbumDisc(item->metadata.album(), item->metadata.disc());
|
||||||
item->sort_text = item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
|
item->sort_text = item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
|
||||||
@@ -1245,6 +1257,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
|
|||||||
item->metadata.set_album(row.value(1).toString());
|
item->metadata.set_album(row.value(1).toString());
|
||||||
item->metadata.set_album_id(row.value(2).toString());
|
item->metadata.set_album_id(row.value(2).toString());
|
||||||
item->metadata.set_disc(row.value(3).toInt());
|
item->metadata.set_disc(row.value(3).toInt());
|
||||||
|
item->metadata.set_grouping(row.value(4).toString());
|
||||||
item->key.append(ContainerKey(type, item->metadata));
|
item->key.append(ContainerKey(type, item->metadata));
|
||||||
item->display_text = PrettyYearAlbumDisc(item->metadata.year(), item->metadata.album(), item->metadata.disc());
|
item->display_text = PrettyYearAlbumDisc(item->metadata.year(), item->metadata.album(), item->metadata.disc());
|
||||||
item->sort_text = SortTextForNumber(qMax(0, item->metadata.year())) + item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
|
item->sort_text = SortTextForNumber(qMax(0, item->metadata.year())) + item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
|
||||||
@@ -1267,6 +1280,7 @@ CollectionItem *CollectionModel::ItemFromQuery(const GroupBy type, const bool si
|
|||||||
item->metadata.set_album(row.value(2).toString());
|
item->metadata.set_album(row.value(2).toString());
|
||||||
item->metadata.set_album_id(row.value(3).toString());
|
item->metadata.set_album_id(row.value(3).toString());
|
||||||
item->metadata.set_disc(row.value(4).toInt());
|
item->metadata.set_disc(row.value(4).toInt());
|
||||||
|
item->metadata.set_grouping(row.value(5).toString());
|
||||||
item->key.append(ContainerKey(type, item->metadata));
|
item->key.append(ContainerKey(type, item->metadata));
|
||||||
item->display_text = PrettyYearAlbumDisc(item->metadata.effective_originalyear(), item->metadata.album(), item->metadata.disc());
|
item->display_text = PrettyYearAlbumDisc(item->metadata.effective_originalyear(), item->metadata.album(), item->metadata.disc());
|
||||||
item->sort_text = SortTextForNumber(qMax(0, item->metadata.effective_originalyear())) + item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
|
item->sort_text = SortTextForNumber(qMax(0, item->metadata.effective_originalyear())) + item->metadata.album() + SortTextForNumber(qMax(0, item->metadata.disc()));
|
||||||
@@ -1411,6 +1425,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
|
|||||||
case GroupBy_Album:{
|
case GroupBy_Album:{
|
||||||
item->metadata.set_album(s.album());
|
item->metadata.set_album(s.album());
|
||||||
item->metadata.set_album_id(s.album_id());
|
item->metadata.set_album_id(s.album_id());
|
||||||
|
item->metadata.set_grouping(s.grouping());
|
||||||
item->key.append(ContainerKey(type, s));
|
item->key.append(ContainerKey(type, s));
|
||||||
item->display_text = TextOrUnknown(s.album());
|
item->display_text = TextOrUnknown(s.album());
|
||||||
item->sort_text = SortTextForArtist(s.album());
|
item->sort_text = SortTextForArtist(s.album());
|
||||||
@@ -1420,6 +1435,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
|
|||||||
item->metadata.set_album(s.album());
|
item->metadata.set_album(s.album());
|
||||||
item->metadata.set_album_id(s.album_id());
|
item->metadata.set_album_id(s.album_id());
|
||||||
item->metadata.set_disc(s.disc());
|
item->metadata.set_disc(s.disc());
|
||||||
|
item->metadata.set_grouping(s.grouping());
|
||||||
item->key.append(ContainerKey(type, s));
|
item->key.append(ContainerKey(type, s));
|
||||||
item->display_text = PrettyAlbumDisc(s.album(), s.disc());
|
item->display_text = PrettyAlbumDisc(s.album(), s.disc());
|
||||||
item->sort_text = s.album() + SortTextForNumber(qMax(0, s.disc()));
|
item->sort_text = s.album() + SortTextForNumber(qMax(0, s.disc()));
|
||||||
@@ -1440,6 +1456,7 @@ CollectionItem *CollectionModel::ItemFromSong(const GroupBy type, const bool sig
|
|||||||
item->metadata.set_album(s.album());
|
item->metadata.set_album(s.album());
|
||||||
item->metadata.set_album_id(s.album_id());
|
item->metadata.set_album_id(s.album_id());
|
||||||
item->metadata.set_disc(s.disc());
|
item->metadata.set_disc(s.disc());
|
||||||
|
item->metadata.set_grouping(s.grouping());
|
||||||
item->key.append(ContainerKey(type, s));
|
item->key.append(ContainerKey(type, s));
|
||||||
item->display_text = PrettyYearAlbumDisc(s.year(), s.album(), s.disc());
|
item->display_text = PrettyYearAlbumDisc(s.year(), s.album(), s.disc());
|
||||||
item->sort_text = SortTextForNumber(qMax(0, s.year())) + s.album() + SortTextForNumber(qMax(0, s.disc()));
|
item->sort_text = SortTextForNumber(qMax(0, s.year())) + s.album() + SortTextForNumber(qMax(0, s.disc()));
|
||||||
|
|||||||
@@ -45,10 +45,10 @@
|
|||||||
|
|
||||||
#include "core/simpletreemodel.h"
|
#include "core/simpletreemodel.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "core/sqlrow.h"
|
||||||
#include "covermanager/albumcoverloader.h"
|
#include "covermanager/albumcoverloader.h"
|
||||||
#include "collectionquery.h"
|
#include "collectionquery.h"
|
||||||
#include "collectionitem.h"
|
#include "collectionitem.h"
|
||||||
#include "sqlrow.h"
|
|
||||||
#include "covermanager/albumcoverloaderoptions.h"
|
#include "covermanager/albumcoverloaderoptions.h"
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
|
|||||||
@@ -155,11 +155,11 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
|
|||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
value.metaType().id() == QMetaType::QString
|
value.metaType().id() == QMetaType::QString
|
||||||
#else
|
#else
|
||||||
value.type() == QVariant::String
|
value.type() == QVariant::String
|
||||||
#endif
|
#endif
|
||||||
&& value.toString().isNull()) {
|
&& value.toString().isNull()) {
|
||||||
where_clauses_ << QString("%1 %2 ?").arg(column, op);
|
where_clauses_ << QString("%1 %2 ?").arg(column, op);
|
||||||
bound_values_ << QString("");
|
bound_values_ << QString("");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,4 +125,4 @@ class CollectionQuery : public QSqlQuery {
|
|||||||
int limit_;
|
int limit_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COLLECTIONQUERY_H
|
#endif // COLLECTIONQUERY_H
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
action_delete_files_->setVisible(regular_elements == regular_editable && delete_files_);
|
action_delete_files_->setVisible(delete_files_);
|
||||||
#else
|
#else
|
||||||
action_delete_files_->setVisible(false);
|
action_delete_files_->setVisible(false);
|
||||||
#endif
|
#endif
|
||||||
@@ -440,7 +440,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
action_delete_files_->setEnabled(regular_elements == regular_editable && delete_files_);
|
action_delete_files_->setEnabled(delete_files_);
|
||||||
#else
|
#else
|
||||||
action_delete_files_->setEnabled(false);
|
action_delete_files_->setEnabled(false);
|
||||||
#endif
|
#endif
|
||||||
@@ -671,10 +671,17 @@ void CollectionView::Delete() {
|
|||||||
if (!delete_files_) return;
|
if (!delete_files_) return;
|
||||||
|
|
||||||
SongList selected_songs = GetSelectedSongs();
|
SongList selected_songs = GetSelectedSongs();
|
||||||
|
|
||||||
|
SongList songs;
|
||||||
QStringList files;
|
QStringList files;
|
||||||
|
songs.reserve(selected_songs.count());
|
||||||
files.reserve(selected_songs.count());
|
files.reserve(selected_songs.count());
|
||||||
for (const Song &song : selected_songs) {
|
for (const Song &song : selected_songs) {
|
||||||
files << song.url().toString();
|
QString filename = song.url().toLocalFile();
|
||||||
|
if (!files.contains(filename)) {
|
||||||
|
songs << song;
|
||||||
|
files << filename;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (DeleteConfirmationDialog::warning(files) != QDialogButtonBox::Yes) return;
|
if (DeleteConfirmationDialog::warning(files) != QDialogButtonBox::Yes) return;
|
||||||
|
|
||||||
@@ -683,7 +690,7 @@ void CollectionView::Delete() {
|
|||||||
|
|
||||||
DeleteFiles *delete_files = new DeleteFiles(app_->task_manager(), storage, true);
|
DeleteFiles *delete_files = new DeleteFiles(app_->task_manager(), storage, true);
|
||||||
QObject::connect(delete_files, &DeleteFiles::Finished, this, &CollectionView::DeleteFilesFinished);
|
QObject::connect(delete_files, &DeleteFiles::Finished, this, &CollectionView::DeleteFilesFinished);
|
||||||
delete_files->Start(selected_songs);
|
delete_files->Start(songs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,11 +68,6 @@
|
|||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
namespace {
|
|
||||||
static const char *kNoMediaFile = ".nomedia";
|
|
||||||
static const char *kNoMusicFile = ".nomusic";
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
QStringList CollectionWatcher::sValidImages = QStringList() << "jpg" << "png" << "gif" << "jpeg";
|
QStringList CollectionWatcher::sValidImages = QStringList() << "jpg" << "png" << "gif" << "jpeg";
|
||||||
|
|
||||||
CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
||||||
@@ -84,9 +79,10 @@ CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
|
|||||||
original_thread_(nullptr),
|
original_thread_(nullptr),
|
||||||
scan_on_startup_(true),
|
scan_on_startup_(true),
|
||||||
monitor_(true),
|
monitor_(true),
|
||||||
song_tracking_(true),
|
song_tracking_(false),
|
||||||
mark_songs_unavailable_(true),
|
mark_songs_unavailable_(source_ == Song::Source_Collection),
|
||||||
expire_unavailable_songs_days_(60),
|
expire_unavailable_songs_days_(60),
|
||||||
|
overwrite_playcount_(false),
|
||||||
overwrite_rating_(false),
|
overwrite_rating_(false),
|
||||||
stop_requested_(false),
|
stop_requested_(false),
|
||||||
abort_requested_(false),
|
abort_requested_(false),
|
||||||
@@ -149,9 +145,16 @@ void CollectionWatcher::ReloadSettings() {
|
|||||||
scan_on_startup_ = s.value("startup_scan", true).toBool();
|
scan_on_startup_ = s.value("startup_scan", true).toBool();
|
||||||
monitor_ = s.value("monitor", true).toBool();
|
monitor_ = s.value("monitor", true).toBool();
|
||||||
QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList();
|
QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList();
|
||||||
song_tracking_ = s.value("song_tracking", false).toBool();
|
if (source_ == Song::Source_Collection) {
|
||||||
mark_songs_unavailable_ = song_tracking_ ? true : s.value("mark_songs_unavailable", true).toBool();
|
song_tracking_ = s.value("song_tracking", false).toBool();
|
||||||
|
mark_songs_unavailable_ = song_tracking_ ? true : s.value("mark_songs_unavailable", true).toBool();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
song_tracking_ = false;
|
||||||
|
mark_songs_unavailable_ = false;
|
||||||
|
}
|
||||||
expire_unavailable_songs_days_ = s.value("expire_unavailable_songs", 60).toInt();
|
expire_unavailable_songs_days_ = s.value("expire_unavailable_songs", 60).toInt();
|
||||||
|
overwrite_playcount_ = s.value("overwrite_playcount", false).toBool();
|
||||||
overwrite_rating_ = s.value("overwrite_rating", false).toBool();
|
overwrite_rating_ = s.value("overwrite_rating", false).toBool();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
@@ -238,7 +241,7 @@ void CollectionWatcher::ScanTransaction::AddToProgressMax(const quint64 n) {
|
|||||||
void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
|
void CollectionWatcher::ScanTransaction::CommitNewOrUpdatedSongs() {
|
||||||
|
|
||||||
if (!deleted_songs.isEmpty()) {
|
if (!deleted_songs.isEmpty()) {
|
||||||
if (mark_songs_unavailable_) {
|
if (mark_songs_unavailable_ && watcher_->source() == Song::Source_Collection) {
|
||||||
emit watcher_->SongsUnavailable(deleted_songs);
|
emit watcher_->SongsUnavailable(deleted_songs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -413,7 +416,6 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
|
|||||||
void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory &subdir, const quint64 files_count, ScanTransaction *t, const bool force_noincremental) {
|
void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory &subdir, const quint64 files_count, ScanTransaction *t, const bool force_noincremental) {
|
||||||
|
|
||||||
QFileInfo path_info(path);
|
QFileInfo path_info(path);
|
||||||
QDir path_dir(path);
|
|
||||||
|
|
||||||
// Do not scan symlinked dirs that are already in collection
|
// Do not scan symlinked dirs that are already in collection
|
||||||
if (path_info.isSymLink()) {
|
if (path_info.isSymLink()) {
|
||||||
@@ -425,11 +427,6 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not scan directories containing a .nomedia or .nomusic file
|
|
||||||
if (path_dir.exists(kNoMediaFile) || path_dir.exists(kNoMusicFile)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool songs_missing_fingerprint = false;
|
bool songs_missing_fingerprint = false;
|
||||||
#ifdef HAVE_SONGFINGERPRINTING
|
#ifdef HAVE_SONGFINGERPRINTING
|
||||||
if (song_tracking_) {
|
if (song_tracking_) {
|
||||||
@@ -479,7 +476,10 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
|||||||
else {
|
else {
|
||||||
QString ext_part(ExtensionPart(child));
|
QString ext_part(ExtensionPart(child));
|
||||||
QString dir_part(DirectoryPart(child));
|
QString dir_part(DirectoryPart(child));
|
||||||
if (sValidImages.contains(ext_part)) {
|
if (child_info.suffix() == "tmp" || child_info.baseName() == "qt_temp") {
|
||||||
|
t->AddToProgress(1);
|
||||||
|
}
|
||||||
|
else if (sValidImages.contains(ext_part)) {
|
||||||
album_art[dir_part] << child;
|
album_art[dir_part] << child;
|
||||||
t->AddToProgress(1);
|
t->AddToProgress(1);
|
||||||
}
|
}
|
||||||
@@ -736,7 +736,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file,
|
|||||||
const Song matching_cue_song = sections_map[new_cue_song.beginning_nanosec()];
|
const Song matching_cue_song = sections_map[new_cue_song.beginning_nanosec()];
|
||||||
new_cue_song.set_id(matching_cue_song.id());
|
new_cue_song.set_id(matching_cue_song.id());
|
||||||
if (!new_cue_song.has_embedded_cover()) new_cue_song.set_art_automatic(image);
|
if (!new_cue_song.has_embedded_cover()) new_cue_song.set_art_automatic(image);
|
||||||
new_cue_song.MergeUserSetData(matching_cue_song, true);
|
new_cue_song.MergeUserSetData(matching_cue_song, true, true);
|
||||||
AddChangedSong(file, matching_cue_song, new_cue_song, t);
|
AddChangedSong(file, matching_cue_song, new_cue_song, t);
|
||||||
used_ids.insert(matching_cue_song.id());
|
used_ids.insert(matching_cue_song.id());
|
||||||
}
|
}
|
||||||
@@ -779,7 +779,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file,
|
|||||||
song_on_disk.set_id(matching_song.id());
|
song_on_disk.set_id(matching_song.id());
|
||||||
song_on_disk.set_fingerprint(fingerprint);
|
song_on_disk.set_fingerprint(fingerprint);
|
||||||
if (!song_on_disk.has_embedded_cover()) song_on_disk.set_art_automatic(image);
|
if (!song_on_disk.has_embedded_cover()) song_on_disk.set_art_automatic(image);
|
||||||
song_on_disk.MergeUserSetData(matching_song, !overwrite_rating_);
|
song_on_disk.MergeUserSetData(matching_song, !overwrite_playcount_, !overwrite_rating_);
|
||||||
AddChangedSong(file, matching_song, song_on_disk, t);
|
AddChangedSong(file, matching_song, song_on_disk, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1217,9 +1217,6 @@ quint64 CollectionWatcher::FilesCountForPath(ScanTransaction *t, const QString &
|
|||||||
QFileInfo path_info(child);
|
QFileInfo path_info(child);
|
||||||
|
|
||||||
if (path_info.isDir()) {
|
if (path_info.isDir()) {
|
||||||
if (path_info.exists(kNoMediaFile) || path_info.exists(kNoMusicFile)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (path_info.isSymLink()) {
|
if (path_info.isSymLink()) {
|
||||||
QString real_path = path_info.symLinkTarget();
|
QString real_path = path_info.symLinkTarget();
|
||||||
for (const Directory &dir : std::as_const(watched_dirs_)) {
|
for (const Directory &dir : std::as_const(watched_dirs_)) {
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ class CollectionWatcher : public QObject {
|
|||||||
public:
|
public:
|
||||||
explicit CollectionWatcher(Song::Source source, QObject *parent = nullptr);
|
explicit CollectionWatcher(Song::Source source, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
Song::Source source() { return source_; }
|
||||||
|
|
||||||
void set_backend(CollectionBackend *backend) { backend_ = backend; }
|
void set_backend(CollectionBackend *backend) { backend_ = backend; }
|
||||||
void set_task_manager(TaskManager *task_manager) { task_manager_ = task_manager; }
|
void set_task_manager(TaskManager *task_manager) { task_manager_ = task_manager; }
|
||||||
void set_device_name(const QString &device_name) { device_name_ = device_name; }
|
void set_device_name(const QString &device_name) { device_name_ = device_name; }
|
||||||
@@ -216,6 +218,7 @@ class CollectionWatcher : public QObject {
|
|||||||
bool song_tracking_;
|
bool song_tracking_;
|
||||||
bool mark_songs_unavailable_;
|
bool mark_songs_unavailable_;
|
||||||
int expire_unavailable_songs_days_;
|
int expire_unavailable_songs_days_;
|
||||||
|
bool overwrite_playcount_;
|
||||||
bool overwrite_rating_;
|
bool overwrite_rating_;
|
||||||
|
|
||||||
bool stop_requested_;
|
bool stop_requested_;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#cmakedefine HAVE_BACKTRACE
|
#cmakedefine HAVE_BACKTRACE
|
||||||
#cmakedefine HAVE_GIO
|
#cmakedefine HAVE_GIO
|
||||||
|
#cmakedefine HAVE_GIO_UNIX
|
||||||
#cmakedefine HAVE_DBUS
|
#cmakedefine HAVE_DBUS
|
||||||
#cmakedefine HAVE_X11
|
#cmakedefine HAVE_X11
|
||||||
#cmakedefine HAVE_UDISKS2
|
#cmakedefine HAVE_UDISKS2
|
||||||
@@ -15,7 +16,6 @@
|
|||||||
#cmakedefine HAVE_LIBGPOD
|
#cmakedefine HAVE_LIBGPOD
|
||||||
#cmakedefine HAVE_LIBMTP
|
#cmakedefine HAVE_LIBMTP
|
||||||
#cmakedefine HAVE_LIBPULSE
|
#cmakedefine HAVE_LIBPULSE
|
||||||
#cmakedefine HAVE_SPARKLE
|
|
||||||
#cmakedefine HAVE_QTSPARKLE
|
#cmakedefine HAVE_QTSPARKLE
|
||||||
#cmakedefine HAVE_SONGFINGERPRINTING
|
#cmakedefine HAVE_SONGFINGERPRINTING
|
||||||
#cmakedefine HAVE_MUSICBRAINZ
|
#cmakedefine HAVE_MUSICBRAINZ
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2020-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2020-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
#include "contextview.h"
|
#include "contextview.h"
|
||||||
#include "contextalbum.h"
|
#include "contextalbum.h"
|
||||||
|
|
||||||
const int ContextAlbum::kWidgetSpacing = 40;
|
const int ContextAlbum::kFadeTimeLineMs = 1000;
|
||||||
|
|
||||||
ContextAlbum::ContextAlbum(QWidget *parent)
|
ContextAlbum::ContextAlbum(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -51,23 +51,26 @@ ContextAlbum::ContextAlbum(QWidget *parent)
|
|||||||
context_view_(nullptr),
|
context_view_(nullptr),
|
||||||
album_cover_choice_controller_(nullptr),
|
album_cover_choice_controller_(nullptr),
|
||||||
downloading_covers_(false),
|
downloading_covers_(false),
|
||||||
timeline_fade_(new QTimeLine(1000, this)),
|
timeline_fade_(new QTimeLine(kFadeTimeLineMs, this)),
|
||||||
image_strawberry_(":/pictures/strawberry.png"),
|
image_strawberry_(":/pictures/strawberry.png"),
|
||||||
image_original_(image_strawberry_),
|
image_original_(image_strawberry_),
|
||||||
pixmap_previous_opacity_(0),
|
pixmap_current_opacity_(1.0) {
|
||||||
prev_width_(width()) {
|
|
||||||
|
|
||||||
setObjectName("context-widget-album");
|
setObjectName("context-widget-album");
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
cover_loader_options_.desired_height_ = 600;
|
cover_loader_options_.desired_height_ = width();
|
||||||
cover_loader_options_.pad_output_image_ = true;
|
cover_loader_options_.pad_output_image_ = true;
|
||||||
cover_loader_options_.scale_output_image_ = true;
|
cover_loader_options_.scale_output_image_ = true;
|
||||||
QImage image = ImageUtils::ScaleAndPad(image_strawberry_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
QImage image = ImageUtils::ScaleAndPad(image_strawberry_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
||||||
if (!image.isNull()) pixmap_current_ = QPixmap::fromImage(image);
|
if (!image.isNull()) {
|
||||||
|
pixmap_current_ = QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
QObject::connect(timeline_fade_, &QTimeLine::valueChanged, this, &ContextAlbum::FadePreviousTrack);
|
timeline_fade_->setDirection(QTimeLine::Forward);
|
||||||
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
|
QObject::connect(timeline_fade_, &QTimeLine::valueChanged, this, &ContextAlbum::FadeCurrentCover);
|
||||||
|
QObject::connect(timeline_fade_, &QTimeLine::finished, this, &ContextAlbum::FadeCurrentCoverFinished);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +89,21 @@ void ContextAlbum::Init(ContextView *context_view, AlbumCoverChoiceController *a
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::contextMenuEvent(QContextMenuEvent *e) {
|
QSize ContextAlbum::sizeHint() const {
|
||||||
if (menu_ && image_original_ != image_strawberry_) menu_->popup(mapToGlobal(e->pos()));
|
|
||||||
|
return QSize(pixmap_current_.width(), pixmap_current_.height());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::paintEvent(QPaintEvent*) {
|
||||||
|
|
||||||
|
QPainter p(this);
|
||||||
|
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
DrawPreviousCovers(&p);
|
||||||
|
DrawImage(&p, pixmap_current_, pixmap_current_opacity_);
|
||||||
|
DrawSpinner(&p);
|
||||||
|
p.end();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
|
void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||||
@@ -99,93 +115,146 @@ void ContextAlbum::mouseDoubleClickEvent(QMouseEvent *e) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::paintEvent(QPaintEvent*) {
|
void ContextAlbum::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
|
|
||||||
QPainter p(this);
|
if (menu_ && image_original_ != image_strawberry_) {
|
||||||
|
menu_->popup(mapToGlobal(e->pos()));
|
||||||
DrawImage(&p);
|
}
|
||||||
|
else {
|
||||||
// Draw the previous track's image if we're fading
|
QWidget::contextMenuEvent(e);
|
||||||
if (!pixmap_previous_.isNull()) {
|
|
||||||
p.setOpacity(pixmap_previous_opacity_);
|
|
||||||
p.drawPixmap(0, 0, pixmap_previous_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::DrawImage(QPainter *p) {
|
void ContextAlbum::UpdateWidth(const int new_width) {
|
||||||
|
|
||||||
p->setRenderHint(QPainter::SmoothPixmapTransform);
|
if (new_width != cover_loader_options_.desired_height_) {
|
||||||
|
cover_loader_options_.desired_height_ = new_width;
|
||||||
if (width() != prev_width_) {
|
ScaleCover();
|
||||||
cover_loader_options_.desired_height_ = width() - kWidgetSpacing;
|
ScalePreviousCovers();
|
||||||
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
updateGeometry();
|
||||||
if (image.isNull()) pixmap_current_ = QPixmap();
|
|
||||||
else pixmap_current_ = QPixmap::fromImage(image);
|
|
||||||
prev_width_ = width();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p->drawPixmap(0, 0, width() - kWidgetSpacing, width() - kWidgetSpacing, pixmap_current_);
|
|
||||||
if (downloading_covers_ && spinner_animation_) {
|
|
||||||
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbum::FadePreviousTrack(const qreal value) {
|
|
||||||
|
|
||||||
pixmap_previous_opacity_ = value;
|
|
||||||
if (qFuzzyCompare(pixmap_previous_opacity_, qreal(0.0))) {
|
|
||||||
image_previous_ = QImage();
|
|
||||||
pixmap_previous_ = QPixmap();
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
|
|
||||||
if (value == 0 && image_original_ == image_strawberry_) {
|
|
||||||
emit FadeStopFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbum::ScaleCover() {
|
|
||||||
|
|
||||||
cover_loader_options_.desired_height_ = width() - kWidgetSpacing;
|
|
||||||
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
|
||||||
if (image.isNull()) pixmap_current_ = QPixmap();
|
|
||||||
else pixmap_current_ = QPixmap::fromImage(image);
|
|
||||||
prev_width_ = width();
|
|
||||||
update();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbum::SetImage(QImage image) {
|
void ContextAlbum::SetImage(QImage image) {
|
||||||
|
|
||||||
if (image.isNull()) image = image_strawberry_;
|
if (image.isNull()) {
|
||||||
|
image = image_strawberry_;
|
||||||
|
}
|
||||||
|
|
||||||
if (downloading_covers_) {
|
if (downloading_covers_) {
|
||||||
downloading_covers_ = false;
|
downloading_covers_ = false;
|
||||||
spinner_animation_.reset();
|
spinner_animation_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the current pixmap so we can fade between them
|
QImage image_previous = image_original_;
|
||||||
pixmap_previous_ = QPixmap(width() - kWidgetSpacing, width() - kWidgetSpacing);
|
QPixmap pixmap_previous = pixmap_current_;
|
||||||
pixmap_previous_.fill(palette().window().color());
|
qreal opacity_previous = pixmap_current_opacity_;
|
||||||
pixmap_previous_opacity_ = 1.0;
|
|
||||||
|
|
||||||
QPainter p(&pixmap_previous_);
|
|
||||||
DrawImage(&p);
|
|
||||||
p.end();
|
|
||||||
|
|
||||||
image_previous_ = image_original_;
|
|
||||||
image_original_ = image;
|
image_original_ = image;
|
||||||
|
pixmap_current_opacity_ = 0.0;
|
||||||
ScaleCover();
|
ScaleCover();
|
||||||
|
|
||||||
// Were we waiting for this cover to load before we started fading?
|
if (!pixmap_previous.isNull()) {
|
||||||
if (!pixmap_previous_.isNull() && timeline_fade_) {
|
std::shared_ptr<PreviousCover> previous_cover = std::make_shared<PreviousCover>();
|
||||||
|
previous_cover->image = image_previous;
|
||||||
|
previous_cover->pixmap = pixmap_previous;
|
||||||
|
previous_cover->opacity = opacity_previous;
|
||||||
|
previous_cover->timeline.reset(new QTimeLine(kFadeTimeLineMs), [](QTimeLine *timeline) { timeline->deleteLater(); });
|
||||||
|
previous_cover->timeline->setDirection(QTimeLine::Backward);
|
||||||
|
previous_cover->timeline->setCurrentTime(timeline_fade_->state() == QTimeLine::Running ? timeline_fade_->currentTime() : kFadeTimeLineMs);
|
||||||
|
QObject::connect(previous_cover->timeline.get(), &QTimeLine::valueChanged, this, [this, previous_cover]() { FadePreviousCover(previous_cover); });
|
||||||
|
QObject::connect(previous_cover->timeline.get(), &QTimeLine::finished, this, [this, previous_cover]() { FadePreviousCoverFinished(previous_cover); });
|
||||||
|
previous_covers_ << previous_cover;
|
||||||
|
previous_cover->timeline->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeline_fade_->state() == QTimeLine::Running) {
|
||||||
timeline_fade_->stop();
|
timeline_fade_->stop();
|
||||||
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
|
}
|
||||||
timeline_fade_->start();
|
timeline_fade_->start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::DrawImage(QPainter *p, const QPixmap &pixmap, const qreal opacity) {
|
||||||
|
|
||||||
|
if (qFuzzyCompare(opacity, qreal(0.0))) return;
|
||||||
|
|
||||||
|
p->setOpacity(opacity);
|
||||||
|
p->drawPixmap(0, 0, pixmap.width(), pixmap.height(), pixmap);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::DrawSpinner(QPainter *p) {
|
||||||
|
|
||||||
|
if (downloading_covers_) {
|
||||||
|
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::DrawPreviousCovers(QPainter *p) {
|
||||||
|
|
||||||
|
for (std::shared_ptr<PreviousCover> previous_cover : previous_covers_) {
|
||||||
|
DrawImage(p, previous_cover->pixmap, previous_cover->opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadeCurrentCover(const qreal value) {
|
||||||
|
|
||||||
|
if (value <= pixmap_current_opacity_) return;
|
||||||
|
|
||||||
|
pixmap_current_opacity_ = value;
|
||||||
|
update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadeCurrentCoverFinished() {
|
||||||
|
|
||||||
|
if (image_original_ == image_strawberry_) {
|
||||||
|
emit FadeStopFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadePreviousCover(std::shared_ptr<PreviousCover> previous_cover) {
|
||||||
|
|
||||||
|
if (previous_cover->timeline->currentValue() >= previous_cover->opacity) return;
|
||||||
|
|
||||||
|
previous_cover->opacity = previous_cover->timeline->currentValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::FadePreviousCoverFinished(std::shared_ptr<PreviousCover> previous_cover) {
|
||||||
|
|
||||||
|
previous_covers_.removeAll(previous_cover);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::ScaleCover() {
|
||||||
|
|
||||||
|
QImage image = ImageUtils::ScaleAndPad(image_original_, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
||||||
|
if (image.isNull()) {
|
||||||
|
pixmap_current_ = QPixmap();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pixmap_current_ = QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextAlbum::ScalePreviousCovers() {
|
||||||
|
|
||||||
|
for (std::shared_ptr<PreviousCover> previous_cover : previous_covers_) {
|
||||||
|
QImage image = ImageUtils::ScaleAndPad(previous_cover->image, cover_loader_options_.scale_output_image_, cover_loader_options_.pad_output_image_, cover_loader_options_.desired_height_);
|
||||||
|
if (image.isNull()) {
|
||||||
|
previous_cover->pixmap = QPixmap();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
previous_cover->pixmap = QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2020-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2020-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
@@ -50,15 +51,31 @@ class ContextAlbum : public QWidget {
|
|||||||
|
|
||||||
void Init(ContextView *context_view, AlbumCoverChoiceController *album_cover_choice_controller);
|
void Init(ContextView *context_view, AlbumCoverChoiceController *album_cover_choice_controller);
|
||||||
void SetImage(QImage image = QImage());
|
void SetImage(QImage image = QImage());
|
||||||
|
void UpdateWidth(const int width);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
QSize sizeHint() const override;
|
||||||
void paintEvent(QPaintEvent*) override;
|
void paintEvent(QPaintEvent*) override;
|
||||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
|
||||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||||
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DrawImage(QPainter *p);
|
|
||||||
|
struct PreviousCover {
|
||||||
|
PreviousCover() : opacity(0.0) {}
|
||||||
|
QImage image;
|
||||||
|
QPixmap pixmap;
|
||||||
|
qreal opacity;
|
||||||
|
std::shared_ptr<QTimeLine> timeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<std::shared_ptr<PreviousCover>> previous_covers_;
|
||||||
|
|
||||||
|
void DrawImage(QPainter *p, const QPixmap &pixmap, const qreal opacity);
|
||||||
|
void DrawSpinner(QPainter *p);
|
||||||
|
void DrawPreviousCovers(QPainter *p);
|
||||||
void ScaleCover();
|
void ScaleCover();
|
||||||
|
void ScalePreviousCovers();
|
||||||
void GetCoverAutomatically();
|
void GetCoverAutomatically();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -67,13 +84,16 @@ class ContextAlbum : public QWidget {
|
|||||||
private slots:
|
private slots:
|
||||||
void Update() { update(); }
|
void Update() { update(); }
|
||||||
void AutomaticCoverSearchDone();
|
void AutomaticCoverSearchDone();
|
||||||
void FadePreviousTrack(const qreal value);
|
void FadeCurrentCover(const qreal value);
|
||||||
|
void FadeCurrentCoverFinished();
|
||||||
|
void FadePreviousCover(std::shared_ptr<PreviousCover> previouscover);
|
||||||
|
void FadePreviousCoverFinished(std::shared_ptr<PreviousCover> previouscover);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SearchCoverInProgress();
|
void SearchCoverInProgress();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kWidgetSpacing;
|
static const int kFadeTimeLineMs;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMenu *menu_;
|
QMenu *menu_;
|
||||||
@@ -84,12 +104,9 @@ class ContextAlbum : public QWidget {
|
|||||||
QTimeLine *timeline_fade_;
|
QTimeLine *timeline_fade_;
|
||||||
QImage image_strawberry_;
|
QImage image_strawberry_;
|
||||||
QImage image_original_;
|
QImage image_original_;
|
||||||
QImage image_previous_;
|
|
||||||
QPixmap pixmap_current_;
|
QPixmap pixmap_current_;
|
||||||
QPixmap pixmap_previous_;
|
qreal pixmap_current_opacity_;
|
||||||
qreal pixmap_previous_opacity_;
|
|
||||||
std::unique_ptr<QMovie> spinner_animation_;
|
std::unique_ptr<QMovie> spinner_animation_;
|
||||||
int prev_width_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTEXTALBUM_H
|
#endif // CONTEXTALBUM_H
|
||||||
|
|||||||
@@ -1,390 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QList>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QPixmapCache>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/database.h"
|
|
||||||
#include "core/iconloader.h"
|
|
||||||
#include "collection/collectionquery.h"
|
|
||||||
#include "collection/collectionbackend.h"
|
|
||||||
#include "collection/collectionmodel.h"
|
|
||||||
#include "collection/collectionitem.h"
|
|
||||||
#include "playlist/playlistmanager.h"
|
|
||||||
#include "playlist/songmimedata.h"
|
|
||||||
#include "covermanager/albumcoverloader.h"
|
|
||||||
#include "covermanager/albumcoverloaderoptions.h"
|
|
||||||
#include "covermanager/albumcoverloaderresult.h"
|
|
||||||
|
|
||||||
#include "contextalbumsmodel.h"
|
|
||||||
|
|
||||||
const int ContextAlbumsModel::kPrettyCoverSize = 32;
|
|
||||||
|
|
||||||
ContextAlbumsModel::ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent)
|
|
||||||
: SimpleTreeModel<CollectionItem>(new CollectionItem(this), parent),
|
|
||||||
backend_(backend),
|
|
||||||
app_(app),
|
|
||||||
album_icon_(IconLoader::Load("cdcase")) {
|
|
||||||
|
|
||||||
root_->lazy_loaded = true;
|
|
||||||
|
|
||||||
cover_loader_options_.get_image_data_ = false;
|
|
||||||
cover_loader_options_.scale_output_image_ = true;
|
|
||||||
cover_loader_options_.pad_output_image_ = true;
|
|
||||||
cover_loader_options_.desired_height_ = kPrettyCoverSize;
|
|
||||||
|
|
||||||
QObject::connect(app_->album_cover_loader(), &AlbumCoverLoader::AlbumCoverLoaded, this, &ContextAlbumsModel::AlbumCoverLoaded);
|
|
||||||
|
|
||||||
QIcon nocover = IconLoader::Load("cdcase");
|
|
||||||
QList<QSize> nocover_sizes = nocover.availableSizes();
|
|
||||||
no_cover_icon_ = nocover.pixmap(nocover_sizes.last()).scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextAlbumsModel::~ContextAlbumsModel() { delete root_; }
|
|
||||||
|
|
||||||
void ContextAlbumsModel::AddSongs(const SongList &songs) {
|
|
||||||
|
|
||||||
for (const Song &song : songs) {
|
|
||||||
if (song_nodes_.contains(song.id())) continue;
|
|
||||||
QString key = CollectionModel::ContainerKey(CollectionModel::GroupBy_Album, song);
|
|
||||||
CollectionItem *container = nullptr;
|
|
||||||
if (container_nodes_.contains(key)) {
|
|
||||||
container = container_nodes_[key];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
container = ItemFromSong(CollectionItem::Type_Container, true, root_, song, 0);
|
|
||||||
container_nodes_.insert(key, container);
|
|
||||||
}
|
|
||||||
song_nodes_[song.id()] = ItemFromSong(CollectionItem::Type_Song, true, container, song, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ContextAlbumsModel::AlbumIconPixmapCacheKey(const QModelIndex &idx) {
|
|
||||||
|
|
||||||
QStringList path;
|
|
||||||
QModelIndex index_copy(idx);
|
|
||||||
while (index_copy.isValid()) {
|
|
||||||
path.prepend(index_copy.data().toString());
|
|
||||||
index_copy = index_copy.parent();
|
|
||||||
}
|
|
||||||
return "contextalbumsart:" + path.join("/");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ContextAlbumsModel::AlbumIcon(const QModelIndex &idx) {
|
|
||||||
|
|
||||||
CollectionItem *item = IndexToItem(idx);
|
|
||||||
if (!item) return no_cover_icon_;
|
|
||||||
|
|
||||||
// Check the cache for a pixmap we already loaded.
|
|
||||||
const QString cache_key = AlbumIconPixmapCacheKey(idx);
|
|
||||||
|
|
||||||
QPixmap cached_pixmap;
|
|
||||||
if (QPixmapCache::find(cache_key, &cached_pixmap)) {
|
|
||||||
return cached_pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maybe we're loading a pixmap already?
|
|
||||||
if (pending_cache_keys_.contains(cache_key)) {
|
|
||||||
return no_cover_icon_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No art is cached and we're not loading it already. Load art for the first song in the album.
|
|
||||||
SongList songs = GetChildSongs(idx);
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
const quint64 id = app_->album_cover_loader()->LoadImageAsync(cover_loader_options_, songs.first());
|
|
||||||
pending_art_.insert(id, ItemAndCacheKey(item, cache_key));
|
|
||||||
pending_cache_keys_.insert(cache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return no_cover_icon_;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) {
|
|
||||||
|
|
||||||
if (!pending_art_.contains(id)) return;
|
|
||||||
|
|
||||||
ItemAndCacheKey item_and_cache_key = pending_art_.take(id);
|
|
||||||
|
|
||||||
CollectionItem *item = item_and_cache_key.first;
|
|
||||||
if (!item) return;
|
|
||||||
|
|
||||||
const QString &cache_key = item_and_cache_key.second;
|
|
||||||
if (pending_cache_keys_.contains(cache_key)) {
|
|
||||||
pending_cache_keys_.remove(cache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert this image in the cache.
|
|
||||||
if (!result.success || result.image_scaled.isNull() || result.type == AlbumCoverLoaderResult::Type_ManuallyUnset) {
|
|
||||||
// Set the no_cover image so we don't continually try to load art.
|
|
||||||
QPixmapCache::insert(cache_key, no_cover_icon_);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QPixmap image_pixmap;
|
|
||||||
image_pixmap = QPixmap::fromImage(result.image_scaled);
|
|
||||||
QPixmapCache::insert(cache_key, image_pixmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QModelIndex idx = ItemToIndex(item);
|
|
||||||
|
|
||||||
emit dataChanged(idx, idx);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ContextAlbumsModel::data(const QModelIndex &idx, int role) const {
|
|
||||||
|
|
||||||
const CollectionItem *item = IndexToItem(idx);
|
|
||||||
|
|
||||||
if (role == Qt::DecorationRole && item->type == CollectionItem::Type_Container && item->container_level == 0) {
|
|
||||||
return const_cast<ContextAlbumsModel*>(this)->AlbumIcon(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data(item, role);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
case Qt::ToolTipRole:
|
|
||||||
return item->DisplayText();
|
|
||||||
|
|
||||||
case Qt::DecorationRole:
|
|
||||||
switch (item->type) {
|
|
||||||
case CollectionItem::Type_Container:
|
|
||||||
if (item->type == CollectionItem::Type_Container && item->container_level == 0) { return album_icon_; }
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Role_Type:
|
|
||||||
return item->type;
|
|
||||||
|
|
||||||
case Role_ContainerType:
|
|
||||||
return item->type;
|
|
||||||
|
|
||||||
case Role_Key:
|
|
||||||
return item->key;
|
|
||||||
|
|
||||||
case Role_Artist:
|
|
||||||
return item->metadata.artist();
|
|
||||||
|
|
||||||
case Role_Editable:
|
|
||||||
if (item->type == CollectionItem::Type_Container) {
|
|
||||||
// if we have even one non editable item as a child, we ourselves are not available for edit
|
|
||||||
if (!item->children.isEmpty()) {
|
|
||||||
for (CollectionItem *child : item->children) {
|
|
||||||
if (!data(child, role).toBool()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (item->type == CollectionItem::Type_Song) {
|
|
||||||
return item->metadata.IsEditable();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Role_SortText:
|
|
||||||
return item->SortText();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsModel::Reset() {
|
|
||||||
|
|
||||||
for (QMap<QString, CollectionItem*>::const_iterator it = container_nodes_.constBegin(); it != container_nodes_.constEnd(); ++it) {
|
|
||||||
const QString cache_key = AlbumIconPixmapCacheKey(ItemToIndex(it.value()));
|
|
||||||
QPixmapCache::remove(cache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
beginResetModel();
|
|
||||||
delete root_;
|
|
||||||
song_nodes_.clear();
|
|
||||||
container_nodes_.clear();
|
|
||||||
pending_art_.clear();
|
|
||||||
pending_cache_keys_.clear();
|
|
||||||
|
|
||||||
root_ = new CollectionItem(this);
|
|
||||||
root_->lazy_loaded = true;
|
|
||||||
endResetModel();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionItem *ContextAlbumsModel::ItemFromSong(CollectionItem::Type item_type, const bool signal, CollectionItem *parent, const Song &s, const int container_level) {
|
|
||||||
|
|
||||||
if (signal) beginInsertRows(ItemToIndex(parent), static_cast<int>(parent->children.count()), static_cast<int>(parent->children.count()));
|
|
||||||
|
|
||||||
CollectionItem *item = new CollectionItem(item_type, parent);
|
|
||||||
item->container_level = container_level;
|
|
||||||
item->lazy_loaded = true;
|
|
||||||
|
|
||||||
if (item_type == CollectionItem::Type_Container) {
|
|
||||||
item->key = CollectionModel::ContainerKey(CollectionModel::GroupBy_Album, s);
|
|
||||||
item->display_text = CollectionModel::TextOrUnknown(s.album());
|
|
||||||
item->sort_text = CollectionModel::SortTextForArtist(s.album());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item->key = s.album() + " " + s.title();
|
|
||||||
item->display_text = CollectionModel::TextOrUnknown(s.title());
|
|
||||||
item->sort_text = CollectionModel::SortTextForSong(s);
|
|
||||||
item->metadata = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signal) endInsertRows();
|
|
||||||
|
|
||||||
return item;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags ContextAlbumsModel::flags(const QModelIndex &idx) const {
|
|
||||||
|
|
||||||
switch (IndexToItem(idx)->type) {
|
|
||||||
case CollectionItem::Type_Song:
|
|
||||||
case CollectionItem::Type_Container:
|
|
||||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
|
|
||||||
case CollectionItem::Type_Root:
|
|
||||||
case CollectionItem::Type_LoadingIndicator:
|
|
||||||
default:
|
|
||||||
return Qt::ItemIsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ContextAlbumsModel::mimeTypes() const {
|
|
||||||
return QStringList() << "text/uri-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
QMimeData *ContextAlbumsModel::mimeData(const QModelIndexList &indexes) const {
|
|
||||||
|
|
||||||
if (indexes.isEmpty()) return nullptr;
|
|
||||||
|
|
||||||
SongMimeData *data = new SongMimeData;
|
|
||||||
QList<QUrl> urls;
|
|
||||||
QSet<int> song_ids;
|
|
||||||
|
|
||||||
data->backend = backend_;
|
|
||||||
|
|
||||||
for (const QModelIndex &idx : indexes) {
|
|
||||||
GetChildSongs(IndexToItem(idx), &urls, &data->songs, &song_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
data->setUrls(urls);
|
|
||||||
data->name_for_new_playlist_ = PlaylistManager::GetNameForNewPlaylist(data->songs);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContextAlbumsModel::CompareItems(const CollectionItem *a, const CollectionItem *b) const {
|
|
||||||
|
|
||||||
QVariant left(data(a, ContextAlbumsModel::Role_SortText));
|
|
||||||
QVariant right(data(b, ContextAlbumsModel::Role_SortText));
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
if (left.metaType().id() == QMetaType::Int)
|
|
||||||
#else
|
|
||||||
if (left.type() == QVariant::Int)
|
|
||||||
#endif
|
|
||||||
return left.toInt() < right.toInt();
|
|
||||||
else return left.toString() < right.toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const {
|
|
||||||
|
|
||||||
switch (item->type) {
|
|
||||||
case CollectionItem::Type_Container:{
|
|
||||||
|
|
||||||
QList<CollectionItem*> children = item->children;
|
|
||||||
std::sort(children.begin(), children.end(), std::bind(&ContextAlbumsModel::CompareItems, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
|
|
||||||
for (CollectionItem *child : children) {
|
|
||||||
GetChildSongs(child, urls, songs, song_ids);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CollectionItem::Type_Song:
|
|
||||||
urls->append(item->metadata.url());
|
|
||||||
if (!song_ids->contains(item->metadata.id())) {
|
|
||||||
songs->append(item->metadata);
|
|
||||||
song_ids->insert(item->metadata.id());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SongList ContextAlbumsModel::GetChildSongs(const QModelIndexList &indexes) const {
|
|
||||||
|
|
||||||
QList<QUrl> dontcare;
|
|
||||||
SongList ret;
|
|
||||||
QSet<int> song_ids;
|
|
||||||
|
|
||||||
for (const QModelIndex &idx : indexes) {
|
|
||||||
GetChildSongs(IndexToItem(idx), &dontcare, &ret, &song_ids);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SongList ContextAlbumsModel::GetChildSongs(const QModelIndex &idx) const {
|
|
||||||
return GetChildSongs(QModelIndexList() << idx);
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CONTEXTALBUMSMODEL_H
|
|
||||||
#define CONTEXTALBUMSMODEL_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QPair>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QList>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QIcon>
|
|
||||||
|
|
||||||
#include "core/simpletreemodel.h"
|
|
||||||
#include "core/song.h"
|
|
||||||
#include "collection/collectionquery.h"
|
|
||||||
#include "collection/collectionitem.h"
|
|
||||||
#include "covermanager/albumcoverloaderoptions.h"
|
|
||||||
#include "covermanager/albumcoverloaderresult.h"
|
|
||||||
|
|
||||||
class QMimeData;
|
|
||||||
|
|
||||||
class Application;
|
|
||||||
class CollectionBackend;
|
|
||||||
class CollectionItem;
|
|
||||||
|
|
||||||
class ContextAlbumsModel : public SimpleTreeModel<CollectionItem> {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ContextAlbumsModel(CollectionBackend *backend, Application *app, QObject *parent = nullptr);
|
|
||||||
~ContextAlbumsModel() override;
|
|
||||||
|
|
||||||
static const int kPrettyCoverSize;
|
|
||||||
|
|
||||||
enum Role {
|
|
||||||
Role_Type = Qt::UserRole + 1,
|
|
||||||
Role_ContainerType,
|
|
||||||
Role_SortText,
|
|
||||||
Role_Key,
|
|
||||||
Role_Artist,
|
|
||||||
Role_Editable,
|
|
||||||
LastRole
|
|
||||||
};
|
|
||||||
|
|
||||||
void GetChildSongs(CollectionItem *item, QList<QUrl> *urls, SongList *songs, QSet<int> *song_ids) const;
|
|
||||||
SongList GetChildSongs(const QModelIndex &idx) const;
|
|
||||||
SongList GetChildSongs(const QModelIndexList &indexes) const;
|
|
||||||
|
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &idx) const override;
|
|
||||||
QStringList mimeTypes() const override;
|
|
||||||
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
|
||||||
|
|
||||||
void Reset();
|
|
||||||
void AddSongs(const SongList &songs);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CollectionItem *ItemFromSong(CollectionItem::Type item_type, const bool signal, CollectionItem *parent, const Song &s, const int container_level);
|
|
||||||
|
|
||||||
static QString AlbumIconPixmapCacheKey(const QModelIndex &idx);
|
|
||||||
QVariant AlbumIcon(const QModelIndex &idx);
|
|
||||||
QVariant data(const CollectionItem *item, int role) const;
|
|
||||||
bool CompareItems(const CollectionItem *a, const CollectionItem *b) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CollectionBackend *backend_;
|
|
||||||
Application *app_;
|
|
||||||
QueryOptions query_options_;
|
|
||||||
QMap<QString, CollectionItem*> container_nodes_;
|
|
||||||
QMap<int, CollectionItem*> song_nodes_;
|
|
||||||
QIcon album_icon_;
|
|
||||||
QPixmap no_cover_icon_;
|
|
||||||
AlbumCoverLoaderOptions cover_loader_options_;
|
|
||||||
typedef QPair<CollectionItem*, QString> ItemAndCacheKey;
|
|
||||||
QMap<quint64, ItemAndCacheKey> pending_art_;
|
|
||||||
QSet<QString> pending_cache_keys_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTEXTALBUMSMODEL_H
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <qcoreevent.h>
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QTreeView>
|
|
||||||
#include <QItemSelectionModel>
|
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
#include <QAbstractItemView>
|
|
||||||
#include <QStyleOptionViewItem>
|
|
||||||
#include <QAbstractScrollArea>
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QList>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QString>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QLocale>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QAction>
|
|
||||||
#include <QRect>
|
|
||||||
#include <QSize>
|
|
||||||
#include <QToolTip>
|
|
||||||
#include <QWhatsThis>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/iconloader.h"
|
|
||||||
#include "core/mimedata.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "collection/collectiondirectorymodel.h"
|
|
||||||
#include "collection/collectionmodel.h"
|
|
||||||
#include "collection/collectionitem.h"
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
# include "device/devicemanager.h"
|
|
||||||
# include "device/devicestatefiltermodel.h"
|
|
||||||
#endif
|
|
||||||
#include "dialogs/edittagdialog.h"
|
|
||||||
#include "organize/organizedialog.h"
|
|
||||||
|
|
||||||
#include "contextalbumsmodel.h"
|
|
||||||
#include "contextalbumsview.h"
|
|
||||||
|
|
||||||
ContextItemDelegate::ContextItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
|
|
||||||
|
|
||||||
bool ContextItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Q_UNUSED(option);
|
|
||||||
|
|
||||||
if (!event || !view) return false;
|
|
||||||
|
|
||||||
QString text = displayText(idx.data(), QLocale::system());
|
|
||||||
|
|
||||||
if (text.isEmpty() || !event) return false;
|
|
||||||
|
|
||||||
switch (event->type()) {
|
|
||||||
case QEvent::ToolTip: {
|
|
||||||
|
|
||||||
QSize real_text = sizeHint(option, idx);
|
|
||||||
QRect displayed_text = view->visualRect(idx);
|
|
||||||
bool is_elided = displayed_text.width() < real_text.width();
|
|
||||||
|
|
||||||
if (is_elided) {
|
|
||||||
QToolTip::showText(event->globalPos(), text, view);
|
|
||||||
}
|
|
||||||
else if (idx.data(Qt::ToolTipRole).isValid()) {
|
|
||||||
// If the item has a tooltip text, display it
|
|
||||||
QString tooltip_text = idx.data(Qt::ToolTipRole).toString();
|
|
||||||
QToolTip::showText(event->globalPos(), tooltip_text, view);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// in case that another text was previously displayed
|
|
||||||
QToolTip::hideText();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case QEvent::QueryWhatsThis:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case QEvent::WhatsThis:
|
|
||||||
QWhatsThis::showText(event->globalPos(), text, view);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextAlbumsView::ContextAlbumsView(QWidget *parent)
|
|
||||||
: AutoExpandingTreeView(parent),
|
|
||||||
app_(nullptr),
|
|
||||||
context_menu_(nullptr),
|
|
||||||
load_(nullptr),
|
|
||||||
add_to_playlist_(nullptr),
|
|
||||||
add_to_playlist_enqueue_(nullptr),
|
|
||||||
open_in_new_playlist_(nullptr),
|
|
||||||
organize_(nullptr),
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_(nullptr),
|
|
||||||
#endif
|
|
||||||
edit_track_(nullptr),
|
|
||||||
edit_tracks_(nullptr),
|
|
||||||
show_in_browser_(nullptr),
|
|
||||||
is_in_keyboard_search_(false),
|
|
||||||
model_(nullptr) {
|
|
||||||
|
|
||||||
setStyleSheet("border: none;");
|
|
||||||
|
|
||||||
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
|
|
||||||
setItemDelegate(new ContextItemDelegate(this));
|
|
||||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
||||||
setHeaderHidden(true);
|
|
||||||
setAllColumnsShowFocus(true);
|
|
||||||
setDragEnabled(true);
|
|
||||||
setDragDropMode(QAbstractItemView::DragOnly);
|
|
||||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
||||||
SetAddOnDoubleClick(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextAlbumsView::~ContextAlbumsView() = default;
|
|
||||||
|
|
||||||
void ContextAlbumsView::SaveFocus() {
|
|
||||||
|
|
||||||
QModelIndex current = currentIndex();
|
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
|
||||||
if (!type.isValid() || !(type.toInt() == CollectionItem::Type_Song || type.toInt() == CollectionItem::Type_Container || type.toInt() == CollectionItem::Type_Divider)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_selected_path_.clear();
|
|
||||||
last_selected_song_ = Song();
|
|
||||||
last_selected_container_ = QString();
|
|
||||||
|
|
||||||
switch (type.toInt()) {
|
|
||||||
case CollectionItem::Type_Song: {
|
|
||||||
QModelIndex index = current;
|
|
||||||
SongList songs = model_->GetChildSongs(index);
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
last_selected_song_ = songs.last();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CollectionItem::Type_Container:
|
|
||||||
case CollectionItem::Type_Divider: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveContainerPath(current);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::SaveContainerPath(const QModelIndex &child) {
|
|
||||||
|
|
||||||
QModelIndex current = model()->parent(child);
|
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
|
||||||
if (!type.isValid() || !(type.toInt() == CollectionItem::Type_Container || type.toInt() == CollectionItem::Type_Divider)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString text = model()->data(current, ContextAlbumsModel::Role_SortText).toString();
|
|
||||||
last_selected_path_ << text;
|
|
||||||
SaveContainerPath(current);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::RestoreFocus() {
|
|
||||||
|
|
||||||
if (last_selected_container_.isEmpty() && last_selected_song_.url().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RestoreLevelFocus();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContextAlbumsView::RestoreLevelFocus(const QModelIndex &parent) {
|
|
||||||
|
|
||||||
if (model()->canFetchMore(parent)) {
|
|
||||||
model()->fetchMore(parent);
|
|
||||||
}
|
|
||||||
int rows = model()->rowCount(parent);
|
|
||||||
for (int i = 0; i < rows; i++) {
|
|
||||||
QModelIndex current = model()->index(i, 0, parent);
|
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
|
||||||
switch (type.toInt()) {
|
|
||||||
case CollectionItem::Type_Song:
|
|
||||||
if (!last_selected_song_.url().isEmpty()) {
|
|
||||||
QModelIndex index = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(current);
|
|
||||||
const SongList songs = model_->GetChildSongs(index);
|
|
||||||
if (std::any_of(songs.begin(), songs.end(), [this](const Song &song) { return song == last_selected_song_; })) {
|
|
||||||
setCurrentIndex(current);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::Init(Application *app) {
|
|
||||||
|
|
||||||
app_ = app;
|
|
||||||
|
|
||||||
model_ = new ContextAlbumsModel(app_->collection_backend(), app_, this);
|
|
||||||
model_->Reset();
|
|
||||||
|
|
||||||
setModel(model_);
|
|
||||||
|
|
||||||
QObject::connect(model_, &ContextAlbumsModel::modelAboutToBeReset, this, &ContextAlbumsView::SaveFocus);
|
|
||||||
QObject::connect(model_, &ContextAlbumsModel::modelReset, this, &ContextAlbumsView::RestoreFocus);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::paintEvent(QPaintEvent *event) {
|
|
||||||
QTreeView::paintEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::mouseReleaseEvent(QMouseEvent *e) {
|
|
||||||
QTreeView::mouseReleaseEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
|
||||||
|
|
||||||
if (!context_menu_) {
|
|
||||||
context_menu_ = new QMenu(this);
|
|
||||||
|
|
||||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Append to current playlist"), this, &ContextAlbumsView::AddToPlaylist);
|
|
||||||
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"), tr("Replace current playlist"), this, &ContextAlbumsView::Load);
|
|
||||||
open_in_new_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"), tr("Open in new playlist"), this, &ContextAlbumsView::OpenInNewPlaylist);
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue track"), this, &ContextAlbumsView::AddToPlaylistEnqueue);
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
organize_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, &ContextAlbumsView::Organize);
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, &ContextAlbumsView::CopyToDevice);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
edit_track_ = context_menu_->addAction(IconLoader::Load("edit-rename"), tr("Edit track information..."), this, &ContextAlbumsView::EditTracks);
|
|
||||||
edit_tracks_ = context_menu_->addAction(IconLoader::Load("edit-rename"), tr("Edit tracks information..."), this, &ContextAlbumsView::EditTracks);
|
|
||||||
show_in_browser_ = context_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, &ContextAlbumsView::ShowInBrowser);
|
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
|
||||||
QObject::connect(app_->device_manager()->connected_devices_model(), &DeviceStateFilterModel::IsEmptyChanged, copy_to_device_, &QAction::setDisabled);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
context_menu_index_ = indexAt(e->pos());
|
|
||||||
if (!context_menu_index_.isValid()) return;
|
|
||||||
QModelIndexList selected_indexes = selectionModel()->selectedRows();
|
|
||||||
|
|
||||||
int regular_elements = 0;
|
|
||||||
int regular_editable = 0;
|
|
||||||
|
|
||||||
for (const QModelIndex &idx : selected_indexes) {
|
|
||||||
regular_elements++;
|
|
||||||
if (model_->data(idx, ContextAlbumsModel::Role_Editable).toBool()) {
|
|
||||||
regular_editable++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if custom plugin actions should be enabled / visible
|
|
||||||
const int songs_selected = regular_elements;
|
|
||||||
const bool regular_elements_only = songs_selected == regular_elements && regular_elements > 0;
|
|
||||||
|
|
||||||
// in all modes
|
|
||||||
load_->setEnabled(songs_selected > 0);
|
|
||||||
add_to_playlist_->setEnabled(songs_selected > 0);
|
|
||||||
open_in_new_playlist_->setEnabled(songs_selected > 0);
|
|
||||||
add_to_playlist_enqueue_->setEnabled(songs_selected > 0);
|
|
||||||
|
|
||||||
// if neither edit_track not edit_tracks are available, we show disabled edit_track element
|
|
||||||
edit_track_->setVisible(regular_editable <= 1);
|
|
||||||
edit_track_->setEnabled(regular_editable == 1);
|
|
||||||
|
|
||||||
organize_->setVisible(regular_elements_only);
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_->setVisible(regular_elements_only);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// only when all selected items are editable
|
|
||||||
organize_->setEnabled(regular_elements == regular_editable);
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
context_menu_->popup(e->globalPos());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::Load() {
|
|
||||||
|
|
||||||
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
|
|
||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
|
||||||
mimedata->clear_first_ = true;
|
|
||||||
}
|
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::AddToPlaylist() {
|
|
||||||
|
|
||||||
emit AddToPlaylistSignal(model()->mimeData(selectedIndexes()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::AddToPlaylistEnqueue() {
|
|
||||||
|
|
||||||
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
|
|
||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
|
||||||
mimedata->enqueue_now_ = true;
|
|
||||||
}
|
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::OpenInNewPlaylist() {
|
|
||||||
|
|
||||||
QMimeData *q_mimedata = model()->mimeData(selectedIndexes());
|
|
||||||
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
|
|
||||||
mimedata->open_in_new_playlist_ = true;
|
|
||||||
}
|
|
||||||
emit AddToPlaylistSignal(q_mimedata);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::scrollTo(const QModelIndex &idx, ScrollHint hint) {
|
|
||||||
|
|
||||||
if (is_in_keyboard_search_) {
|
|
||||||
QTreeView::scrollTo(idx, QAbstractItemView::PositionAtTop);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QTreeView::scrollTo(idx, hint);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SongList ContextAlbumsView::GetSelectedSongs() const {
|
|
||||||
QModelIndexList selected_indexes = selectionModel()->selectedRows();
|
|
||||||
return model_->GetChildSongs(selected_indexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::Organize() {
|
|
||||||
|
|
||||||
if (!organize_dialog_) {
|
|
||||||
organize_dialog_ = std::make_unique<OrganizeDialog>(app_->task_manager(), app_->collection_backend(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
|
||||||
organize_dialog_->SetCopy(false);
|
|
||||||
if (organize_dialog_->SetSongs(GetSelectedSongs())) {
|
|
||||||
organize_dialog_->show();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::EditTracks() {
|
|
||||||
|
|
||||||
if (!edit_tag_dialog_) {
|
|
||||||
edit_tag_dialog_ = std::make_unique<EditTagDialog>(app_, this);
|
|
||||||
}
|
|
||||||
edit_tag_dialog_->SetSongs(GetSelectedSongs());
|
|
||||||
edit_tag_dialog_->show();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::CopyToDevice() {
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
if (!organize_dialog_) {
|
|
||||||
organize_dialog_ = std::make_unique<OrganizeDialog>(app_->task_manager(), nullptr, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
|
||||||
organize_dialog_->SetCopy(true);
|
|
||||||
organize_dialog_->SetSongs(GetSelectedSongs());
|
|
||||||
organize_dialog_->show();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextAlbumsView::ShowInBrowser() const {
|
|
||||||
|
|
||||||
const SongList songs = GetSelectedSongs();
|
|
||||||
QList<QUrl> urls;
|
|
||||||
urls.reserve(songs.count());
|
|
||||||
for (const Song &song : songs) {
|
|
||||||
urls << song.url();
|
|
||||||
}
|
|
||||||
|
|
||||||
Utilities::OpenInFileBrowser(urls);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* Strawberry Music Player
|
|
||||||
* This code was part of Clementine.
|
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
|
||||||
*
|
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Strawberry is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CONTEXTALBUMSVIEW_H
|
|
||||||
#define CONTEXTALBUMSVIEW_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QAbstractItemView>
|
|
||||||
#include <QStyledItemDelegate>
|
|
||||||
#include <QStyleOption>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "core/song.h"
|
|
||||||
#include "widgets/autoexpandingtreeview.h"
|
|
||||||
|
|
||||||
class QWidget;
|
|
||||||
class QMenu;
|
|
||||||
class QAction;
|
|
||||||
class QContextMenuEvent;
|
|
||||||
class QHelpEvent;
|
|
||||||
class QMouseEvent;
|
|
||||||
class QPaintEvent;
|
|
||||||
|
|
||||||
class Application;
|
|
||||||
class ContextAlbumsModel;
|
|
||||||
class EditTagDialog;
|
|
||||||
class OrganizeDialog;
|
|
||||||
|
|
||||||
class ContextItemDelegate : public QStyledItemDelegate {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ContextItemDelegate(QObject *parent);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ContextAlbumsView : public AutoExpandingTreeView {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ContextAlbumsView(QWidget *parent = nullptr);
|
|
||||||
~ContextAlbumsView() override;
|
|
||||||
|
|
||||||
// Returns Songs currently selected in the collection view.
|
|
||||||
// Please note that the selection is recursive meaning that if for example an album is selected this will return all of it's songs.
|
|
||||||
SongList GetSelectedSongs() const;
|
|
||||||
|
|
||||||
void Init(Application *app);
|
|
||||||
|
|
||||||
// QTreeView
|
|
||||||
void scrollTo(const QModelIndex &idx, ScrollHint hint = EnsureVisible) override;
|
|
||||||
|
|
||||||
ContextAlbumsModel *albums_model() { return model_; }
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void SaveFocus();
|
|
||||||
void RestoreFocus();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// QWidget
|
|
||||||
void paintEvent(QPaintEvent *event) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
|
||||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void Load();
|
|
||||||
void AddToPlaylist();
|
|
||||||
void AddToPlaylistEnqueue();
|
|
||||||
void OpenInNewPlaylist();
|
|
||||||
void Organize();
|
|
||||||
void CopyToDevice();
|
|
||||||
void EditTracks();
|
|
||||||
void ShowInBrowser() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RecheckIsEmpty();
|
|
||||||
bool RestoreLevelFocus(const QModelIndex &parent = QModelIndex());
|
|
||||||
void SaveContainerPath(const QModelIndex &child);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Application *app_;
|
|
||||||
|
|
||||||
QMenu *context_menu_;
|
|
||||||
QModelIndex context_menu_index_;
|
|
||||||
QAction *load_;
|
|
||||||
QAction *add_to_playlist_;
|
|
||||||
QAction *add_to_playlist_enqueue_;
|
|
||||||
QAction *open_in_new_playlist_;
|
|
||||||
QAction *organize_;
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
QAction *copy_to_device_;
|
|
||||||
#endif
|
|
||||||
QAction *edit_track_;
|
|
||||||
QAction *edit_tracks_;
|
|
||||||
QAction *show_in_browser_;
|
|
||||||
|
|
||||||
std::unique_ptr<OrganizeDialog> organize_dialog_;
|
|
||||||
std::unique_ptr<EditTagDialog> edit_tag_dialog_;
|
|
||||||
|
|
||||||
bool is_in_keyboard_search_;
|
|
||||||
|
|
||||||
// Save focus
|
|
||||||
Song last_selected_song_;
|
|
||||||
QString last_selected_container_;
|
|
||||||
QSet<QString> last_selected_path_;
|
|
||||||
|
|
||||||
ContextAlbumsModel *model_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTEXTALBUMSVIEW_H
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2013-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QSpacerItem>
|
#include <QSpacerItem>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QTextEdit>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
|
#include "widgets/resizabletextedit.h"
|
||||||
#include "engine/engine_fwd.h"
|
#include "engine/engine_fwd.h"
|
||||||
#include "engine/enginebase.h"
|
#include "engine/enginebase.h"
|
||||||
#include "engine/enginetype.h"
|
#include "engine/enginetype.h"
|
||||||
@@ -66,8 +68,8 @@
|
|||||||
|
|
||||||
#include "contextview.h"
|
#include "contextview.h"
|
||||||
#include "contextalbum.h"
|
#include "contextalbum.h"
|
||||||
#include "contextalbumsmodel.h"
|
|
||||||
#include "contextalbumsview.h"
|
const int ContextView::kWidgetSpacing = 50;
|
||||||
|
|
||||||
ContextView::ContextView(QWidget *parent)
|
ContextView::ContextView(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -75,18 +77,17 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
collectionview_(nullptr),
|
collectionview_(nullptr),
|
||||||
album_cover_choice_controller_(nullptr),
|
album_cover_choice_controller_(nullptr),
|
||||||
lyrics_fetcher_(nullptr),
|
lyrics_fetcher_(nullptr),
|
||||||
menu_(new QMenu(this)),
|
menu_options_(new QMenu(this)),
|
||||||
action_show_album_(nullptr),
|
action_show_album_(nullptr),
|
||||||
action_show_data_(nullptr),
|
action_show_data_(nullptr),
|
||||||
action_show_output_(nullptr),
|
action_show_output_(nullptr),
|
||||||
action_show_albums_(nullptr),
|
|
||||||
action_show_lyrics_(nullptr),
|
action_show_lyrics_(nullptr),
|
||||||
action_search_lyrics_(nullptr),
|
action_search_lyrics_(nullptr),
|
||||||
layout_container_(new QVBoxLayout()),
|
layout_container_(new QVBoxLayout()),
|
||||||
widget_scrollarea_(new QWidget(this)),
|
widget_scrollarea_(new QWidget(this)),
|
||||||
layout_scrollarea_(new QVBoxLayout()),
|
layout_scrollarea_(new QVBoxLayout()),
|
||||||
scrollarea_(new QScrollArea(this)),
|
scrollarea_(new QScrollArea(this)),
|
||||||
label_top_(new QLabel(this)),
|
textedit_top_(new ResizableTextEdit(this)),
|
||||||
widget_album_(new ContextAlbum(this)),
|
widget_album_(new ContextAlbum(this)),
|
||||||
widget_stacked_(new QStackedWidget(this)),
|
widget_stacked_(new QStackedWidget(this)),
|
||||||
widget_stop_(new QWidget(this)),
|
widget_stop_(new QWidget(this)),
|
||||||
@@ -94,19 +95,13 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
layout_stop_(new QVBoxLayout()),
|
layout_stop_(new QVBoxLayout()),
|
||||||
layout_play_(new QVBoxLayout()),
|
layout_play_(new QVBoxLayout()),
|
||||||
label_stop_summary_(new QLabel(this)),
|
label_stop_summary_(new QLabel(this)),
|
||||||
spacer_stop_bottom_(new QSpacerItem(0, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
|
|
||||||
widget_play_data_(new QWidget(this)),
|
widget_play_data_(new QWidget(this)),
|
||||||
widget_play_output_(new QWidget(this)),
|
widget_play_output_(new QWidget(this)),
|
||||||
layout_play_data_(new QGridLayout()),
|
layout_play_data_(new QGridLayout()),
|
||||||
layout_play_output_(new QGridLayout()),
|
layout_play_output_(new QGridLayout()),
|
||||||
label_play_albums_(new QLabel(this)),
|
textedit_play_lyrics_(new ResizableTextEdit(this)),
|
||||||
label_play_lyrics_(new QLabel(this)),
|
|
||||||
widget_albums_(new ContextAlbumsView(this)),
|
|
||||||
//spacer_play_album_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
|
||||||
spacer_play_output_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
spacer_play_output_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
||||||
spacer_play_data_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
spacer_play_data_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
||||||
spacer_play_albums_(new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)),
|
|
||||||
spacer_play_bottom_(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
|
|
||||||
label_filetype_title_(new QLabel(this)),
|
label_filetype_title_(new QLabel(this)),
|
||||||
label_length_title_(new QLabel(this)),
|
label_length_title_(new QLabel(this)),
|
||||||
label_samplerate_title_(new QLabel(this)),
|
label_samplerate_title_(new QLabel(this)),
|
||||||
@@ -125,12 +120,10 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
label_engine_(new QLabel(this)),
|
label_engine_(new QLabel(this)),
|
||||||
label_device_icon_(new QLabel(this)),
|
label_device_icon_(new QLabel(this)),
|
||||||
label_engine_icon_(new QLabel(this)),
|
label_engine_icon_(new QLabel(this)),
|
||||||
spacer_bottom_(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding)),
|
|
||||||
lyrics_tried_(false),
|
lyrics_tried_(false),
|
||||||
lyrics_id_(-1),
|
lyrics_id_(-1),
|
||||||
font_size_headline_(0),
|
font_size_headline_(0),
|
||||||
font_size_normal_(0),
|
font_size_normal_(0) {
|
||||||
prev_width_(0) {
|
|
||||||
|
|
||||||
setLayout(layout_container_);
|
setLayout(layout_container_);
|
||||||
|
|
||||||
@@ -143,23 +136,21 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
scrollarea_->setWidget(widget_scrollarea_);
|
scrollarea_->setWidget(widget_scrollarea_);
|
||||||
scrollarea_->setContentsMargins(0, 0, 0, 0);
|
scrollarea_->setContentsMargins(0, 0, 0, 0);
|
||||||
scrollarea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
scrollarea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
scrollarea_->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
widget_scrollarea_->setObjectName("context-widget-scrollarea");
|
widget_scrollarea_->setObjectName("context-widget-scrollarea");
|
||||||
widget_scrollarea_->setLayout(layout_scrollarea_);
|
widget_scrollarea_->setLayout(layout_scrollarea_);
|
||||||
widget_scrollarea_->setContentsMargins(0, 0, 0, 0);
|
widget_scrollarea_->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
label_top_->setAlignment(Qt::AlignTop|Qt::AlignLeft);
|
textedit_top_->setReadOnly(true);
|
||||||
label_top_->setWordWrap(true);
|
textedit_top_->setFrameShape(QFrame::NoFrame);
|
||||||
label_top_->setMinimumHeight(50);
|
|
||||||
label_top_->setContentsMargins(0, 0, 32, 0);
|
|
||||||
label_top_->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
||||||
|
|
||||||
layout_scrollarea_->setObjectName("context-layout-scrollarea");
|
layout_scrollarea_->setObjectName("context-layout-scrollarea");
|
||||||
layout_scrollarea_->setContentsMargins(15, 15, 15, 15);
|
layout_scrollarea_->setContentsMargins(15, 15, 15, 15);
|
||||||
layout_scrollarea_->addWidget(label_top_);
|
layout_scrollarea_->addWidget(textedit_top_);
|
||||||
layout_scrollarea_->addWidget(widget_album_);
|
layout_scrollarea_->addWidget(widget_album_);
|
||||||
layout_scrollarea_->addWidget(widget_stacked_);
|
layout_scrollarea_->addWidget(widget_stacked_);
|
||||||
layout_scrollarea_->addSpacerItem(spacer_bottom_);
|
layout_scrollarea_->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||||
|
|
||||||
widget_stacked_->setContentsMargins(0, 0, 0, 0);
|
widget_stacked_->setContentsMargins(0, 0, 0, 0);
|
||||||
widget_stacked_->addWidget(widget_stop_);
|
widget_stacked_->addWidget(widget_stop_);
|
||||||
@@ -176,9 +167,10 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
|
|
||||||
// Stopped
|
// Stopped
|
||||||
|
|
||||||
layout_stop_->setContentsMargins(5, 0, 40, 0);
|
label_stop_summary_->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||||
|
|
||||||
|
layout_stop_->setContentsMargins(0, 0, 0, 0);
|
||||||
layout_stop_->addWidget(label_stop_summary_);
|
layout_stop_->addWidget(label_stop_summary_);
|
||||||
layout_stop_->addSpacerItem(spacer_stop_bottom_);
|
|
||||||
|
|
||||||
// Playing
|
// Playing
|
||||||
|
|
||||||
@@ -244,33 +236,25 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
|
|
||||||
widget_play_data_->setLayout(layout_play_data_);
|
widget_play_data_->setLayout(layout_play_data_);
|
||||||
|
|
||||||
label_play_lyrics_->setWordWrap(true);
|
textedit_play_lyrics_->setReadOnly(true);
|
||||||
label_play_lyrics_->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
textedit_play_lyrics_->setFrameShape(QFrame::NoFrame);
|
||||||
|
textedit_play_lyrics_->hide();
|
||||||
|
|
||||||
widget_albums_->hide();
|
layout_play_->setContentsMargins(0, 0, 0, 0);
|
||||||
label_play_albums_->setWordWrap(true);
|
|
||||||
label_play_albums_->hide();
|
|
||||||
|
|
||||||
layout_play_->setContentsMargins(5, 0, 40, 0);
|
|
||||||
layout_play_->addWidget(widget_play_output_);
|
layout_play_->addWidget(widget_play_output_);
|
||||||
layout_play_->addSpacerItem(spacer_play_output_);
|
layout_play_->addSpacerItem(spacer_play_output_);
|
||||||
layout_play_->addWidget(widget_play_data_);
|
layout_play_->addWidget(widget_play_data_);
|
||||||
layout_play_->addSpacerItem(spacer_play_data_);
|
layout_play_->addSpacerItem(spacer_play_data_);
|
||||||
layout_play_->addWidget(label_play_albums_);
|
layout_play_->addWidget(textedit_play_lyrics_);
|
||||||
layout_play_->addWidget(widget_albums_);
|
layout_play_->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||||
layout_play_->addSpacerItem(spacer_play_albums_);
|
|
||||||
layout_play_->addWidget(label_play_lyrics_);
|
|
||||||
layout_play_->addSpacerItem(spacer_play_bottom_);
|
|
||||||
|
|
||||||
labels_play_ << label_engine_title_
|
labels_play_ << label_engine_title_
|
||||||
<< label_device_title_
|
<< label_device_title_
|
||||||
<< label_filetype_title_
|
<< label_filetype_title_
|
||||||
<< label_length_title_
|
<< label_length_title_
|
||||||
<< label_samplerate_title_
|
<< label_samplerate_title_
|
||||||
<< label_bitdepth_title_
|
<< label_bitdepth_title_
|
||||||
<< label_bitrate_title_
|
<< label_bitrate_title_;
|
||||||
<< label_play_albums_
|
|
||||||
<< label_play_lyrics_;
|
|
||||||
|
|
||||||
labels_play_data_ << label_engine_icon_
|
labels_play_data_ << label_engine_icon_
|
||||||
<< label_engine_
|
<< label_engine_
|
||||||
@@ -280,27 +264,16 @@ ContextView::ContextView(QWidget *parent)
|
|||||||
<< label_length_
|
<< label_length_
|
||||||
<< label_samplerate_
|
<< label_samplerate_
|
||||||
<< label_bitdepth_
|
<< label_bitdepth_
|
||||||
<< label_bitrate_
|
<< label_bitrate_;
|
||||||
<< label_play_albums_
|
|
||||||
<< label_play_lyrics_;
|
|
||||||
|
|
||||||
labels_play_all_ = labels_play_ << labels_play_data_;
|
labels_play_all_ = labels_play_ << labels_play_data_;
|
||||||
|
|
||||||
QFontDatabase::addApplicationFont(":/fonts/HumongousofEternitySt.ttf");
|
textedit_play_ << textedit_play_lyrics_;
|
||||||
|
|
||||||
QObject::connect(widget_album_, &ContextAlbum::FadeStopFinished, this, &ContextView::FadeStopFinished);
|
QObject::connect(widget_album_, &ContextAlbum::FadeStopFinished, this, &ContextView::FadeStopFinished);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::resizeEvent(QResizeEvent*) {
|
|
||||||
|
|
||||||
if (width() != prev_width_) {
|
|
||||||
widget_album_->setFixedSize(width() - 15, width());
|
|
||||||
prev_width_ = width();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller) {
|
void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller) {
|
||||||
|
|
||||||
app_ = app;
|
app_ = app;
|
||||||
@@ -308,7 +281,6 @@ void ContextView::Init(Application *app, CollectionView *collectionview, AlbumCo
|
|||||||
album_cover_choice_controller_ = album_cover_choice_controller;
|
album_cover_choice_controller_ = album_cover_choice_controller;
|
||||||
|
|
||||||
widget_album_->Init(this, album_cover_choice_controller_);
|
widget_album_->Init(this, album_cover_choice_controller_);
|
||||||
widget_albums_->Init(app_);
|
|
||||||
lyrics_fetcher_ = new LyricsFetcher(app_->lyrics_providers(), this);
|
lyrics_fetcher_ = new LyricsFetcher(app_->lyrics_providers(), this);
|
||||||
|
|
||||||
QObject::connect(collectionview_, &CollectionView::TotalSongCountUpdated_, this, &ContextView::UpdateNoSong);
|
QObject::connect(collectionview_, &CollectionView::TotalSongCountUpdated_, this, &ContextView::UpdateNoSong);
|
||||||
@@ -334,10 +306,6 @@ void ContextView::AddActions() {
|
|||||||
action_show_output_->setCheckable(true);
|
action_show_output_->setCheckable(true);
|
||||||
action_show_output_->setChecked(true);
|
action_show_output_->setChecked(true);
|
||||||
|
|
||||||
action_show_albums_ = new QAction(tr("Show albums by artist"), this);
|
|
||||||
action_show_albums_->setCheckable(true);
|
|
||||||
action_show_albums_->setChecked(false);
|
|
||||||
|
|
||||||
action_show_lyrics_ = new QAction(tr("Show song lyrics"), this);
|
action_show_lyrics_ = new QAction(tr("Show song lyrics"), this);
|
||||||
action_show_lyrics_->setCheckable(true);
|
action_show_lyrics_->setCheckable(true);
|
||||||
action_show_lyrics_->setChecked(true);
|
action_show_lyrics_->setChecked(true);
|
||||||
@@ -346,20 +314,18 @@ void ContextView::AddActions() {
|
|||||||
action_search_lyrics_->setCheckable(true);
|
action_search_lyrics_->setCheckable(true);
|
||||||
action_search_lyrics_->setChecked(true);
|
action_search_lyrics_->setChecked(true);
|
||||||
|
|
||||||
menu_->addAction(action_show_album_);
|
menu_options_->addAction(action_show_album_);
|
||||||
menu_->addAction(action_show_data_);
|
menu_options_->addAction(action_show_data_);
|
||||||
menu_->addAction(action_show_output_);
|
menu_options_->addAction(action_show_output_);
|
||||||
menu_->addAction(action_show_albums_);
|
menu_options_->addAction(action_show_lyrics_);
|
||||||
menu_->addAction(action_show_lyrics_);
|
menu_options_->addAction(action_search_lyrics_);
|
||||||
menu_->addAction(action_search_lyrics_);
|
menu_options_->addSeparator();
|
||||||
menu_->addSeparator();
|
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
QObject::connect(action_show_album_, &QAction::triggered, this, &ContextView::ActionShowAlbums);
|
QObject::connect(action_show_album_, &QAction::triggered, this, &ContextView::ActionShowAlbum);
|
||||||
QObject::connect(action_show_data_, &QAction::triggered, this, &ContextView::ActionShowData);
|
QObject::connect(action_show_data_, &QAction::triggered, this, &ContextView::ActionShowData);
|
||||||
QObject::connect(action_show_output_, &QAction::triggered, this, &ContextView::ActionShowOutput);
|
QObject::connect(action_show_output_, &QAction::triggered, this, &ContextView::ActionShowOutput);
|
||||||
QObject::connect(action_show_albums_, &QAction::triggered, this, &ContextView::ActionShowAlbums);
|
|
||||||
QObject::connect(action_show_lyrics_, &QAction::triggered, this, &ContextView::ActionShowLyrics);
|
QObject::connect(action_show_lyrics_, &QAction::triggered, this, &ContextView::ActionShowLyrics);
|
||||||
QObject::connect(action_search_lyrics_, &QAction::triggered, this, &ContextView::ActionSearchLyrics);
|
QObject::connect(action_search_lyrics_, &QAction::triggered, this, &ContextView::ActionSearchLyrics);
|
||||||
|
|
||||||
@@ -374,12 +340,11 @@ void ContextView::ReloadSettings() {
|
|||||||
action_show_album_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUM], true).toBool());
|
action_show_album_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUM], true).toBool());
|
||||||
action_show_data_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::TECHNICAL_DATA], false).toBool());
|
action_show_data_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::TECHNICAL_DATA], false).toBool());
|
||||||
action_show_output_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ENGINE_AND_DEVICE], false).toBool());
|
action_show_output_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ENGINE_AND_DEVICE], false).toBool());
|
||||||
action_show_albums_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUMS_BY_ARTIST], false).toBool());
|
|
||||||
action_show_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SONG_LYRICS], true).toBool());
|
action_show_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SONG_LYRICS], true).toBool());
|
||||||
action_search_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SEARCH_LYRICS], true).toBool());
|
action_search_lyrics_->setChecked(s.value(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::SEARCH_LYRICS], true).toBool());
|
||||||
font_headline_ = s.value("font_headline", font().family()).toString();
|
font_headline_ = s.value("font_headline", font().family()).toString();
|
||||||
font_normal_ = s.value("font_normal", font().family()).toString();
|
font_normal_ = s.value("font_normal", font().family()).toString();
|
||||||
font_size_headline_ = s.value("font_size_headline", ContextSettingsPage::kDefaultFontSizeHeadline).toReal();
|
font_size_headline_ = s.value("font_size_headline", ContextSettingsPage::kDefaultFontSizeHeadline).toReal();
|
||||||
font_size_normal_ = s.value("font_size_normal", font().pointSizeF()).toReal();
|
font_size_normal_ = s.value("font_size_normal", font().pointSizeF()).toReal();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
@@ -394,6 +359,16 @@ void ContextView::ReloadSettings() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextView::resizeEvent(QResizeEvent *e) {
|
||||||
|
|
||||||
|
if (e->size().width() != e->oldSize().width()) {
|
||||||
|
widget_album_->UpdateWidth(width() - kWidgetSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::resizeEvent(e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void ContextView::Playing() {}
|
void ContextView::Playing() {}
|
||||||
|
|
||||||
void ContextView::Stopped() {
|
void ContextView::Stopped() {
|
||||||
@@ -441,6 +416,7 @@ void ContextView::FadeStopFinished() {
|
|||||||
widget_stacked_->setCurrentWidget(widget_stop_);
|
widget_stacked_->setCurrentWidget(widget_stop_);
|
||||||
NoSong();
|
NoSong();
|
||||||
ResetSong();
|
ResetSong();
|
||||||
|
widget_stacked_->updateGeometry();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,9 +434,8 @@ void ContextView::NoSong() {
|
|||||||
widget_album_->show();
|
widget_album_->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
label_top_->setStyleSheet("font: 20pt \"Humongous of Eternity St\"; font-weight: Regular;");
|
textedit_top_->setStyleSheet("font: 20pt 'Open Sans', 'FreeSans', 'FreeSerif', 'Liberation Serif'; font-weight: Regular;");
|
||||||
|
textedit_top_->setText(tr("No song playing"));
|
||||||
label_top_->setText(tr("No song playing"));
|
|
||||||
|
|
||||||
QString html;
|
QString html;
|
||||||
if (collectionview_->TotalSongs() == 1) html += tr("%1 song").arg(collectionview_->TotalSongs());
|
if (collectionview_->TotalSongs() == 1) html += tr("%1 song").arg(collectionview_->TotalSongs());
|
||||||
@@ -482,17 +457,20 @@ void ContextView::NoSong() {
|
|||||||
|
|
||||||
void ContextView::UpdateFonts() {
|
void ContextView::UpdateFonts() {
|
||||||
|
|
||||||
|
QString font_style = QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_normal_).arg(font_size_normal_);
|
||||||
for (QLabel *l : labels_play_all_) {
|
for (QLabel *l : labels_play_all_) {
|
||||||
l->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_normal_).arg(font_size_normal_));
|
l->setStyleSheet(font_style);
|
||||||
|
}
|
||||||
|
for (QTextEdit *e : textedit_play_) {
|
||||||
|
e->setStyleSheet(font_style);
|
||||||
}
|
}
|
||||||
label_play_albums_->setStyleSheet(QString("background-color: #3DADE8; color: rgb(255, 255, 255); font: %1pt \"%2\"; font-weight: regular;").arg(font_size_normal_).arg(font_normal_));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::SetSong() {
|
void ContextView::SetSong() {
|
||||||
|
|
||||||
label_top_->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_headline_).arg(font_size_headline_));
|
textedit_top_->setStyleSheet(QString("font: %2pt \"%1\"; font-weight: regular;").arg(font_headline_).arg(font_size_headline_));
|
||||||
label_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song_playing_, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song_playing_, "<br />", true)));
|
textedit_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song_playing_, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song_playing_, "<br />", true)));
|
||||||
|
|
||||||
label_stop_summary_->clear();
|
label_stop_summary_->clear();
|
||||||
|
|
||||||
@@ -605,51 +583,23 @@ void ContextView::SetSong() {
|
|||||||
spacer_play_output_->changeSize(0, 0, QSizePolicy::Fixed);
|
spacer_play_output_->changeSize(0, 0, QSizePolicy::Fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action_show_albums_->isChecked() && song_prev_.artist() != song_playing_.artist()) {
|
if (action_show_lyrics_->isChecked() && !lyrics_.isEmpty()) {
|
||||||
CollectionBackend::AlbumList albumlist;
|
textedit_play_lyrics_->setText(lyrics_);
|
||||||
widget_albums_->albums_model()->Reset();
|
textedit_play_lyrics_->show();
|
||||||
albumlist = app_->collection_backend()->GetAlbumsByArtist(song_playing_.effective_albumartist());
|
|
||||||
if (albumlist.count() > 1) {
|
|
||||||
label_play_albums_->show();
|
|
||||||
widget_albums_->show();
|
|
||||||
label_play_albums_->setText("<b>" + tr("Albums by %1").arg(song_playing_.effective_albumartist().toHtmlEscaped()) + "</b>");
|
|
||||||
for (const CollectionBackend::Album &album : albumlist) {
|
|
||||||
SongList songs = app_->collection_backend()->GetAlbumSongs(song_playing_.effective_albumartist(), album.album);
|
|
||||||
widget_albums_->albums_model()->AddSongs(songs);
|
|
||||||
}
|
|
||||||
spacer_play_albums_->changeSize(20, 10, QSizePolicy::Fixed);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
label_play_albums_->hide();
|
|
||||||
widget_albums_->hide();
|
|
||||||
label_play_albums_->clear();
|
|
||||||
spacer_play_albums_->changeSize(0, 0, QSizePolicy::Fixed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!action_show_albums_->isChecked()) {
|
|
||||||
label_play_albums_->hide();
|
|
||||||
widget_albums_->hide();
|
|
||||||
label_play_albums_->clear();
|
|
||||||
widget_albums_->albums_model()->Reset();
|
|
||||||
spacer_play_albums_->changeSize(0, 0, QSizePolicy::Fixed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action_show_lyrics_->isChecked()) {
|
|
||||||
label_play_lyrics_->show();
|
|
||||||
label_play_lyrics_->setText(lyrics_);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
label_play_lyrics_->hide();
|
textedit_play_lyrics_->clear();
|
||||||
label_play_lyrics_->clear();
|
textedit_play_lyrics_->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
widget_stacked_->setCurrentWidget(widget_play_);
|
widget_stacked_->setCurrentWidget(widget_play_);
|
||||||
|
widget_stacked_->updateGeometry();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::UpdateSong(const Song &song) {
|
void ContextView::UpdateSong(const Song &song) {
|
||||||
|
|
||||||
label_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song, "<br />", true)));
|
textedit_top_->setText(QString("<b>%1</b><br />%2").arg(Utilities::ReplaceMessage(title_fmt_, song, "<br />", true), Utilities::ReplaceMessage(summary_fmt_, song, "<br />", true)));
|
||||||
|
|
||||||
if (action_show_data_->isChecked()) {
|
if (action_show_data_->isChecked()) {
|
||||||
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
|
if (song.filetype() != song_playing_.filetype()) label_filetype_->setText(song.TextForFiletype());
|
||||||
@@ -713,22 +663,43 @@ void ContextView::ResetSong() {
|
|||||||
l->clear();
|
l->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (QTextEdit *l : textedit_play_) {
|
||||||
|
l->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_play_output_->hide();
|
||||||
|
widget_play_data_->hide();
|
||||||
|
textedit_play_lyrics_->hide();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics) {
|
void ContextView::UpdateLyrics(const quint64 id, const QString &provider, const QString &lyrics) {
|
||||||
|
|
||||||
if (static_cast<qint64>(id) != lyrics_id_) return;
|
if (static_cast<qint64>(id) != lyrics_id_) return;
|
||||||
|
|
||||||
lyrics_ = lyrics + "\n\n(Lyrics from " + provider + ")\n";
|
lyrics_ = lyrics + "\n\n(Lyrics from " + provider + ")\n";
|
||||||
lyrics_id_ = -1;
|
lyrics_id_ = -1;
|
||||||
if (action_show_lyrics_->isChecked()) {
|
|
||||||
label_play_lyrics_->setText(lyrics_);
|
if (action_show_lyrics_->isChecked() && !lyrics_.isEmpty()) {
|
||||||
|
textedit_play_lyrics_->setText(lyrics_);
|
||||||
|
textedit_play_lyrics_->show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
textedit_play_lyrics_->clear();
|
||||||
|
textedit_play_lyrics_->hide();
|
||||||
}
|
}
|
||||||
else label_play_lyrics_->clear();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::contextMenuEvent(QContextMenuEvent *e) {
|
void ContextView::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (menu_) menu_->popup(mapToGlobal(e->pos()));
|
|
||||||
|
if (menu_options_ && widget_stacked_->currentWidget() == widget_stop_) {
|
||||||
|
menu_options_->popup(mapToGlobal(e->pos()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QWidget::contextMenuEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::dragEnterEvent(QDragEnterEvent *e) {
|
void ContextView::dragEnterEvent(QDragEnterEvent *e) {
|
||||||
@@ -790,17 +761,6 @@ void ContextView::ActionShowOutput() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::ActionShowAlbums() {
|
|
||||||
|
|
||||||
QSettings s;
|
|
||||||
s.beginGroup(ContextSettingsPage::kSettingsGroup);
|
|
||||||
s.setValue(ContextSettingsPage::kSettingsGroupEnable[ContextSettingsPage::ContextSettingsOrder::ALBUMS_BY_ARTIST], action_show_albums_->isChecked());
|
|
||||||
s.endGroup();
|
|
||||||
song_prev_ = Song();
|
|
||||||
if (song_playing_.is_valid()) SetSong();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextView::ActionShowLyrics() {
|
void ContextView::ActionShowLyrics() {
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
|
* Copyright 2013-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -45,10 +45,10 @@ class QContextMenuEvent;
|
|||||||
class QDragEnterEvent;
|
class QDragEnterEvent;
|
||||||
class QDropEvent;
|
class QDropEvent;
|
||||||
|
|
||||||
|
class ResizableTextEdit;
|
||||||
class Application;
|
class Application;
|
||||||
class CollectionView;
|
class CollectionView;
|
||||||
class AlbumCoverChoiceController;
|
class AlbumCoverChoiceController;
|
||||||
class ContextAlbumsView;
|
|
||||||
class LyricsFetcher;
|
class LyricsFetcher;
|
||||||
|
|
||||||
class ContextView : public QWidget {
|
class ContextView : public QWidget {
|
||||||
@@ -60,12 +60,11 @@ class ContextView : public QWidget {
|
|||||||
void Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller);
|
void Init(Application *app, CollectionView *collectionview, AlbumCoverChoiceController *album_cover_choice_controller);
|
||||||
|
|
||||||
ContextAlbum *album_widget() const { return widget_album_; }
|
ContextAlbum *album_widget() const { return widget_album_; }
|
||||||
ContextAlbumsView *albums_widget() const { return widget_albums_; }
|
|
||||||
bool album_enabled() const { return action_show_album_->isChecked(); }
|
bool album_enabled() const { return action_show_album_->isChecked(); }
|
||||||
Song song_playing() const { return song_playing_; }
|
Song song_playing() const { return song_playing_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent*) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void contextMenuEvent(QContextMenuEvent*) override;
|
void contextMenuEvent(QContextMenuEvent*) override;
|
||||||
void dragEnterEvent(QDragEnterEvent*) override;
|
void dragEnterEvent(QDragEnterEvent*) override;
|
||||||
void dropEvent(QDropEvent*) override;
|
void dropEvent(QDropEvent*) override;
|
||||||
@@ -88,7 +87,6 @@ class ContextView : public QWidget {
|
|||||||
void ActionShowAlbum();
|
void ActionShowAlbum();
|
||||||
void ActionShowData();
|
void ActionShowData();
|
||||||
void ActionShowOutput();
|
void ActionShowOutput();
|
||||||
void ActionShowAlbums();
|
|
||||||
void ActionShowLyrics();
|
void ActionShowLyrics();
|
||||||
void ActionSearchLyrics();
|
void ActionSearchLyrics();
|
||||||
void UpdateNoSong();
|
void UpdateNoSong();
|
||||||
@@ -104,16 +102,17 @@ class ContextView : public QWidget {
|
|||||||
void AlbumCoverLoaded(const Song &song, const QImage &image);
|
void AlbumCoverLoaded(const Song &song, const QImage &image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int kWidgetSpacing;
|
||||||
|
|
||||||
Application *app_;
|
Application *app_;
|
||||||
CollectionView *collectionview_;
|
CollectionView *collectionview_;
|
||||||
AlbumCoverChoiceController *album_cover_choice_controller_;
|
AlbumCoverChoiceController *album_cover_choice_controller_;
|
||||||
LyricsFetcher *lyrics_fetcher_;
|
LyricsFetcher *lyrics_fetcher_;
|
||||||
|
|
||||||
QMenu *menu_;
|
QMenu *menu_options_;
|
||||||
QAction *action_show_album_;
|
QAction *action_show_album_;
|
||||||
QAction *action_show_data_;
|
QAction *action_show_data_;
|
||||||
QAction *action_show_output_;
|
QAction *action_show_output_;
|
||||||
QAction *action_show_albums_;
|
|
||||||
QAction *action_show_lyrics_;
|
QAction *action_show_lyrics_;
|
||||||
QAction *action_search_lyrics_;
|
QAction *action_search_lyrics_;
|
||||||
|
|
||||||
@@ -121,7 +120,7 @@ class ContextView : public QWidget {
|
|||||||
QWidget *widget_scrollarea_;
|
QWidget *widget_scrollarea_;
|
||||||
QVBoxLayout *layout_scrollarea_;
|
QVBoxLayout *layout_scrollarea_;
|
||||||
QScrollArea *scrollarea_;
|
QScrollArea *scrollarea_;
|
||||||
QLabel *label_top_;
|
ResizableTextEdit *textedit_top_;
|
||||||
ContextAlbum *widget_album_;
|
ContextAlbum *widget_album_;
|
||||||
QStackedWidget *widget_stacked_;
|
QStackedWidget *widget_stacked_;
|
||||||
QWidget *widget_stop_;
|
QWidget *widget_stop_;
|
||||||
@@ -129,20 +128,14 @@ class ContextView : public QWidget {
|
|||||||
QVBoxLayout *layout_stop_;
|
QVBoxLayout *layout_stop_;
|
||||||
QVBoxLayout *layout_play_;
|
QVBoxLayout *layout_play_;
|
||||||
QLabel *label_stop_summary_;
|
QLabel *label_stop_summary_;
|
||||||
QSpacerItem *spacer_stop_bottom_;
|
|
||||||
QWidget *widget_play_data_;
|
QWidget *widget_play_data_;
|
||||||
QWidget *widget_play_output_;
|
QWidget *widget_play_output_;
|
||||||
QGridLayout *layout_play_data_;
|
QGridLayout *layout_play_data_;
|
||||||
QGridLayout *layout_play_output_;
|
QGridLayout *layout_play_output_;
|
||||||
QLabel *label_play_albums_;
|
ResizableTextEdit *textedit_play_lyrics_;
|
||||||
QLabel *label_play_lyrics_;
|
|
||||||
ContextAlbumsView *widget_albums_;
|
|
||||||
|
|
||||||
//QSpacerItem *spacer_play_album_;
|
|
||||||
QSpacerItem *spacer_play_output_;
|
QSpacerItem *spacer_play_output_;
|
||||||
QSpacerItem *spacer_play_data_;
|
QSpacerItem *spacer_play_data_;
|
||||||
QSpacerItem *spacer_play_albums_;
|
|
||||||
QSpacerItem *spacer_play_bottom_;
|
|
||||||
|
|
||||||
QLabel *label_filetype_title_;
|
QLabel *label_filetype_title_;
|
||||||
QLabel *label_length_title_;
|
QLabel *label_length_title_;
|
||||||
@@ -165,8 +158,6 @@ class ContextView : public QWidget {
|
|||||||
QLabel *label_device_icon_;
|
QLabel *label_device_icon_;
|
||||||
QLabel *label_engine_icon_;
|
QLabel *label_engine_icon_;
|
||||||
|
|
||||||
QSpacerItem *spacer_bottom_;
|
|
||||||
|
|
||||||
Song song_playing_;
|
Song song_playing_;
|
||||||
Song song_prev_;
|
Song song_prev_;
|
||||||
QImage image_original_;
|
QImage image_original_;
|
||||||
@@ -181,11 +172,10 @@ class ContextView : public QWidget {
|
|||||||
qreal font_size_normal_;
|
qreal font_size_normal_;
|
||||||
|
|
||||||
QList<QLabel*> labels_play_;
|
QList<QLabel*> labels_play_;
|
||||||
|
QList<ResizableTextEdit*> textedit_play_;
|
||||||
QList<QLabel*> labels_play_data_;
|
QList<QLabel*> labels_play_data_;
|
||||||
QList<QLabel*> labels_play_all_;
|
QList<QLabel*> labels_play_all_;
|
||||||
|
|
||||||
int prev_width_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTEXTVIEW_H
|
#endif // CONTEXTVIEW_H
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
// This template function declaration is used in defining arraysize.
|
// This template function declaration is used in defining arraysize.
|
||||||
// Note that the function doesn't need an implementation, as we only
|
// Note that the function doesn't need an implementation, as we only
|
||||||
// use its type.
|
// use its type.
|
||||||
template <typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||||
|
|
||||||
// That gcc wants both of these prototypes seems mysterious. VC, for
|
// That gcc wants both of these prototypes seems mysterious. VC, for
|
||||||
// its part, can't decide which to use (another mystery). Matching of
|
// its part, can't decide which to use (another mystery). Matching of
|
||||||
// template overloads: the final frontier.
|
// template overloads: the final frontier.
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
template <typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,7 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#ifndef _MSC_VER
|
#include <getopt.h>
|
||||||
# include <getopt.h>
|
|
||||||
#endif
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@@ -121,7 +119,6 @@ void CommandlineOptions::RemoveArg(const QString &starts_with, int count) {
|
|||||||
|
|
||||||
bool CommandlineOptions::Parse() {
|
bool CommandlineOptions::Parse() {
|
||||||
|
|
||||||
#ifndef _MSC_VER // TODO: Consider QCommandLineOption.
|
|
||||||
static const struct option kOptions[] = {
|
static const struct option kOptions[] = {
|
||||||
{"help", no_argument, nullptr, 'h'},
|
{"help", no_argument, nullptr, 'h'},
|
||||||
{"play", no_argument, nullptr, 'p'},
|
{"play", no_argument, nullptr, 'p'},
|
||||||
@@ -322,8 +319,6 @@ bool CommandlineOptions::Parse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,15 +401,21 @@ void Database::ExecSchemaCommandsFromFile(QSqlDatabase &db, const QString &filen
|
|||||||
qFatal("Couldn't open schema file %s for reading: %s", filename.toUtf8().constData(), schema_file.errorString().toUtf8().constData());
|
qFatal("Couldn't open schema file %s for reading: %s", filename.toUtf8().constData(), schema_file.errorString().toUtf8().constData());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ExecSchemaCommands(db, QString::fromUtf8(schema_file.readAll()), schema_version, in_transaction);
|
QByteArray data = schema_file.readAll();
|
||||||
|
QString schema = QString::fromUtf8(data);
|
||||||
|
if (schema.contains("\r\n")) {
|
||||||
|
schema = schema.replace("\r\n", "\n");
|
||||||
|
}
|
||||||
schema_file.close();
|
schema_file.close();
|
||||||
|
ExecSchemaCommands(db, schema, schema_version, in_transaction);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int schema_version, bool in_transaction) {
|
void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int schema_version, bool in_transaction) {
|
||||||
|
|
||||||
// Run each command
|
// Run each command
|
||||||
const QStringList commands(schema.split(QRegularExpression("; *\n\n")));
|
QStringList commands;
|
||||||
|
commands = schema.split(QRegularExpression("; *\n\n"));
|
||||||
|
|
||||||
// We don't want this list to reflect possible DB schema changes so we initialize it before executing any statements.
|
// We don't want this list to reflect possible DB schema changes so we initialize it before executing any statements.
|
||||||
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction! Otherwise
|
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction! Otherwise
|
||||||
|
|||||||
@@ -80,13 +80,11 @@ bool FilesystemMusicStorage::CopyToStorage(const CopyJob &job) {
|
|||||||
QFile::rename(cover_src.absoluteFilePath(), cover_dest.absoluteFilePath());
|
QFile::rename(cover_src.absoluteFilePath(), cover_dest.absoluteFilePath());
|
||||||
}
|
}
|
||||||
// Remove empty directories.
|
// Remove empty directories.
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
|
||||||
QDir remove_dir(src.absolutePath(), QString(), QDir::Name, QDir::NoDotAndDotDot);
|
QDir remove_dir(src.absolutePath(), QString(), QDir::Name, QDir::NoDotAndDotDot);
|
||||||
while (remove_dir.isEmpty()) {
|
while (remove_dir.isEmpty()) {
|
||||||
if (!QDir().rmdir(remove_dir.absolutePath())) break;
|
if (!QDir().rmdir(remove_dir.absolutePath())) break;
|
||||||
remove_dir.cdUp();
|
remove_dir.cdUp();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (dest.exists() && !job.overwrite_) {
|
if (dest.exists() && !job.overwrite_) {
|
||||||
@@ -111,12 +109,12 @@ bool FilesystemMusicStorage::DeleteFromStorage(const DeleteJob &job) {
|
|||||||
|
|
||||||
if (job.use_trash_) {
|
if (job.use_trash_) {
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
if (fileInfo.isDir()) {
|
if (fileInfo.isDir()) {
|
||||||
return Utilities::MoveToTrashRecursive(path);
|
return Utilities::MoveToTrashRecursive(path);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return QFile::moveToTrash(path);
|
return QFile::moveToTrash(path);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ QIcon IconLoader::Load(const QString &name, const int fixed_size, const int min_
|
|||||||
|
|
||||||
QList<int> sizes;
|
QList<int> sizes;
|
||||||
if (fixed_size == 0) {
|
if (fixed_size == 0) {
|
||||||
sizes << 22 << 32 << 48 << 64;
|
sizes << 22 << 32 << 48 << 64 << 128;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sizes << fixed_size;
|
sizes << fixed_size;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
// Usage:
|
// Usage:
|
||||||
// Lazy<Foo> my_lazy_object([]() { return new Foo; });
|
// Lazy<Foo> my_lazy_object([]() { return new Foo; });
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
class Lazy {
|
class Lazy {
|
||||||
public:
|
public:
|
||||||
explicit Lazy(std::function<T*()> init) : init_(init) {}
|
explicit Lazy(std::function<T*()> init) : init_(init) {}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ namespace mac {
|
|||||||
void MacMain();
|
void MacMain();
|
||||||
void SetShortcutHandler(GlobalShortcutsBackendMacOS *handler);
|
void SetShortcutHandler(GlobalShortcutsBackendMacOS *handler);
|
||||||
void SetApplicationHandler(PlatformInterface *handler);
|
void SetApplicationHandler(PlatformInterface *handler);
|
||||||
void CheckForUpdates();
|
|
||||||
|
|
||||||
void EnableFullScreen(const QWidget &main_window);
|
void EnableFullScreen(const QWidget &main_window);
|
||||||
|
|
||||||
|
|||||||
@@ -55,10 +55,6 @@
|
|||||||
#include "globalshortcuts/globalshortcutsmanager.h"
|
#include "globalshortcuts/globalshortcutsmanager.h"
|
||||||
#include "globalshortcuts/globalshortcutsbackend-macos.h"
|
#include "globalshortcuts/globalshortcutsbackend-macos.h"
|
||||||
|
|
||||||
#ifdef HAVE_SPARKLE
|
|
||||||
# import <SUUpdater.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -71,7 +67,7 @@
|
|||||||
|
|
||||||
QDebug operator<<(QDebug dbg, NSObject *object) {
|
QDebug operator<<(QDebug dbg, NSObject *object) {
|
||||||
|
|
||||||
QString ns_format = [ [NSString stringWithFormat:@"%@", object] UTF8String];
|
QString ns_format = [[NSString stringWithFormat:@"%@", object] UTF8String];
|
||||||
dbg.nospace() << ns_format;
|
dbg.nospace() << ns_format;
|
||||||
return dbg.space();
|
return dbg.space();
|
||||||
|
|
||||||
@@ -153,11 +149,12 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
|
|||||||
|
|
||||||
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
|
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
|
||||||
|
|
||||||
key_tap_ = [ [SPMediaKeyTap alloc] initWithDelegate:self];
|
key_tap_ = [[SPMediaKeyTap alloc] initWithDelegate:self];
|
||||||
if ([SPMediaKeyTap usesGlobalMediaKeyTap]) {
|
if ([SPMediaKeyTap usesGlobalMediaKeyTap]) {
|
||||||
if ([key_tap_ startWatchingMediaKeys]) {
|
if ([key_tap_ startWatchingMediaKeys]) {
|
||||||
qLog(Debug) << "Media key monitoring started";
|
qLog(Debug) << "Media key monitoring started";
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
qLog(Warning) << "Failed to start media key monitoring";
|
qLog(Warning) << "Failed to start media key monitoring";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +182,7 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
|
|||||||
|
|
||||||
qLog(Debug) << "Wants to open:" << filenames;
|
qLog(Debug) << "Wants to open:" << filenames;
|
||||||
[filenames enumerateObjectsUsingBlock:^(id object, NSUInteger, BOOL*) {
|
[filenames enumerateObjectsUsingBlock:^(id object, NSUInteger, BOOL*) {
|
||||||
[self application:app openFile:(NSString*)object];
|
[self application:app openFile:reinterpret_cast<NSString*>(object)];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -258,7 +255,7 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
|
|||||||
|
|
||||||
- (void)SetApplicationHandler:(PlatformInterface*)handler {
|
- (void)SetApplicationHandler:(PlatformInterface*)handler {
|
||||||
|
|
||||||
delegate_ = [ [AppDelegate alloc] initWithHandler:handler];
|
delegate_ = [[AppDelegate alloc] initWithHandler:handler];
|
||||||
// App-shortcut-handler set before delegate is set.
|
// App-shortcut-handler set before delegate is set.
|
||||||
// this makes sure the delegate's shortcut_handler is set
|
// this makes sure the delegate's shortcut_handler is set
|
||||||
[delegate_ setShortcutHandler:shortcut_handler_];
|
[delegate_ setShortcutHandler:shortcut_handler_];
|
||||||
@@ -267,7 +264,7 @@ QDebug operator<<(QDebug dbg, NSObject *object) {
|
|||||||
// FIXME
|
// FIXME
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
[ [NSUserNotificationCenter defaultUserNotificationCenter]setDelegate:delegate_];
|
[[NSUserNotificationCenter defaultUserNotificationCenter]setDelegate:delegate_];
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -288,10 +285,6 @@ void MacMain() {
|
|||||||
ScopedNSAutoreleasePool pool;
|
ScopedNSAutoreleasePool pool;
|
||||||
// Creates and sets the magic global variable so QApplication will find it.
|
// Creates and sets the magic global variable so QApplication will find it.
|
||||||
[MacApplication sharedApplication];
|
[MacApplication sharedApplication];
|
||||||
#ifdef HAVE_SPARKLE
|
|
||||||
// Creates and sets the magic global variable for Sparkle.
|
|
||||||
[ [SUUpdater sharedUpdater] setDelegate:NSApp];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,12 +296,6 @@ void SetApplicationHandler(PlatformInterface *handler) {
|
|||||||
[NSApp SetApplicationHandler:handler];
|
[NSApp SetApplicationHandler:handler];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckForUpdates() {
|
|
||||||
#ifdef HAVE_SPARKLE
|
|
||||||
[ [SUUpdater sharedUpdater] checkForUpdates:NSApp];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int MapFunctionKey(int keycode) {
|
static int MapFunctionKey(int keycode) {
|
||||||
|
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
@@ -416,7 +403,7 @@ QKeySequence KeySequenceFromNSEvent(NSEvent *event) {
|
|||||||
|
|
||||||
void DumpDictionary(CFDictionaryRef dict) {
|
void DumpDictionary(CFDictionaryRef dict) {
|
||||||
|
|
||||||
NSDictionary *d = (NSDictionary*)dict;
|
NSDictionary *d = reinterpret_cast<NSDictionary*>(dict);
|
||||||
NSLog(@"%@", d);
|
NSLog(@"%@", d);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,6 @@
|
|||||||
#include "widgets/trackslider.h"
|
#include "widgets/trackslider.h"
|
||||||
#include "osd/osdbase.h"
|
#include "osd/osdbase.h"
|
||||||
#include "context/contextview.h"
|
#include "context/contextview.h"
|
||||||
#include "context/contextalbumsview.h"
|
|
||||||
#include "collection/collection.h"
|
#include "collection/collection.h"
|
||||||
#include "collection/collectionbackend.h"
|
#include "collection/collectionbackend.h"
|
||||||
#include "collection/collectiondirectorymodel.h"
|
#include "collection/collectiondirectorymodel.h"
|
||||||
@@ -221,6 +220,18 @@ const int kTrackSliderUpdateTimeMs = 200;
|
|||||||
const int kTrackPositionUpdateTimeMs = 1000;
|
const int kTrackPositionUpdateTimeMs = 1000;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
#ifdef HAVE_QTSPARKLE
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-msvc-x64";
|
||||||
|
# else
|
||||||
|
# ifdef __x86_64__
|
||||||
|
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-mingw-x64";
|
||||||
|
# else
|
||||||
|
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-mingw-x86";
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_icon, OSDBase *osd, const CommandlineOptions &options, QWidget *parent)
|
MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_icon, OSDBase *osd, const CommandlineOptions &options, QWidget *parent)
|
||||||
: QMainWindow(parent),
|
: QMainWindow(parent),
|
||||||
ui_(new Ui_MainWindow),
|
ui_(new Ui_MainWindow),
|
||||||
@@ -324,7 +335,8 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
hidden_(false),
|
hidden_(false),
|
||||||
exit_(false),
|
exit_(false),
|
||||||
exit_count_(0),
|
exit_count_(0),
|
||||||
delete_files_(false) {
|
delete_files_(false),
|
||||||
|
ignore_close_(false) {
|
||||||
|
|
||||||
qLog(Debug) << "Starting";
|
qLog(Debug) << "Starting";
|
||||||
|
|
||||||
@@ -334,6 +346,8 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
// Initialize the UI
|
// Initialize the UI
|
||||||
ui_->setupUi(this);
|
ui_->setupUi(this);
|
||||||
|
|
||||||
|
setWindowIcon(IconLoader::Load("strawberry"));
|
||||||
|
|
||||||
album_cover_choice_controller_->Init(app);
|
album_cover_choice_controller_->Init(app);
|
||||||
|
|
||||||
ui_->multi_loading_indicator->SetTaskManager(app_->task_manager());
|
ui_->multi_loading_indicator->SetTaskManager(app_->task_manager());
|
||||||
@@ -446,6 +460,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
ui_->action_remove_duplicates->setIcon(IconLoader::Load("list-remove"));
|
ui_->action_remove_duplicates->setIcon(IconLoader::Load("list-remove"));
|
||||||
ui_->action_remove_unavailable->setIcon(IconLoader::Load("list-remove"));
|
ui_->action_remove_unavailable->setIcon(IconLoader::Load("list-remove"));
|
||||||
ui_->action_remove_from_playlist->setIcon(IconLoader::Load("list-remove"));
|
ui_->action_remove_from_playlist->setIcon(IconLoader::Load("list-remove"));
|
||||||
|
ui_->action_save_all_playlists->setIcon(IconLoader::Load("document-save-all"));
|
||||||
|
|
||||||
// Configure
|
// Configure
|
||||||
|
|
||||||
@@ -476,9 +491,9 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
QObject::connect(file_view_, &FileView::CopyToCollection, this, &MainWindow::CopyFilesToCollection);
|
QObject::connect(file_view_, &FileView::CopyToCollection, this, &MainWindow::CopyFilesToCollection);
|
||||||
QObject::connect(file_view_, &FileView::MoveToCollection, this, &MainWindow::MoveFilesToCollection);
|
QObject::connect(file_view_, &FileView::MoveToCollection, this, &MainWindow::MoveFilesToCollection);
|
||||||
QObject::connect(file_view_, &FileView::EditTags, this, &MainWindow::EditFileTags);
|
QObject::connect(file_view_, &FileView::EditTags, this, &MainWindow::EditFileTags);
|
||||||
#ifndef Q_OS_WIN
|
# ifndef Q_OS_WIN
|
||||||
QObject::connect(file_view_, &FileView::CopyToDevice, this, &MainWindow::CopyFilesToDevice);
|
QObject::connect(file_view_, &FileView::CopyToDevice, this, &MainWindow::CopyFilesToDevice);
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
file_view_->SetTaskManager(app_->task_manager());
|
file_view_->SetTaskManager(app_->task_manager());
|
||||||
|
|
||||||
@@ -536,8 +551,8 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
QObject::connect(app_->scrobbler(), &AudioScrobbler::ErrorMessage, this, &MainWindow::ShowErrorDialog);
|
QObject::connect(app_->scrobbler(), &AudioScrobbler::ErrorMessage, this, &MainWindow::ShowErrorDialog);
|
||||||
|
|
||||||
// Playlist view actions
|
// Playlist view actions
|
||||||
ui_->action_next_playlist->setShortcuts(QList<QKeySequence>() << QKeySequence::fromString("Ctrl+Tab")<< QKeySequence::fromString("Ctrl+PgDown"));
|
ui_->action_next_playlist->setShortcuts(QList<QKeySequence>() << QKeySequence::fromString("Ctrl+Tab") << QKeySequence::fromString("Ctrl+PgDown"));
|
||||||
ui_->action_previous_playlist->setShortcuts(QList<QKeySequence>() << QKeySequence::fromString("Ctrl+Shift+Tab")<< QKeySequence::fromString("Ctrl+PgUp"));
|
ui_->action_previous_playlist->setShortcuts(QList<QKeySequence>() << QKeySequence::fromString("Ctrl+Shift+Tab") << QKeySequence::fromString("Ctrl+PgUp"));
|
||||||
|
|
||||||
// Actions for switching tabs will be global to the entire window, so adding them here
|
// Actions for switching tabs will be global to the entire window, so adding them here
|
||||||
addAction(ui_->action_next_playlist);
|
addAction(ui_->action_next_playlist);
|
||||||
@@ -551,8 +566,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
ui_->button_scrobble->setDefaultAction(ui_->action_toggle_scrobbling);
|
ui_->button_scrobble->setDefaultAction(ui_->action_toggle_scrobbling);
|
||||||
ui_->button_love->setDefaultAction(ui_->action_love);
|
ui_->button_love->setDefaultAction(ui_->action_love);
|
||||||
|
|
||||||
ui_->playlist->SetActions(ui_->action_new_playlist, ui_->action_load_playlist, ui_->action_save_playlist, ui_->action_clear_playlist, ui_->action_next_playlist, /* These two actions aren't associated */ ui_->action_previous_playlist /* to a button but to the main window */ );
|
ui_->playlist->SetActions(ui_->action_new_playlist, ui_->action_load_playlist, ui_->action_save_playlist, ui_->action_clear_playlist, ui_->action_next_playlist, /* These two actions aren't associated */ ui_->action_previous_playlist /* to a button but to the main window */, ui_->action_save_all_playlists);
|
||||||
|
|
||||||
// Add the shuffle and repeat action groups to the menu
|
// Add the shuffle and repeat action groups to the menu
|
||||||
ui_->action_shuffle_mode->setMenu(ui_->playlist_sequence->shuffle_menu());
|
ui_->action_shuffle_mode->setMenu(ui_->playlist_sequence->shuffle_menu());
|
||||||
ui_->action_repeat_mode->setMenu(ui_->playlist_sequence->repeat_menu());
|
ui_->action_repeat_mode->setMenu(ui_->playlist_sequence->repeat_menu());
|
||||||
@@ -680,7 +694,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
QObject::connect(tidal_view_->albums_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
QObject::connect(tidal_view_->albums_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
||||||
QObject::connect(tidal_view_->songs_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
QObject::connect(tidal_view_->songs_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
||||||
QObject::connect(tidal_view_->search_view(), &InternetSearchView::AddToPlaylist, this, &MainWindow::AddToPlaylist);
|
QObject::connect(tidal_view_->search_view(), &InternetSearchView::AddToPlaylist, this, &MainWindow::AddToPlaylist);
|
||||||
if (TidalService *tidalservice = qobject_cast<TidalService*> (app_->internet_services()->ServiceBySource(Song::Source_Tidal))) {
|
if (TidalService *tidalservice = qobject_cast<TidalService*>(app_->internet_services()->ServiceBySource(Song::Source_Tidal))) {
|
||||||
QObject::connect(this, &MainWindow::AuthorizationUrlReceived, tidalservice, &TidalService::AuthorizationUrlReceived);
|
QObject::connect(this, &MainWindow::AuthorizationUrlReceived, tidalservice, &TidalService::AuthorizationUrlReceived);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -779,10 +793,9 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
thumbbar_->SetActions(QList<QAction*>() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr << ui_->action_love);
|
thumbbar_->SetActions(QList<QAction*>() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr << ui_->action_love);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_SPARKLE) || defined(HAVE_QTSPARKLE)
|
#if defined(HAVE_QTSPARKLE)
|
||||||
QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
|
QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
|
||||||
check_updates->setMenuRole(QAction::ApplicationSpecificRole);
|
check_updates->setMenuRole(QAction::ApplicationSpecificRole);
|
||||||
QObject::connect(check_updates, &QAction::triggered, this, &MainWindow::CheckForUpdates);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GLOBALSHORTCUTS
|
#ifdef HAVE_GLOBALSHORTCUTS
|
||||||
@@ -819,7 +832,6 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
QObject::connect(this, &MainWindow::AlbumCoverReady, context_view_, &ContextView::AlbumCoverLoaded);
|
QObject::connect(this, &MainWindow::AlbumCoverReady, context_view_, &ContextView::AlbumCoverLoaded);
|
||||||
QObject::connect(this, &MainWindow::SearchCoverInProgress, context_view_->album_widget(), &ContextAlbum::SearchCoverInProgress);
|
QObject::connect(this, &MainWindow::SearchCoverInProgress, context_view_->album_widget(), &ContextAlbum::SearchCoverInProgress);
|
||||||
QObject::connect(context_view_, &ContextView::AlbumEnabledChanged, this, &MainWindow::TabSwitched);
|
QObject::connect(context_view_, &ContextView::AlbumEnabledChanged, this, &MainWindow::TabSwitched);
|
||||||
QObject::connect(context_view_->albums_widget(), &ContextAlbumsView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
|
||||||
|
|
||||||
// Analyzer
|
// Analyzer
|
||||||
QObject::connect(ui_->analyzer, &AnalyzerContainer::WheelEvent, this, &MainWindow::VolumeWheelEvent);
|
QObject::connect(ui_->analyzer, &AnalyzerContainer::WheelEvent, this, &MainWindow::VolumeWheelEvent);
|
||||||
@@ -949,7 +961,6 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
break;
|
break;
|
||||||
case BehaviourSettingsPage::Startup_Hide:
|
case BehaviourSettingsPage::Startup_Hide:
|
||||||
if (tray_icon_->IsSystemTrayAvailable() && tray_icon_->isVisible()) {
|
if (tray_icon_->IsSystemTrayAvailable() && tray_icon_->isVisible()) {
|
||||||
hide();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// fallthrough
|
// fallthrough
|
||||||
@@ -969,7 +980,9 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
hidden_ = settings_.value("hidden", false).toBool();
|
hidden_ = settings_.value("hidden", false).toBool();
|
||||||
setVisible(!hidden_);
|
if (!hidden_) {
|
||||||
|
show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1001,12 +1014,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_QTSPARKLE
|
#ifdef HAVE_QTSPARKLE
|
||||||
QUrl sparkle_url;
|
QUrl sparkle_url(QTSPARKLE_URL);
|
||||||
#if defined(Q_OS_MACOS)
|
|
||||||
sparkle_url.setUrl("https://www.strawberrymusicplayer.org/sparkle-macos");
|
|
||||||
#elif defined(Q_OS_WIN)
|
|
||||||
sparkle_url.setUrl("https://www.strawberrymusicplayer.org/sparkle-windows");
|
|
||||||
#endif
|
|
||||||
if (!sparkle_url.isEmpty()) {
|
if (!sparkle_url.isEmpty()) {
|
||||||
qLog(Debug) << "Creating Qt Sparkle updater";
|
qLog(Debug) << "Creating Qt Sparkle updater";
|
||||||
qtsparkle::Updater *updater = new qtsparkle::Updater(sparkle_url, this);
|
qtsparkle::Updater *updater = new qtsparkle::Updater(sparkle_url, this);
|
||||||
@@ -1216,7 +1224,8 @@ void MainWindow::Exit() {
|
|||||||
QObject::connect(app_->player()->engine(), &EngineBase::FadeoutFinishedSignal, this, &MainWindow::DoExit);
|
QObject::connect(app_->player()->engine(), &EngineBase::FadeoutFinishedSignal, this, &MainWindow::DoExit);
|
||||||
if (app_->player()->GetState() == Engine::Playing) {
|
if (app_->player()->GetState() == Engine::Playing) {
|
||||||
app_->player()->Stop();
|
app_->player()->Stop();
|
||||||
hide();
|
ignore_close_ = true;
|
||||||
|
close();
|
||||||
if (tray_icon_->IsSystemTrayAvailable()) {
|
if (tray_icon_->IsSystemTrayAvailable()) {
|
||||||
tray_icon_->setVisible(false);
|
tray_icon_->setVisible(false);
|
||||||
}
|
}
|
||||||
@@ -1245,11 +1254,11 @@ void MainWindow::ExitFinished() {
|
|||||||
void MainWindow::EngineChanged(Engine::EngineType enginetype) {
|
void MainWindow::EngineChanged(Engine::EngineType enginetype) {
|
||||||
|
|
||||||
ui_->action_equalizer->setEnabled(enginetype == Engine::EngineType::GStreamer);
|
ui_->action_equalizer->setEnabled(enginetype == Engine::EngineType::GStreamer);
|
||||||
#ifdef Q_OS_WIN
|
#if defined(HAVE_AUDIOCD) && !defined(Q_OS_WIN)
|
||||||
|
ui_->action_open_cd->setEnabled(enginetype == Engine::EngineType::GStreamer);
|
||||||
|
#else
|
||||||
ui_->action_open_cd->setEnabled(false);
|
ui_->action_open_cd->setEnabled(false);
|
||||||
ui_->action_open_cd->setVisible(false);
|
ui_->action_open_cd->setVisible(false);
|
||||||
#else
|
|
||||||
ui_->action_open_cd->setEnabled(enginetype == Engine::EngineType::GStreamer);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1544,16 +1553,13 @@ void MainWindow::VolumeWheelEvent(const int delta) {
|
|||||||
void MainWindow::ToggleShowHide() {
|
void MainWindow::ToggleShowHide() {
|
||||||
|
|
||||||
if (hidden_) {
|
if (hidden_) {
|
||||||
show();
|
|
||||||
SetHiddenInTray(false);
|
SetHiddenInTray(false);
|
||||||
}
|
}
|
||||||
else if (isActiveWindow()) {
|
else if (isActiveWindow()) {
|
||||||
hide();
|
|
||||||
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
||||||
SetHiddenInTray(true);
|
SetHiddenInTray(true);
|
||||||
}
|
}
|
||||||
else if (isMinimized()) {
|
else if (isMinimized()) {
|
||||||
hide();
|
|
||||||
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
||||||
SetHiddenInTray(false);
|
SetHiddenInTray(false);
|
||||||
}
|
}
|
||||||
@@ -1588,8 +1594,14 @@ void MainWindow::showEvent(QShowEvent *e) {
|
|||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *e) {
|
void MainWindow::closeEvent(QCloseEvent *e) {
|
||||||
|
|
||||||
|
if (ignore_close_) {
|
||||||
|
ignore_close_ = false;
|
||||||
|
QMainWindow::closeEvent(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!exit_) {
|
if (!exit_) {
|
||||||
if (!hidden_ && keep_running_ && e->spontaneous() && tray_icon_->IsSystemTrayAvailable()) {
|
if (!hidden_ && keep_running_ && tray_icon_->IsSystemTrayAvailable()) {
|
||||||
SetHiddenInTray(true);
|
SetHiddenInTray(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1610,7 +1622,8 @@ void MainWindow::SetHiddenInTray(const bool hidden) {
|
|||||||
if (hidden) {
|
if (hidden) {
|
||||||
was_maximized_ = isMaximized();
|
was_maximized_ = isMaximized();
|
||||||
was_minimized_ = isMinimized();
|
was_minimized_ = isMinimized();
|
||||||
hide();
|
ignore_close_ = true;
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (was_minimized_) {
|
if (was_minimized_) {
|
||||||
@@ -2184,7 +2197,7 @@ void MainWindow::AddFile() {
|
|||||||
PlaylistParser parser(app_->collection_backend());
|
PlaylistParser parser(app_->collection_backend());
|
||||||
|
|
||||||
// Show dialog
|
// Show dialog
|
||||||
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(), tr(kAllFilesFilterSpec)));
|
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(PlaylistParser::Type_Load), tr(kAllFilesFilterSpec)));
|
||||||
|
|
||||||
if (file_names.isEmpty()) return;
|
if (file_names.isEmpty()) return;
|
||||||
|
|
||||||
@@ -2275,7 +2288,7 @@ void MainWindow::PlaylistRemoveCurrent() {
|
|||||||
void MainWindow::PlaylistClearCurrent() {
|
void MainWindow::PlaylistClearCurrent() {
|
||||||
|
|
||||||
if (app_->playlist_manager()->current()->rowCount() > Playlist::kUndoItemLimit) {
|
if (app_->playlist_manager()->current()->rowCount() > Playlist::kUndoItemLimit) {
|
||||||
QMessageBox messagebox(QMessageBox::Warning, tr("Clear playlist"), tr("Playlist has %1 songs, too large to undo, are you sure you want to clear the playlist?").arg(app_->playlist_manager()->current()->rowCount()), QMessageBox::Ok|QMessageBox::Cancel);
|
QMessageBox messagebox(QMessageBox::Warning, tr("Clear playlist"), tr("Playlist has %1 songs, too large to undo, are you sure you want to clear the playlist?").arg(app_->playlist_manager()->current()->rowCount()), QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
messagebox.setTextFormat(Qt::RichText);
|
messagebox.setTextFormat(Qt::RichText);
|
||||||
int result = messagebox.exec();
|
int result = messagebox.exec();
|
||||||
switch (result) {
|
switch (result) {
|
||||||
@@ -2492,12 +2505,6 @@ bool MainWindow::LoadUrl(const QString &url) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::CheckForUpdates() {
|
|
||||||
#if defined(Q_OS_MACOS)
|
|
||||||
mac::CheckForUpdates();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::PlaylistUndoRedoChanged(QAction *undo, QAction *redo) {
|
void MainWindow::PlaylistUndoRedoChanged(QAction *undo, QAction *redo) {
|
||||||
|
|
||||||
playlist_menu_->insertAction(playlist_undoredo_, undo);
|
playlist_menu_->insertAction(playlist_undoredo_, undo);
|
||||||
@@ -2881,22 +2888,20 @@ void MainWindow::Raise() {
|
|||||||
show();
|
show();
|
||||||
activateWindow();
|
activateWindow();
|
||||||
hidden_ = false;
|
hidden_ = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) {
|
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) {
|
||||||
#else
|
# else
|
||||||
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) {
|
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) {
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
if (exit_count_ == 0 && message) {
|
if (exit_count_ == 0 && message) {
|
||||||
MSG *msg = static_cast<MSG*>(message);
|
MSG *msg = static_cast<MSG*>(message);
|
||||||
thumbbar_->HandleWinEvent(msg);
|
thumbbar_->HandleWinEvent(msg);
|
||||||
}
|
}
|
||||||
return QMainWindow::nativeEvent(eventType, message, result);
|
return QMainWindow::nativeEvent(eventType, message, result);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
@@ -3142,8 +3147,10 @@ void MainWindow::PlaylistDelete() {
|
|||||||
QModelIndex source_idx = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_idx);
|
QModelIndex source_idx = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_idx);
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
|
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
|
||||||
if (!item || !item->Metadata().url().isLocalFile()) continue;
|
if (!item || !item->Metadata().url().isLocalFile()) continue;
|
||||||
|
QString filename = item->Metadata().url().toLocalFile();
|
||||||
|
if (files.contains(filename)) continue;
|
||||||
selected_songs << item->Metadata();
|
selected_songs << item->Metadata();
|
||||||
files << item->Metadata().url().toLocalFile();
|
files << filename;
|
||||||
if (item == app_->player()->GetCurrentItem()) is_current_item = true;
|
if (item == app_->player()->GetCurrentItem()) is_current_item = true;
|
||||||
}
|
}
|
||||||
if (selected_songs.isEmpty()) return;
|
if (selected_songs.isEmpty()) return;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user