Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
OpenBoard
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lifo
Nicolas Ollinger
OpenBoard
Commits
9ae7c579
Commit
9ae7c579
authored
Oct 01, 2012
by
Aleksei Kanash
Browse files
Options
Browse Files
Download
Plain Diff
Merged Import from CFF and export to CFF fixes.
parents
5872c093
b49a01d9
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
448 additions
and
104 deletions
+448
-104
UBCFFAdaptor.cpp
plugins/cffadaptor/src/UBCFFAdaptor.cpp
+45
-6
UBCFFAdaptor.h
plugins/cffadaptor/src/UBCFFAdaptor.h
+1
-1
UBCFFConstants.h
plugins/cffadaptor/src/UBCFFConstants.h
+7
-3
UBCFFSubsetAdaptor.cpp
src/adaptors/UBCFFSubsetAdaptor.cpp
+233
-59
UBCFFSubsetAdaptor.h
src/adaptors/UBCFFSubsetAdaptor.h
+2
-1
UBSvgSubsetAdaptor.cpp
src/adaptors/UBSvgSubsetAdaptor.cpp
+147
-33
UBSvgSubsetAdaptor.h
src/adaptors/UBSvgSubsetAdaptor.h
+1
-0
UBGraphicsPolygonItem.cpp
src/domain/UBGraphicsPolygonItem.cpp
+7
-0
UBGraphicsPolygonItem.h
src/domain/UBGraphicsPolygonItem.h
+2
-0
UBGraphicsScene.cpp
src/domain/UBGraphicsScene.cpp
+1
-0
UBGraphicsScene.h
src/domain/UBGraphicsScene.h
+2
-1
No files found.
plugins/cffadaptor/src/UBCFFAdaptor.cpp
View file @
9ae7c579
...
...
@@ -550,8 +550,8 @@ QDomElement UBCFFAdaptor::UBToCFFConverter::parsePage(const QString &pageFileNam
pageFile
.
close
();
return
QDomElement
();
}
}
else
if
(
tagname
==
tUBZGroup
)
{
group
=
parseGroupPageSection
(
nextTopElement
);
}
else
if
(
tagname
==
tUBZGroup
s
)
{
group
=
parseGroup
s
PageSection
(
nextTopElement
);
if
(
group
.
isNull
())
{
qDebug
()
<<
"Page doesn't contains any groups."
;
pageFile
.
close
();
...
...
@@ -634,6 +634,7 @@ QDomElement UBCFFAdaptor::UBToCFFConverter::parseSvgPageSection(const QDomElemen
else
if
(
tagName
==
tUBZLine
)
parseUBZLine
(
nextElement
,
svgElements
);
else
if
(
tagName
==
tUBZPolygon
)
parseUBZPolygon
(
nextElement
,
svgElements
);
else
if
(
tagName
==
tUBZPolyline
)
parseUBZPolyline
(
nextElement
,
svgElements
);
else
if
(
tagName
==
tUBZGroups
)
parseGroupsPageSection
(
nextElement
);
nextElement
=
nextElement
.
nextSiblingElement
();
}
...
...
@@ -694,12 +695,34 @@ bool UBCFFAdaptor::UBToCFFConverter::writeExtendedIwbSection()
// extended element options
// editable, background, locked are supported for now
QDomElement
UBCFFAdaptor
::
UBToCFFConverter
::
parseGroup
PageSection
(
const
QDomElement
&
elemen
t
)
QDomElement
UBCFFAdaptor
::
UBToCFFConverter
::
parseGroup
sPageSection
(
const
QDomElement
&
groupRoo
t
)
{
// First sankore side implementation needed. TODO in Sankore 1.5
Q_UNUSED
(
element
)
qDebug
()
<<
"parsing ubz group section
"
;
if
(
!
groupRoot
.
hasChildNodes
())
{
qDebug
()
<<
"Group root is empty
"
;
return
QDomElement
();
}
QDomElement
groupElement
=
groupRoot
.
firstChildElement
();
while
(
!
groupElement
.
isNull
())
{
QDomElement
extendedElement
=
mDataModel
->
createElementNS
(
iwbNS
,
groupElement
.
tagName
());
QDomElement
groupChildElement
=
groupElement
.
firstChildElement
();
while
(
!
groupChildElement
.
isNull
())
{
QDomElement
extSubElement
=
mDataModel
->
createElementNS
(
iwbNS
,
groupChildElement
.
tagName
());
extSubElement
.
setAttribute
(
aRef
,
groupChildElement
.
attribute
(
aID
,
QUuid
().
toString
()));
extendedElement
.
appendChild
(
extSubElement
);
groupChildElement
=
groupChildElement
.
nextSiblingElement
();
}
mExtendedElements
.
append
(
extendedElement
);
groupElement
=
groupElement
.
nextSiblingElement
();
}
qDebug
()
<<
"parsing ubz group section"
;
return
groupRoot
;
}
QString
UBCFFAdaptor
::
UBToCFFConverter
::
getDstContentFolderName
(
const
QString
&
elementType
)
...
...
@@ -1250,6 +1273,19 @@ bool UBCFFAdaptor::UBToCFFConverter::setCFFAttribute(const QString &attributeNam
{
setGeometryFromUBZ
(
ubzElement
,
svgElement
);
}
else
if
(
attributeName
.
contains
(
aUBZUuid
))
{
QString
parentId
=
ubzElement
.
attribute
(
aUBZParent
);
QString
id
;
if
(
!
parentId
.
isEmpty
())
id
=
"{"
+
parentId
+
"}"
+
"{"
+
ubzElement
.
attribute
(
aUBZUuid
)
+
"}"
;
else
id
=
"{"
+
ubzElement
.
attribute
(
aUBZUuid
)
+
"}"
;
svgElement
.
setAttribute
(
aID
,
id
);
}
else
if
(
attributeName
.
contains
(
aUBZHref
)
||
attributeName
.
contains
(
aSrc
))
{
...
...
@@ -1799,7 +1835,10 @@ bool UBCFFAdaptor::UBToCFFConverter::parseUBZPolygon(const QDomElement &element,
if
(
0
<
iwbElementPart
.
attributes
().
count
())
{
QString
id
=
QUuid
::
createUuid
().
toString
();
QString
id
=
svgElementPart
.
attribute
(
aUBZUuid
);
if
(
id
.
isEmpty
())
id
=
QUuid
::
createUuid
().
toString
();
svgElementPart
.
setAttribute
(
aID
,
id
);
iwbElementPart
.
setAttribute
(
aRef
,
id
);
...
...
plugins/cffadaptor/src/UBCFFAdaptor.h
View file @
9ae7c579
...
...
@@ -63,7 +63,7 @@ private:
QDomElement
parseSvgPageSection
(
const
QDomElement
&
element
);
void
writeQDomElementToXML
(
const
QDomNode
&
node
);
bool
writeExtendedIwbSection
();
QDomElement
parseGroup
PageSection
(
const
QDomElement
&
elemen
t
);
QDomElement
parseGroup
sPageSection
(
const
QDomElement
&
groupRoo
t
);
bool
createBackground
(
const
QDomElement
&
element
,
QMultiMap
<
int
,
QDomElement
>
&
dstSvgList
);
QString
createBackgroundImage
(
const
QDomElement
&
element
,
QSize
size
);
...
...
plugins/cffadaptor/src/UBCFFConstants.h
View file @
9ae7c579
...
...
@@ -28,6 +28,7 @@ const QString tIWBPageSet = "pageset";
const
QString
tId
=
"id"
;
const
QString
tElement
=
"element"
;
const
QString
tUBZGroup
=
"group"
;
const
QString
tUBZGroups
=
"groups"
;
const
QString
tUBZG
=
"g"
;
const
QString
tUBZPolygon
=
"polygon"
;
const
QString
tUBZPolyline
=
"polyline"
;
...
...
@@ -67,6 +68,7 @@ const QString aBackground = "background";
const
QString
aCrossedBackground
=
"crossed-background"
;
const
QString
aUBZType
=
"type"
;
const
QString
aUBZUuid
=
"uuid"
;
const
QString
aUBZParent
=
"parent"
;
const
QString
aFill
=
"fill"
;
// IWB attribute contans color to fill
const
QString
aID
=
"id"
;
// ID of any svg element can be placed in to iwb section
...
...
@@ -334,8 +336,10 @@ stroke-lineshape-end \
const
QString
ubzElementAttributesToConvert
(
" \
xlink:href, \
src, \
transform \
"
);
transform, \
uuid \
"
);
// additional attributes. Have references in SVG section.
const
QString
svgElementAttributes
(
" \
...
...
src/adaptors/UBCFFSubsetAdaptor.cpp
View file @
9ae7c579
...
...
@@ -16,6 +16,7 @@
#include <QSvgGenerator>
#include <QSvgRenderer>
#include <QPixmap>
#include <QMap>
#include "core/UBPersistenceManager.h"
...
...
@@ -248,6 +249,11 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &elem
painter
.
end
();
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
svgItem
->
setUuid
(
QUuid
(
uuid
));
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -298,6 +304,11 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgEllipse(const QDomElement &e
painter
.
end
();
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
svgItem
->
setUuid
(
QUuid
(
uuid
));
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -373,6 +384,30 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
brush
.
setColor
(
fillColor
);
brush
.
setStyle
(
Qt
::
SolidPattern
);
QUuid
itemUuid
(
element
.
attribute
(
aId
).
right
(
QUuid
().
toString
().
length
()));
QUuid
itemGroupUuid
(
element
.
attribute
(
aId
).
left
(
QUuid
().
toString
().
length
()
-
1
));
if
(
!
itemUuid
.
isNull
()
&&
(
itemGroupUuid
!=
itemUuid
))
// reimported from UBZ
{
UBGraphicsPolygonItem
*
graphicsPolygon
=
mCurrentScene
->
polygonToPolygonItem
(
polygon
);
graphicsPolygon
->
setBrush
(
brush
);
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
graphicsPolygon
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
,
graphicsPolygon
);
}
mCurrentScene
->
addItem
(
graphicsPolygon
);
graphicsPolygon
->
setUuid
(
itemUuid
);
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
itemUuid
);
}
else
// single CFF
{
QSvgGenerator
*
generator
=
createSvgGenerator
(
width
+
pen
.
width
(),
height
+
pen
.
width
());
QPainter
painter
;
...
...
@@ -390,6 +425,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QUuid
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
svgItem
->
setUuid
(
uuid
);
svgItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
,
svgItem
);
...
...
@@ -403,7 +442,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
}
delete
generator
;
}
return
true
;
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvgPolyline
(
const
QDomElement
&
element
)
...
...
@@ -441,6 +480,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
//bounding rect lef top corner coordinates
qreal
x1
=
polygon
.
boundingRect
().
topLeft
().
x
();
qreal
y1
=
polygon
.
boundingRect
().
topLeft
().
y
();
//bounding rect dimensions
qreal
width
=
polygon
.
boundingRect
().
width
();
qreal
height
=
polygon
.
boundingRect
().
height
();
...
...
@@ -458,19 +498,54 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
pen
.
setColor
(
strokeColor
);
pen
.
setWidth
(
strokeWidth
);
QBrush
brush
;
brush
.
setColor
(
strokeColor
);
brush
.
setStyle
(
Qt
::
SolidPattern
);
QUuid
itemUuid
(
element
.
attribute
(
aId
).
right
(
QUuid
().
toString
().
length
()));
QUuid
itemGroupUuid
(
element
.
attribute
(
aId
).
left
(
QUuid
().
toString
().
length
()
-
1
));
if
(
!
itemUuid
.
isNull
()
&&
(
itemGroupUuid
!=
itemUuid
))
// reimported from UBZ
{
UBGraphicsPolygonItem
*
graphicsPolygon
=
new
UBGraphicsPolygonItem
(
polygon
);
UBGraphicsStroke
*
stroke
=
new
UBGraphicsStroke
();
graphicsPolygon
->
setStroke
(
stroke
);
graphicsPolygon
->
setBrush
(
brush
);
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
graphicsPolygon
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
,
graphicsPolygon
);
}
mCurrentScene
->
addItem
(
graphicsPolygon
);
graphicsPolygon
->
setUuid
(
itemUuid
);
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
itemUuid
);
}
else
// simple CFF
{
QSvgGenerator
*
generator
=
createSvgGenerator
(
width
+
pen
.
width
(),
height
+
pen
.
width
());
QPainter
painter
;
painter
.
begin
(
generator
);
//drawing to svg tmp file
painter
.
translate
(
pen
.
widthF
()
/
2
-
x1
,
pen
.
widthF
()
/
2
-
y1
);
painter
.
translate
(
pen
.
widthF
()
/
2
-
x1
,
pen
.
widthF
()
/
2
-
y1
);
painter
.
setBrush
(
brush
);
painter
.
setPen
(
pen
);
painter
.
drawPolyline
(
polygon
);
painter
.
drawPolygon
(
polygon
);
painter
.
end
();
//add resulting svg file to scene
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
svgItem
->
setUuid
(
QUuid
(
uuid
));
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -478,7 +553,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
,
svgItem
);
}
repositionSvgItem
(
svgItem
,
width
+
strokeWidth
,
height
+
strokeWidth
,
x1
+
transform
.
m31
()
-
strokeWidth
/
2
,
y1
+
transform
.
m32
()
+
strokeWidth
/
2
,
transform
);
repositionSvgItem
(
svgItem
,
width
+
strokeWidth
,
height
+
strokeWidth
,
x1
-
strokeWidth
/
2
+
transform
.
m31
(),
y1
+
strokeWidth
/
2
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
svgItem
);
if
(
mGSectionContainer
)
...
...
@@ -487,6 +562,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
}
delete
generator
;
}
return
true
;
}
...
...
@@ -621,6 +698,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &elem
//add resulting svg file to scene
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
svgItem
->
setUuid
(
QUuid
(
uuid
));
svgItem
->
resetTransform
();
repositionSvgItem
(
svgItem
,
width
,
height
,
x
+
transform
.
m31
(),
y
+
transform
.
m32
(),
transform
);
hashSceneItem
(
element
,
svgItem
);
...
...
@@ -734,6 +815,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &
UBGraphicsTextItem
*
svgItem
=
mCurrentScene
->
addTextHtml
(
doc
.
toHtml
());
svgItem
->
resize
(
width
,
height
);
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
svgItem
->
setUuid
(
QUuid
(
uuid
));
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -783,6 +868,11 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgImage(const QDomElement &ele
}
UBGraphicsPixmapItem
*
pixItem
=
mCurrentScene
->
addPixmap
(
pix
,
NULL
);
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
pixItem
->
setUuid
(
QUuid
(
uuid
));
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -830,6 +920,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &ele
UBGraphicsWidgetItem
*
flashItem
=
mCurrentScene
->
addW3CWidget
(
QUrl
::
fromLocalFile
(
flashUrl
));
flashItem
->
setSourceUrl
(
urlPath
);
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
flashItem
->
setUuid
(
QUuid
(
uuid
));
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -867,14 +961,15 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgAudio(const QDomElement &ele
concreteUrl
=
QUrl
::
fromLocalFile
(
audioPath
);
}
QUuid
uuid
=
QUuid
::
createUuid
();
QString
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
QString
destFile
;
bool
b
=
UBPersistenceManager
::
persistenceManager
()
->
addFileToDocument
(
mCurrentScene
->
document
(),
concreteUrl
.
toLocalFile
(),
UBPersistenceManager
::
audioDirectory
,
uuid
,
QUuid
(
uuid
)
,
destFile
);
if
(
!
b
)
{
...
...
@@ -883,6 +978,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgAudio(const QDomElement &ele
concreteUrl
=
QUrl
::
fromLocalFile
(
destFile
);
UBGraphicsMediaItem
*
audioItem
=
mCurrentScene
->
addAudio
(
concreteUrl
,
false
);
QTransform
transform
;
QString
textTransform
=
parentOfAudio
.
attribute
(
aTransform
);
...
...
@@ -920,15 +1016,15 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &ele
concreteUrl
=
QUrl
::
fromLocalFile
(
videoPath
);
}
Q
Uuid
uuid
=
QUuid
::
createUuid
();
Q
String
uuid
=
QUuid
::
createUuid
().
toString
();
mRefToUuidMap
.
insert
(
element
.
attribute
(
aId
),
uuid
);
QString
destFile
;
bool
b
=
UBPersistenceManager
::
persistenceManager
()
->
addFileToDocument
(
mCurrentScene
->
document
(),
concreteUrl
.
toLocalFile
(),
UBPersistenceManager
::
videoDirectory
,
uuid
,
QUuid
(
uuid
)
,
destFile
);
if
(
!
b
)
{
...
...
@@ -937,6 +1033,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &ele
concreteUrl
=
QUrl
::
fromLocalFile
(
destFile
);
UBGraphicsMediaItem
*
videoItem
=
mCurrentScene
->
addVideo
(
concreteUrl
,
false
);
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
...
...
@@ -980,8 +1077,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &p
{
QString
tagName
=
parent
.
tagName
();
if
(
parent
.
namespaceURI
()
!=
svgNS
)
{
q
Debu
g
()
<<
"Incorrect namespace, error at content file, line number"
<<
parent
.
lineNumber
();
return
false
;
q
Warnin
g
()
<<
"Incorrect namespace, error at content file, line number"
<<
parent
.
lineNumber
();
//
return false;
}
if
(
tagName
==
tG
&&
!
parseGSection
(
parent
))
return
false
;
...
...
@@ -1027,8 +1124,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPageset(const QDomElement &p
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseIwbMeta
(
const
QDomElement
&
element
)
{
if
(
element
.
namespaceURI
()
!=
iwbNS
)
{
q
Debu
g
()
<<
"incorrect meta namespace, incorrect document"
;
return
false
;
q
Warnin
g
()
<<
"incorrect meta namespace, incorrect document"
;
//
return false;
}
return
true
;
...
...
@@ -1036,8 +1133,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbMeta(const QDomElement &elem
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvg
(
const
QDomElement
&
svgSection
)
{
if
(
svgSection
.
namespaceURI
()
!=
svgNS
)
{
q
Debu
g
()
<<
"incorrect svg namespace, incorrect document"
;
return
false
;
q
Warnin
g
()
<<
"incorrect svg namespace, incorrect document"
;
//
return false;
}
parseSvgSectionAttr
(
svgSection
);
...
...
@@ -1052,15 +1149,92 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvg(const QDomElement &svgSecti
return
true
;
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseIwbGroup
(
QDomElement
&
parent
)
UBGraphicsGroupContainerItem
*
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseIwbGroup
(
QDomElement
&
parent
)
{
//TODO. Create groups from elements parsed by parseIwbElement() function
if
(
parent
.
namespaceURI
()
!=
iwbNS
)
{
q
Debu
g
()
<<
"incorrect iwb group namespace, incorrect document"
;
return
false
;
q
Warnin
g
()
<<
"incorrect iwb group namespace, incorrect document"
;
//
return false;
}
return
true
;
UBGraphicsGroupContainerItem
*
group
=
new
UBGraphicsGroupContainerItem
();
QMultiMap
<
QString
,
UBGraphicsPolygonItem
*>
strokesGroupsContainer
;
QList
<
QGraphicsItem
*>
groupContainer
;
QString
currentStrokeIdentifier
;
QDomElement
currentStrokeElement
=
parent
.
firstChildElement
();
while
(
!
currentStrokeElement
.
isNull
())
{
if
(
tGroup
==
currentStrokeElement
.
tagName
())
group
->
addToGroup
(
parseIwbGroup
(
currentStrokeElement
));
else
{
QString
ref
=
currentStrokeElement
.
attribute
(
aRef
);
QString
uuid
=
mRefToUuidMap
[
ref
];
if
(
!
uuid
.
isEmpty
())
{
if
(
ref
.
size
()
>
QUuid
().
toString
().
length
())
// create stroke group
{
currentStrokeIdentifier
=
ref
.
left
(
QUuid
().
toString
().
length
()
-
1
);
UBGraphicsPolygonItem
*
strokeByUuid
=
qgraphicsitem_cast
<
UBGraphicsPolygonItem
*>
(
mCurrentScene
->
itemForUuid
(
QUuid
(
ref
.
right
(
QUuid
().
toString
().
length
()))));
if
(
strokeByUuid
)
strokesGroupsContainer
.
insert
(
currentStrokeIdentifier
,
strokeByUuid
);
}
else
// single elements in group
groupContainer
.
append
(
mCurrentScene
->
itemForUuid
(
QUuid
(
uuid
)));
}
}
currentStrokeElement
=
currentStrokeElement
.
nextSiblingElement
();
}
foreach
(
QString
key
,
strokesGroupsContainer
.
keys
().
toSet
())
{
UBGraphicsStrokesGroup
*
pStrokesGroup
=
new
UBGraphicsStrokesGroup
();
UBGraphicsStroke
*
currentStroke
=
new
UBGraphicsStroke
();
foreach
(
UBGraphicsPolygonItem
*
poly
,
strokesGroupsContainer
.
values
(
key
))
{
if
(
poly
)
{
mCurrentScene
->
removeItem
(
poly
);
mCurrentScene
->
removeItemFromDeletion
(
poly
);
poly
->
setStrokesGroup
(
pStrokesGroup
);
poly
->
setStroke
(
currentStroke
);
pStrokesGroup
->
addToGroup
(
poly
);
}
}
if
(
currentStroke
->
polygons
().
empty
())
delete
currentStroke
;
if
(
pStrokesGroup
->
childItems
().
count
())
mCurrentScene
->
addItem
(
pStrokesGroup
);
else
delete
pStrokesGroup
;
if
(
pStrokesGroup
)
{
QGraphicsItem
*
strokeGroup
=
qgraphicsitem_cast
<
QGraphicsItem
*>
(
pStrokesGroup
);
groupContainer
.
append
(
strokeGroup
);
}
}
foreach
(
QGraphicsItem
*
item
,
groupContainer
)
group
->
addToGroup
(
item
);
if
(
group
->
childItems
().
count
())
{
mCurrentScene
->
addItem
(
group
);
if
(
1
==
group
->
childItems
().
count
())
{
group
->
destroy
(
false
);
}
}
return
group
;
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
strToBool
(
QString
str
)
...
...
@@ -1071,8 +1245,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::strToBool(QString str)
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseIwbElement
(
QDomElement
&
element
)
{
if
(
element
.
namespaceURI
()
!=
iwbNS
)
{
q
Debu
g
()
<<
"incorrect iwb element namespace, incorrect document"
;
return
false
;
q
Warnin
g
()
<<
"incorrect iwb element namespace, incorrect document"
;
//
return false;
}
bool
locked
=
false
;
...
...
src/adaptors/UBCFFSubsetAdaptor.h
View file @
9ae7c579
...
...
@@ -74,6 +74,7 @@ private:
QDomDocument
mDOMdoc
;
QDomNode
mCurrentDOMElement
;
QHash
<
QString
,
UBGraphicsItem
*>
persistedItems
;
QMap
<
QString
,
QString
>
mRefToUuidMap
;
QDir
mTmpFlashDir
;
void
addItemToGSection
(
QGraphicsItem
*
item
);
...
...
@@ -102,7 +103,7 @@ private:
inline
bool
parseSvgFlash
(
const
QDomElement
&
element
);
inline
bool
parseSvgAudio
(
const
QDomElement
&
element
);
inline
bool
parseSvgVideo
(
const
QDomElement
&
element
);
inline
bool
parseIwbGroup
(
QDomElement
&
parent
);
inline
UBGraphicsGroupContainerItem
*
parseIwbGroup
(
QDomElement
&
parent
);
inline
bool
parseIwbElement
(
QDomElement
&
element
);
inline
void
parseTSpan
(
const
QDomElement
&
parent
,
QPainter
&
painter
,
qreal
&
curX
,
qreal
&
curY
,
qreal
&
width
,
qreal
&
height
,
qreal
&
linespacing
,
QRectF
&
lastDrawnTextBoundingRect
...
...
src/adaptors/UBSvgSubsetAdaptor.cpp
View file @
9ae7c579
...
...
@@ -48,6 +48,7 @@
#include "frameworks/UBFileSystemUtils.h"
#include "frameworks/UBStringUtils.h"
#include "frameworks/UBFileSystemUtils.h"
#include "core/UBSettings.h"
#include "core/UBSetting.h"
...
...
@@ -79,6 +80,7 @@ const QString UBSvgSubsetAdaptor::sFormerUniboardDocumentNamespaceUri = "http://
const
QString
tElement
=
"element"
;
const
QString
tGroup
=
"group"
;
const
QString
tStrokeGroup
=
"strokeGroup"
;
const
QString
tGroups
=
"groups"
;
const
QString
aId
=
"id"
;
...
...
@@ -553,6 +555,10 @@ UBGraphicsScene* UBSvgSubsetAdaptor::UBSvgSubsetReader::loadScene()
if
(
polygonItem
)
{
mScene
->
addItem
(
polygonItem
);
polygonItem
->
setUuid
(
uuidFromSvg
);
if
(
annotationGroup
)
{
polygonItem
->
setStroke
(
annotationGroup
);
...
...
@@ -989,31 +995,45 @@ UBGraphicsScene* UBSvgSubsetAdaptor::UBSvgSubsetReader::loadScene()
UBGraphicsGroupContainerItem
*
UBSvgSubsetAdaptor
::
UBSvgSubsetReader
::
readGroup
()
{
UBGraphicsGroupContainerItem
*
result
=
new
UBGraphicsGroupContainerItem
();
UBGraphicsGroupContainerItem
*
group
=
new
UBGraphicsGroupContainerItem
();
QMultiMap
<
QString
,
UBGraphicsPolygonItem
*>
strokesGroupsContainer
;
QList
<
QGraphicsItem
*>
groupContainer
;
QString
currentStrokeIdentifier
;
QUuid
groupUuid
=
QUuid
(
mXmlReader
.
attributes
().
value
(
aId
).
toString
());
mXmlReader
.
readNext
();
while
(
!
mXmlReader
.
atEnd
())
{
while
(
!
mXmlReader
.
atEnd
())
{
if
(
mXmlReader
.
isEndElement
())
{
mXmlReader
.
readNext
();
result
->
setUuid
(
groupUuid
);
if
(
!
result
->
childItems
().
count
())
{
delete
result
;
result
=
0
;
}
break
;
}
else
if
(
mXmlReader
.
isStartElement
())
{
if
(
mXmlReader
.
name
()
==
tGroup
)
{
}
else
if
(
mXmlReader
.
isStartElement
())
{
if
(
mXmlReader
.
name
()
==
tGroup
)
{
qDebug
()
<<
"came across the group id is"
<<
mXmlReader
.
attributes
().
value
(
aId
);
UBGraphicsGroupContainerItem
*
curGroup
=
readGroup
();
if
(
curGroup
)
{
result
->
addToGroup
(
curGroup
);
if
(
curGroup
)
groupContainer
.
append
(
curGroup
);
}
}
else
if
(
mXmlReader
.
name
()
==
tElement
)
{
else
if
(
mXmlReader
.
name
()
==
tElement
)
{
QString
id
=
mXmlReader
.
attributes
().
value
(
aId
).
toString
();
QString
itemId
=
id
.
right
(
QUuid
().
toString
().
size
());
QString
groupId
=
id
.
left
(
QUuid
().
toString
().
size
());
QGraphicsItem
*
curItem
=
readElementFromGroup
();
if
(
curItem
)
{
result
->
addToGroup
(
curItem
);
UBGraphicsPolygonItem
*
curPolygon
=
qgraphicsitem_cast
<
UBGraphicsPolygonItem
*>
(
curItem
);
if
(
curPolygon
&&
!
groupId
.
isEmpty
()
&&
!
itemId
.
isEmpty
()
&&
itemId
!=
groupId
)
{
strokesGroupsContainer
.
insert
(
groupId
,
curPolygon
);
}
else
// item
{
groupContainer
.
append
(
curItem
);
}
}
else
{
mXmlReader
.
skipCurrentElement
();
...
...
@@ -1023,7 +1043,49 @@ UBGraphicsGroupContainerItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::readGroup()
}
}
return
result
;
foreach
(
QString
key
,
strokesGroupsContainer
.
keys
().
toSet
())
{
UBGraphicsStrokesGroup
*
pStrokesGroup
=
new
UBGraphicsStrokesGroup
();
UBGraphicsStroke
*
currentStroke
=
new
UBGraphicsStroke
();
foreach
(
UBGraphicsPolygonItem
*
poly
,
strokesGroupsContainer
.
values
(
key
))
{
if
(
poly
)
{
mScene
->
removeItem
(
poly
);
mScene
->
removeItemFromDeletion
(
poly
);
poly
->
setStrokesGroup
(
pStrokesGroup
);
poly
->
setStroke
(
currentStroke
);
pStrokesGroup
->
addToGroup
(
poly
);
}
}
if
(
currentStroke
->
polygons
().
empty
())
delete
currentStroke
;
if
(
pStrokesGroup
->
childItems
().
count
())
mScene
->
addItem
(
pStrokesGroup
);
else
delete
pStrokesGroup
;
if
(
pStrokesGroup
)
{
QGraphicsItem
*
strokeGroup
=
qgraphicsitem_cast
<
QGraphicsItem
*>
(
pStrokesGroup
);
groupContainer
.
append
(
strokeGroup
);
}
}
foreach
(
QGraphicsItem
*
item
,
groupContainer
)
group
->
addToGroup
(
item
);
if
(
group
->
childItems
().
count
())
{
mScene
->
addItem
(
group
);
if
(
1
==
group
->
childItems
().
count
())
{
group
->
destroy
(
false
);
}
}
return
group
;
}
void
UBSvgSubsetAdaptor
::
UBSvgSubsetReader
::
readGroupRoot
()
...
...
@@ -1051,8 +1113,9 @@ void UBSvgSubsetAdaptor::UBSvgSubsetReader::readGroupRoot()
QGraphicsItem
*
UBSvgSubsetAdaptor
::
UBSvgSubsetReader
::
readElementFromGroup
()
{
QGraphicsItem
*
result
=
0
;
result
=
mScene
->
itemForUuid
(
QUuid
(
mXmlReader
.
attributes
().
value
(
aId
).
toString
()));
QString
id
=
mXmlReader
.
attributes
().
value
(
aId
).
toString
();
QString
uuid
=
id
.
right
(
QUuid
().
toString
().
size
());
result
=
mScene
->
itemForUuid
(
QUuid
(
uuid
));
mXmlReader
.
skipCurrentElement
();
mXmlReader
.
readNext
();
...
...
@@ -1152,10 +1215,20 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(int pageIndex)
QGraphicsItem
*
item
=
items
.
takeFirst
();
// Is the item a strokes group?
UBGraphicsStrokesGroup
*
strokesGroupItem
=
qgraphicsitem_cast
<
UBGraphicsStrokesGroup
*>
(
item
);
if
(
strokesGroupItem
&&
strokesGroupItem
->
isVisible
()){
mXmlWriter
.
writeStartElement
(
"g"
);
mXmlWriter
.
writeAttribute
(
UBSettings
::
uniboardDocumentNamespaceUri
,
"uuid"
,
UBStringUtils
::
toCanonicalUuid
(
strokesGroupItem
->
uuid
()));
QDomElement
newGroupElement
;
if
(
!
strokesGroupItem
->
parentItem
()
&&
strokesGroupItem
->
childItems
().
count
())
{
newGroupElement
=
groupDomDocument
.
createElement
(
tGroup
);
newGroupElement
.
setAttribute
(
aId
,
strokesGroupItem
->
uuid
().
toString
());
groupRoot
.
appendChild
(
newGroupElement
);
}
//disabling g section parsing as a group of elements. Use groups refs instead
// mXmlWriter.writeStartElement("g");
// mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "uuid", UBStringUtils::toCanonicalUuid(strokesGroupItem->uuid()));
QMatrix
matrix
=
item
->
sceneMatrix
();
if
(
!
matrix
.
isIdentity
()){
mXmlWriter
.
writeAttribute
(
"transform"
,
toSvgTransform
(
matrix
));
...
...
@@ -1163,14 +1236,21 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(int pageIndex)
// Add the polygons
foreach
(
QGraphicsItem
*
item
,
strokesGroupItem
->
childItems
()){
UBGraphicsPolygonItem
*
poly
=
qgraphicsitem_cast
<
UBGraphicsPolygonItem
*>
(
item
);
if
(
NULL
!=
poly
){
polygonItemToSvgPolygon
(
poly
,
true
);
if
(
!
newGroupElement
.
isNull
())
{
QDomElement
curPolygonElement
=
groupDomDocument
.
createElement
(
tElement
);
curPolygonElement
.
setAttribute
(
aId
,
strokesGroupItem
->
uuid
().
toString
()
+
poly
->
uuid
().
toString
());
newGroupElement
.
appendChild
(
curPolygonElement
);
}
items
.
removeOne
(
poly
);
}
}
mXmlWriter
.
writeEndElement
();
//g
//
mXmlWriter.writeEndElement(); //g
}
// Is the item a polygon?
...
...
@@ -1401,12 +1481,12 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(int pageIndex)
QDomElement
curElement
=
groupRoot
.
firstChildElement
();
while
(
!
curElement
.
isNull
())
{
if
(
curElement
.
hasAttribute
(
aId
))
{
mXmlWriter
.
writeStartElement
(
tGroup
);
mXmlWriter
.
writeStartElement
(
curElement
.
tagName
()
);
mXmlWriter
.
writeAttribute
(
aId
,
curElement
.
attribute
(
aId
));
QDomElement
curSubElement
=
curElement
.
firstChildElement
();
while
(
!
curSubElement
.
isNull
())
{
if
(
curSubElement
.
hasAttribute
(
aId
))
{
mXmlWriter
.
writeStartElement
(
tElement
);
mXmlWriter
.
writeStartElement
(
curSubElement
.
tagName
()
);
mXmlWriter
.
writeAttribute
(
aId
,
curSubElement
.
attribute
(
aId
));
mXmlWriter
.
writeEndElement
();
curSubElement
=
curSubElement
.
nextSiblingElement
();
...
...
@@ -1454,8 +1534,16 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistGroupToDom(QGraphicsItem *gro
if
(
!
tmpUuid
.
isNull
())
{
if
(
item
->
type
()
==
UBGraphicsGroupContainerItem
::
Type
&&
item
->
childItems
().
count
())
{
persistGroupToDom
(
item
,
curParent
,
groupDomDocument
);
}
else
if
(
item
->
type
()
==
UBGraphicsStrokesGroup
::
Type
)
{
foreach
(
QGraphicsItem
*
polygonItem
,
item
->
childItems
())
{
QDomElement
curPolygonElement
=
groupDomDocument
->
createElement
(
tElement
);
curPolygonElement
.
setAttribute
(
aId
,
tmpUuid
.
toString
()
+
UBGraphicsItem
::
getOwnUuid
(
polygonItem
).
toString
());
curGroupElement
.
appendChild
(
curPolygonElement
);
}
}
else
{
QDomElement
curSubElement
=
groupDomDocument
->
createElement
(
tGroup
);
QDomElement
curSubElement
=
groupDomDocument
->
createElement
(
tElement
);
curSubElement
.
setAttribute
(
aId
,
tmpUuid
);
curGroupElement
.
appendChild
(
curSubElement
);
}
...
...
@@ -1464,6 +1552,27 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistGroupToDom(QGraphicsItem *gro
}
}
void
UBSvgSubsetAdaptor
::
UBSvgSubsetWriter
::
persistStrokeToDom
(
QGraphicsItem
*
strokeItem
,
QDomElement
*
curParent
,
QDomDocument
*
curDomDocument
)
{
QUuid
uuid
=
UBGraphicsScene
::
getPersonalUuid
(
strokeItem
);
if
(
!
uuid
.
isNull
())
{
QDomElement
curStrokesGroupElement
=
curDomDocument
->
createElement
(
tStrokeGroup
);
curStrokesGroupElement
.
setAttribute
(
aId
,
uuid
);
curParent
->
appendChild
(
curStrokesGroupElement
);
foreach
(
QGraphicsItem
*
item
,
strokeItem
->
childItems
())
{
QUuid
tmpUuid
=
UBGraphicsScene
::
getPersonalUuid
(
item
);
if
(
!
tmpUuid
.
isNull
())
{
if
(
item
->
type
()
==
UBGraphicsPolygonItem
::
Type
&&
item
->
childItems
().
count
())
{
QDomElement
curSubElement
=
curDomDocument
->
createElement
(
tElement
);
curSubElement
.
setAttribute
(
aId
,
tmpUuid
);
curStrokesGroupElement
.
appendChild
(
curSubElement
);
}
}
}
}
}
void
UBSvgSubsetAdaptor
::
UBSvgSubsetWriter
::
polygonItemToSvgLine
(
UBGraphicsPolygonItem
*
polygonItem
,
bool
groupHoldsInfo
)
{
mXmlWriter
.
writeStartElement
(
"line"
);
...
...
@@ -1615,6 +1724,11 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::polygonItemToSvgPolygon(UBGraphicsPo
,
"fill-on-light-background"
,
polygonItem
->
colorOnLightBackground
().
name
());
}
mXmlWriter
.
writeAttribute
(
UBSettings
::
uniboardDocumentNamespaceUri
,
"uuid"
,
UBStringUtils
::
toCanonicalUuid
(
polygonItem
->
uuid
()));
if
(
polygonItem
->
parentItem
())
{
mXmlWriter
.
writeAttribute
(
UBSettings
::
uniboardDocumentNamespaceUri
,
"parent"
,
UBStringUtils
::
toCanonicalUuid
(
UBGraphicsItem
::
getOwnUuid
(
polygonItem
->
parentItem
())));
}
mXmlWriter
.
writeEndElement
();
}
}
...
...
src/adaptors/UBSvgSubsetAdaptor.h
View file @
9ae7c579
...
...
@@ -179,6 +179,7 @@ class UBSvgSubsetAdaptor
private
:
void
persistGroupToDom
(
QGraphicsItem
*
groupItem
,
QDomElement
*
curParent
,
QDomDocument
*
curDomDocument
);
void
persistStrokeToDom
(
QGraphicsItem
*
strokeItem
,
QDomElement
*
curParent
,
QDomDocument
*
curDomDocument
);
void
polygonItemToSvgPolygon
(
UBGraphicsPolygonItem
*
polygonItem
,
bool
groupHoldsInfo
);
void
polygonItemToSvgLine
(
UBGraphicsPolygonItem
*
polygonItem
,
bool
groupHoldsInfo
);
void
strokeToSvgPolyline
(
UBGraphicsStroke
*
stroke
,
bool
groupHoldsInfo
);
...
...
src/domain/UBGraphicsPolygonItem.cpp
View file @
9ae7c579
...
...
@@ -60,6 +60,13 @@ UBGraphicsPolygonItem::UBGraphicsPolygonItem (const QLineF& pLine, qreal pWidth)
void
UBGraphicsPolygonItem
::
initialize
()
{
setData
(
UBGraphicsItemData
::
itemLayerType
,
QVariant
(
itemLayerType
::
DrawingItem
));
//Necessary to set if we want z value to be assigned correctly
setUuid
(
QUuid
::
createUuid
());
}
void
UBGraphicsPolygonItem
::
setUuid
(
const
QUuid
&
pUuid
)
{
UBItem
::
setUuid
(
pUuid
);
setData
(
UBGraphicsItemData
::
ItemUuid
,
QVariant
(
pUuid
));
//store item uuid inside the QGraphicsItem to fast operations with Items on the scene
}
void
UBGraphicsPolygonItem
::
clearStroke
()
...
...
src/domain/UBGraphicsPolygonItem.h
View file @
9ae7c579
...
...
@@ -39,6 +39,8 @@ class UBGraphicsPolygonItem : public QGraphicsPolygonItem, public UBItem
void
initialize
();
void
setUuid
(
const
QUuid
&
pUuid
);
void
setStrokesGroup
(
UBGraphicsStrokesGroup
*
group
);
UBGraphicsStrokesGroup
*
strokesGroup
()
const
{
return
mpGroup
;}
void
setColor
(
const
QColor
&
color
);
...
...
src/domain/UBGraphicsScene.cpp
View file @
9ae7c579
...
...
@@ -1713,6 +1713,7 @@ QRectF UBGraphicsScene::normalizedSceneRect(qreal ratio)
QGraphicsItem
*
UBGraphicsScene
::
itemForUuid
(
QUuid
uuid
)
{
QGraphicsItem
*
result
=
0
;
QString
ui
=
uuid
.
toString
();
//simple search before implementing container for fast access
foreach
(
QGraphicsItem
*
item
,
items
())
{
...
...
src/domain/UBGraphicsScene.h
View file @
9ae7c579
...
...
@@ -302,6 +302,8 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem
static
QUuid
getPersonalUuid
(
QGraphicsItem
*
item
);
UBGraphicsPolygonItem
*
polygonToPolygonItem
(
const
QPolygonF
pPolygon
);
public
slots
:
void
initStroke
();
void
hideEraser
();
...
...
@@ -338,7 +340,6 @@ public slots:
UBGraphicsPolygonItem
*
lineToPolygonItem
(
const
QLineF
&
pLine
,
const
qreal
&
pWidth
);
UBGraphicsPolygonItem
*
arcToPolygonItem
(
const
QLineF
&
pStartRadius
,
qreal
pSpanAngle
,
qreal
pWidth
);
UBGraphicsPolygonItem
*
polygonToPolygonItem
(
const
QPolygonF
pPolygon
);
void
initPolygonItem
(
UBGraphicsPolygonItem
*
);
...
...
Write
Preview
Markdown
is supported
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