mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[IFT] split Learn IDE panel into platform and IFT; make Interactive Courses extendable
GitOrigin-RevId: 8bbee632ea187872b94b273ce815fd722bd940b0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2643fa9d3b
commit
4940c62966
@@ -6,6 +6,7 @@ import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
@@ -68,6 +69,11 @@ public abstract class ApplicationInfo {
|
||||
|
||||
public abstract String getKeyConversionUrl();
|
||||
|
||||
@Nullable
|
||||
public String getGettingStartedUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract boolean hasHelp();
|
||||
|
||||
public abstract boolean hasContextHelp();
|
||||
|
||||
@@ -1916,6 +1916,12 @@ welcome.screen.action.docs.how.tos.action.text=Docs and How-Tos
|
||||
welcome.screen.plugins.title=Plugins
|
||||
welcome.screen.projects.title=Projects
|
||||
welcome.screen.customize.title=Customize
|
||||
welcome.screen.learnIde.title=Learn IDE
|
||||
|
||||
welcome.screen.learnIde.interactive.courses.text=Interactive Courses
|
||||
welcome.screen.learnIde.help.and.resources.text=Help and Resources
|
||||
|
||||
|
||||
|
||||
welcome.screen.color.theme.header=Color theme
|
||||
welcome.screen.ide.font.size.label=IDE font:
|
||||
|
||||
@@ -289,6 +289,7 @@ public interface IdeActions {
|
||||
@NonNls String GROUP_WELCOME_SCREEN_DOC = "WelcomeScreen.Documentation";
|
||||
@NonNls String GROUP_WELCOME_SCREEN_CONFIGURE = "WelcomeScreen.Configure";
|
||||
@NonNls String GROUP_WELCOME_SCREEN_HELP = "WelcomeScreen.Help";
|
||||
@NonNls String GROUP_WELCOME_SCREEN_LEARN_IDE = "WelcomeScreen.LearnIdeHelp";
|
||||
@NonNls String ACTION_KEYMAP_REFERENCE="Help.KeymapReference";
|
||||
@NonNls String ACTION_MOVE = "Move";
|
||||
@NonNls String ACTION_RENAME = "RenameElement";
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm
|
||||
|
||||
import javax.swing.Action
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JComponent
|
||||
|
||||
interface InteractiveCourseData {
|
||||
|
||||
fun getName(): String
|
||||
|
||||
fun getDescription(): String
|
||||
|
||||
fun getIcon(): Icon
|
||||
|
||||
fun getActionButtonName(): String
|
||||
|
||||
fun getAction(): Action
|
||||
|
||||
fun getExpandContent(): JComponent
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
interface InteractiveCourseFactory {
|
||||
|
||||
companion object {
|
||||
val INTERACTIVE_COURSE_FACTORY_EP = ExtensionPointName<InteractiveCourseFactory>("com.intellij.interactiveCourseFactory")
|
||||
}
|
||||
|
||||
fun getInteractiveCourseData(): InteractiveCourseData
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationInfo;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GettingStartedAction extends AnAction implements DumbAware {
|
||||
private final String myUrl;
|
||||
|
||||
public GettingStartedAction() {
|
||||
myUrl = ApplicationInfo.getInstance().getGettingStartedUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
//boolean enabled = myUrl != null;
|
||||
//e.getPresentation().setEnabledAndVisible(enabled);
|
||||
e.getPresentation().setEnabledAndVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
if (myUrl != null) {
|
||||
BrowserUtil.browse(myUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen
|
||||
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.wm.WelcomeScreenTab
|
||||
import com.intellij.openapi.wm.WelcomeTabFactory
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.learnIde.LearnIdeContentPanel
|
||||
import javax.swing.JComponent
|
||||
|
||||
class LearnIdeTabFactory: WelcomeTabFactory {
|
||||
override fun createWelcomeTab(parentDisposable: Disposable): WelcomeScreenTab {
|
||||
return object : TabbedWelcomeScreen.DefaultWelcomeScreenTab(IdeBundle.message("welcome.screen.learnIde.title")) {
|
||||
override fun buildComponent(): JComponent {
|
||||
return LearnIdeContentPanel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen.learnIde
|
||||
|
||||
import com.intellij.ui.scale.JBUIScale
|
||||
import java.awt.Dimension
|
||||
import java.awt.event.MouseEvent
|
||||
import javax.swing.JTextPane
|
||||
import javax.swing.plaf.ComponentUI
|
||||
import javax.swing.plaf.FontUIResource
|
||||
import javax.swing.plaf.TextUI
|
||||
import javax.swing.text.DefaultCaret
|
||||
import javax.swing.text.SimpleAttributeSet
|
||||
import javax.swing.text.StyleConstants
|
||||
|
||||
class HeightLimitedPane(text: String, val relativeFontSize: Int, val style: SimpleAttributeSet, val _width: Int? = null) : JTextPane() {
|
||||
init {
|
||||
isEditable = false
|
||||
document.insertString(0, text, style)
|
||||
//ensure that style has been applied
|
||||
StyleConstants.setFontSize(style, (font.size2D + JBUIScale.scale(relativeFontSize)).toInt())
|
||||
styledDocument.setCharacterAttributes(0, text.length, style, true)
|
||||
styledDocument.setParagraphAttributes(0, text.length, style, true)
|
||||
isOpaque = false
|
||||
isEditable = false
|
||||
alignmentX = LEFT_ALIGNMENT
|
||||
highlighter = null
|
||||
//make JTextPane transparent for mouse actions
|
||||
caret = object : DefaultCaret() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
this@HeightLimitedPane.parent.mouseListeners.forEach { it.mousePressed(e) }
|
||||
}
|
||||
|
||||
override fun mouseReleased(e: MouseEvent?) {
|
||||
this@HeightLimitedPane.parent.mouseListeners.forEach { it.mouseReleased(e) }
|
||||
}
|
||||
|
||||
override fun mouseEntered(e: MouseEvent?) {
|
||||
this@HeightLimitedPane.parent.mouseListeners.forEach { it.mouseEntered(e) }
|
||||
}
|
||||
|
||||
override fun mouseExited(e: MouseEvent?) {
|
||||
this@HeightLimitedPane.parent.mouseListeners.forEach { it.mouseExited(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMaximumSize(): Dimension {
|
||||
if (_width == null) {
|
||||
return this.preferredSize
|
||||
}
|
||||
else {
|
||||
return Dimension(width, this.preferredSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUI(ui: TextUI?) {
|
||||
super.setUI(ui)
|
||||
if (font != null) {
|
||||
font = FontUIResource(font.deriveFont(font.size2D + JBUIScale.scale(relativeFontSize)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUI(newUI: ComponentUI?) {
|
||||
super.setUI(newUI)
|
||||
}
|
||||
|
||||
override fun updateUI() {
|
||||
super.updateUI()
|
||||
if (font != null && style != null) {
|
||||
StyleConstants.setFontSize(style, font.size)
|
||||
styledDocument.setCharacterAttributes(0, text.length, style, true)
|
||||
styledDocument.setParagraphAttributes(0, text.length, style, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen.learnIde
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.wm.InteractiveCourseData
|
||||
import com.intellij.ui.RoundedLineBorder
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.*
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import java.awt.event.MouseListener
|
||||
import javax.swing.*
|
||||
import javax.swing.border.CompoundBorder
|
||||
import javax.swing.border.EmptyBorder
|
||||
import javax.swing.plaf.FontUIResource
|
||||
import javax.swing.plaf.LabelUI
|
||||
|
||||
class InteractiveCoursePanel(private val data: InteractiveCourseData) : JPanel() {
|
||||
|
||||
private enum class ContentState { COLLAPSED, EXPANDED }
|
||||
|
||||
private val pluginPanelWidth = 72
|
||||
private val chevronPanelWidth = 55
|
||||
|
||||
val startLearningButton = JButton()
|
||||
|
||||
private val interactiveCourseDescription = HeightLimitedPane(data.getDescription(), -1, LearnIdeContentColorsAndFonts.REGULAR)
|
||||
private val interactiveCourseContent = createInteractiveCourseContent()
|
||||
|
||||
private var contentState: ContentState = ContentState.COLLAPSED
|
||||
private val expandCollapseListener: MouseListener = createExpandCollapseListener()
|
||||
|
||||
private val expandedCourseContent = data.getExpandContent()
|
||||
private val chevronPanel = JPanel()
|
||||
private val chevronLabel = JLabel(AllIcons.General.ChevronDown)
|
||||
val pluginPanel = JPanel()
|
||||
val pluginLabel = JLabel(data.getIcon())
|
||||
|
||||
private val roundBorder1px = CompoundBorder(RoundedLineBorder(LearnIdeContentColorsAndFonts.InteractiveCoursesBorder, 4, 1),
|
||||
JBUI.Borders.emptyRight(5))
|
||||
|
||||
private val calculateInnerComponentHeight: () -> Int = { preferredSize.height }
|
||||
|
||||
init {
|
||||
initPluginPanel()
|
||||
initChevronPanel()
|
||||
|
||||
layout = BoxLayout(this, BoxLayout.LINE_AXIS)
|
||||
isOpaque = false
|
||||
border = roundBorder1px
|
||||
alignmentX = LEFT_ALIGNMENT
|
||||
|
||||
add(pluginPanel)
|
||||
add(interactiveCourseContent)
|
||||
add(chevronPanel)
|
||||
|
||||
addMouseListener(expandCollapseListener)
|
||||
interactiveCourseDescription.addMouseListener(expandCollapseListener)
|
||||
}
|
||||
|
||||
private fun initChevronPanel() {
|
||||
chevronPanel.apply {
|
||||
layout = BorderLayout()
|
||||
isOpaque = false
|
||||
alignmentY = TOP_ALIGNMENT
|
||||
add(chevronLabel, BorderLayout.CENTER)
|
||||
add(JPanel()
|
||||
.apply { preferredSize = Dimension(chevronPanelWidth, 1); minimumSize = Dimension(chevronPanelWidth, 1); isOpaque = false },
|
||||
BorderLayout.NORTH)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initPluginPanel() {
|
||||
pluginPanel.apply {
|
||||
layout = BorderLayout()
|
||||
border = EmptyBorder(12, 0, 0, 0)
|
||||
isOpaque = false
|
||||
add(pluginLabel, BorderLayout.NORTH)
|
||||
alignmentY = TOP_ALIGNMENT
|
||||
add(JPanel()
|
||||
.apply { preferredSize = Dimension(pluginPanelWidth, 1); minimumSize = Dimension(pluginPanelWidth, 1); isOpaque = false },
|
||||
BorderLayout.CENTER)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMaximumSize(): Dimension {
|
||||
return Dimension(this.preferredSize.width, calculateInnerComponentHeight())
|
||||
}
|
||||
|
||||
private fun createInteractiveCourseContent(): JPanel {
|
||||
val panel = JPanel()
|
||||
panel.layout = BoxLayout(panel, BoxLayout.PAGE_AXIS)
|
||||
panel.isOpaque = false
|
||||
panel.alignmentY = TOP_ALIGNMENT
|
||||
|
||||
panel.add(rigid(12, 10))
|
||||
|
||||
val learnIdeFeaturesHeader = object : JBLabel(data.getName()) {
|
||||
override fun setUI(ui: LabelUI?) {
|
||||
super.setUI(ui)
|
||||
if (font != null) {
|
||||
font = FontUIResource(font.deriveFont(font.size2D).deriveFont(Font.BOLD))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
learnIdeFeaturesHeader.alignmentX = LEFT_ALIGNMENT
|
||||
panel.add(learnIdeFeaturesHeader)
|
||||
|
||||
panel.add(rigid(1, 4))
|
||||
panel.add(interactiveCourseDescription)
|
||||
panel.add(rigid(4, 9))
|
||||
|
||||
startLearningButton.action = data.getAction()
|
||||
startLearningButton.margin = Insets(0, 0, 0, 0)
|
||||
startLearningButton.isSelected = true
|
||||
startLearningButton.isOpaque = false
|
||||
startLearningButton.alignmentX = LEFT_ALIGNMENT
|
||||
|
||||
val buttonPlace = buttonPixelHunting(startLearningButton)
|
||||
panel.add(buttonPlace)
|
||||
|
||||
panel.add(rigid(18, 21))
|
||||
|
||||
return panel
|
||||
}
|
||||
|
||||
private fun createExpandCollapseListener(): MouseAdapter {
|
||||
return object : MouseAdapter() {
|
||||
override fun mouseEntered(e: MouseEvent?) {
|
||||
if (contentState == ContentState.EXPANDED) return
|
||||
activateLearnIdeFeaturesPanel()
|
||||
}
|
||||
|
||||
override fun mouseExited(e: MouseEvent?) {
|
||||
if (e == null) return
|
||||
deactivateLearnIdeFeaturesPanel(e.locationOnScreen)
|
||||
}
|
||||
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
onLearnIdeFeaturesPanelClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buttonPixelHunting(button: JButton): JPanel {
|
||||
|
||||
val buttonSizeWithoutInsets = Dimension(button.preferredSize.width - button.insets.left - button.insets.right,
|
||||
button.preferredSize.height - button.insets.top - button.insets.bottom)
|
||||
|
||||
val buttonPlace = JPanel().apply {
|
||||
layout = null
|
||||
maximumSize = buttonSizeWithoutInsets
|
||||
preferredSize = buttonSizeWithoutInsets
|
||||
minimumSize = buttonSizeWithoutInsets
|
||||
isOpaque = false
|
||||
alignmentX = LEFT_ALIGNMENT
|
||||
}
|
||||
|
||||
buttonPlace.add(button)
|
||||
button.bounds = Rectangle(-button.insets.left, -button.insets.top, button.preferredSize.width, button.preferredSize.height)
|
||||
|
||||
return buttonPlace
|
||||
}
|
||||
|
||||
private fun activateLearnIdeFeaturesPanel() {
|
||||
background = LearnIdeContentColorsAndFonts.HoveredColor
|
||||
isOpaque = true
|
||||
repaint()
|
||||
cursor = Cursor(Cursor.HAND_CURSOR);
|
||||
}
|
||||
|
||||
private fun deactivateLearnIdeFeaturesPanel(mouseLocationOnScreen: Point) {
|
||||
if (pointerInLearnIdeFeaturesPanel(mouseLocationOnScreen)) return
|
||||
isOpaque = false
|
||||
repaint()
|
||||
cursor = Cursor(Cursor.DEFAULT_CURSOR)
|
||||
}
|
||||
|
||||
private fun onLearnIdeFeaturesPanelClick() {
|
||||
if (contentState == ContentState.COLLAPSED) {
|
||||
expandContent()
|
||||
chevronLabel.icon = AllIcons.General.ChevronUp
|
||||
contentState = ContentState.EXPANDED
|
||||
}
|
||||
else {
|
||||
collapseContent()
|
||||
chevronLabel.icon = AllIcons.General.ChevronDown
|
||||
contentState = ContentState.COLLAPSED
|
||||
}
|
||||
chevronLabel.repaint()
|
||||
}
|
||||
|
||||
private fun expandContent() {
|
||||
this.isOpaque = false
|
||||
interactiveCourseDescription.maximumSize = interactiveCourseDescription.preferredSize
|
||||
interactiveCourseContent.add(expandedCourseContent)
|
||||
chevronPanel.maximumSize = chevronPanel.size
|
||||
interactiveCourseContent.revalidate()
|
||||
interactiveCourseContent.repaint()
|
||||
repaint()
|
||||
|
||||
}
|
||||
|
||||
private fun collapseContent() {
|
||||
val pointerLocation = MouseInfo.getPointerInfo().location
|
||||
if (pointerInLearnIdeFeaturesPanel(pointerLocation)) activateLearnIdeFeaturesPanel()
|
||||
interactiveCourseContent.remove(expandedCourseContent)
|
||||
interactiveCourseContent.revalidate()
|
||||
interactiveCourseContent.repaint()
|
||||
repaint()
|
||||
}
|
||||
|
||||
private fun pointerInLearnIdeFeaturesPanel(mouseLocationOnScreen: Point) =
|
||||
Rectangle(Point(locationOnScreen.x + 1, locationOnScreen.y + 1),
|
||||
Dimension(bounds.size.width - 2, bounds.size.height - 2)).contains(
|
||||
mouseLocationOnScreen)
|
||||
|
||||
|
||||
private fun rigid(_width: Int, _height: Int): Component {
|
||||
return Box.createRigidArea(
|
||||
Dimension(JBUI.scale(_width), JBUI.scale(_height))).apply { (this as JComponent).alignmentX = LEFT_ALIGNMENT }
|
||||
}
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen.learnIde
|
||||
|
||||
import com.intellij.ide.ui.UISettings
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.Font
|
||||
import java.awt.font.TextAttribute
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.text.SimpleAttributeSet
|
||||
import javax.swing.text.StyleConstants
|
||||
|
||||
object LearnIdeContentColorsAndFonts {
|
||||
|
||||
val InteractiveCoursesBorder = JBColor.namedColor("Button.startBorderColor", JBColor(0x87AFDA, 0x5E6060))
|
||||
private val fontSize: Int by lazy { UISettings.instance.fontSize.ifZero(JBUI.scale(13)) }
|
||||
private val fontFace: String by lazy { UISettings.instance.fontFace ?: JLabel().font.fontName }
|
||||
|
||||
val HeaderFont: Font by lazy { Font(fontFace, Font.BOLD, fontSize + 5) }
|
||||
val HeaderColor = JBColor.namedColor("ParameterInfo.foreground", JBColor(0x1D1D1D, 0xBBBBBB))
|
||||
|
||||
|
||||
val HoveredColor = JBColor.namedColor("Plugins.lightSelectionBackground", JBColor(0xEDF6FE, 0x464A4D))
|
||||
val REGULAR = SimpleAttributeSet()
|
||||
|
||||
val ModuleHeaderColor = JBColor.namedColor("link", JBColor(0x2470B3, 0x589DF6))
|
||||
val ModuleDescriptionColor = JBColor.namedColor("disabledText", JBColor(0x8C8C8C, 0x777777))
|
||||
val MODULE_HEADER = SimpleAttributeSet()
|
||||
val MODULE_DESCRIPTION = SimpleAttributeSet()
|
||||
|
||||
val PARAGRAPH_STYLE = SimpleAttributeSet()
|
||||
val HEADER = SimpleAttributeSet()
|
||||
|
||||
init {
|
||||
StyleConstants.setFontSize(REGULAR, UISettings.instance.fontSize - 1)
|
||||
StyleConstants.setFontFamily(REGULAR, UISettings.instance.fontFace)
|
||||
StyleConstants.setForeground(REGULAR, HeaderColor)
|
||||
|
||||
StyleConstants.setLeftIndent(REGULAR, 0.0f)
|
||||
StyleConstants.setRightIndent(REGULAR, 0f)
|
||||
StyleConstants.setSpaceAbove(REGULAR, 0.0f)
|
||||
StyleConstants.setSpaceBelow(REGULAR, 0.0f)
|
||||
StyleConstants.setLineSpacing(REGULAR, 0.0f)
|
||||
|
||||
StyleConstants.setFontSize(HEADER, HeaderFont.size)
|
||||
StyleConstants.setFontFamily(HEADER, UISettings.instance.fontFace)
|
||||
StyleConstants.setForeground(HEADER, HeaderColor)
|
||||
StyleConstants.setBold(HEADER, true)
|
||||
HEADER.addAttribute(TextAttribute.TRACKING, -0.1)
|
||||
|
||||
StyleConstants.setLeftIndent(PARAGRAPH_STYLE, 0.0f)
|
||||
StyleConstants.setRightIndent(PARAGRAPH_STYLE, 0f)
|
||||
StyleConstants.setSpaceAbove(PARAGRAPH_STYLE, 0.0f)
|
||||
StyleConstants.setSpaceBelow(PARAGRAPH_STYLE, 0.0f)
|
||||
StyleConstants.setLineSpacing(PARAGRAPH_STYLE, 0.0f)
|
||||
|
||||
StyleConstants.setFontFamily(MODULE_HEADER, UISettings.instance.fontFace)
|
||||
StyleConstants.setFontSize(MODULE_HEADER, UISettings.instance.fontSize - 1)
|
||||
StyleConstants.setForeground(MODULE_HEADER, ModuleHeaderColor)
|
||||
StyleConstants.setLeftIndent(MODULE_HEADER, 0.0f)
|
||||
StyleConstants.setRightIndent(MODULE_HEADER, 0f)
|
||||
StyleConstants.setSpaceAbove(MODULE_HEADER, 0.0f)
|
||||
StyleConstants.setSpaceBelow(MODULE_HEADER, 0.0f)
|
||||
StyleConstants.setLineSpacing(MODULE_HEADER, 0.0f)
|
||||
|
||||
StyleConstants.setFontFamily(MODULE_DESCRIPTION, UISettings.instance.fontFace)
|
||||
StyleConstants.setFontSize(MODULE_DESCRIPTION, UISettings.instance.fontSize - 2)
|
||||
StyleConstants.setForeground(MODULE_DESCRIPTION, ModuleDescriptionColor)
|
||||
StyleConstants.setLeftIndent(MODULE_DESCRIPTION, 0.0f)
|
||||
StyleConstants.setRightIndent(MODULE_DESCRIPTION, 0f)
|
||||
StyleConstants.setSpaceAbove(MODULE_DESCRIPTION, 0.0f)
|
||||
StyleConstants.setSpaceBelow(MODULE_DESCRIPTION, 0.0f)
|
||||
StyleConstants.setLineSpacing(MODULE_DESCRIPTION, 0.0f)
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun Int.ifZero(nonZeroValue: Int): Int =
|
||||
if (this == 0) nonZeroValue else this
|
||||
|
||||
}
|
||||
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen.learnIde
|
||||
|
||||
import com.intellij.icons.AllIcons.Ide.External_link_arrow
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.ide.actions.GettingStartedAction
|
||||
import com.intellij.ide.actions.HelpTopicsAction
|
||||
import com.intellij.ide.actions.JetBrainsTvAction
|
||||
import com.intellij.ide.actions.WhatsNewAction
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||
import com.intellij.openapi.wm.InteractiveCourseFactory
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenUIManager
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.learnIde.LearnIdeContentColorsAndFonts.HEADER
|
||||
import com.intellij.ui.AncestorListenerAdapter
|
||||
import com.intellij.ui.components.JBScrollPane
|
||||
import com.intellij.ui.components.labels.LinkLabel
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.*
|
||||
import javax.swing.*
|
||||
import javax.swing.border.EmptyBorder
|
||||
import javax.swing.event.AncestorEvent
|
||||
|
||||
class LearnIdeContentPanel : JPanel() {
|
||||
|
||||
private val interactiveCoursesPanel: JPanel = JPanel()
|
||||
private val helpAndResourcesPanel: JPanel = JPanel()
|
||||
|
||||
private val viewComponent: JPanel = JPanel().apply { layout = BorderLayout(); background = WelcomeScreenUIManager.getProjectsBackground() }
|
||||
private val myScrollPane: JBScrollPane = JBScrollPane(viewComponent, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER).apply { border = JBUI.Borders.empty()}
|
||||
|
||||
private val interactiveCoursesHeader: JTextPane = HeightLimitedPane(IdeBundle.message("welcome.screen.learnIde.interactive.courses.text"),
|
||||
5, HEADER)
|
||||
|
||||
private val helpAndResourcesHeader: JTextPane = HeightLimitedPane(IdeBundle.message("welcome.screen.learnIde.help.and.resources.text"), 5, HEADER)
|
||||
|
||||
init {
|
||||
layout = BorderLayout()
|
||||
isFocusable = false
|
||||
isOpaque = true
|
||||
background = WelcomeScreenUIManager.getProjectsBackground()
|
||||
|
||||
val contentPanel = JPanel()
|
||||
contentPanel.layout = BoxLayout(contentPanel, BoxLayout.PAGE_AXIS)
|
||||
|
||||
//get all Interactive Courses
|
||||
contentPanel.addInteractiveCoursesPanel()
|
||||
contentPanel.addHelpAndResourcesPanel()
|
||||
contentPanel.add(Box.createVerticalGlue())
|
||||
|
||||
//set LearnPanel UI
|
||||
contentPanel.border = EmptyBorder(24, 24, 24, 24)
|
||||
contentPanel.isOpaque = false
|
||||
viewComponent.add(contentPanel, BorderLayout.CENTER)
|
||||
add(myScrollPane, BorderLayout.CENTER)
|
||||
|
||||
contentPanel.bounds = Rectangle(contentPanel.location, contentPanel.preferredSize)
|
||||
revalidate()
|
||||
repaint()
|
||||
}
|
||||
|
||||
private fun Container.addHelpAndResourcesPanel() {
|
||||
helpAndResourcesPanel.apply {
|
||||
layout = BoxLayout(this, BoxLayout.PAGE_AXIS)
|
||||
isOpaque = false
|
||||
add(helpAndResourcesHeader)
|
||||
add(rigid(0, 1))
|
||||
addHelpActions()
|
||||
}
|
||||
this.add(helpAndResourcesPanel)
|
||||
}
|
||||
|
||||
private fun Container.addInteractiveCoursesPanel() {
|
||||
val interactiveCourses = InteractiveCourseFactory.INTERACTIVE_COURSE_FACTORY_EP.extensions.map {it.getInteractiveCourseData()}
|
||||
interactiveCoursesPanel.layout = BoxLayout(interactiveCoursesPanel, BoxLayout.PAGE_AXIS)
|
||||
interactiveCoursesPanel.isOpaque = false
|
||||
|
||||
if (interactiveCourses.isNotEmpty()) {
|
||||
interactiveCoursesPanel.add(interactiveCoursesHeader)
|
||||
var actionButton: JButton? = null
|
||||
for (interactiveCourse in interactiveCourses) {
|
||||
interactiveCoursesPanel.add(rigid(0, 12))
|
||||
val interactiveCoursePanel = InteractiveCoursePanel(interactiveCourse)
|
||||
interactiveCoursesPanel.add(interactiveCoursePanel)
|
||||
if (actionButton == null) actionButton = interactiveCoursePanel.startLearningButton
|
||||
}
|
||||
addAncestorListener(object : AncestorListenerAdapter() {
|
||||
override fun ancestorAdded(event: AncestorEvent?) {
|
||||
rootPane?.defaultButton = actionButton
|
||||
}
|
||||
})
|
||||
this.add(interactiveCoursesPanel)
|
||||
this.add(rigid(1, 32))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun addHelpActions() {
|
||||
val whatsNewAction = WhatsNewAction()
|
||||
if (emptyWelcomeScreenEventFromAction(whatsNewAction).presentation.isEnabled) {
|
||||
helpAndResourcesPanel.add(linkLabelByAction(WhatsNewAction()))
|
||||
helpAndResourcesPanel.add(rigid(1, 16))
|
||||
}
|
||||
val helpActions = ActionManager.getInstance().getAction(IdeActions.GROUP_WELCOME_SCREEN_LEARN_IDE) as ActionGroup
|
||||
val anActionEvent = emptyWelcomeScreenEventFromAction(helpActions)
|
||||
helpActions.getChildren(anActionEvent).forEach {
|
||||
if (setOf<String>(HelpTopicsAction::class.java.simpleName, GettingStartedAction::class.java.simpleName,
|
||||
JetBrainsTvAction::class.java.simpleName).any { simpleName -> simpleName == it.javaClass.simpleName }) {
|
||||
helpAndResourcesPanel.add(linkLabelByAction(it).wrapWithUrlPanel())
|
||||
}
|
||||
else {
|
||||
helpAndResourcesPanel.add(linkLabelByAction(it))
|
||||
|
||||
}
|
||||
helpAndResourcesPanel.add(rigid(1, 6))
|
||||
}
|
||||
}
|
||||
|
||||
private fun LinkLabel<Any>.wrapWithUrlPanel(): JPanel {
|
||||
val jPanel = JPanel()
|
||||
jPanel.isOpaque = false
|
||||
jPanel.layout = BoxLayout(jPanel, BoxLayout.LINE_AXIS)
|
||||
jPanel.add(this, BorderLayout.CENTER)
|
||||
jPanel.add(JLabel(External_link_arrow), BorderLayout.EAST)
|
||||
jPanel.maximumSize = jPanel.preferredSize
|
||||
jPanel.alignmentX = LEFT_ALIGNMENT
|
||||
return jPanel
|
||||
}
|
||||
|
||||
private fun emptyWelcomeScreenEventFromAction(action: AnAction) =
|
||||
AnActionEvent.createFromAnAction(action, null, ActionPlaces.WELCOME_SCREEN, DataContext.EMPTY_CONTEXT)
|
||||
|
||||
private fun linkLabelByAction(it: AnAction): LinkLabel<Any> {
|
||||
return LinkLabel<Any>(it.templateText, null).apply {
|
||||
alignmentX = LEFT_ALIGNMENT
|
||||
setListener({ _, _ -> performActionOnWelcomeScreen(it) }, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun rigid(_width: Int, _height: Int): Component {
|
||||
return Box.createRigidArea(
|
||||
Dimension(JBUI.scale(_width), JBUI.scale(_height))).apply { (this as JComponent).alignmentX = LEFT_ALIGNMENT }
|
||||
}
|
||||
|
||||
private fun performActionOnWelcomeScreen(action: AnAction) {
|
||||
val anActionEvent = AnActionEvent.createFromAnAction(action, null, ActionPlaces.WELCOME_SCREEN, DataContext.EMPTY_CONTEXT)
|
||||
ActionUtil.performActionDumbAware(action, anActionEvent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1136,6 +1136,8 @@ action.Help.KeymapReference.text=_Keymap Reference
|
||||
action.Help.KeymapReference.description=Open PDF file with the default keymap reference card.
|
||||
action.Help.JetBrainsTV.text=_Demos and Screencasts
|
||||
action.Help.JetBrainsTV.description=View short live demos introducing features of JetBrains products.
|
||||
action.Help.GettingStarted.text=Getting Started
|
||||
action.Help.GettingStarted.description=Knowledge base and learning materials.
|
||||
action.CheckForUpdate.text=_Check for Updates...
|
||||
action.CheckForUpdate.description=Checks for available IDE and plugin updates
|
||||
action.CheckForUpdate.WelcomeScreen.text=Check for Updates
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
<extensionPoint name="welcomeScreen" interface="com.intellij.openapi.wm.WelcomeScreenProvider"/>
|
||||
<extensionPoint name="welcomeFrameProvider" interface="com.intellij.openapi.wm.WelcomeFrameProvider" dynamic="true"/>
|
||||
<extensionPoint name="welcomeTabFactory" interface="com.intellij.openapi.wm.WelcomeTabFactory" dynamic="true"/>
|
||||
<extensionPoint name="interactiveCourseFactory" interface="com.intellij.openapi.wm.InteractiveCourseFactory" dynamic="true"/>
|
||||
<extensionPoint name="welcomeScreenCustomization" interface="com.intellij.openapi.wm.WelcomeScreenCustomization" dynamic="true"/>
|
||||
|
||||
<extensionPoint name="statistic.eventLog.eventLoggerProvider" interface="com.intellij.internal.statistic.eventLog.StatisticsEventLoggerProvider"/>
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
order="after ProjectsWelcomeTab"/>
|
||||
<welcomeTabFactory id="PluginsWelcomeTab" implementation="com.intellij.openapi.wm.impl.welcomeScreen.PluginsTabFactory"
|
||||
order="after CustomizeWelcomeTab"/>
|
||||
<welcomeTabFactory id="LearnIdeWelcomeTab" implementation="com.intellij.openapi.wm.impl.welcomeScreen.LearnIdeTabFactory"
|
||||
order="after PluginsWelcomeTab'"/>
|
||||
<welcomeScreenCustomization id="defaultCustomization"
|
||||
implementation="com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenDefaultCustomization"/>
|
||||
|
||||
|
||||
@@ -771,6 +771,7 @@
|
||||
<action id="OnlineDocAction" class="com.intellij.ide.actions.OnlineDocAction"/>
|
||||
<action id="Help.KeymapReference" class="com.intellij.ide.actions.RefCardAction"/>
|
||||
<action id="Help.JetBrainsTV" class="com.intellij.ide.actions.JetBrainsTvAction"/>
|
||||
<action id="Help.GettingStarted" class="com.intellij.ide.actions.GettingStartedAction"/>
|
||||
<action id="ShowTips" class="com.intellij.ide.actions.ShowTipsAction"/>
|
||||
<separator/>
|
||||
<action id="ProductivityGuide" class="com.intellij.featureStatistics.actions.ShowFeatureUsageStatisticsAction"/>
|
||||
@@ -939,6 +940,15 @@
|
||||
<reference ref="CheckForUpdate"/>
|
||||
</group>
|
||||
|
||||
<group id="WelcomeScreen.LearnIdeHelp">
|
||||
<reference ref="HelpTopics"/>
|
||||
<reference ref="Help.GettingStarted"/>
|
||||
<reference ref="Help.JetBrainsTV"/>
|
||||
<reference ref="Help.KeymapReference"/>
|
||||
<reference ref="ShowTips"/>
|
||||
</group>
|
||||
|
||||
|
||||
<group id="WelcomeScreenRecentProjectActionGroup">
|
||||
<action id="WelcomeScreen.OpenSelected" class="com.intellij.openapi.wm.impl.welcomeScreen.OpenSelectedProjectsAction"/>
|
||||
<action id="WelcomeScreen.NewGroup" class="com.intellij.openapi.wm.impl.welcomeScreen.CreateNewProjectGroupAction"/>
|
||||
|
||||
Reference in New Issue
Block a user