Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140307
tst_EventView.qml
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
19 KB
Referenced Files
None
Subscribers
None
tst_EventView.qml
View Options
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import
QtQuick
2.3
import
QtQuick
.
Layouts
1.15
import
QtTest
1.0
import
moe
.
kazv
.
mxc
.
kazv
0.0
as
MK
import
org
.
kde
.
kirigami
2.13
as
Kirigami
import
'../../contents/ui'
as
Kazv
import
'test-helpers.js'
as
Helpers
import
'test-helpers'
as
QmlHelpers
QmlHelpers
.
TestItem
{
id: item
property
var
activateUserPage:
mockHelper
.
noop
()
property
var
paginateBackRequested:
mockHelper
.
noop
()
property
var
viewEventHistoryRequested:
mockHelper
.
noop
()
property
var
pinEventRequested:
mockHelper
.
noop
()
property
var
unpinEventRequested:
mockHelper
.
noop
()
property
var
deleteEventRequested:
mockHelper
.
noop
()
property
var
timeline:
({
gaps:
{},
})
property
var
pinnedEvents:
({
count:
2
,
eventIds:
{
'$123'
:
true
,
'$456'
:
true
,
},
})
property
var
room:
({
resendMessage:
mockHelper
.
promise
(),
removeLocalEcho:
mockHelper
.
promise
(),
ensureStateEvent:
mockHelper
.
promise
(),
messageById:
(
_id
)
=>
item
.
textEvent
,
member:
(
_id
)
=>
({}),
})
property
var
localEcho:
({
eventId:
''
,
sender:
''
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.text'
,
body:
'some body'
,
},
encrypted:
false
,
isState:
false
,
unsignedData:
{},
isLocalEcho:
true
,
isSending:
true
,
isFailed:
false
,
txnId:
'some-txn-id'
,
})
property
var
failedLocalEcho:
Object
.
assign
({},
item
.
localEcho
,
{
isSending:
false
,
isFailed:
true
,
})
property
var
textEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.text'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
htmlEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.text'
,
body:
'**some body**'
,
format:
'org.matrix.custom.html'
,
formatted_body:
'<strong>some body</strong>'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
replyHtmlEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
replyingToEventId:
'$xxx'
,
content:
{
msgtype:
'm.text'
,
body:
'> some quote\n**some body**'
,
format:
'org.matrix.custom.html'
,
formatted_body:
'<mx-reply><blockquote>some quote</blockquote></mx-reply><strong>some body</strong>'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
replyNoQuoteHtmlEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
replyingToEventId:
'$xxx'
,
content:
{
msgtype:
'm.text'
,
body:
'**some body**'
,
format:
'org.matrix.custom.html'
,
formatted_body:
'<strong>some body</strong>'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
redactedEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{},
redacted:
true
,
formattedTime:
'4:06 P.M.'
,
})
property
var
imageEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.image'
,
body:
'some body'
,
info:
{
h:
Kirigami
.
Units
.
gridUnit
*
10
,
w:
Kirigami
.
Units
.
gridUnit
*
10
,
}
},
formattedTime:
'4:06 P.M.'
,
})
property
var
stickerEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.sticker'
,
stateKey:
''
,
content:
{
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
eventBySomeoneElse:
({
eventId:
''
,
sender:
'@bar:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.image'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
eventTextBySomeoneElse:
({
eventId:
''
,
sender:
'@bar:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.text'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
ignoredEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
relationType:
'm.replace'
,
stateKey:
''
,
content:
{
msgtype:
'm.image'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
unknownTypeEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'moe.kazv.mxc.unknown.event'
,
stateKey:
''
,
content:
{
msgtype:
'm.image'
,
body:
'some body'
,
},
})
property
var
unknownMsgtypeEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'moe.kazv.mxc.unknown.msgtype'
,
body:
'some body'
,
},
})
property
var
cannotDecryptEvent:
({
eventId:
''
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'moe.kazv.mxc.cannot.decrypt'
,
body:
'some body'
,
},
})
property
var
editedEvent:
({
eventId:
'!some-event-id'
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
stateKey:
''
,
content:
{
msgtype:
'm.text'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
isEdited:
true
,
})
property
var
pinnedEvent:
({
eventId:
'$123'
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
content:
{
msgtype:
'm.text'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
notPinnedEvent:
({
eventId:
'$789'
,
sender:
'@foo:tusooa.xyz'
,
type:
'm.room.message'
,
content:
{
msgtype:
'm.text'
,
body:
'some body'
,
},
formattedTime:
'4:06 P.M.'
,
})
property
var
sender:
({
membership:
'join'
,
userId:
'@foo:tusooa.xyz'
,
name:
'foo'
,
avatarMxcUri:
''
,
})
property
var
senderOther:
({
membership:
'join'
,
userId:
'@bar:tusooa.xyz'
,
name:
'bar'
,
avatarMxcUri:
''
,
})
property
var
eventViewComp:
Component
{
Kazv
.
EventView
{
Layout.fillWidth:
true
event:
QtObject
{
property
var
eventId:
'$some-event-id'
function
readers
()
{
return
0
;
}
}
sender:
item
.
sender
isGapped:
true
}
}
property
var
eventComp:
Component
{
QtObject
{
property
var
eventId:
'$some-event-id'
function
readers
()
{
return
0
;
}
}
}
ColumnLayout
{
anchors.fill:
parent
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventView
event:
item
.
localEcho
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewFailed
event:
item
.
failedLocalEcho
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewText
event:
item
.
textEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewHtml
event:
item
.
htmlEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewHtmlReply
event:
item
.
replyHtmlEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewHtmlReplyNoQuote
event:
item
.
replyNoQuoteHtmlEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewRedacted
event:
item
.
redactedEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewUnknownType
event:
item
.
unknownTypeEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewUnknownMsgtype
event:
item
.
unknownMsgtypeEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewCannotDecrypt
event:
item
.
cannotDecryptEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewCollapseSameSender
event:
item
.
imageEvent
sender:
item
.
sender
prevEvent:
item
.
redactedEvent
}
Kazv
.
EventView
{
id: eventViewCollapseLocalEcho
event:
item
.
localEcho
sender:
item
.
sender
prevEvent:
item
.
redactedEvent
}
Kazv
.
EventView
{
id: eventViewDontCollapseDifferentSender
event:
item
.
imageEvent
sender:
item
.
sender
prevEvent:
item
.
eventBySomeoneElse
}
Kazv
.
EventView
{
id: eventViewDontCollapseLocalEchoDifferentSender
event:
item
.
localEcho
sender:
item
.
sender
prevEvent:
item
.
eventBySomeoneElse
}
Kazv
.
EventView
{
id: eventViewDontCollapseIgnoredEvent
event:
item
.
imageEvent
sender:
item
.
sender
prevEvent:
item
.
ignoredEvent
}
Kazv
.
EventView
{
id: eventViewTextBySomeoneElse
event:
item
.
eventTextBySomeoneElse
sender:
item
.
senderOther
}
Kazv
.
EventView
{
id: eventViewImage
event:
item
.
imageEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewImageCompact
compactMode:
true
event:
item
.
imageEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewSticker
event:
item
.
stickerEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
id: eventViewStickerCompact
compactMode:
true
event:
item
.
stickerEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewEdited
event:
item
.
editedEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewPinned
event:
item
.
pinnedEvent
sender:
item
.
sender
}
Kazv
.
EventView
{
Layout.fillWidth:
true
id: eventViewNotPinned
event:
item
.
notPinnedEvent
sender:
item
.
sender
}
}
TestCase
{
id: eventViewTest
name:
'EventViewTest'
when:
windowShown
function
init
()
{
item
.
matrixSdk
.
userId
=
'@foo:tusooa.xyz'
;
eventView
.
event
=
item
.
localEcho
;
mockHelper
.
clearAll
();
}
function
test_localEcho
()
{
const
indicator
=
findChild
(
eventView
,
'localEchoIndicator'
);
verify
(
indicator
);
verify
(
indicator
.
icon
.
name
===
'state-sync'
);
verify
(
indicator
.
Accessible
.
name
===
l10n
.
get
(
'event-sending'
));
const
resendButton
=
findChild
(
eventView
,
'localEchoIndicator'
);
verify
(
resendButton
);
verify
(
!
resendButton
.
enabled
);
verify
(
!
findChild
(
eventView
,
'timeIndicator'
).
visible
);
}
function
test_localEchoFailedRemove
()
{
const
indicator
=
findChild
(
eventViewFailed
,
'localEchoIndicator'
);
verify
(
indicator
);
verify
(
indicator
.
visible
);
verify
(
indicator
.
icon
.
name
===
'state-warning'
);
verify
(
indicator
.
Accessible
.
name
===
l10n
.
get
(
'event-resend'
));
const
menuComp
=
findChild
(
eventViewFailed
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
const
deleteAction
=
findChild
(
menu
,
'deleteMenuItem'
);
verify
(
deleteAction
.
enabled
);
deleteAction
.
trigger
();
compare
(
deleteEventRequested
.
calledTimes
(),
1
);
}
function
test_sentMessage
()
{
const
indicator
=
findChild
(
eventViewText
,
'localEchoIndicator'
);
verify
(
indicator
);
verify
(
!
indicator
.
visible
);
verify
(
findChild
(
eventViewText
,
'timeIndicator'
).
visible
);
}
function
test_htmlMessage
()
{
const
text
=
findChild
(
eventViewHtml
,
'eventViewMainItem'
);
verify
(
text
.
textFormat
===
TextEdit
.
RichText
);
verify
(
text
.
text
.
includes
(
'some body'
));
}
function
test_htmlMessageReply
()
{
const
text
=
findChild
(
eventViewHtmlReply
,
'eventViewMainItem'
);
verify
(
text
.
textFormat
===
TextEdit
.
RichText
);
verify
(
!
text
.
text
.
includes
(
'<blockquote>'
));
}
function
test_htmlMessageReplyNoQuote
()
{
const
text
=
findChild
(
eventViewHtmlReplyNoQuote
,
'eventViewMainItem'
);
verify
(
text
.
textFormat
===
TextEdit
.
RichText
);
verify
(
!
text
.
text
.
includes
(
'<blockquote>'
));
verify
(
text
.
text
.
includes
(
'some body'
));
}
function
test_menuText
()
{
const
menuComp
=
findChild
(
eventViewText
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
verify
(
menu
);
tryVerify
(()
=>
findChild
(
menu
,
'replyToMenuItem'
).
enabled
);
tryVerify
(()
=>
findChild
(
menu
,
'editMenuItem'
).
enabled
);
tryVerify
(()
=>
findChild
(
menu
,
'deleteMenuItem'
).
enabled
);
}
function
test_menuRedacted
()
{
const
menuComp
=
findChild
(
eventViewRedacted
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
verify
(
menu
);
tryVerify
(()
=>
!
findChild
(
menu
,
'replyToMenuItem'
).
enabled
);
tryVerify
(()
=>
!
findChild
(
menu
,
'deleteMenuItem'
).
enabled
);
}
function
test_fallback
()
{
verify
(
findChild
(
eventViewUnknownType
,
'fallbackIcon'
));
verify
(
findChild
(
eventViewUnknownType
,
'textEventContent'
).
text
===
l10n
.
get
(
'event-fallback-text'
,
{
type:
unknownTypeEvent
.
type
}));
verify
(
findChild
(
eventViewUnknownMsgtype
,
'fallbackIcon'
));
verify
(
findChild
(
eventViewUnknownMsgtype
,
'textEventContent'
).
text
===
l10n
.
get
(
'event-msgtype-fallback-text'
,
{
msgtype:
unknownMsgtypeEvent
.
content
.
msgtype
}));
verify
(
findChild
(
eventViewCannotDecrypt
,
'fallbackIcon'
));
verify
(
findChild
(
eventViewCannotDecrypt
,
'textEventContent'
).
text
===
l10n
.
get
(
'event-cannot-decrypt-text'
));
}
function
test_collapseSender
()
{
verify
(
!
findChild
(
eventViewCollapseSameSender
,
'senderAvatar'
).
visible
);
verify
(
findChild
(
eventViewCollapseSameSender
,
'senderCollapsedPlaceholder'
).
visible
);
verify
(
!
findChild
(
eventViewCollapseLocalEcho
,
'senderAvatar'
).
visible
);
verify
(
findChild
(
eventViewCollapseLocalEcho
,
'senderCollapsedPlaceholder'
).
visible
);
verify
(
findChild
(
eventViewDontCollapseDifferentSender
,
'senderAvatar'
).
visible
);
verify
(
!
findChild
(
eventViewDontCollapseDifferentSender
,
'senderCollapsedPlaceholder'
).
visible
);
verify
(
findChild
(
eventViewDontCollapseLocalEchoDifferentSender
,
'senderAvatar'
).
visible
);
verify
(
!
findChild
(
eventViewDontCollapseLocalEchoDifferentSender
,
'senderCollapsedPlaceholder'
).
visible
);
verify
(
findChild
(
eventViewDontCollapseIgnoredEvent
,
'senderAvatar'
).
visible
);
verify
(
!
findChild
(
eventViewDontCollapseIgnoredEvent
,
'senderCollapsedPlaceholder'
).
visible
);
}
function
test_eventByOther
()
{
const
menuComp
=
findChild
(
eventViewTextBySomeoneElse
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
verify
(
menu
);
tryVerify
(()
=>
!
findChild
(
menu
,
'editMenuItem'
).
enabled
);
}
function
test_menuSelfDestruct
()
{
const
menuComp
=
findChild
(
eventViewTextBySomeoneElse
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
verify
(
menu
);
menu
.
popup
(
item
);
menu
.
dismiss
();
const
menu2
=
menuComp
.
createObject
(
menuComp
.
parent
);
menu2
.
popup
(
item
);
menu2
.
dismiss
();
}
function
test_userLink
()
{
const
text
=
findChild
(
eventViewText
,
'textEventContent'
);
text
.
linkActivated
(
'https://matrix.to/#/@mew:example.com'
);
tryVerify
(()
=>
item
.
room
.
ensureStateEvent
.
calledTimes
());
verify
(
Helpers
.
deepEqual
(
item
.
room
.
ensureStateEvent
.
lastArgs
(),
[
'm.room.member'
,
'@mew:example.com'
]));
item
.
room
.
ensureStateEvent
.
lastRetVal
().
resolve
(
true
,
{});
tryVerify
(()
=>
item
.
activateUserPage
.
calledTimes
());
}
function
test_senderNameOverrided
()
{
const
name
=
findChild
(
eventViewText
,
'userNicknameText'
);
compare
(
name
.
text
,
l10n
.
get
(
'user-name-overrided'
,
{
overridedName:
'something'
,
globalName:
'foo'
}));
}
function
test_senderNameNotOverrided
()
{
const
name
=
findChild
(
eventViewTextBySomeoneElse
,
'userNicknameText'
);
compare
(
name
.
text
,
'bar'
);
}
function
test_paginateBack
()
{
const
obj
=
item
.
eventViewComp
.
createObject
(
item
);
tryVerify
(()
=>
item
.
paginateBackRequested
.
calledTimes
());
verify
(
item
.
paginateBackRequested
.
lastArgs
()[
0
]
===
'$some-event-id'
);
item
.
paginateBackRequested
.
clear
();
obj
.
event
.
eventId
=
'$some-other-event-id'
;
tryVerify
(()
=>
item
.
paginateBackRequested
.
calledTimes
()
===
1
);
verify
(
item
.
paginateBackRequested
.
lastArgs
()[
0
]
===
'$some-other-event-id'
);
item
.
paginateBackRequested
.
clear
();
const
newEvent
=
eventComp
.
createObject
(
item
);
obj
.
event
=
newEvent
;
tryVerify
(()
=>
item
.
paginateBackRequested
.
calledTimes
()
===
1
);
verify
(
item
.
paginateBackRequested
.
lastArgs
()[
0
]
===
'$some-event-id'
);
item
.
paginateBackRequested
.
clear
();
obj
.
isGapped
=
false
;
verify
(
item
.
paginateBackRequested
.
calledTimes
()
===
0
);
}
function
test_avatarClick
()
{
const
avatar
=
findChild
(
eventViewText
,
'senderAvatar'
);
mouseClick
(
avatar
);
tryVerify
(()
=>
item
.
activateUserPage
.
calledTimes
()
===
1
);
// verify that the user id is passed
verify
(
item
.
activateUserPage
.
lastArgs
()[
2
]
===
'@foo:tusooa.xyz'
);
}
function
test_imageEvent
()
{
verify
(
!
findChild
(
eventViewImage
,
'summaryLabel'
).
visible
);
verify
(
findChild
(
eventViewImage
,
'bodyLabel'
).
visible
);
verify
(
findChild
(
eventViewImageCompact
,
'summaryLabel'
).
visible
);
verify
(
!
findChild
(
eventViewImageCompact
,
'bodyLabel'
).
visible
);
verify
(
!
findChild
(
eventViewSticker
,
'summaryLabel'
).
visible
);
verify
(
findChild
(
eventViewSticker
,
'bodyLabel'
).
visible
);
verify
(
findChild
(
eventViewStickerCompact
,
'summaryLabel'
).
visible
);
verify
(
!
findChild
(
eventViewStickerCompact
,
'bodyLabel'
).
visible
);
const
image
=
findChild
(
eventViewImageCompact
,
'mainImage'
);
verify
(
image
.
height
<=
Kirigami
.
Units
.
gridUnit
*
5
);
}
function
test_history
()
{
{
const
menuComp
=
findChild
(
eventViewText
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
const
action
=
findChild
(
menu
,
'viewHistoryMenuItem'
);
verify
(
!
action
.
enabled
);
}
{
const
menuComp
=
findChild
(
eventViewEdited
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
const
action
=
findChild
(
menu
,
'viewHistoryMenuItem'
);
verify
(
action
.
enabled
);
action
.
trigger
();
compare
(
viewEventHistoryRequested
.
calledTimes
(),
1
);
compare
(
viewEventHistoryRequested
.
lastArgs
()[
0
],
'!some-event-id'
);
}
}
function
test_pinned
()
{
{
const
menuComp
=
findChild
(
eventViewPinned
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
const
action
=
findChild
(
menu
,
'pinUnpinMenuItem'
);
verify
(
action
.
enabled
);
action
.
trigger
();
compare
(
unpinEventRequested
.
calledTimes
(),
1
);
compare
(
unpinEventRequested
.
lastArgs
()[
0
],
'$123'
);
compare
(
pinEventRequested
.
calledTimes
(),
0
);
}
{
const
menuComp
=
findChild
(
eventViewNotPinned
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
const
action
=
findChild
(
menu
,
'pinUnpinMenuItem'
);
verify
(
action
.
enabled
);
action
.
trigger
();
compare
(
pinEventRequested
.
calledTimes
(),
1
);
compare
(
pinEventRequested
.
lastArgs
()[
0
],
'$789'
);
compare
(
pinEventRequested
.
calledTimes
(),
1
);
}
{
const
menuComp
=
findChild
(
eventView
,
'bubble'
).
menuComp
;
const
menu
=
menuComp
.
createObject
(
menuComp
.
parent
);
const
action
=
findChild
(
menu
,
'pinUnpinMenuItem'
);
verify
(
!
action
.
enabled
);
}
}
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 19, 5:18 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55346
Default Alt Text
tst_EventView.qml (19 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment