Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Multimedia
KMix
Commits
508c9c5d
Commit
508c9c5d
authored
Feb 10, 2021
by
Jonathan Marten
Browse files
GUIProfile: Port deprecated QXmlSimpleReader -> QXmlStreamReader
parent
c6d436f5
Changes
3
Hide whitespace changes
Inline
Side-by-side
gui/dialogviewconfiguration.cpp
View file @
508c9c5d
...
...
@@ -312,7 +312,6 @@ void DialogViewConfiguration::apply()
}
prof
->
setControls
(
newControlset
);
prof
->
finalizeProfile
();
prof
->
setDirty
();
// --- Step 3: Tell the view, that it has changed (probably it needs some "polishing" ---
...
...
gui/guiprofile.cpp
View file @
508c9c5d
...
...
@@ -24,15 +24,17 @@
#include <QDir>
#include <QSaveFile>
#include <QXmlStreamWriter>
#include <QXmlS
imple
Reader>
#include <QXmlS
tream
Reader>
#include <QStandardPaths>
// KMix
#include "core/mixer.h"
QMap
<
QString
,
GUIProfile
*>
s_profiles
;
const
QString
s_profileDir
(
"profiles"
);
#undef DEBUG_XMLREADER
static
QMap
<
QString
,
GUIProfile
*>
s_profiles
;
static
const
QString
s_profileDir
(
"profiles"
);
static
QString
visibilityToString
(
GuiVisibility
vis
)
...
...
@@ -322,8 +324,6 @@ GUIProfile* GUIProfile::fallbackProfile(const Mixer *mixer)
fallback
->
_soundcardDriver
=
mixer
->
getDriverName
();
fallback
->
_soundcardName
=
mixer
->
readableName
();
fallback
->
finalizeProfile
();
fallback
->
_mixerId
=
mixer
->
id
();
fallback
->
setId
(
fullQualifiedProfileName
);
// this one contains some soundcard id (basename + instance)
fallback
->
setName
(
buildReadableProfileName
(
mixer
,
QString
(
"default"
)));
// The caller can rename this if he likes
...
...
@@ -344,29 +344,61 @@ GUIProfile* GUIProfile::fallbackProfile(const Mixer *mixer)
/**
* Fill the profile with the data from the given XML profile file.
* @par
ref_
fileName: Full qualified filename (with path).
* @par fileName: Full qualified filename (with path).
* @return bool True, if the profile was successfully created. False if not (e.g. parsing error).
*/
bool
GUIProfile
::
readProfile
(
const
QString
&
ref_fileName
)
{
QXmlSimpleReader
xmlReader
;
qCDebug
(
KMIX_LOG
)
<<
"Read profile"
<<
ref_fileName
;
QFile
xmlFile
(
ref_fileName
);
QXmlInputSource
source
(
&
xmlFile
);
GUIProfileParser
gpp
(
this
);
xmlReader
.
setContentHandler
(
&
gpp
);
bool
ok
=
xmlReader
.
parse
(
source
);
//std::cout << "Raw Profile: " << *this;
if
(
ok
)
{
ok
=
finalizeProfile
();
}
// Read OK
else
{
// !! this error message about faulty profiles should probably be surrounded with i18n()
qCCritical
(
KMIX_LOG
)
<<
"ERROR: The profile"
<<
ref_fileName
<<
"contains errors, and cannot be used"
;
bool
GUIProfile
::
readProfile
(
const
QString
&
fileName
)
{
qCDebug
(
KMIX_LOG
)
<<
"reading"
<<
fileName
;
QFile
xmlFile
(
fileName
);
bool
ok
=
xmlFile
.
open
(
QIODevice
::
ReadOnly
);
if
(
ok
)
{
GUIProfileParser
gpp
(
this
);
QXmlStreamReader
reader
(
&
xmlFile
);
while
(
!
reader
.
atEnd
())
{
bool
startOk
=
reader
.
readNextStartElement
();
if
(
!
startOk
)
{
#ifdef DEBUG_XMLREADER
qCDebug
(
KMIX_LOG
)
<<
" no more start elements"
;
#endif
break
;
}
const
QString
&
name
=
reader
.
name
().
toString
().
toLower
();
const
QXmlStreamAttributes
attrs
=
reader
.
attributes
();
#ifdef DEBUG_XMLREADER
qCDebug
(
KMIX_LOG
)
<<
" element"
<<
name
<<
"has"
<<
attrs
.
count
()
<<
"attributes:"
;
for
(
const
QXmlStreamAttribute
&
attr
:
qAsConst
(
attrs
))
{
qCDebug
(
KMIX_LOG
)
<<
" "
<<
attr
.
name
()
<<
"="
<<
attr
.
value
();
}
#endif
if
(
name
==
"soundcard"
)
{
gpp
.
addSoundcard
(
attrs
);
continue
;
// then read contained elements
}
else
if
(
name
==
"control"
)
gpp
.
addControl
(
attrs
);
else
if
(
name
==
"product"
)
gpp
.
addProduct
(
attrs
);
else
if
(
name
==
"profile"
)
gpp
.
addProfileInfo
(
attrs
);
else
qCDebug
(
KMIX_LOG
)
<<
"Unknown XML tag"
<<
name
<<
"at line"
<<
reader
.
lineNumber
();
reader
.
skipCurrentElement
();
}
if
(
reader
.
hasError
())
{
qCWarning
(
KMIX_LOG
)
<<
"XML parse error at line"
<<
reader
.
lineNumber
()
<<
"-"
<<
reader
.
errorString
();
ok
=
false
;
}
}
return
ok
;
return
(
ok
)
;
}
...
...
@@ -425,9 +457,9 @@ bool GUIProfile::writeProfile()
// name= prd->productName
writer
.
writeAttribute
(
"name"
,
prd
->
productName
);
// release= prd->productRelease
if
(
!
prd
->
productRelease
.
is
Null
())
writer
.
writeAttribute
(
"release"
,
prd
->
productRelease
);
if
(
!
prd
->
productRelease
.
is
Empty
())
writer
.
writeAttribute
(
"release"
,
prd
->
productRelease
);
// comment= prd->comment
if
(
!
prd
->
comment
.
is
Null
())
writer
.
writeAttribute
(
"comment"
,
prd
->
comment
);
if
(
!
prd
->
comment
.
is
Empty
())
writer
.
writeAttribute
(
"comment"
,
prd
->
comment
);
// />
writer
.
writeEndElement
();
}
// for all products
...
...
@@ -440,7 +472,7 @@ bool GUIProfile::writeProfile()
writer
.
writeAttribute
(
"id"
,
profControl
->
id
());
// name= profControl->name()
const
QString
name
=
profControl
->
name
();
if
(
!
name
.
is
Null
()
&&
name
!=
profControl
->
id
())
writer
.
writeAttribute
(
"name"
,
name
);
if
(
!
name
.
is
Empty
()
&&
name
!=
profControl
->
id
())
writer
.
writeAttribute
(
"name"
,
name
);
// subcontrols= profControl->renderSubcontrols()
writer
.
writeAttribute
(
"subcontrols"
,
profControl
->
renderSubcontrols
());
// show= visibilityToString(profControl->getVisibility())
...
...
@@ -470,12 +502,6 @@ bool GUIProfile::writeProfile()
}
/** This is now empty. It can be removed */
bool
GUIProfile
::
finalizeProfile
()
const
{
return
(
true
);
}
// -------------------------------------------------------------------------------------
void
GUIProfile
::
setControls
(
ControlSet
&
newControlSet
)
...
...
@@ -681,205 +707,103 @@ QString ProfControl::renderSubcontrols() const
// ### PARSER START ################################################
GUIProfileParser
::
GUIProfileParser
(
GUIProfile
*
ref_gp
)
:
_guiProfile
(
ref_gp
)
GUIProfileParser
::
GUIProfileParser
(
GUIProfile
*
ref_gp
)
{
_scope
=
GUIProfileParser
::
NONE
;
// no scope yet
_guiProfile
=
ref_gp
;
}
bool
GUIProfileParser
::
startDocument
()
{
_scope
=
GUIProfileParser
::
NONE
;
// no scope yet
return
true
;
}
bool
GUIProfileParser
::
startElement
(
const
QString
&
,
const
QString
&
,
const
QString
&
qName
,
const
QXmlAttributes
&
attributes
)
void
GUIProfileParser
::
addSoundcard
(
const
QXmlStreamAttributes
&
attributes
)
{
switch
(
_scope
)
{
case
GUIProfileParser
::
NONE
:
/** we are reading the "top level" ***************************/
if
(
qName
.
toLower
()
==
"soundcard"
)
{
_scope
=
GUIProfileParser
::
SOUNDCARD
;
addSoundcard
(
attributes
);
}
else
{
// skip unknown top-level nodes
qCWarning
(
KMIX_LOG
)
<<
"Ignoring unsupported element"
<<
qName
;
}
// we are accepting <soundcard> only
break
;
case
GUIProfileParser
::
SOUNDCARD
:
if
(
qName
.
toLower
()
==
"product"
)
{
// Defines product names under which the chipset/hardware is sold
addProduct
(
attributes
);
}
else
if
(
qName
.
toLower
()
==
"control"
)
{
addControl
(
attributes
);
}
else
if
(
qName
.
toLower
()
==
"profile"
)
{
addProfileInfo
(
attributes
);
}
else
{
qCWarning
(
KMIX_LOG
)
<<
"Ignoring unsupported element"
<<
qName
;
}
// we are accepting <product>, <control> and <tab>
const
QString
driver
=
attributes
.
value
(
"driver"
).
toString
();
const
QString
version
=
attributes
.
value
(
"version"
).
toString
();
const
QString
name
=
attributes
.
value
(
"name"
).
toString
();
const
QString
type
=
attributes
.
value
(
"type"
).
toString
();
const
QString
generation
=
attributes
.
value
(
"generation"
).
toString
();
break
;
// Adding a card makes only sense if we have at least
// the driver and product name.
if
(
driver
.
isEmpty
()
||
name
.
isEmpty
()
)
return
;
}
// switch()
return
tru
e
;
}
_guiProfile
->
_soundcardDriver
=
driver
;
_guiProfile
->
_soundcardName
=
nam
e
;
_guiProfile
->
_soundcardType
=
type
;
bool
GUIProfileParser
::
endElement
(
const
QString
&
,
const
QString
&
,
const
QString
&
qName
)
{
if
(
qName
==
"soundcard"
)
{
_scope
=
GUIProfileParser
::
NONE
;
// should work out OK, as we don't nest soundcard entries
}
return
true
;
}
void
GUIProfileParser
::
addSoundcard
(
const
QXmlAttributes
&
attributes
)
{
/*
std::cout << "Soundcard: ";
printAttributes(attributes);
*/
QString
driver
=
attributes
.
value
(
"driver"
);
QString
version
=
attributes
.
value
(
"version"
);
QString
name
=
attributes
.
value
(
"name"
);
QString
type
=
attributes
.
value
(
"type"
);
QString
generation
=
attributes
.
value
(
"generation"
);
if
(
!
driver
.
isNull
()
&&
!
name
.
isNull
()
)
{
_guiProfile
->
_soundcardDriver
=
driver
;
_guiProfile
->
_soundcardName
=
name
;
if
(
type
.
isNull
()
)
{
_guiProfile
->
_soundcardType
=
""
;
}
else
{
_guiProfile
->
_soundcardType
=
type
;
}
if
(
version
.
isNull
()
)
{
_guiProfile
->
_driverVersionMin
=
0
;
_guiProfile
->
_driverVersionMax
=
0
;
}
else
{
std
::
pair
<
QString
,
QString
>
versionMinMax
;
splitPair
(
version
,
versionMinMax
,
':'
);
_guiProfile
->
_driverVersionMin
=
versionMinMax
.
first
.
toULong
();
_guiProfile
->
_driverVersionMax
=
versionMinMax
.
second
.
toULong
();
}
if
(
type
.
isNull
()
)
{
type
=
""
;
};
if
(
generation
.
isNull
()
)
{
_guiProfile
->
_generation
=
0
;
}
else
{
// Hint: If the conversion fails, _generation will be assigned 0 (which is fine)
_guiProfile
->
_generation
=
generation
.
toUInt
();
}
}
if
(
version
.
isEmpty
())
{
_guiProfile
->
_driverVersionMin
=
0
;
_guiProfile
->
_driverVersionMax
=
0
;
}
else
{
const
QStringList
versionMinMax
=
version
.
split
(
':'
,
Qt
::
KeepEmptyParts
);
_guiProfile
->
_driverVersionMin
=
versionMinMax
.
value
(
0
).
toULong
();
_guiProfile
->
_driverVersionMax
=
versionMinMax
.
value
(
1
).
toULong
();
}
_guiProfile
->
_generation
=
generation
.
toUInt
();
}
void
GUIProfileParser
::
addProfileInfo
(
const
QXmlAttributes
&
attributes
)
{
QString
name
=
attributes
.
value
(
"name"
);
QString
id
=
attributes
.
value
(
"id"
);
void
GUIProfileParser
::
addProfileInfo
(
const
QXmlStreamAttributes
&
attributes
)
{
const
QString
name
=
attributes
.
value
(
"name"
)
.
toString
()
;
const
QString
id
=
attributes
.
value
(
"id"
)
.
toString
()
;
_guiProfile
->
setId
(
id
);
_guiProfile
->
setName
(
name
);
}
void
GUIProfileParser
::
addProduct
(
const
QXmlAttributes
&
attributes
)
{
/*
std::cout << "Product: ";
printAttributes(attributes);
*/
QString
vendor
=
attributes
.
value
(
"vendor"
);
QString
name
=
attributes
.
value
(
"name"
);
QString
release
=
attributes
.
value
(
"release"
);
QString
comment
=
attributes
.
value
(
"comment"
);
if
(
!
vendor
.
isNull
()
&&
!
name
.
isNull
()
)
{
// Adding a product makes only sense if we have at least vendor and product name
ProfProduct
*
prd
=
new
ProfProduct
();
prd
->
vendor
=
vendor
;
prd
->
productName
=
name
;
prd
->
productRelease
=
release
;
prd
->
comment
=
comment
;
_guiProfile
->
addProduct
(
prd
);
}
}
void
GUIProfileParser
::
addControl
(
const
QXmlAttributes
&
attributes
)
{
/*
std::cout << "Control: ";
printAttributes(attributes);
*/
QString
id
=
attributes
.
value
(
"id"
);
QString
subcontrols
=
attributes
.
value
(
"subcontrols"
);
QString
name
=
attributes
.
value
(
"name"
);
QString
show
=
attributes
.
value
(
"show"
);
QString
background
=
attributes
.
value
(
"background"
);
QString
switchtype
=
attributes
.
value
(
"switchtype"
);
QString
mandatory
=
attributes
.
value
(
"mandatory"
);
QString
split
=
attributes
.
value
(
"split"
);
bool
isMandatory
=
false
;
if
(
!
id
.
isNull
()
)
{
// We need at least an "id". We can set defaults for the rest, if undefined.
if
(
subcontrols
.
isNull
()
||
subcontrols
.
isEmpty
()
)
{
subcontrols
=
'*'
;
// for compatibility reasons, we interpret an empty string as match-all (aka "*")
}
if
(
name
.
isNull
()
)
{
// ignore. isNull() will be checked by all users.
}
if
(
!
mandatory
.
isNull
()
&&
mandatory
==
"true"
)
{
isMandatory
=
true
;
}
if
(
!
background
.
isNull
()
)
{
// ignore. isNull() will be checked by all users.
}
if
(
!
switchtype
.
isNull
()
)
{
// ignore. isNull() will be checked by all users.
}
void
GUIProfileParser
::
addProduct
(
const
QXmlStreamAttributes
&
attributes
)
{
const
QString
vendor
=
attributes
.
value
(
"vendor"
).
toString
();
const
QString
name
=
attributes
.
value
(
"name"
).
toString
();
const
QString
release
=
attributes
.
value
(
"release"
).
toString
();
const
QString
comment
=
attributes
.
value
(
"comment"
).
toString
();
ProfControl
*
profControl
=
new
ProfControl
(
id
,
subcontrols
);
// Adding a product makes only sense if we have at least
// the vendor and product name.
if
(
vendor
.
isEmpty
()
||
name
.
isEmpty
())
return
;
profControl
->
setName
(
name
);
profControl
->
setVisibility
(
show
.
isNull
()
?
"all"
:
show
);
profControl
->
setBackgroundColor
(
background
);
profControl
->
setSwitchtype
(
switchtype
);
profControl
->
setMandatory
(
isMandatory
);
if
(
split
==
"true"
)
profControl
->
setSplit
(
true
);
ProfProduct
*
prd
=
new
ProfProduct
();
prd
->
vendor
=
vendor
;
prd
->
productName
=
name
;
prd
->
productRelease
=
release
;
prd
->
comment
=
comment
;
_guiProfile
->
addControl
(
profControl
);
}
// id != null
_guiProfile
->
addProduct
(
prd
);
}
void
GUIProfileParser
::
printAttributes
(
const
QXmlAttributes
&
attributes
)
{
if
(
attributes
.
length
()
>
0
)
{
for
(
int
i
=
0
;
i
<
attributes
.
length
();
i
++
)
{
qCDebug
(
KMIX_LOG
)
<<
i
<<
attributes
.
qName
(
i
)
<<
"="
<<
attributes
.
value
(
i
);
}
}
}
void
GUIProfileParser
::
splitPair
(
const
QString
&
pairString
,
std
::
pair
<
QString
,
QString
>&
result
,
char
delim
)
void
GUIProfileParser
::
addControl
(
const
QXmlStreamAttributes
&
attributes
)
{
int
delimPos
=
pairString
.
indexOf
(
delim
);
if
(
delimPos
==
-
1
)
{
// delimiter not found => use an empty String for "second"
result
.
first
=
pairString
;
result
.
second
=
""
;
}
else
{
// delimiter found
result
.
first
=
pairString
.
mid
(
0
,
delimPos
);
result
.
second
=
pairString
.
left
(
delimPos
+
1
);
}
const
QString
id
=
attributes
.
value
(
"id"
).
toString
();
const
QString
subcontrols
=
attributes
.
value
(
"subcontrols"
).
toString
();
const
QString
name
=
attributes
.
value
(
"name"
).
toString
();
const
QString
show
=
attributes
.
value
(
"show"
).
toString
();
const
QString
background
=
attributes
.
value
(
"background"
).
toString
();
const
QString
switchtype
=
attributes
.
value
(
"switchtype"
).
toString
();
const
QString
mandatory
=
attributes
.
value
(
"mandatory"
).
toString
();
const
QString
split
=
attributes
.
value
(
"split"
).
toString
();
// We need at least an "id". We can set defaults for the rest, if undefined.
if
(
id
.
isEmpty
())
return
;
// ignore whether 'name' is null, will be checked by all users.
bool
isMandatory
=
(
mandatory
==
"true"
);
// ignore whether 'background' is null, will be checked by all users.
// ignore whether 'switchtype' is null, will be checked by all users.
// For compatibility reasons, we interpret an empty string as match-all (aka "*")
ProfControl
*
profControl
=
new
ProfControl
(
id
,
(
subcontrols
.
isEmpty
()
?
"*"
:
subcontrols
));
profControl
->
setName
(
name
);
profControl
->
setVisibility
(
show
.
isEmpty
()
?
"all"
:
show
);
profControl
->
setBackgroundColor
(
background
);
profControl
->
setSwitchtype
(
switchtype
);
profControl
->
setMandatory
(
isMandatory
);
if
(
split
==
"true"
)
profControl
->
setSplit
(
true
);
_guiProfile
->
addControl
(
profControl
);
}
gui/guiprofile.h
View file @
508c9c5d
...
...
@@ -18,21 +18,17 @@
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef
_
GUIPROFILE_
H
_
#define
_
GUIPROFILE_
H
_
#ifndef GUIPROFILE__
H
#define GUIPROFILE__
H
class
Mixer
;
#include <qstring.h>
#include <qlist.h>
#include
"kmix_debug.h"
#include
<set>
#include <qxml.h>
#include <QColor>
#include <QTextStream>
#include <QString>
#include <string>
#include <set>
#include <ostream>
class
Mixer
;
class
QXmlStreamAttributes
;
struct
ProfProduct
...
...
@@ -125,7 +121,7 @@ private:
// For applying custom colors
QString
_backgroundColor
;
// For defining the switch type when it is not a standard p
a
lyback or capture switch
// For defining the switch type when it is not a standard pl
a
yback or capture switch
QString
_switchtype
;
// show or hide (contains the GUI type: simple, extended, all)
...
...
@@ -149,17 +145,16 @@ struct ProductComparator
class
GUIProfile
{
public:
typedef
std
::
set
<
ProfProduct
*
,
ProductComparator
>
ProductSet
;
typedef
QList
<
ProfControl
*>
ControlSet
;
typedef
std
::
set
<
ProfProduct
*
,
ProductComparator
>
ProductSet
;
typedef
QList
<
ProfControl
*>
ControlSet
;
public:
GUIProfile
();
~
GUIProfile
();
bool
readProfile
(
const
QString
&
ref_fileNamestring
);
bool
finalizeProfile
()
const
;
bool
readProfile
(
const
QString
&
fileName
);
bool
writeProfile
();
bool
isDirty
()
const
{
return
(
_dirty
);
}
void
setDirty
()
{
_dirty
=
true
;
}
...
...
@@ -204,27 +199,18 @@ private:
};
class
GUIProfileParser
:
public
QXmlDefaultHandler
class
GUIProfileParser
{
public:
explicit
GUIProfileParser
(
GUIProfile
*
ref_gp
);
// Enumeration for the scope
enum
ProfileScope
{
NONE
,
SOUNDCARD
};
bool
startDocument
()
override
;
bool
startElement
(
const
QString
&
,
const
QString
&
,
const
QString
&
,
const
QXmlAttributes
&
)
override
;
bool
endElement
(
const
QString
&
,
const
QString
&
,
const
QString
&
)
override
;
explicit
GUIProfileParser
(
GUIProfile
*
ref_gp
);
void
addControl
(
const
QXmlStreamAttributes
&
attributes
);
void
addProduct
(
const
QXmlStreamAttributes
&
attributes
);
void
addSoundcard
(
const
QXmlStreamAttributes
&
attributes
);
void
addProfileInfo
(
const
QXmlStreamAttributes
&
attributes
);
private:
void
addControl
(
const
QXmlAttributes
&
attributes
);
void
addProduct
(
const
QXmlAttributes
&
attributes
);
void
addSoundcard
(
const
QXmlAttributes
&
attributes
);
void
addProfileInfo
(
const
QXmlAttributes
&
attributes
);
void
printAttributes
(
const
QXmlAttributes
&
attributes
);
void
splitPair
(
const
QString
&
pairString
,
std
::
pair
<
QString
,
QString
>&
result
,
char
delim
);
ProfileScope
_scope
;
GUIProfile
*
_guiProfile
;
GUIProfile
*
_guiProfile
;
};
#endif //
_
GUIPROFILE_
H
_
#endif //
GUIPROFILE__
H
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment