/*************************************************************/ /* */ /* Copyright (C) Microsoft Corporation. All rights reserved. */ /* */ /*************************************************************/ import Colors 1.0 import Fonts 1.0 import QtQuick 2.7 import QtQuick.Controls 2.4 import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.4 import QtQml 2.2 import "HelperFunctions.js" as HelperFunctions // Error list item, data is configured by an ActivityCenterErrorData struct // stored in a list in the ErrorModel FocusScope { anchors.left: parent.left anchors.right: parent.right height: rootMessageRect.height id: errorItem // Attaches to parent so we can access data property variant parentErrorsList: ListView.view property var messageColors: HelperFunctions.chooseListItemMessageColor(errorsModel.isWarningsOnly, errorsModel.isQuietErrorsOnly); // SinglePageEntry follows custom theme. Otherwise follow default error list theme property variant buttonOneTheme: HelperFunctions.chooseListItemButtonOneTheme(errorsModel.hasSingleFrontPageEntry, errorsModel.isWarningOnly, errorsModel.isQuietErrorsOnly); property variant buttonTwoTheme: (errorsModel.hasSingleFrontPageEntry && !errorsModel.isWarningOnly) ? Colors.acm_buttons.error_transparent : Colors.acm_buttons.primary_transparent function isSelfOrChildActive() { return (activeFocus || learnMoreLinkId.activeFocus || buttonOne.activeFocus || buttonTwo.activeFocus || errorCheckBox.activeFocus); } property bool containsHoverFocus: (itemMouseArea.containsMouse || learnMoreLinkId.hovered || buttonOne.containsMouse || buttonTwo.containsMouse || errorCheckBox.hovered) Rectangle { id: hoverRectangle anchors.fill: parent color: (errorsModel.hasSingleFrontPageEntry) ? messageColors.background : HelperFunctions.chooseListItemBackgroundColor( headerModel.isUsingActivityCenter2, isSelfOrChildActive(), true, containsHoverFocus) border.color: isSelfOrChildActive() ? Colors.activity_center.list.border_focus : "transparent" border.width: 1 focus: true radius: (errorsModel.hasSingleFrontPageEntry || errorsModel.isHeroImageDisplay) ? 3 : 0 KeyNavigation.left: buttonTwo KeyNavigation.right: buttonOne function makeItemCurrent() { if (parentErrorsList) { parentErrorsList.currentIndex = index; parentErrorsList.positionViewAtIndex(index, ListView.Visible); parentErrorsList.forceActiveFocus(); } } function mainAction() { makeItemCurrent(); errorsModel.MainAction(index, errorCheckBox.checked); } MouseArea { id: itemMouseArea anchors.fill: parent hoverEnabled: true onClicked: hoverRectangle.mainAction(index, errorCheckBox.checked) } Accessible.role: Accessible.LayeredPane Accessible.name: (errorsModel.hasSingleFrontPageEntry) ? (errorsModel.GetPrimaryErrorData("primaryText") + "," + errorsModel.GetPrimaryErrorData("secondaryText")) : (primaryText + ";" + itemIndexAccessibleText + ";" + secondaryText) Accessible.focusable: true Accessible.selectable: true Accessible.selected: errorItem.ListView.isCurrentItem Accessible.ignored: !visible Accessible.onPressAction: activateAndDoAction(); function activateAndDoAction() { hoverRectangle.makeItemCurrent() hoverRectangle.mainAction(index, errorCheckBox.checked); } Keys.onEnterPressed: activateAndDoAction() Keys.onReturnPressed: activateAndDoAction() Keys.onSpacePressed: activateAndDoAction() Rectangle { id: rootMessageRect readonly property int verticalPadding: 8 readonly property int horizontalPadding: 12 height: visible ? (errorsModel.hasSingleFrontPageEntry) ? Math.max(messageInner.height, 60) : messageInner.height : 0 activeFocusOnTab: false // Focus should go to content instead anchors.left: parent.left anchors.right: parent.right color: "transparent" // So the hoverRectangle shows through Rectangle { id: messageInner anchors.top: parent.top anchors.topMargin: errorsModel.isHeroImageDisplay ? 0 : rootMessageRect.verticalPadding anchors.left: parent.left anchors.leftMargin: errorsModel.isHeroImageDisplay ? 0 : rootMessageRect.horizontalPadding anchors.right: parent.right anchors.rightMargin: errorsModel.isHeroImageDisplay ? 0 : rootMessageRect.horizontalPadding height: (heroImage.height + messageTextGroup.height + loaderRect.height + actionButtons.height + rootMessageRect.verticalPadding + (errorCheckBox.visible ? (errorCheckBox.height + rootMessageRect.verticalPadding) : 0 ) + rootMessageRect.verticalPadding) color: "transparent" Image { id: heroImage width: errorsModel.isHeroImageDisplay ? 250 : 0 height: errorsModel.isHeroImageDisplay ? 150: 0 sourceSize.width: width sourceSize.height: height anchors.left:parent.left anchors.right: parent.right fillMode: Image.PreserveAspectCrop anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.topMargin: 0 anchors.bottomMargin: 0 anchors.top: parent.top visible: errorsModel.isHeroImageDisplay source: errorsModel.isHeroImageDisplay ? errorsModel.GetPrimaryErrorData("megaImage") : (errorsModel.isMegaModeDisplay ? "file:///" + imageLocation + errorsModel.GetPrimaryErrorData("megaImage") : "file:///" + imageLocation + errorsModel.GetPrimaryErrorData("imageUrl")) } Image { id: messageIcon width: errorsModel.hasSingleFrontPageEntry ? (errorsModel.isMegaModeDisplay ? 0: 48) : 32 height: width sourceSize.width: 48 sourceSize.height: 48 anchors.left: parent.left anchors.top: heroImage.bottom anchors.topMargin: 3 anchors.leftMargin: errorsModel.isHeroImageDisplay ? rootMessageRect.horizontalPadding : 0 fillMode: Image.PreserveAspectFit visible: !errorsModel.isMegaModeDisplay // If an imageUrl isn't specified, then we know we should use the file icon image source: errorsModel.hasSingleFrontPageEntry ? (errorsModel.GetPrimaryErrorData("imageUrl") ? ("file:///" + imageLocation + errorsModel.GetPrimaryErrorData("imageUrl") ) : errorsModel.GetPrimaryErrorData("fileImage")) : (imageUrl ? ("file:///" + imageLocation + imageUrl) : fileImage) } Column { id: messageTextGroup anchors.left: messageIcon.right anchors.leftMargin: rootMessageRect.horizontalPadding anchors.right : parent.right anchors.top: heroImage.bottom anchors.topMargin: errorsModel.isHeroImageDisplay ? 8 : 0 Text { id: messagePrimary color: (errorsModel.hasSingleFrontPageEntry) ? messageColors.text: containsHoverFocus ? Colors.common.text_hover : Colors.common.text text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("primaryText") : primaryText height: visible ? undefined : 0 font.family: Fonts.semibold font.styleName: "Semibold" font.pixelSize: errorsModel.isMegaModeDisplay ? 15: 14 anchors.left: messageTextGroup.left anchors.right: messageTextGroup.right wrapMode: Text.WordWrap horizontalAlignment: errorsModel.isMegaModeDisplay ? Text.AlignHCenter: Text.AlignLeft verticalAlignment: Text.AlignTop } Image { id: messageMegaImage width: errorsModel.isMegaModeDisplay ? 278 : 0 height: errorsModel.isMegaModeDisplay ? 102: 0 sourceSize.width: width sourceSize.height: height anchors.left: messageTextGroup.left anchors.right: messageTextGroup.right fillMode: Image.PreserveAspectFit anchors.leftMargin: 44 anchors.rightMargin: 44 anchors.topMargin: 16 anchors.bottomMargin: 16 visible: errorsModel.isMegaModeDisplay source: errorsModel.isHeroImageDisplay ? errorsModel.GetPrimaryErrorData("megaImage") : (errorsModel.isMegaModeDisplay ? "file:///" + imageLocation + errorsModel.GetPrimaryErrorData("megaImage") : "file:///" + imageLocation + errorsModel.GetPrimaryErrorData("imageUrl")) } Text { id: messageSecondary color: (errorsModel.hasSingleFrontPageEntry) ? messageColors.text : containsHoverFocus ? Colors.common.text_secondary_hovering : Colors.common.text_secondary text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("secondaryText") : secondaryText // "Title only" errors exist, currently by setting text to " " // In this case, hide the secondary text field visible: (text != " ") height: visible ? undefined : 0 font.pixelSize: errorsModel.isMegaModeDisplay ? 14: 12 font.family: Fonts.semilight wrapMode: Text.WordWrap horizontalAlignment: errorsModel.isMegaModeDisplay ? Text.AlignHCenter: Text.AlignLeft anchors.left: parent.left anchors.right: parent.right } Text { id: messageTertiary color: (errorsModel.hasSingleFrontPageEntry) ? messageColors.text : containsHoverFocus ? Colors.common.text_secondary_hovering : Colors.common.text_secondary visible: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("hasTertiaryText") : hasTertiaryText text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("tertiaryText") : tertiaryText height: visible ? undefined : 0 font.pixelSize: 12 font.family: Fonts.semilight wrapMode: Text.WordWrap horizontalAlignment: Text.AlignLeft anchors.left: parent.left anchors.right: parent.right topPadding: rootMessageRect.verticalPadding // To manually center the list text, we add a margin on the left side // but leave the right side for small pixel overflow property bool centerText: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("centerTertiaryText") : centerTertiaryText property int marginCalc: ((parent.width - contentWidth - messageIcon.width) / 2) anchors.leftMargin: centerText ? (Math.max(marginCalc, 0)) : 0 // Provides extra spacing between each line lineHeight : 1.2 Accessible.role: Accessible.StaticText Accessible.name: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("tertiaryTextAccessible") : tertiaryTextAccessible Accessible.focusable: true activeFocusOnTab: true Accessible.ignored: !visible } Button { id: learnMoreLinkId width: Math.min(parent.width, contentItem.learnMoreTextItem.width) anchors.left: messageTertiary.visible ? messageTertiary.left : parent.left height: visible ? contentItem.paintedHeight : 0 leftPadding: 0 rightPadding: 0 bottomPadding: 0 topPadding: 0 activeFocusOnTab: true visible: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("hasLearnMoreLink") : hasLearnMoreLink contentItem: Text { id: learnMoreTextItem text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("learnMoreText") : learnMoreText font.family: Fonts.standard font.pixelSize: 12 font.underline: learnMoreLinkId.visualFocus color: parent.pressed ? Colors.common.hyperlink_pressed : parent.hovered ? Colors.common.hyperlink_hovering : Colors.common.hyperlink horizontalAlignment: Text.AlignLeft } background: Rectangle { implicitWidth: learnMoreLinkId.width implicitHeight: learnMoreLinkId.height color: "transparent" } function launchLearnMoreAction() { errorsModel.LearnMoreClicked(index, errorCheckBox.checked); } Accessible.ignored: !visible Accessible.onPressAction: launchLearnMoreAction() Accessible.name: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("learnMoreText") : learnMoreText Keys.onEnterPressed: launchLearnMoreAction() Keys.onReturnPressed: launchLearnMoreAction() Keys.onSpacePressed: launchLearnMoreAction() MouseArea { id: folderLinkMouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: parent.launchLearnMoreAction() } } Button { id: secondLinkId width: Math.min(parent.width, contentItem.secondLinkTextItem.width) anchors.left: messageTertiary.visible ? messageTertiary.left : parent.left height: visible ? contentItem.paintedHeight : 0 leftPadding: 0 rightPadding: 0 bottomPadding: 0 topPadding: 0 activeFocusOnTab: true visible: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("hasSecondLink") : hasSecondLink contentItem: Text { id: secondLinkTextItem text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("secondLinkText") : secondLinkText font.family: Fonts.standard font.pixelSize: 12 font.underline: secondLinkId.visualFocus color: parent.pressed ? Colors.common.hyperlink_pressed : parent.hovered ? Colors.common.hyperlink_hovering : Colors.common.hyperlink horizontalAlignment: Text.AlignLeft } background: Rectangle { implicitWidth: secondLinkId.width implicitHeight: secondLinkId.height color: "transparent" } function launchSecondLinkAction() { errorsModel.SecondLinkClicked(index, errorCheckBox.checked); } Accessible.ignored: !visible Accessible.onPressAction: launchSecondLinkAction() Accessible.name: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("secondLinkText") : secondLinkText Keys.onEnterPressed: launchSecondLinkAction() Keys.onReturnPressed: launchSecondLinkAction() Keys.onSpacePressed: launchSecondLinkAction() MouseArea { id: secondLinkMouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: parent.launchSecondLinkAction() } } } // This area contains custom controls configured for each error. // If the ActivityCenterErrorData struct specifies the customControlFile // This qml file will be loaded below Rectangle { id: loaderRect height: errorsModel.hasSingleFrontPageEntry ? (errorsModel.GetPrimaryErrorData("hasCustomControl") ? childrenRect.height : 0 ) : ( hasCustomControl ? childrenRect.height : 0) anchors.top: (errorCheckBox.visible ? errorCheckBox.bottom : messageTextGroup.bottom) anchors.left: messageTextGroup.left anchors.topMargin: rootMessageRect.verticalPadding visible: errorsModel.hasSingleFrontPageEntry ? (errorsModel.GetPrimaryErrorData("customControlsFile").length === 0) : (customControlsFile.length === 0) Loader { source: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("customControlsFile") : customControlsFile asynchronous: true active: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("hasCustomControl") : hasCustomControl visible: (status === Loader.Ready) } } CheckBox { id: errorCheckBox visible: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("hasCheckbox") : hasCheckbox spacing: 2 topPadding: -1 bottomPadding: 0 // Anchor to left and shift over checkbox by width of error icon image, // so the user can click in the empty area under the icon leftPadding: messageIcon.width + rootMessageRect.horizontalPadding rightPadding: messageIcon.width + rootMessageRect.horizontalPadding anchors.top: messageTextGroup.bottom anchors.left: parent.left anchors.topMargin: visible ? rootMessageRect.verticalPadding : 0 height: visible ? contentItem.paintedHeight : 0 contentItem: Text { id: checkboxTextLabel width: errorCheckBox.width anchors.left: indicatorBox.right leftPadding: errorCheckBox.spacing rightPadding: errorCheckBox.spacing text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("checkboxText") : checkboxText color: messageColors.text font.pixelSize: 12 font.family: Fonts.standard font.weight: Font.Light } indicator: Rectangle { id: indicatorBox implicitWidth: 14 implicitHeight: 14 border.width: parent.visualFocus ? 2 : 1 border.color: buttonOneTheme.button x: headerModel.isRTL ? (parent.width - parent.leftPadding - implicitWidth ) : parent.leftPadding Image { sourceSize.width: 14 sourceSize.height: 14 anchors.fill: parent source: "file:///" + imageLocation + "checkboxComposite.svg" visible: errorCheckBox.checked } } // Workaround for accessibility, Controls2.0 read accessible text from text, // instead of setting Accessible.name. Displayed text is based off contentItem (checkboxTextLabel) text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("checkboxText") : checkboxText Accessible.ignored: !visible Accessible.role: Accessible.CheckBox Accessible.focusable: true } Flow { id: actionButtons objectName: "actionButtons" spacing: 8 visible: (errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("buttonOneVisible") || errorsModel.GetPrimaryErrorData("buttonTwoVisible") : buttonOneVisible || buttonTwo.visible) anchors.top: errorCheckBox.bottom anchors.left: messageTextGroup.left anchors.topMargin: visible ? rootMessageRect.verticalPadding : 0 bottomPadding: visible ? rootMessageRect.verticalPadding : 0 anchors.right: parent.right // We need to manually set the height larger so the flow spaces the item below, instead of next to the other item height: errorsModel.isMegaModeDisplay ? buttonOne.height + buttonTwo.height + (2 * rootMessageRect.verticalPadding) : childrenRect.height + (visible ? (rootMessageRect.verticalPadding) : 0) flow: errorsModel.isMegaModeDisplay ? Flow.TopToBottom: Flow.LeftToRight property int maxButtonWidth: Math.max(buttonOne.width, buttonTwo.width) // To manually center the buttons, we add a margin on each side to fill up any empty space // maxButtonWidth represents the largest button. property int marginCalc: (parent.width - maxButtonWidth) / 2 anchors.leftMargin: errorsModel.isMegaModeDisplay ? marginCalc: 0 anchors.rightMargin: errorsModel.isMegaModeDisplay ? marginCalc: 0 SimpleButton { id: buttonOne visible: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("buttonOneVisible") : buttonOneVisible width: visible ? (errorsModel.isMegaModeDisplay || errorsModel.isHeroImageDisplay) ? Math.max(externalWidth, buttonTwo.externalWidth): externalWidth: 0 height: visible ? 28 : 0 // Save into separate value to break circular references in width calculation property var externalWidth : visible ? ((textcontrol.width > 80) ? textcontrol.width : 80) : 0 colorScheme: buttonOneTheme radius: 3 focusunderline: true activeFocusOnTab: true KeyNavigation.left: hoverRectangle KeyNavigation.right: buttonTwo textcontrol.font.pixelSize: errorsModel.isMegaModeDisplay ? 14: 12 textcontrol.text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("primaryButtonText") : primaryButtonText textcontrol.font.family: Fonts.semibold textcontrol.font.styleName: "Semibold" textcontrol.topPadding: 4 textcontrol.bottomPadding: 4 textcontrol.leftPadding: 12 textcontrol.rightPadding: 12 callback: function() { errorsModel.PrimaryAction(index, errorCheckBox.checked); } Accessible.name: textcontrol.text Accessible.ignored: !visible } SimpleButton { id: buttonTwo visible: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("buttonTwoVisible") : buttonTwoVisible width: visible ? errorsModel.isMegaModeDisplay ? Math.max(externalWidth, buttonOne.externalWidth): externalWidth: 0 height: visible ? 28 : 0 colorScheme: buttonTwoTheme radius: 3 focusunderline: true activeFocusOnTab: true KeyNavigation.left: buttonOne KeyNavigation.right: hoverRectangle // Save into separate value to break circular references in width calculation property var externalWidth : visible ? ((textcontrol.width > 80) ? textcontrol.width : 80) : 0 anchors.topMargin: (errorsModel.isMegaModeDisplay || errorsModel.isHeroImageDisplay) ? 4: 0 textcontrol.font.pixelSize: errorsModel.isMegaModeDisplay ? 14: 12 textcontrol.text: errorsModel.hasSingleFrontPageEntry ? errorsModel.GetPrimaryErrorData("secondaryButtonText") : secondaryButtonText textcontrol.font.family: Fonts.semibold textcontrol.font.styleName: "Semibold" textcontrol.topPadding: 4 textcontrol.bottomPadding: 4 textcontrol.leftPadding: 12 textcontrol.rightPadding: 12 textcontrol.font.bold: true callback: function() { errorsModel.SecondaryAction(index, errorCheckBox.checked); } Accessible.name: textcontrol.text Accessible.ignored: !visible } } } } } }