Просмотр исходного кода

[Full] Started support of projects list

Dmitry Yu Okunev лет назад: 9
Родитель
Сommit
0a7b42344a
10 измененных файлов с 360 добавлено и 33 удалено
  1. 4 1
      helpwindow.ui
  2. BIN
      images/help.png
  3. 44 0
      mainwindow-common.cpp
  4. 10 0
      mainwindow-common.h
  5. 157 19
      mainwindow-full.cpp
  6. 24 0
      mainwindow-full.h
  7. 106 13
      mainwindow-full.ui
  8. 1 0
      mephi-tasks.qrc
  9. 10 0
      redmine.cpp
  10. 4 0
      redmine.h

+ 4 - 1
helpwindow.ui

@@ -42,7 +42,10 @@ p, li { white-space: pre-wrap; }
 </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
 <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Клиентское приложение для системы управления задачами и проектами НИЯУ МИФИ.</p>
 <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Автор: Окунев Дмитрий Юрьевич &amp;lt;dyokunev@mephi.ru&amp;gt;, Управление Информатизации, 2015&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Контакты для обратной связи:&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;    Электронная почта:  &lt;span style=&quot; font-weight:600;&quot;&gt;tasks@mephi.ru&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;	&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;— Управление Информатизации, 2015&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
    </property>
   </widget>
  </widget>

BIN
images/help.png


+ 44 - 0
mainwindow-common.cpp

@@ -145,3 +145,47 @@ MainWindowCommon::~MainWindowCommon()
     qsettings.setValue("sortorder",  (int)this->sortOrder);
     return;
 }
+
+/**** updateProjects ****/
+
+void MainWindowCommon::projects_clear()
+{
+    this->projects_list.clear();
+}
+
+void MainWindowCommon::project_add(QJsonObject project_json)
+{
+    this->projects_list.append(project_json);
+}
+
+void MainWindowCommon::projects_display()
+{
+    qFatal("projects_display() is not re-implemented by the derivative object");
+}
+
+QList<QJsonObject> MainWindowCommon::projects_get()
+{
+    return this->projects_list;
+}
+
+void MainWindowCommon::get_projects_callback(QNetworkReply *reply, QJsonDocument *json, void *arg) {
+    (void)reply; (void)arg;
+
+    QJsonObject answer   = json->object();
+    QJsonArray  projects = answer["projects"].toArray();
+
+    this->projects_clear();
+
+    foreach (const QJsonValue &project_val, projects)
+        this->project_add(project_val.toObject());
+
+    this->projects_display();
+    return;
+}
+
+int MainWindowCommon::updateProjects() {
+    redmine->get_projects((Redmine::callback_t)&MainWindowCommon::get_projects_callback, this);
+    return 0;
+}
+
+/**** /updateProjects ****/

+ 10 - 0
mainwindow-common.h

@@ -48,11 +48,21 @@ protected:
     enum ESortColumn sortColumn[SORT_DEPTH];
     QMap <enum ESortColumn, sortfunct_t> sortFunctMap;
 
+    int updateProjects();
+    QList <QJsonObject> projects_get();
+
 signals:
 
 public slots:
 
 private:
+    /* projects */
+
+    virtual void projects_display();
+    void get_projects_callback(QNetworkReply *reply, QJsonDocument *json, void *arg);
+    void projects_clear();
+    void project_add(QJsonObject project_json);
+    QList <QJsonObject> projects_list;
 };
 
 #endif // MAINWINDOWCOMMON_H

+ 157 - 19
mainwindow-full.cpp

@@ -22,11 +22,16 @@
 #include "mainwindow-full.h"
 #include "ui_mainwindow-full.h"
 
+#include "helpwindow.h"
+
 MainWindowFull::MainWindowFull(QWidget *parent) :
     MainWindowCommon(parent),
     ui(new Ui::MainWindowFull)
 {
-    ui->setupUi(this);
+    this->ui->setupUi(this);
+
+    connect(redmine, SIGNAL(callback_call      (void*,callback_t,QNetworkReply*,QJsonDocument*,void*)),
+            this,    SLOT(  callback_dispatcher(void*,callback_t,QNetworkReply*,QJsonDocument*,void*)) );
 
     this->setWindowTitle("Система «Задачи» НИЯУ МИФИ");
 
@@ -35,49 +40,98 @@ MainWindowFull::MainWindowFull(QWidget *parent) :
 
     this->setDockOptions(AllowTabbedDocks | AllowNestedDocks);
 
-    ui->navigationDock->installEventFilter(this);
-    ui->issueDock->installEventFilter(this);
-    ui->filtersDock->installEventFilter(this);
+    this->ui->navigationDock->installEventFilter(this);
+    this->ui->issueDock->installEventFilter(this);
+    this->ui->filtersDock->installEventFilter(this);
+    this->ui->centralWidget->installEventFilter(this);
+
+    this->ui->navigationDock->setMinimumWidth(this->navigationDockInitialWidth);
+    this->ui->filtersDock->setMinimumWidth(this->filtersDockInitialWidth);
+    this->ui->issueDock->setMinimumHeight(this->issueDockInitialHeight);
 
-    this->setMinimumWidth(1280);
+    QStringList projectsColumns;
+    projectsColumns << "Проект" << "Кол-во";
+    this->ui->projects->setHeaderLabels(projectsColumns);
 
-    ui->navigationDock->setMinimumWidth(this->navigationDockInitialWidth);
+    QStringList issuesColumns;
+    issuesColumns << "Название" << "Исполнитель" << "Срок" << "Статус" << "Обновлено";
+    this->ui->issuesTree->setHeaderLabels(issuesColumns);
+
+    this->updateProjects();
 
     return;
 }
 
+MainWindowFull::~MainWindowFull()
+{
+    delete ui;
+}
+
+/**** ui ****/
 
-void MainWindowFull::on_resize_navigationDock(QResizeEvent *event) {
-    /*if (event->oldSize().width() != -1 && event->size().width() != event->oldSize().width())
-        if (event->size().width() - event->oldSize().width() > -(this->navigationDockInitialWidth)/2) */
-            ui->navigationDock->setMinimumWidth(0);
+void unlockDockWidth(QDockWidget *widget, QResizeEvent *event, int initialWidth) {
+    if (event->oldSize().width() != -1 && event->size().width() != event->oldSize().width())
+        if (event->size().width() - event->oldSize().width() > -initialWidth/2)
+            widget->setMinimumWidth(0);
+}
+
+void unlockDockHeight(QDockWidget *widget, QResizeEvent *event, int initialHeight) {
+    if (event->oldSize().height() != -1 && event->size().height() != event->oldSize().height())
+        if (event->size().height() - event->oldSize().height() > -initialHeight/2)
+            widget->setMinimumHeight(0);
+}
+
+void MainWindowFull::on_resize_centralWidget(QResizeEvent *event) {
+/*
+    qDebug("centralWidget Resized (New Size) - Width: %d Height: %d (was: %d x %d)",
+        event->size().width(),
+        event->size().height(),
+        event->oldSize().width(),
+        event->oldSize().height()
+     );*/
 
+    this->ui->issuesLayout->setGeometry(QRect(0, 0, event->size().width(), event->size().height()-10));
 
+    return;
+}
+
+void MainWindowFull::on_resize_navigationDock(QResizeEvent *event) {
+    unlockDockWidth(this->ui->navigationDock, event, this->navigationDockInitialWidth);
+/*
     qDebug("navigationDock Resized (New Size) - Width: %d Height: %d (was: %d x %d)",
         event->size().width(),
         event->size().height(),
         event->oldSize().width(),
         event->oldSize().height()
-     );
+     );*/
+
+    this->ui->navigationTabs->resize(event->size());
+    this->ui->projects->resize(event->size());
 
     return;
 }
 
 void MainWindowFull::on_resize_issueDock(QResizeEvent *event) {
-    /*
+    unlockDockHeight(this->ui->issueDock, event, this->issueDockInitialHeight);
+/*
     qDebug("issueDock Resized (New Size) - Width: %d Height: %d",
         event->size().width(),
-        event->size().height());
-*/
+        event->size().height());*/
+
+    this->ui->issueLayout->setGeometry(QRect(0, 0, event->size().width(), event->size().height()-10));
+
     return;
 }
 
 void MainWindowFull::on_resize_filtersDock(QResizeEvent *event) {
-    /*
+    unlockDockWidth(this->ui->filtersDock, event, this->filtersDockInitialWidth);
+/*
     qDebug("filtersDock Resized (New Size) - Width: %d Height: %d",
         event->size().width(),
-        event->size().height());
-*/
+        event->size().height());*/
+
+    this->ui->filtersLayout->setGeometry(QRect(0, 0, event->size().width(), event->size().height()-10));
+
     return;
 }
 
@@ -92,11 +146,95 @@ bool MainWindowFull::eventFilter(QObject *obj, QEvent *event) {
         else
         if (obj == ui->filtersDock)
             this->on_resize_filtersDock   (static_cast<QResizeEvent*>(event));
+        else
+        if (obj == ui->centralWidget)
+            this->on_resize_centralWidget (static_cast<QResizeEvent*>(event));
     }
     return QWidget::eventFilter(obj, event);
 }
 
-MainWindowFull::~MainWindowFull()
+/**** /ui ****/
+
+/**** actions ****/
+
+void MainWindowFull::on_actionHelp_triggered()
 {
-    delete ui;
+    HelpWindow *win = new HelpWindow(this);
+    win->show();
 }
+
+void MainWindowFull::on_actionQuit_triggered()
+{
+    application->quit();
+}
+
+void MainWindowFull::on_toolActionHelp_triggered()
+{
+    this->on_actionHelp_triggered();
+}
+
+/**** /actions ****/
+
+/**** updateProjects ****/
+
+void MainWindowFull::project_display_recursive(QTreeWidgetItem *item, QJsonObject project) {
+    qDebug("MainWindowFull::project_display_recursive()");
+
+    int project_id = project["id"].toInt();
+
+    item->setText(0, QString::number(project_id));
+    item->setText(1, project["name"].toString());
+
+    foreach (const QJsonObject &child, this->projects_hierarchy[project_id]) {
+        this->project_display_child(item, child);
+    }
+}
+
+void MainWindowFull::project_display_child(QTreeWidgetItem *parent, QJsonObject child)
+{
+    qDebug("MainWindowFull::project_display_child()");
+
+    QTreeWidgetItem *item = new QTreeWidgetItem(parent);
+    this->project_display_recursive(item, child);
+}
+
+void MainWindowFull::project_display_topone(int pos)
+{
+    qDebug("pos: %i", pos);
+
+    QJsonObject project    = this->projects_row2project[pos];
+    QTreeWidgetItem *item = new QTreeWidgetItem(this->ui->projects);
+
+    this->project_display_recursive(item, project);
+}
+
+void MainWindowFull::projects_display()
+{
+    qDebug("MainWindowFull::projects_display()");
+
+    int topprojects_count = 0;
+    QList<QJsonObject> projects_list = this->projects_get();
+
+    this->projects_hierarchy.clear();
+
+    foreach (const QJsonObject &project, projects_list) {
+        int parent_id;
+
+        if (project.contains("parent"))
+            parent_id = project["parent"].toObject()["id"].toInt();
+        else
+            parent_id = 0;
+
+        qDebug("parent_id == %i", parent_id);
+        this->projects_hierarchy[parent_id].append(project);
+    }
+
+    foreach (const QJsonObject &project, this->projects_hierarchy[0]) {
+        this->projects_row2project.insert(topprojects_count, project);
+        this->project_display_topone(topprojects_count);
+
+        topprojects_count++;
+    }
+}
+
+/**** /updateProjects ****/

+ 24 - 0
mainwindow-full.h

@@ -1,6 +1,8 @@
 #ifndef MAINWINDOWFULL_H
 #define MAINWINDOWFULL_H
 
+#include <QTreeWidget>
+
 #include <mainwindow-common.h>
 
 namespace Ui {
@@ -10,6 +12,7 @@ class MainWindowFull;
 class MainWindowFull : public MainWindowCommon
 {
     Q_OBJECT
+    CALLBACK_DISPATCHER(Redmine, MainWindowFull, NULL)
 
 public:
     explicit MainWindowFull(QWidget *parent = 0);
@@ -18,14 +21,35 @@ public:
 protected:
     bool eventFilter(QObject *obj, QEvent *event);
 
+private slots:
+    void on_actionHelp_triggered();
+
+    void on_actionQuit_triggered();
+
+    void on_toolActionHelp_triggered();
+
 private:
     Ui::MainWindowFull *ui;
 
+    void projects_display();
+
+    void on_resize_centralWidget(QResizeEvent *event);
     void on_resize_navigationDock(QResizeEvent *event);
     void on_resize_filtersDock(QResizeEvent *event);
     void on_resize_issueDock(QResizeEvent *event);
 
     int navigationDockInitialWidth = 272;
+    int filtersDockInitialWidth    = 100;
+    int issueDockInitialHeight     = 300;
+
+    QHash<int, QJsonObject> projects_row2project;
+    QHash<int, QJsonObject> issues_row2issue;
+
+    void project_display_topone(int pos);
+    void project_display_child(QTreeWidgetItem *parent, QJsonObject child);
+    void project_display_recursive(QTreeWidgetItem *item, QJsonObject project);
+
+    QHash<int, QList<QJsonObject>> projects_hierarchy;
 };
 
 #endif // MAINWINDOWFULL_H

+ 106 - 13
mainwindow-full.ui

@@ -19,24 +19,50 @@
   <property name="dockOptions">
    <set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks</set>
   </property>
-  <widget class="QWidget" name="centralwidget">
+  <widget class="QWidget" name="centralWidget">
+   <property name="enabled">
+    <bool>true</bool>
+   </property>
    <widget class="QWidget" name="verticalLayoutWidget_2">
     <property name="geometry">
      <rect>
       <x>0</x>
-      <y>9</y>
-      <width>791</width>
-      <height>541</height>
+      <y>0</y>
+      <width>1161</width>
+      <height>701</height>
      </rect>
     </property>
-    <layout class="QVBoxLayout" name="verticalLayout_2">
+    <layout class="QVBoxLayout" name="issuesLayout">
      <item>
-      <widget class="QTreeWidget" name="treeWidget_2">
+      <widget class="QTreeWidget" name="issuesTree">
+       <property name="columnCount">
+        <number>5</number>
+       </property>
        <column>
         <property name="text">
          <string notr="true">1</string>
         </property>
        </column>
+       <column>
+        <property name="text">
+         <string notr="true">2</string>
+        </property>
+       </column>
+       <column>
+        <property name="text">
+         <string notr="true">3</string>
+        </property>
+       </column>
+       <column>
+        <property name="text">
+         <string notr="true">4</string>
+        </property>
+       </column>
+       <column>
+        <property name="text">
+         <string notr="true">5</string>
+        </property>
+       </column>
       </widget>
      </item>
     </layout>
@@ -51,6 +77,20 @@
      <height>19</height>
     </rect>
    </property>
+   <widget class="QMenu" name="menu">
+    <property name="title">
+     <string>Программа</string>
+    </property>
+    <addaction name="actionQuit"/>
+   </widget>
+   <widget class="QMenu" name="menu_2">
+    <property name="title">
+     <string>Информация</string>
+    </property>
+    <addaction name="actionHelp"/>
+   </widget>
+   <addaction name="menu"/>
+   <addaction name="menu_2"/>
   </widget>
   <widget class="QDockWidget" name="navigationDock">
    <property name="locale">
@@ -73,7 +113,7 @@
       </rect>
      </property>
      <property name="currentIndex">
-      <number>0</number>
+      <number>1</number>
      </property>
      <property name="elideMode">
       <enum>Qt::ElideNone</enum>
@@ -87,7 +127,7 @@
       <attribute name="title">
        <string>Проекты</string>
       </attribute>
-      <widget class="QTreeWidget" name="treeWidget">
+      <widget class="QTreeWidget" name="projects">
        <property name="geometry">
         <rect>
          <x>0</x>
@@ -105,11 +145,19 @@
        <property name="headerHidden">
         <bool>true</bool>
        </property>
+       <property name="columnCount">
+        <number>2</number>
+       </property>
        <column>
         <property name="text">
          <string notr="true">1</string>
         </property>
        </column>
+       <column>
+        <property name="text">
+         <string notr="true">2</string>
+        </property>
+       </column>
       </widget>
      </widget>
      <widget class="QWidget" name="structureTab">
@@ -175,23 +223,68 @@
       </rect>
      </property>
      <layout class="QGridLayout" name="issueLayout">
-      <item row="1" column="0">
-       <widget class="QPushButton" name="pushButton">
+      <item row="1" column="1">
+       <widget class="QPushButton" name="issueCommitButton">
         <property name="text">
-         <string>PushButton</string>
+         <string>Подтвердить</string>
         </property>
        </widget>
       </item>
-      <item row="0" column="0">
+      <item row="0" column="1">
        <widget class="QComboBox" name="comboBox"/>
       </item>
+      <item row="0" column="0">
+       <widget class="QTextEdit" name="textEdit">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </widget>
   </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+  <widget class="QToolBar" name="toolBar">
+   <property name="windowTitle">
+    <string>toolBar</string>
+   </property>
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+   <addaction name="separator"/>
+   <addaction name="toolActionHelp"/>
+  </widget>
+  <action name="toolActionHelp">
+   <property name="icon">
+    <iconset resource="mephi-tasks.qrc">
+     <normaloff>:/images/help.png</normaloff>:/images/help.png</iconset>
+   </property>
+   <property name="text">
+    <string>Помощь</string>
+   </property>
+   <property name="toolTip">
+    <string>Помощь</string>
+   </property>
+  </action>
+  <action name="actionQuit">
+   <property name="text">
+    <string>Завершить</string>
+   </property>
+  </action>
+  <action name="actionHelp">
+   <property name="text">
+    <string>Помощь</string>
+   </property>
+  </action>
   <zorder>filtersDock</zorder>
   <zorder>issueDock</zorder>
  </widget>
- <resources/>
+ <resources>
+  <include location="mephi-tasks.qrc"/>
+ </resources>
  <connections/>
 </ui>

+ 1 - 0
mephi-tasks.qrc

@@ -2,5 +2,6 @@
     <qresource prefix="/">
         <file>images/good.png</file>
         <file>images/bad.png</file>
+        <file>images/help.png</file>
     </qresource>
 </RCC>

+ 10 - 0
redmine.cpp

@@ -151,6 +151,16 @@ QNetworkReply *Redmine::get_issues(callback_t callback,
 
 /********* /get_issues *********/
 
+/********* get_projects *********/
+
+QNetworkReply *Redmine::get_projects(callback_t callback,
+        void *arg, bool free_arg)
+{
+    return this->request(GET, "projects", NULL, callback, arg, free_arg);
+}
+
+/********* /get_projects *********/
+
 /********* get_user *********/
 
 struct get_user_callback_arg {

+ 4 - 0
redmine.h

@@ -53,6 +53,10 @@ public:
      */
     QNetworkReply *get_issues(callback_t callback, void *arg, bool free_arg = false);
 
+    /* Request all projects
+     */
+    QNetworkReply *get_projects(callback_t callback, void *arg, bool free_arg = false);
+
     /* Get issue status info
      */
     QJsonObject get_issue_status(int issue_status_id);