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
973e1df2
Commit
973e1df2
authored
Apr 25, 2012
by
Ivan Ilin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CFF import fixes
parent
0e7ba267
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
199 additions
and
116 deletions
+199
-116
UBCFFSubsetAdaptor.cpp
src/adaptors/UBCFFSubsetAdaptor.cpp
+192
-113
UBCFFSubsetAdaptor.h
src/adaptors/UBCFFSubsetAdaptor.h
+5
-2
UBSvgSubsetAdaptor.cpp
src/adaptors/UBSvgSubsetAdaptor.cpp
+2
-1
No files found.
src/adaptors/UBCFFSubsetAdaptor.cpp
View file @
973e1df2
...
@@ -54,6 +54,8 @@ static QString tIwb = "iwb";
...
@@ -54,6 +54,8 @@ static QString tIwb = "iwb";
static
QString
tMeta
=
"meta"
;
static
QString
tMeta
=
"meta"
;
static
QString
tPage
=
"page"
;
static
QString
tPage
=
"page"
;
static
QString
tPageset
=
"pageset"
;
static
QString
tPageset
=
"pageset"
;
static
QString
tG
=
"g"
;
static
QString
tSwitch
=
"switch"
;
static
QString
tPolygon
=
"polygon"
;
static
QString
tPolygon
=
"polygon"
;
static
QString
tPolyline
=
"polyline"
;
static
QString
tPolyline
=
"polyline"
;
static
QString
tRect
=
"rect"
;
static
QString
tRect
=
"rect"
;
...
@@ -64,7 +66,7 @@ static QString tTspan = "tspan";
...
@@ -64,7 +66,7 @@ static QString tTspan = "tspan";
static
QString
tBreak
=
"tbreak"
;
static
QString
tBreak
=
"tbreak"
;
static
QString
tImage
=
"image"
;
static
QString
tImage
=
"image"
;
static
QString
tFlash
=
"flash"
;
static
QString
tFlash
=
"flash"
;
static
QString
tAudio
=
"a
udio
"
;
static
QString
tAudio
=
"a"
;
static
QString
tVideo
=
"video"
;
static
QString
tVideo
=
"video"
;
//attribute names definition
//attribute names definition
...
@@ -163,6 +165,31 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parse()
...
@@ -163,6 +165,31 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parse()
return
result
;
return
result
;
}
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseGSection
(
const
QDomElement
&
element
)
{
QDomElement
currentSvgElement
=
element
.
firstChildElement
();
while
(
!
currentSvgElement
.
isNull
())
{
if
(
!
parseSvgElement
(
currentSvgElement
))
return
false
;
currentSvgElement
=
currentSvgElement
.
nextSiblingElement
();
}
return
true
;
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvgSwitchSection
(
const
QDomElement
&
element
)
{
QDomElement
currentSvgElement
=
element
.
firstChildElement
();
while
(
!
currentSvgElement
.
isNull
())
{
if
(
parseSvgElement
(
currentSvgElement
))
return
true
;
}
return
false
;
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvgRect
(
const
QDomElement
&
element
)
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvgRect
(
const
QDomElement
&
element
)
{
{
qreal
x1
=
element
.
attribute
(
aX
).
toDouble
();
qreal
x1
=
element
.
attribute
(
aX
).
toDouble
();
...
@@ -177,7 +204,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &elem
...
@@ -177,7 +204,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &elem
QColor
fillColor
=
!
textFillColor
.
isNull
()
?
colorFromString
(
textFillColor
)
:
QColor
();
QColor
fillColor
=
!
textFillColor
.
isNull
()
?
colorFromString
(
textFillColor
)
:
QColor
();
QColor
strokeColor
=
!
textStrokeColor
.
isNull
()
?
colorFromString
(
textStrokeColor
)
:
QColor
();
QColor
strokeColor
=
!
textStrokeColor
.
isNull
()
?
colorFromString
(
textStrokeColor
)
:
QColor
();
int
strokeWidth
=
!
textStrokeWidth
.
isNull
()
?
textStrokeWidth
.
toInt
()
:
0
;
int
strokeWidth
=
textStrokeWidth
.
toInt
();
x1
-=
strokeWidth
/
2
;
y1
-=
strokeWidth
/
2
;
width
+=
strokeWidth
;
height
+=
strokeWidth
;
//init svg generator with temp file
//init svg generator with temp file
QSvgGenerator
*
generator
=
createSvgGenerator
(
width
,
height
);
QSvgGenerator
*
generator
=
createSvgGenerator
(
width
,
height
);
...
@@ -206,13 +238,13 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &elem
...
@@ -206,13 +238,13 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &elem
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
svgItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
svgItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
svgItem
,
width
,
height
,
x1
,
y1
,
hastransform
,
transform
);
repositionSvgItem
(
svgItem
,
width
,
height
,
x1
,
y1
,
transform
);
hashSceneItem
(
element
,
svgItem
);
hashSceneItem
(
element
,
svgItem
);
delete
generator
;
delete
generator
;
...
@@ -251,13 +283,14 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgEllipse(const QDomElement &e
...
@@ -251,13 +283,14 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgEllipse(const QDomElement &e
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
svgItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
svgItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
svgItem
,
rx
*
2
,
ry
*
2
,
cx
-
rx
,
cy
-
ry
,
hastransform
,
transform
);
repositionSvgItem
(
svgItem
,
rx
*
2
,
ry
*
2
,
cx
-
2
*
rx
,
cy
+
ry
,
transform
);
hashSceneItem
(
element
,
svgItem
);
hashSceneItem
(
element
,
svgItem
);
delete
generator
;
delete
generator
;
...
@@ -308,7 +341,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
...
@@ -308,7 +341,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
QColor
strokeColor
=
!
strokeColorText
.
isEmpty
()
?
colorFromString
(
strokeColorText
)
:
QColor
();
QColor
strokeColor
=
!
strokeColorText
.
isEmpty
()
?
colorFromString
(
strokeColorText
)
:
QColor
();
QColor
fillColor
=
!
fillColorText
.
isEmpty
()
?
colorFromString
(
fillColorText
)
:
QColor
();
QColor
fillColor
=
!
fillColorText
.
isEmpty
()
?
colorFromString
(
fillColorText
)
:
QColor
();
int
strokeWidth
=
strokeWidthText
.
to
Int
()
>
0
?
strokeWidthText
.
toInt
()
:
0
;
int
strokeWidth
=
strokeWidthText
.
to
Double
()
;
QPen
pen
;
QPen
pen
;
pen
.
setColor
(
strokeColor
);
pen
.
setColor
(
strokeColor
);
...
@@ -334,12 +367,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
...
@@ -334,12 +367,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &e
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
svgItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
svgItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
svgItem
,
width
+
10
,
height
+
10
,
x1
-
5
,
y1
-
5
,
hastransform
,
transform
);
repositionSvgItem
(
svgItem
,
width
+
strokeWidth
,
height
+
strokeWidth
,
x1
-
strokeWidth
/
2
+
transform
.
m31
(),
y1
+
strokeWidth
/
2
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
svgItem
);
hashSceneItem
(
element
,
svgItem
);
delete
generator
;
delete
generator
;
...
@@ -389,7 +422,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
...
@@ -389,7 +422,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
QString
strokeWidthText
=
element
.
attribute
(
aStrokewidth
);
QString
strokeWidthText
=
element
.
attribute
(
aStrokewidth
);
QColor
strokeColor
=
!
strokeColorText
.
isEmpty
()
?
colorFromString
(
strokeColorText
)
:
QColor
();
QColor
strokeColor
=
!
strokeColorText
.
isEmpty
()
?
colorFromString
(
strokeColorText
)
:
QColor
();
int
strokeWidth
=
strokeWidthText
.
toInt
()
>
0
?
strokeWidthText
.
toInt
()
:
0
;
int
strokeWidth
=
strokeWidthText
.
toDouble
();
width
+=
strokeWidth
;
height
+=
strokeWidth
;
QPen
pen
;
QPen
pen
;
pen
.
setColor
(
strokeColor
);
pen
.
setColor
(
strokeColor
);
...
@@ -400,7 +436,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
...
@@ -400,7 +436,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
painter
.
begin
(
generator
);
//drawing to svg tmp file
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
.
setPen
(
pen
);
painter
.
setPen
(
pen
);
painter
.
drawPolyline
(
polygon
);
painter
.
drawPolyline
(
polygon
);
...
@@ -410,12 +446,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
...
@@ -410,12 +446,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
svgItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
svgItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
svgItem
,
width
+
10
,
height
+
10
,
x1
-
5
,
y1
-
5
,
hastransform
,
transform
);
repositionSvgItem
(
svgItem
,
width
+
strokeWidth
,
height
+
strokeWidth
,
x1
+
transform
.
m31
()
-
strokeWidth
/
2
,
y1
+
transform
.
m32
()
+
strokeWidth
/
2
,
transform
);
hashSceneItem
(
element
,
svgItem
);
hashSceneItem
(
element
,
svgItem
);
delete
generator
;
delete
generator
;
...
@@ -539,7 +575,6 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &elem
...
@@ -539,7 +575,6 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &elem
// remember if text area has transform
// remember if text area has transform
// QString transformString;
// QString transformString;
QTransform
transform
=
fontTransform
;
QTransform
transform
=
fontTransform
;
bool
hasTransform
=
!
fontTransform
.
isIdentity
();
QRectF
lastDrawnTextBoundingRect
;
QRectF
lastDrawnTextBoundingRect
;
//parse text area tags
//parse text area tags
...
@@ -554,7 +589,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &elem
...
@@ -554,7 +589,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &elem
//add resulting svg file to scene
//add resulting svg file to scene
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
UBGraphicsSvgItem
*
svgItem
=
mCurrentScene
->
addSvg
(
QUrl
::
fromLocalFile
(
generator
->
fileName
()));
repositionSvgItem
(
svgItem
,
width
,
height
,
x
,
y
,
hasTransform
,
transform
);
svgItem
->
resetTransform
();
repositionSvgItem
(
svgItem
,
width
,
height
,
x
+
transform
.
m31
(),
y
+
transform
.
m32
(),
transform
);
hashSceneItem
(
element
,
svgItem
);
hashSceneItem
(
element
,
svgItem
);
delete
generator
;
delete
generator
;
...
@@ -661,10 +697,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &
...
@@ -661,10 +697,10 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
svgItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
svgItem
);
hastransform
=
true
;
}
}
//by default all the textAreas are not editable
//by default all the textAreas are not editable
...
@@ -673,7 +709,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &
...
@@ -673,7 +709,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &
curDelegate
->
setEditable
(
false
);
curDelegate
->
setEditable
(
false
);
}
}
repositionSvgItem
(
svgItem
,
width
,
height
,
x
,
y
,
hastransform
,
transform
);
repositionSvgItem
(
svgItem
,
width
,
height
,
x
+
transform
.
m31
(),
y
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
svgItem
);
hashSceneItem
(
element
,
svgItem
);
return
true
;
return
true
;
...
@@ -705,12 +741,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgImage(const QDomElement &ele
...
@@ -705,12 +741,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgImage(const QDomElement &ele
UBGraphicsPixmapItem
*
pixItem
=
mCurrentScene
->
addPixmap
(
pix
);
UBGraphicsPixmapItem
*
pixItem
=
mCurrentScene
->
addPixmap
(
pix
);
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
pixItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
pixItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
pixItem
,
width
,
height
,
x
,
y
,
hastransform
,
transform
);
repositionSvgItem
(
pixItem
,
width
,
height
,
x
+
transform
.
m31
(),
y
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
pixItem
);
hashSceneItem
(
element
,
pixItem
);
return
true
;
return
true
;
...
@@ -747,10 +783,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &ele
...
@@ -747,10 +783,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &ele
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
flashItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
flashItem
);
}
}
repositionSvgItem
(
flashItem
,
width
,
height
,
x
,
y
,
true
,
transform
);
repositionSvgItem
(
flashItem
,
width
,
height
,
x
+
transform
.
m31
(),
y
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
flashItem
);
hashSceneItem
(
element
,
flashItem
);
return
true
;
return
true
;
...
@@ -758,32 +796,42 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &ele
...
@@ -758,32 +796,42 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &ele
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvgAudio
(
const
QDomElement
&
element
)
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
parseSvgAudio
(
const
QDomElement
&
element
)
{
{
qreal
x
=
element
.
attribute
(
aX
).
toDouble
();
QDomElement
parentOfAudio
=
element
.
firstChild
().
toElement
();
qreal
y
=
element
.
attribute
(
aY
).
toDouble
();
qreal
width
=
element
.
attribute
(
aWidth
).
toDouble
();
qreal
x
=
parentOfAudio
.
attribute
(
aX
).
toDouble
();
qreal
height
=
element
.
attribute
(
aHeight
).
toDouble
();
qreal
y
=
parentOfAudio
.
attribute
(
aY
).
toDouble
();
QString
itemRefPath
=
element
.
attribute
(
aHref
);
QString
itemRefPath
=
element
.
attribute
(
aHref
);
QUrl
urlPath
;
QUrl
concreteUrl
;
if
(
!
itemRefPath
.
isNull
())
{
if
(
!
itemRefPath
.
isNull
())
{
QString
vide
oPath
=
pwdContent
+
"/"
+
itemRefPath
;
QString
audi
oPath
=
pwdContent
+
"/"
+
itemRefPath
;
if
(
!
QFile
::
exists
(
vide
oPath
))
{
if
(
!
QFile
::
exists
(
audi
oPath
))
{
qDebug
()
<<
"can't load file"
<<
pwdContent
+
"/"
+
itemRefPath
<<
"maybe file corrupted"
;
qDebug
()
<<
"can't load file"
<<
pwdContent
+
"/"
+
itemRefPath
<<
"maybe file corrupted"
;
return
false
;
return
false
;
}
}
urlPath
=
QUrl
::
fromLocalFile
(
vide
oPath
);
concreteUrl
=
QUrl
::
fromLocalFile
(
audi
oPath
);
}
}
UBGraphicsAudioItem
*
audioItem
=
mCurrentScene
->
addAudio
(
urlPath
,
false
);
QUuid
uuid
=
QUuid
::
createUuid
();
#ifdef Q_WS_X11
concreteUrl
=
QUrl
::
fromLocalFile
(
mCurrentScene
->
document
()
->
persistencePath
()
+
"/"
+
UBPersistenceManager
::
persistenceManager
()
->
addAudioFileToDocument
(
mCurrentScene
->
document
(),
concreteUrl
.
toLocalFile
(),
uuid
));
#else
concreteUrl
=
QUrl
::
fromLocalFile
(
UBPersistenceManager
::
persistenceManager
()
->
addAudioFileToDocument
(
mCurrentScene
->
document
(),
concreteUrl
.
toLocalFile
(),
uuid
));
#endif
UBGraphicsAudioItem
*
audioItem
=
mCurrentScene
->
addAudio
(
concreteUrl
,
false
);
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
parentOfAudio
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
audioItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
audioItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
audioItem
,
width
,
height
,
x
,
y
,
hastransform
,
transform
);
repositionSvgItem
(
audioItem
,
audioItem
->
boundingRect
().
width
(),
audioItem
->
boundingRect
().
height
(),
x
+
transform
.
m31
(),
y
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
audioItem
);
hashSceneItem
(
element
,
audioItem
);
return
true
;
return
true
;
...
@@ -795,31 +843,38 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &ele
...
@@ -795,31 +843,38 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &ele
if
(
parseSvgFlash
(
element
))
return
true
;
if
(
parseSvgFlash
(
element
))
return
true
;
else
return
false
;
else
return
false
;
}
}
qreal
x
=
element
.
attribute
(
aX
).
toDouble
();
qreal
x
=
element
.
attribute
(
aX
).
toDouble
();
qreal
y
=
element
.
attribute
(
aY
).
toDouble
();
qreal
y
=
element
.
attribute
(
aY
).
toDouble
();
qreal
width
=
element
.
attribute
(
aWidth
).
toDouble
();
qreal
height
=
element
.
attribute
(
aHeight
).
toDouble
();
QUrl
urlPath
;
QUrl
concreteUrl
;
if
(
!
itemRefPath
.
isNull
())
{
if
(
!
itemRefPath
.
isNull
())
{
QString
videoPath
=
pwdContent
+
"/"
+
itemRefPath
;
QString
videoPath
=
pwdContent
+
"/"
+
itemRefPath
;
if
(
!
QFile
::
exists
(
videoPath
))
{
if
(
!
QFile
::
exists
(
videoPath
))
{
qDebug
()
<<
"can't load file"
<<
pwdContent
+
"/"
+
itemRefPath
<<
"maybe file corrupted"
;
qDebug
()
<<
"can't load file"
<<
pwdContent
+
"/"
+
itemRefPath
<<
"maybe file corrupted"
;
return
false
;
return
false
;
}
}
urlPath
=
QUrl
::
fromLocalFile
(
videoPath
);
concreteUrl
=
QUrl
::
fromLocalFile
(
videoPath
);
}
}
UBGraphicsVideoItem
*
videoItem
=
mCurrentScene
->
addVideo
(
urlPath
,
false
);
QUuid
uuid
=
QUuid
::
createUuid
();
#ifdef Q_WS_X11
concreteUrl
=
QUrl
::
fromLocalFile
(
mCurrentScene
->
document
()
->
persistencePath
()
+
"/"
+
UBPersistenceManager
::
persistenceManager
()
->
addVideoFileToDocument
(
mCurrentScene
->
document
(),
concreteUrl
.
toLocalFile
(),
uuid
));
#else
concreteUrl
=
QUrl
::
fromLocalFile
(
UBPersistenceManager
::
persistenceManager
()
->
addVideoFileToDocument
(
mCurrentScene
->
document
(),
concreteUrl
.
toLocalFile
(),
uuid
));
#endif
UBGraphicsVideoItem
*
videoItem
=
mCurrentScene
->
addVideo
(
concreteUrl
,
false
);
QTransform
transform
;
QTransform
transform
;
QString
textTransform
=
element
.
attribute
(
aTransform
);
QString
textTransform
=
element
.
attribute
(
aTransform
);
bool
hastransform
=
false
;
videoItem
->
resetTransform
();
if
(
!
textTransform
.
isNull
())
{
if
(
!
textTransform
.
isNull
())
{
transform
=
transformFromString
(
textTransform
);
transform
=
transformFromString
(
textTransform
,
videoItem
);
hastransform
=
true
;
}
}
repositionSvgItem
(
videoItem
,
width
,
height
,
x
-
5
,
y
-
5
,
hastransform
,
transform
);
repositionSvgItem
(
videoItem
,
videoItem
->
boundingRect
().
width
(),
videoItem
->
boundingRect
().
height
(),
x
+
transform
.
m31
(),
y
+
transform
.
m32
()
,
transform
);
hashSceneItem
(
element
,
videoItem
);
hashSceneItem
(
element
,
videoItem
);
return
true
;
return
true
;
...
@@ -849,16 +904,18 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &p
...
@@ -849,16 +904,18 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &p
return
false
;
return
false
;
}
}
if
(
tagName
==
tRect
&&
!
parseSvgRect
(
parent
))
return
false
;
if
(
tagName
==
tG
&&
!
parseGSection
(
parent
))
return
false
;
else
if
(
tagName
==
tEllipse
&&
!
parseSvgEllipse
(
parent
))
return
false
;
else
if
(
tagName
==
tSwitch
&&
!
parseSvgSwitchSection
(
parent
))
return
false
;
else
if
(
tagName
==
tPolygon
&&
!
parseSvgPolygon
(
parent
))
return
false
;
else
if
(
tagName
==
tRect
&&
!
parseSvgRect
(
parent
))
return
false
;
else
if
(
tagName
==
tPolyline
&&
!
parseSvgPolyline
(
parent
))
return
false
;
else
if
(
tagName
==
tEllipse
&&
!
parseSvgEllipse
(
parent
))
return
false
;
else
if
(
tagName
==
tText
&&
!
parseSvgText
(
parent
))
return
false
;
else
if
(
tagName
==
tPolygon
&&
!
parseSvgPolygon
(
parent
))
return
false
;
else
if
(
tagName
==
tTextarea
&&
!
parseSvgTextarea
(
parent
))
return
false
;
else
if
(
tagName
==
tPolyline
&&
!
parseSvgPolyline
(
parent
))
return
false
;
else
if
(
tagName
==
tImage
&&
!
parseSvgImage
(
parent
))
return
false
;
else
if
(
tagName
==
tText
&&
!
parseSvgText
(
parent
))
return
false
;
else
if
(
tagName
==
tFlash
&&
!
parseSvgFlash
(
parent
))
return
false
;
else
if
(
tagName
==
tTextarea
&&
!
parseSvgTextarea
(
parent
))
return
false
;
else
if
(
tagName
==
tAudio
&&
!
parseSvgAudio
(
parent
))
return
false
;
else
if
(
tagName
==
tImage
&&
!
parseSvgImage
(
parent
))
return
false
;
else
if
(
tagName
==
tVideo
&&
!
parseSvgVideo
(
parent
))
return
false
;
else
if
(
tagName
==
tFlash
&&
!
parseSvgFlash
(
parent
))
return
false
;
else
if
(
tagName
==
tAudio
&&
!
parseSvgAudio
(
parent
))
return
false
;
else
if
(
tagName
==
tVideo
&&
!
parseSvgVideo
(
parent
))
return
false
;
return
true
;
return
true
;
}
}
...
@@ -986,7 +1043,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc()
...
@@ -986,7 +1043,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc()
void
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
repositionSvgItem
(
QGraphicsItem
*
item
,
qreal
width
,
qreal
height
,
void
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
repositionSvgItem
(
QGraphicsItem
*
item
,
qreal
width
,
qreal
height
,
qreal
x
,
qreal
y
,
qreal
x
,
qreal
y
,
bool
useTransform
,
QTransform
&
transform
)
QTransform
&
transform
)
{
{
//First using viebox coordinates, then translate them to scene coordinates
//First using viebox coordinates, then translate them to scene coordinates
...
@@ -998,29 +1055,32 @@ void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(QGraphicsItem *ite
...
@@ -998,29 +1055,32 @@ void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(QGraphicsItem *ite
qreal
fullScaleX
=
mVBTransFactor
*
xScale
;
qreal
fullScaleX
=
mVBTransFactor
*
xScale
;
qreal
fullScaleY
=
mVBTransFactor
*
yScale
;
qreal
fullScaleY
=
mVBTransFactor
*
yScale
;
if
(
useTransform
)
{
//if rotation or translation specified
QPointF
oldVector
((
x
-
transform
.
dx
()),
(
y
-
transform
.
dy
()));
QPointF
oldVector
((
x
-
transform
.
dx
()),
(
y
-
transform
.
dy
()));
QTransform
rTransform
;
QTransform
rTransform
(
transform
.
m11
(),
transform
.
m12
(),
transform
.
m21
(),
transform
.
m22
(),
0
,
0
);
QPointF
newVector
=
rTransform
.
map
(
oldVector
);
QPointF
newVector
=
rTransform
.
map
(
oldVector
);
QRectF
sr
=
mCurrentScene
->
sceneRect
();
item
->
setTransform
(
rTransform
.
scale
(
fullScaleX
,
fullScaleY
));
QRectF
sr1
=
mCurrentSceneRect
;
item
->
setPos
((
x
-
mViewBoxCenter
.
x
()
+
(
newVector
-
oldVector
).
x
())
*
mVBTransFactor
,
QRectF
sr2
=
mCurrentScene
->
normalizedSceneRect
();
(
y
-
mViewBoxCenter
.
y
()
+
(
newVector
-
oldVector
).
y
())
*
mVBTransFactor
);
}
else
{
//item is't rotated or translated
QTransform
tr
=
item
->
sceneTransform
();
item
->
setTransform
(
QTransform
(
fullScaleX
,
0
,
0
,
fullScaleY
,
0
,
0
));
item
->
setTransform
(
rTransform
.
scale
(
fullScaleX
,
fullScaleY
),
true
);
itemBounds
=
item
->
boundingRect
();
tr
=
item
->
sceneTransform
();
item
->
setPos
((
int
)((
x
-
mViewBoxCenter
.
x
())
*
mVBTransFactor
),
QPoint
pos
((
int
)((
x
+
mShiftVector
.
x
()
+
(
newVector
-
oldVector
).
x
())
*
mVBTransFactor
),
(
int
)((
y
+
mShiftVector
.
y
()
+
(
newVector
-
oldVector
).
y
())
*
mVBTransFactor
));
(
int
)((
y
-
mViewBoxCenter
.
y
())
*
mVBTransFactor
));
item
->
setPos
(
pos
);
}
}
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
createNewScene
()
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
createNewScene
()
{
{
mCurrentScene
=
UBPersistenceManager
::
persistenceManager
()
->
createDocumentSceneAt
(
mProxy
,
mProxy
->
pageCount
());
mCurrentScene
=
UBPersistenceManager
::
persistenceManager
()
->
createDocumentSceneAt
(
mProxy
,
mProxy
->
pageCount
());
mCurrentScene
->
setURStackEnable
(
false
);
mCurrentScene
->
setURStackEnable
(
false
);
mCurrentSceneRect
=
mCurrentScene
->
normalizedSceneRect
();
mCurrentScene
->
setSceneRect
(
mViewBox
);
mVBTransFactor
=
qMin
(
mCurrentSceneRect
.
width
()
/
mViewPort
.
width
(),
if
((
mCurrentScene
->
sceneRect
().
topLeft
().
x
()
>=
0
)
||
(
mCurrentScene
->
sceneRect
().
topLeft
().
y
()
>=
0
))
{
mCurrentSceneRect
.
height
()
/
mViewPort
.
height
());
mShiftVector
=
-
mViewBox
.
center
();
}
mCurrentSceneRect
=
mViewBox
;
mVBTransFactor
=
qMin
(
mCurrentScene
->
normalizedSceneRect
().
width
()
/
mViewPort
.
width
(),
mCurrentScene
->
normalizedSceneRect
().
height
()
/
mViewPort
.
height
());
return
true
;
return
true
;
}
}
...
@@ -1048,11 +1108,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistScenes()
...
@@ -1048,11 +1108,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistScenes()
qDebug
()
<<
"can't allocate scene, loading failed"
;
qDebug
()
<<
"can't allocate scene, loading failed"
;
return
false
;
return
false
;
}
}
UBSvgSubsetAdaptor
::
persistScene
(
mProxy
,
mCurrentScene
,
i
);
UBGraphicsScene
*
tmpScene
=
UBSvgSubsetAdaptor
::
loadScene
(
mProxy
,
i
);
UBSvgSubsetAdaptor
::
persistScene
(
mProxy
,
mCurrentScene
,
i
);
tmpScene
->
setModified
(
true
);
UBGraphicsScene
*
tmpScene
=
UBSvgSubsetAdaptor
::
loadScene
(
mProxy
,
i
);
UBThumbnailAdaptor
::
persistScene
(
mProxy
->
persistencePath
(),
tmpScene
,
i
);
tmpScene
->
setModified
(
true
);
delete
tmpScene
;
UBThumbnailAdaptor
::
persistScene
(
mProxy
->
persistencePath
(),
tmpScene
,
i
);
delete
tmpScene
;
mCurrentScene
->
setModified
(
false
);
mCurrentScene
->
setModified
(
false
);
}
}
...
@@ -1087,45 +1148,63 @@ QColor UBCFFSubsetAdaptor::UBCFFSubsetReader::colorFromString(const QString& clr
...
@@ -1087,45 +1148,63 @@ QColor UBCFFSubsetAdaptor::UBCFFSubsetReader::colorFromString(const QString& clr
return
QColor
(
clrString
);
return
QColor
(
clrString
);
}
}
QTransform
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
transformFromString
(
const
QString
trString
)
QTransform
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
transformFromString
(
const
QString
trString
,
QGraphicsItem
*
item
)
{
{
qreal
dxr
=
0.0
;
qreal
dyr
=
0.0
;
qreal
dx
=
0.0
;
qreal
dx
=
0.0
;
qreal
dy
=
0.0
;
qreal
dy
=
0.0
;
qreal
angle
=
0.0
;
qreal
angle
=
0.0
;
QTransform
tr
;
//check pattern for strings like 'rotate(10)'
foreach
(
QString
trStr
,
trString
.
split
(
" "
,
QString
::
SkipEmptyParts
))
QRegExp
regexp
(
"rotate
\\
( *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *
\\
)"
);
{
if
(
regexp
.
exactMatch
(
trString
))
{
//check pattern for strings like 'rotate(10)'
angle
=
regexp
.
capturedTexts
().
at
(
1
).
toDouble
();
QRegExp
regexp
(
"rotate
\\
( *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *
\\
)"
);
}
else
{
if
(
regexp
.
exactMatch
(
trStr
))
{
angle
=
regexp
.
capturedTexts
().
at
(
1
).
toDouble
();
if
(
item
)
{
item
->
setTransformOriginPoint
(
QPointF
(
0
,
0
));
item
->
rotate
(
angle
);
}
continue
;
};
//check pattern for strings like 'rotate(10,20,20)' or 'rotate(10.1,10.2,34.2)'
//check pattern for strings like 'rotate(10,20,20)' or 'rotate(10.1,10.2,34.2)'
regexp
.
setPattern
(
"rotate
\\
( *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *
\\
)"
);
regexp
.
setPattern
(
"rotate
\\
( *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *
\\
)"
);
if
(
regexp
.
exactMatch
(
trStr
ing
))
{
if
(
regexp
.
exactMatch
(
trStr
))
{
angle
=
regexp
.
capturedTexts
().
at
(
1
).
toDouble
();
angle
=
regexp
.
capturedTexts
().
at
(
1
).
toDouble
();
dx
=
regexp
.
capturedTexts
().
at
(
2
).
toDouble
();
dxr
=
regexp
.
capturedTexts
().
at
(
2
).
toDouble
();
dy
=
regexp
.
capturedTexts
().
at
(
3
).
toDouble
();
dyr
=
regexp
.
capturedTexts
().
at
(
3
).
toDouble
();
if
(
item
)
{
item
->
setTransformOriginPoint
(
QPointF
(
dxr
,
dyr
)
-
item
->
pos
());
item
->
rotate
(
angle
);
}
continue
;
}
}
}
//check pattern for strings like 'translate(11.0, 12.34)'
regexp
.
setPattern
(
"translate
\\
( *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *,*([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*)*
\\
)"
);
if
(
regexp
.
exactMatch
(
trString
))
{
dx
=
regexp
.
capturedTexts
().
at
(
1
).
toDouble
();
dy
=
regexp
.
capturedTexts
().
at
(
2
).
toDouble
();
}
return
QTransform
().
translate
(
dx
,
dy
).
rotate
(
angle
);
//check pattern for strings like 'translate(11.0, 12.34)'
regexp
.
setPattern
(
"translate
\\
( *([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*) *,*([-+]{0,1}[0-9]*
\\
.{0,1}[0-9]*)*
\\
)"
);
if
(
regexp
.
exactMatch
(
trStr
))
{
dx
=
regexp
.
capturedTexts
().
at
(
1
).
toDouble
();
dy
=
regexp
.
capturedTexts
().
at
(
2
).
toDouble
();
tr
.
translate
(
dx
,
dy
);
continue
;
}
}
return
tr
;
}
}
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
getViewBoxDimenstions
(
const
QString
&
viewBox
)
bool
UBCFFSubsetAdaptor
::
UBCFFSubsetReader
::
getViewBoxDimenstions
(
const
QString
&
viewBox
)
{
{
//check pattern for strings like 'rotate(10)'
QStringList
capturedTexts
=
viewBox
.
split
(
" "
,
QString
::
SkipEmptyParts
);
QRegExp
regexp
(
"([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)"
);
if
(
capturedTexts
.
count
())
if
(
regexp
.
exactMatch
(
viewBox
))
{
{
int
capturesCount
=
regexp
.
capturedTexts
().
count
();
if
(
4
==
capturedTexts
.
count
())
if
(
capturesCount
==
5
&&
regexp
.
capturedTexts
().
at
(
0
).
length
()
==
viewBox
.
length
())
{
{
mViewBox
=
QRectF
(
0
,
0
,
regexp
.
capturedTexts
().
at
(
3
).
toDouble
(),
regexp
.
capturedTexts
().
at
(
4
).
toDouble
());
mViewBox
=
QRectF
(
capturedTexts
.
at
(
0
).
toDouble
(),
capturedTexts
.
at
(
1
).
toDouble
(),
capturedTexts
.
at
(
2
).
toDouble
(),
capturedTexts
.
at
(
3
).
toDouble
());
mViewPort
=
mViewBox
;
mViewPort
=
mViewBox
;
mViewPort
.
translate
(
-
mViewPort
.
center
());
mViewPort
.
translate
(
-
mViewPort
.
center
());
mViewBoxCenter
.
setX
(
mViewBox
.
width
()
/
2
);
mViewBoxCenter
.
setX
(
mViewBox
.
width
()
/
2
);
...
...
src/adaptors/UBCFFSubsetAdaptor.h
View file @
973e1df2
...
@@ -65,6 +65,7 @@ private:
...
@@ -65,6 +65,7 @@ private:
qreal
mVBTransFactor
;
qreal
mVBTransFactor
;
QPointF
mViewBoxCenter
;
QPointF
mViewBoxCenter
;
QSize
mSize
;
QSize
mSize
;
QPointF
mShiftVector
;
private
:
private
:
QDomDocument
mDOMdoc
;
QDomDocument
mDOMdoc
;
...
@@ -85,6 +86,8 @@ private:
...
@@ -85,6 +86,8 @@ private:
bool
parseIwbMeta
(
const
QDomElement
&
element
);
bool
parseIwbMeta
(
const
QDomElement
&
element
);
bool
parseSvg
(
const
QDomElement
&
svgSection
);
bool
parseSvg
(
const
QDomElement
&
svgSection
);
inline
bool
parseGSection
(
const
QDomElement
&
element
);
inline
bool
parseSvgSwitchSection
(
const
QDomElement
&
element
);
inline
bool
parseSvgRect
(
const
QDomElement
&
element
);
inline
bool
parseSvgRect
(
const
QDomElement
&
element
);
inline
bool
parseSvgEllipse
(
const
QDomElement
&
element
);
inline
bool
parseSvgEllipse
(
const
QDomElement
&
element
);
inline
bool
parseSvgPolygon
(
const
QDomElement
&
element
);
inline
bool
parseSvgPolygon
(
const
QDomElement
&
element
);
...
@@ -123,9 +126,9 @@ private:
...
@@ -123,9 +126,9 @@ private:
// helper methods
// helper methods
void
repositionSvgItem
(
QGraphicsItem
*
item
,
qreal
width
,
qreal
height
,
void
repositionSvgItem
(
QGraphicsItem
*
item
,
qreal
width
,
qreal
height
,
qreal
x
,
qreal
y
,
qreal
x
,
qreal
y
,
bool
useTransform
,
QTransform
&
transform
);
QTransform
&
transform
);
QColor
colorFromString
(
const
QString
&
clrString
);
QColor
colorFromString
(
const
QString
&
clrString
);
QTransform
transformFromString
(
const
QString
trString
);
QTransform
transformFromString
(
const
QString
trString
,
QGraphicsItem
*
item
=
0
);
bool
getViewBoxDimenstions
(
const
QString
&
viewBox
);
bool
getViewBoxDimenstions
(
const
QString
&
viewBox
);
QSvgGenerator
*
createSvgGenerator
(
qreal
width
,
qreal
height
);
QSvgGenerator
*
createSvgGenerator
(
qreal
width
,
qreal
height
);
bool
getTempFileName
();
bool
getTempFileName
();
...
...
src/adaptors/UBSvgSubsetAdaptor.cpp
View file @
973e1df2
...
@@ -366,7 +366,8 @@ UBGraphicsScene* UBSvgSubsetAdaptor::UBSvgSubsetReader::loadScene()
...
@@ -366,7 +366,8 @@ UBGraphicsScene* UBSvgSubsetAdaptor::UBSvgSubsetReader::loadScene()
// introduced in UB 4.0
// introduced in UB 4.0
QStringRef
svgViewBox
=
mXmlReader
.
attributes
().
value
(
nsSvg
,
"viewBox"
);
QStringRef
svgViewBox
=
mXmlReader
.
attributes
().
value
(
"viewBox"
);
if
(
!
svgViewBox
.
isNull
())
if
(
!
svgViewBox
.
isNull
())
{
{
...
...
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