fix #138, import new tooltips from plasma 5.9
--without even a small delay!!! we imported them, and loved them!! check them out by playing music or movies!!!v0.6
parent
bcda08df6e
commit
9705cea16d
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2013 by Sebastian Kügler <sebas@kde.org>
|
||||
* Copyright 2014 by Martin Gräßlin <mgraesslin@kde.org>
|
||||
* Copyright 2016 by Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
* Copyright 2017 by Roman Gilg <subdiff@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQml.Models 2.2
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
|
||||
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
|
||||
|
||||
PlasmaExtras.ScrollArea {
|
||||
property Item parentTask
|
||||
property int parentIndex
|
||||
|
||||
property string appName
|
||||
property int pidParent
|
||||
property bool isGroup
|
||||
|
||||
property var windows
|
||||
readonly property bool isWin: windows !== undefined
|
||||
|
||||
property variant icon
|
||||
property url launcherUrl
|
||||
property bool isLauncher
|
||||
property bool isMinimizedParent
|
||||
|
||||
// Needed for generateSubtext()
|
||||
property string displayParent
|
||||
property string genericName
|
||||
property int virtualDesktopParent
|
||||
property bool isOnAllVirtualDesktopsParent
|
||||
property var activitiesParent
|
||||
//
|
||||
readonly property bool isVerticalPanel: plasmoid.formFactor == PlasmaCore.Types.Vertical
|
||||
|
||||
Layout.minimumWidth: contentItem.width
|
||||
Layout.maximumWidth: Layout.minimumWidth
|
||||
|
||||
Layout.minimumHeight: contentItem.height
|
||||
Layout.maximumHeight: Layout.minimumHeight
|
||||
|
||||
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
property int textWidth: theme.mSize(theme.defaultFont).width * 20
|
||||
|
||||
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
|
||||
Component.onCompleted: {
|
||||
flickableItem.interactive = Qt.binding(function() {
|
||||
return isVerticalPanel ? contentItem.height > viewport.height : contentItem.width > viewport.width
|
||||
});
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: contentItem
|
||||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
onContainsMouseChanged: {
|
||||
checkMouseInside();
|
||||
}
|
||||
|
||||
function checkMouseInside(){
|
||||
var isInside = containsMouse || childrenContainMouse();
|
||||
if (isInside){
|
||||
root.disableRestoreZoom = true;
|
||||
checkListHovered.stop();
|
||||
toolTipDelegate.currentItem = parentIndex;
|
||||
}
|
||||
else{
|
||||
root.disableRestoreZoom = false;
|
||||
toolTipDelegate.currentItem = -1;
|
||||
checkListHovered.restart();
|
||||
}
|
||||
}
|
||||
|
||||
function childrenContainMouse() {
|
||||
return singleTask.containsMouse() || groupTask.containsMouse();
|
||||
}
|
||||
|
||||
ToolTipInstance {
|
||||
id: singleTask
|
||||
visible: !isGroup
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: groupTask
|
||||
rows: !isVerticalPanel
|
||||
columns: isVerticalPanel
|
||||
flow: isVerticalPanel ? Grid.TopToBottom : Grid.LeftToRight
|
||||
spacing: units.largeSpacing
|
||||
|
||||
visible: isGroup
|
||||
|
||||
Repeater {
|
||||
id: groupRepeater
|
||||
model: DelegateModel {
|
||||
model: tasksModel
|
||||
rootIndex: tasksModel.makeModelIndex(parentIndex, -1)
|
||||
delegate: ToolTipInstance {}
|
||||
}
|
||||
}
|
||||
|
||||
function containsMouse(){
|
||||
for(var i=0; i<children.length-1; ++i){
|
||||
if(children[i].containsMouse())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,488 @@
|
||||
/*
|
||||
* Copyright 2013 by Sebastian Kügler <sebas@kde.org>
|
||||
* Copyright 2014 by Martin Gräßlin <mgraesslin@kde.org>
|
||||
* Copyright 2016 by Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
* Copyright 2017 by Roman Gilg <subdiff@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQml.Models 2.2
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
|
||||
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
|
||||
Column {
|
||||
property var submodelIndex: tasksModel.makeModelIndex(parentIndex, isGroup ? index : -1)
|
||||
property int flatIndex: isGroup && index != undefined ? index : 0
|
||||
|
||||
spacing: units.smallSpacing
|
||||
|
||||
property string mprisSourceName: mpris2Source.sourceNameForLauncherUrl(toolTipDelegate.launcherUrl, isGroup ? AppPid : pidParent)
|
||||
property var playerData: mprisSourceName != "" ? mpris2Source.data[mprisSourceName] : 0
|
||||
property bool hasPlayer: !!mprisSourceName && !!playerData
|
||||
property bool playing: hasPlayer && playerData.PlaybackStatus === "Playing"
|
||||
property bool canControl: hasPlayer && playerData.CanControl
|
||||
property bool canGoBack: hasPlayer && playerData.CanGoPrevious
|
||||
property bool canGoNext: hasPlayer && playerData.CanGoNext
|
||||
property bool canRaise: hasPlayer && playerData.CanRaise
|
||||
property var currentMetadata: hasPlayer ? playerData.Metadata : ({})
|
||||
|
||||
readonly property string track: {
|
||||
var xesamTitle = currentMetadata["xesam:title"]
|
||||
if (xesamTitle) {
|
||||
return xesamTitle;
|
||||
}
|
||||
// if no track title is given, print out the file name
|
||||
var xesamUrl = currentMetadata["xesam:url"] ? currentMetadata["xesam:url"].toString() : ""
|
||||
if (!xesamUrl) {
|
||||
return "";
|
||||
}
|
||||
var lastSlashPos = xesamUrl.lastIndexOf('/')
|
||||
if (lastSlashPos < 0) {
|
||||
return "";
|
||||
}
|
||||
var lastUrlPart = xesamUrl.substring(lastSlashPos + 1)
|
||||
return decodeURIComponent(lastUrlPart);
|
||||
}
|
||||
readonly property string artist: currentMetadata["xesam:artist"] || ""
|
||||
readonly property string albumArt: currentMetadata["mpris:artUrl"] || ""
|
||||
|
||||
//
|
||||
function containsMouse() {
|
||||
return area1.containsMouse || area2.containsMouse || area3.containsMouse || area4.containsMouse;
|
||||
//|| ( area5 && area5.containsMouse) || (area6 && area6.containsMouse) || (area7 && area7.containsMouse);
|
||||
}
|
||||
|
||||
// launcher icon + text labels + close button
|
||||
RowLayout {
|
||||
id: header
|
||||
Layout.minimumWidth: childrenRect.width
|
||||
Layout.maximumWidth: Layout.minimumWidth
|
||||
|
||||
Layout.minimumHeight: childrenRect.height
|
||||
Layout.maximumHeight: Layout.minimumHeight
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
// launcher icon
|
||||
PlasmaCore.IconItem {
|
||||
source: icon
|
||||
animated: false
|
||||
usesPlasmaTheme: false
|
||||
visible: !isWin
|
||||
}
|
||||
// all textlabels
|
||||
Column {
|
||||
spacing: 0.75 * units.smallSpacing
|
||||
PlasmaComponents.Label {
|
||||
width: isWin ? textWidth : undefined
|
||||
height: theme.mSize(theme.defaultFont).height
|
||||
font.pointSize: -1
|
||||
font.pixelSize: height
|
||||
elide: Text.ElideRight
|
||||
text: appName
|
||||
opacity: flatIndex == 0
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
// window title
|
||||
PlasmaComponents.Label {
|
||||
width: isWin ? textWidth : undefined
|
||||
height: 0.75 * theme.mSize(theme.defaultFont).height
|
||||
font.pointSize: -1
|
||||
font.pixelSize: height
|
||||
elide: Text.ElideRight
|
||||
text: generateTitle()
|
||||
textFormat: Text.PlainText
|
||||
opacity: 0.75
|
||||
}
|
||||
// subtext
|
||||
PlasmaComponents.Label {
|
||||
width: isWin ? textWidth : undefined
|
||||
height: 0.6 * theme.mSize(theme.defaultFont).height
|
||||
font.pointSize: -1
|
||||
font.pixelSize: height
|
||||
elide: Text.ElideRight
|
||||
text: isWin ? generateSubText() : ""
|
||||
textFormat: Text.PlainText
|
||||
opacity: 0.6
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
// close button
|
||||
MouseArea {
|
||||
id: area1
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
|
||||
height: units.iconSizes.smallMedium
|
||||
width: height
|
||||
|
||||
visible: isWin
|
||||
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
backend.cancelHighlightWindows();
|
||||
tasksModel.requestClose(submodelIndex);
|
||||
}
|
||||
onContainsMouseChanged: contentItem.checkMouseInside();
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
anchors.fill: parent
|
||||
active: parent.containsMouse
|
||||
|
||||
source: "window-close"
|
||||
animated: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thumbnail container
|
||||
Item {
|
||||
id: thumbnail
|
||||
width: header.width
|
||||
// similar to 0.5625 = 1 / (16:9) as most screens are
|
||||
// round necessary, otherwise shadow mask for players has gap!
|
||||
height: Math.round(0.5 * width)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
visible: isWin
|
||||
|
||||
Item {
|
||||
id: thumbnailSourceItem
|
||||
anchors.fill: parent
|
||||
|
||||
readonly property bool isMinimized: isGroup ? IsMinimized == true : isMinimizedParent
|
||||
// TODO: this causes XCB error message when being visible the first time
|
||||
property int winId: isWin && windows[flatIndex] != undefined ? windows[flatIndex] : 0
|
||||
|
||||
PlasmaCore.WindowThumbnail {
|
||||
anchors.fill: parent
|
||||
|
||||
visible: !albumArtImage.visible && !thumbnailSourceItem.isMinimized
|
||||
winId: thumbnailSourceItem.winId
|
||||
|
||||
ToolTipWindowMouseArea {
|
||||
id: area2
|
||||
|
||||
anchors.fill: parent
|
||||
rootTask: parentTask
|
||||
modelIndex: submodelIndex
|
||||
winId: thumbnailSourceItem.winId
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: albumArtImage
|
||||
// also Image.Loading to prevent loading thumbnails just because the album art takes a split second to load
|
||||
readonly property bool available: status === Image.Ready || status === Image.Loading
|
||||
|
||||
anchors.fill: parent
|
||||
sourceSize: Qt.size(parent.width, parent.height)
|
||||
asynchronous: true
|
||||
source: albumArt
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
visible: available
|
||||
|
||||
ToolTipWindowMouseArea {
|
||||
id: area3
|
||||
|
||||
anchors.fill: parent
|
||||
rootTask: parentTask
|
||||
modelIndex: submodelIndex
|
||||
winId: thumbnailSourceItem.winId
|
||||
}
|
||||
}
|
||||
|
||||
// when minimized, we don't have a preview, so show the icon
|
||||
PlasmaCore.IconItem {
|
||||
anchors.fill: parent
|
||||
source: icon
|
||||
animated: false
|
||||
usesPlasmaTheme: false
|
||||
visible: thumbnailSourceItem.isMinimized && !albumArtImage.visible
|
||||
|
||||
ToolTipWindowMouseArea {
|
||||
id: area4
|
||||
|
||||
anchors.fill: parent
|
||||
rootTask: parentTask
|
||||
modelIndex: submodelIndex
|
||||
winId: thumbnailSourceItem.winId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loader {
|
||||
anchors.fill: thumbnail
|
||||
sourceComponent: hasPlayer ? playerControlsComp : undefined
|
||||
}
|
||||
|
||||
Component {
|
||||
id: playerControlsComp
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
// TODO: When could this really be the case? A not-launcher-task always has a window!?
|
||||
// if there's no window associated with this task, we might still be able to raise the player
|
||||
// MouseArea {
|
||||
// id: raisePlayerArea
|
||||
// anchors.fill: parent
|
||||
|
||||
// visible: !isWin || !windows[0] && canRaise
|
||||
// onClicked: mpris2Source.raise(mprisSourceName)
|
||||
// }
|
||||
|
||||
Item {
|
||||
id: playerControlsFrostedGlass
|
||||
anchors.fill: parent
|
||||
visible: false // OpacityMask would render it
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height - playerControlsRow.height
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: playerControlsRow.height
|
||||
color: theme.backgroundColor
|
||||
opacity: 0.8
|
||||
}
|
||||
}
|
||||
|
||||
OpacityMask {
|
||||
id: playerControlsOpacityMask
|
||||
anchors.fill: parent
|
||||
source: playerControlsFrostedGlass
|
||||
maskSource: thumbnailSourceItem
|
||||
}
|
||||
|
||||
// prevent accidental click-through when a control is disabled
|
||||
MouseArea {
|
||||
anchors.fill: playerControlsRow
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: playerControlsRow
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
enabled: canControl
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
PlasmaExtras.Heading {
|
||||
Layout.fillWidth: true
|
||||
level: 4
|
||||
wrapMode: Text.NoWrap
|
||||
elide: Text.ElideRight
|
||||
text: track || ""
|
||||
}
|
||||
|
||||
PlasmaExtras.Heading {
|
||||
Layout.fillWidth: true
|
||||
level: 5
|
||||
wrapMode: Text.NoWrap
|
||||
elide: Text.ElideRight
|
||||
text: artist || ""
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: area5
|
||||
|
||||
height: units.iconSizes.smallMedium
|
||||
width: height
|
||||
enabled: canGoBack
|
||||
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
onClicked: mpris2Source.goPrevious(mprisSourceName)
|
||||
onContainsMouseChanged: contentItem.checkMouseInside();
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
anchors.fill: parent
|
||||
enabled: canGoBack
|
||||
active: parent.containsMouse
|
||||
|
||||
source: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward"
|
||||
animated: false
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: area6
|
||||
|
||||
height: units.iconSizes.medium
|
||||
width: height
|
||||
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
onClicked: mpris2Source.playPause(mprisSourceName)
|
||||
onContainsMouseChanged: contentItem.checkMouseInside();
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
anchors.fill: parent
|
||||
active: parent.containsMouse
|
||||
|
||||
source: playing ? "media-playback-pause" : "media-playback-start"
|
||||
animated: false
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: area7
|
||||
|
||||
height: units.iconSizes.smallMedium
|
||||
width: height
|
||||
enabled: canGoNext
|
||||
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
onClicked: mpris2Source.goNext(mprisSourceName)
|
||||
onContainsMouseChanged: contentItem.checkMouseInside();
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
anchors.fill: parent
|
||||
enabled: canGoNext
|
||||
active: parent.containsMouse
|
||||
|
||||
source: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward"
|
||||
animated: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateTitle() {
|
||||
if (!isWin) {
|
||||
return genericName != undefined ? genericName : "";
|
||||
}
|
||||
|
||||
var text;
|
||||
if (isGroup) {
|
||||
if (model.display == undefined) {
|
||||
return "";
|
||||
}
|
||||
text = model.display.toString();
|
||||
} else {
|
||||
text = displayParent;
|
||||
}
|
||||
|
||||
// KWin appends increasing integers in between pointy brackets to otherwise equal window titles.
|
||||
// In this case save <#number> as counter and delete it at the end of text.
|
||||
var counter = text.match(/<\d+>\W*$/);
|
||||
text = text.replace(/\s*<\d+>\W*$/, "");
|
||||
|
||||
// Remove appName from the end of text.
|
||||
var appNameRegex = new RegExp(appName + "$", "i");
|
||||
text = text.replace(appNameRegex, "");
|
||||
text = text.replace(/\s*(?:-|—)*\s*$/, "");
|
||||
|
||||
// Add counter back at the end.
|
||||
if (counter != null) {
|
||||
if (text == "") {
|
||||
text = counter;
|
||||
} else {
|
||||
text = text + " " + counter;
|
||||
}
|
||||
}
|
||||
|
||||
// In case the window title had only redundant informations (i.e. appName), text is now empty.
|
||||
// Add a hyphen to indicate that and avoid empty space.
|
||||
if (text == "") {
|
||||
text = "—";
|
||||
}
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
function generateSubText() {
|
||||
if (activitiesParent == undefined) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var subTextEntries = [];
|
||||
|
||||
var vd = isGroup ? VirtualDesktop : virtualDesktopParent;
|
||||
|
||||
if (!plasmoid.configuration.showOnlyCurrentDesktop
|
||||
&& virtualDesktopInfo.numberOfDesktops > 1
|
||||
&& (isGroup ? IsOnAllVirtualDesktops : isOnAllVirtualDesktopsParent) !== true
|
||||
&& vd != -1
|
||||
&& vd != undefined
|
||||
&& virtualDesktopInfo.desktopNames[vd - 1] != undefined) {
|
||||
subTextEntries.push(i18n("On %1", virtualDesktopInfo.desktopNames[vd - 1]));
|
||||
}
|
||||
|
||||
var act = isGroup ? Activities : activitiesParent;
|
||||
if (act == undefined) {
|
||||
return subTextEntries.join("\n");
|
||||
}
|
||||
|
||||
if (act.length == 0 && activityInfo.numberOfRunningActivities > 1) {
|
||||
subTextEntries.push(i18nc("Which virtual desktop a window is currently on",
|
||||
"Available on all activities"));
|
||||
} else if (act.length > 0) {
|
||||
var activityNames = [];
|
||||
|
||||
for (var i = 0; i < act.length; i++) {
|
||||
var activity = act[i];
|
||||
var activityName = activityInfo.activityName(act[i]);
|
||||
if (activityName == "") {
|
||||
continue;
|
||||
}
|
||||
if (plasmoid.configuration.showOnlyCurrentActivity) {
|
||||
if (activity != activityInfo.currentActivity) {
|
||||
activityNames.push(activityName);
|
||||
}
|
||||
} else if (activity != activityInfo.currentActivity) {
|
||||
activityNames.push(activityName);
|
||||
}
|
||||
}
|
||||
|
||||
if (plasmoid.configuration.showOnlyCurrentActivity) {
|
||||
if (activityNames.length > 0) {
|
||||
subTextEntries.push(i18nc("Activities a window is currently on (apart from the current one)",
|
||||
"Also available on %1", activityNames.join(", ")));
|
||||
}
|
||||
} else if (activityNames.length > 0) {
|
||||
subTextEntries.push(i18nc("Which activities a window is currently on",
|
||||
"Available on %1", activityNames.join(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
return subTextEntries.join("\n");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue