diff --git a/src/icons/logo.svg b/src/icons/logo.svg new file mode 100644 --- /dev/null +++ b/src/icons/logo.svg @@ -0,0 +1,237 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mainwindow.h b/src/mainwindow.h --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -40,6 +40,10 @@ { return qobject_cast(m_map[s].second); } + template T *getButton(const QString &s) + { + return qobject_cast(m_map[s].first); + } }; class MainWindow : public KXmlGuiWindow diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -31,6 +31,7 @@ #include "widgets/3dview/viewer3d.h" #include "widgets/atcoreinstancewidget.h" #include "widgets/videomonitorwidget.h" +#include "widgets/welcomewidget.h" MainWindow::MainWindow(QWidget *parent) : KXmlGuiWindow(parent) @@ -184,7 +185,7 @@ btn->setAutoExclusive(true); btn->setCheckable(true); //3d view is on top set it checked so users see its selected. - btn->setChecked(key == "3d"); + btn->setChecked(key == QStringLiteral("welcome")); btn->setIcon(icon); btn->setFixedSize(48, 48); btn->setIconSize(QSize(48, 48)); @@ -223,6 +224,7 @@ viewer3D->drawModel(url.toString()); }); + setupButton("welcome", i18n("&Welcome"), QIcon::fromTheme("go-home", QIcon(QString(":/%1/home").arg(m_theme))), new WelcomeWidget(this)); setupButton("3d", i18n("&3D"), QIcon::fromTheme("draw-cuboid", QIcon(QString(":/%1/3d").arg(m_theme))), viewer3D); setupButton("gcode", i18n("&GCode"), QIcon::fromTheme("accessories-text-editor", QIcon(":/icon/edit")), m_gcodeEditor); setupButton("video", i18n("&Video"), QIcon::fromTheme("camera-web", QIcon(":/icon/video")), new VideoMonitorWidget(this)); @@ -287,6 +289,11 @@ m_lateral.get("gcode")->loadFile(fileName); m_lateral.get("3d")->drawModel(fileName.toString()); + // Make 3dview focused when opening a file + if (m_openFiles.isEmpty() && m_lateral.m_stack->currentWidget() == m_lateral.get("welcome")){ + m_lateral.getButton("3d")->setChecked(true); + m_lateral.m_stack->setCurrentWidget(m_lateral.get("3d")); + } const int tabs = m_instances->count(); if (!m_openFiles.contains(fileName)) { diff --git a/src/resources.qrc b/src/resources.qrc --- a/src/resources.qrc +++ b/src/resources.qrc @@ -4,6 +4,7 @@ icons/application-exit.svg icons/camera-web.svg icons/kwrite.svg + icons/logo.svg icons/light_configure.svg @@ -29,7 +30,6 @@ icons/dark_stop.svg icons/dark_pause.svg - atelierui.rc diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -7,6 +7,7 @@ videomonitorwidget.cpp atcoreinstancewidget.cpp thermowidget.cpp + welcomewidget.cpp ) add_library(AtelierWidgets STATIC ${widgets_SRCS}) diff --git a/src/widgets/welcomewidget.h b/src/widgets/welcomewidget.h new file mode 100644 --- /dev/null +++ b/src/widgets/welcomewidget.h @@ -0,0 +1,46 @@ +/* Atelier KDE Printer Host for 3D Printing + Copyright (C) <2018> + Author: Lays Rodrigues - lays.rodrigues@kde.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +#include + +class QDomDocument; +class QUrl; + +struct Post{ + QString title; + QString url; + QString date; +}; + +class WelcomeWidget : public QWidget +{ + Q_OBJECT + +public: + WelcomeWidget(QWidget *parent=nullptr); + ~WelcomeWidget(); + +private: + void retrieveRssFeed(); + void parseRss(const QDomDocument& document); + void setupRssFeed(); + QWidget *m_newsFeedWidget; + QList m_postList; +}; diff --git a/src/widgets/welcomewidget.cpp b/src/widgets/welcomewidget.cpp new file mode 100644 --- /dev/null +++ b/src/widgets/welcomewidget.cpp @@ -0,0 +1,179 @@ +/* Atelier KDE Printer Host for 3D Printing + Copyright (C) <2018> + Author: Lays Rodrigues - lays.rodrigues@kde.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "welcomewidget.h" + +#define POSTS_LIMIT 5 + +WelcomeWidget::WelcomeWidget(QWidget *parent): QWidget(parent), m_newsFeedWidget(new QWidget) +{ + QFont appFont = font(); + + auto hlayout = new QHBoxLayout; + auto layout = new QVBoxLayout; + auto label = new QLabel; + + + label->setText(i18n("Welcome to Atelier!")); + appFont.setPointSize(font().pointSize() + 4); + label->setFont(appFont); + hlayout->addWidget(label); + + label = new QLabel; + label->setPixmap(QPixmap(":/icon/logo")); + label->setLayoutDirection(Qt::LayoutDirection::RightToLeft); + hlayout->addWidget(label); + layout->addItem(hlayout); + + auto line = new QFrame; + line->setFrameShape(QFrame::HLine); + layout->addWidget(line); + + appFont.setPointSize(font().pointSize() + 2); + label = new QLabel(i18n("Quick Connect Guide")); + label->setFont(appFont); + layout->addWidget(label); + + for(QString sentence : {i18n("1 - Create a Profile;"), i18n("2 - Select the device;"), i18n("3 - Select the profile and connect.")}){ + label = new QLabel(sentence); + layout->addWidget(label); + } + + label = new QLabel(i18n("Having a connection problem?")); + label->setFont(appFont); + layout->addWidget(label); + + label = new QLabel(i18n("See the info section of the Log for common problems.")); + layout->addWidget(label); + + label = new QLabel(i18n("Check our Atelier Docs for more information.")); + label->setOpenExternalLinks(true); + layout->addWidget(label); + + label = new QLabel(i18n("Check our last news!")); + label->setFont(appFont); + layout->addWidget(label); + retrieveRssFeed(); + layout->addWidget(m_newsFeedWidget); + + label = new QLabel(i18n("Get Involved")); + label->setFont(appFont); + layout->addWidget(label); + + label = new QLabel(QString("")+i18n("Join our Telegram Group!")+QString("")); + label->setOpenExternalLinks(true); + layout->addWidget(label); + + label = new QLabel(i18n("You can also find us on Freenode IRC #kde-atelier")); + layout->addWidget(label); + + auto infoWidget = new QWidget(); + infoWidget->setLayout(layout); + + auto scrollArea = new QScrollArea(this); + scrollArea->setWidget(infoWidget); + scrollArea->setWidgetResizable(true); + + layout = new QVBoxLayout; + layout->addWidget(scrollArea); + setLayout(layout); +} + +WelcomeWidget::~WelcomeWidget(){ + +} + +void WelcomeWidget::retrieveRssFeed(){ + + auto manager = new QNetworkAccessManager(); + for(const QUrl url : { + QUrl("https://rizzitello.wordpress.com/category/atelier/feed/"), + QUrl("https://laysrodriguesdev.wordpress.com/category/atelier/feed/") + }) + { + QNetworkRequest request(url); + request.setRawHeader("User-Agent", "Atelier 1.0"); + manager->get(request); + connect(manager, &QNetworkAccessManager::finished, [&](QNetworkReply *reply){ + if(reply->error()){ + auto layout = new QHBoxLayout; + layout->addWidget(new QLabel(i18n("Failed to fetch the RSS Feed, You may not have an internet connection."))); + m_newsFeedWidget->setLayout(layout); + return; + }else{ + QDomDocument document; + if(document.setContent(reply->readAll())){ + parseRss(document); + } + } + }); + } + // Since the calls above are async, I need to wait a little time + // to have the responses processed before building the widget feed + QTimer::singleShot(2000, this, &WelcomeWidget::setupRssFeed); +} + +void WelcomeWidget::parseRss(const QDomDocument& document){ + auto itemList = document.elementsByTagName("item"); + QRegularExpression dateRegex("(?\\d{2} \\w{3} \\d{4})"); + + for(int i=0; i < itemList.count(); ++i){ + auto node = itemList.at(i); + if(node.isElement()){ + //Sample of date format Wed, 24 May 2017 13:46:07 +0000 + QString pDate = node.firstChildElement("pubDate").toElement().text(); + QRegularExpressionMatch match = dateRegex.match(pDate); + if(match.hasMatch()){ + Post p; + p.title = node.firstChildElement("title").toElement().text(); + p.url = node.firstChildElement("link").toElement().text(); + p.date = match.captured("date"); + m_postList.append(p); + } + } + } +} + +void WelcomeWidget::setupRssFeed(){ + QLocale locale(QLocale::English); + std::stable_sort(m_postList.begin(), m_postList.end(), [locale](const Post& p1, const Post& p2){ + return locale.toDate(p1.date, "dd MMM yyyy") > locale.toDate(p2.date, "dd MMM yyyy"); + }); + auto layout = new QVBoxLayout; + int count = m_postList.count() > POSTS_LIMIT ? POSTS_LIMIT : m_postList.count(); + for(int i =0; i < count; ++i){ + Post item = m_postList.at(i); + QString url = QString("%2").arg(item.url).arg(QString(item.title + " - " + item.date)); + auto lb = new QLabel(url); + lb->setOpenExternalLinks(true); + layout->addWidget(lb); + } + m_newsFeedWidget->setLayout(layout); +}