This commit is contained in:
Vorpal 2025-06-08 10:56:52 +03:00
parent f2139f8727
commit 72ecfdbdd8
11 changed files with 444 additions and 0 deletions

8
icons.qrc Normal file
View File

@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/res">
<file>icons/open-file-48.png</file>
<file>icons/logout-52.png</file>
<file>icons/save-50.png</file>
<file>icons/save-as-64.png</file>
</qresource>
</RCC>

BIN
icons/logout-52.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

BIN
icons/open-file-48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

BIN
icons/save-50.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

BIN
icons/save-as-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

32
ini_utils.pro Normal file
View File

@ -0,0 +1,32 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
TRANSLATIONS += \
ini_utils_ru_RU.ts
CONFIG += lrelease
CONFIG += embed_translations
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
icons.qrc

3
ini_utils_ru_RU.ts Normal file
View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU"></TS>

23
main.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "widget.h"
#include <QApplication>
#include <QLocale>
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "ini_utils_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
a.installTranslator(&translator);
break;
}
}
Widget w;
w.show();
return a.exec();
}

197
widget.cpp Normal file
View File

@ -0,0 +1,197 @@
#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
myTable::myTable(const records &hash):QTableWidget() {
fill(hash);
}
void myTable::fill(const records &hash) {
setRowCount(hash.size());
setColumnCount(2);
int ii=0;
for (const auto &rec: hash ) {
QTableWidgetItem *item1 = new QTableWidgetItem(rec.first);
QTableWidgetItem *item2 = new QTableWidgetItem(rec.second);
setItem(ii, 0, item1);
setItem(ii, 1, item2);
++ii;
}
}
Widget::Widget(QWidget *parent)
: QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
ui->lineEdit->hide();
ui->pushButton->setIcon(QIcon(":/res/icons/open-file-48.png"));
ui->pushButton->setIconSize(QSize(28, 28));
ui->pushButton->setToolTip("Открыть INI файл...");
ui->pushButton_2->setIcon(QIcon(":/res/icons/logout-52.png"));
ui->pushButton_2->setIconSize(QSize(26, 22));
ui->pushButton_2->setToolTip("Выход");
ui->pushButton_3->setIcon(QIcon(":/res/icons/save-as-64.png"));
ui->pushButton_3->setIconSize(QSize(28, 28));
ui->pushButton_3->setToolTip("Сохранить как...");
ui->pushButton_3->setEnabled(false);
ui->pushButton_4->setIcon(QIcon(":/res/icons/save-50.png"));
ui->pushButton_4->setIconSize(QSize(26, 26));
ui->pushButton_4->setToolTip("Сохранить");
ui->pushButton_4->setEnabled(false);
ui->tabWidget->hide();
setWindowIcon(QIcon());
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QString pathStr = ui->lineEdit->text();
if (pathStr.isEmpty()) pathStr = QDir::currentPath();
QString fileName = QFileDialog::getOpenFileName(this,
tr("Выберите файл"),
pathStr,
tr("INI файлы (*.ini)"));
if (!fileName.isEmpty()) {
ui->lineEdit->setText(fileName);
QTimer::singleShot(200, this, SLOT(genTabs()));
}
}
void Widget::genTabs() {
ui->tabWidget->hide();
tabs.clear();
QTabWidget *tw = ui->tabWidget;
for (int i=tw->count()-1; i>=0; i--) {
QWidget *w = tw->widget(i);
tw->removeTab(i);
if (w!= nullptr) delete w;
}
tw->clear();
this->setWindowTitle(ui->lineEdit->text());
QFile file(ui->lineEdit->text());
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, "Ошибка", "Ошибка открытия файла");
ui->pushButton_3->setEnabled(false);
ui->pushButton_4->setEnabled(false);
return;
}
ui->pushButton_3->setEnabled(true);
ui->pushButton_4->setEnabled(true);
proceedFile(file);
if (file.isOpen()) file.close();
const QIcon nullIcon;
for (int i=0; i<tabs.size(); ++i) {
myTable *local_tab = new myTable(tabs[i].m_hash);
tw->addTab(local_tab, nullIcon, tabs[i].m_name);
}
tw->setCurrentIndex(0);
tw->show();
}
void Widget::on_lineEdit_returnPressed()
{
QTimer::singleShot(200, this, SLOT(genTabs()));
}
void Widget::on_pushButton_2_clicked()
{
close();
}
void Widget::proceedFile(QFile &file) {
int numLine = 0;
comments.clear();
while (!file.atEnd()) {
numLine++;
QByteArray line = file.readLine();
QString str = QString::fromLocal8Bit(line.data());
if (str.length()>1 && str.right(2) == "\r\n") str.chop(2);
while (!str.isEmpty() && str.back()=='\t') str.chop(1);
if (str.isEmpty()) continue;
if (str.front()==';') {
comments.insert(numLine, str);
continue;
}
if (str.front() == '[') {
tabs.push_back(tabChapter(str));
continue;
}
QString strKey = str.section('=', 0, 0);
QString strData = str.section('=', 1);
QPair<QString, QString> pair(strKey, strData);
tabs.back().m_hash.push_back(pair);
}
}
void Widget::on_pushButton_4_clicked()
{
// saveBtn
QString path = ui->lineEdit->text();
saveDataToFile(path);
}
void Widget::on_pushButton_3_clicked()
{
// saveAsBtn
QString pathStr = ui->lineEdit->text();
if (pathStr.isEmpty()) pathStr = QDir::currentPath();
QString fileName = QFileDialog::getSaveFileName(this,
tr("Выберите файл"),
pathStr,
tr("INI файлы (*.ini)"));
if (!fileName.isEmpty()) {
saveDataToFile(fileName);
}
}
void Widget::saveDataToFile(QString &name) {
QFile fd(name);
if (!fd.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(this, "Ошибка файла", "Ошибка открытия файла на запись");
}
int numLine = 1;
while (comments.find(numLine)!=comments.end()) {
fd.write(comments[numLine++].toLocal8Bit());
fd.write("\n");
}
for (int i=0; i<ui->tabWidget->count(); ++i) {
fd.write(ui->tabWidget->tabText(i).toLocal8Bit());
fd.write("\n");
numLine++;
while (comments.find(numLine)!=comments.end()) {
fd.write(comments[numLine++].toLocal8Bit());
fd.write("\n");
}
myTable *tab = (myTable *)ui->tabWidget->widget(i);
for (int j=0; j<tab->rowCount(); j++) {
QString str = tab->item(j, 0)->text() +
QString("=") + tab->item(j, 1)->text() + "\n";
fd.write(str.toLocal8Bit());
numLine++;
while (comments.find(numLine)!=comments.end()) {
fd.write(comments[numLine++].toLocal8Bit());
fd.write("\n");
}
}
fd.write("\n");
numLine++;
}
if (fd.isOpen()) fd.close();
setWindowTitle(name);
}

63
widget.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QFile>
#include <QTimer>
#include <QMessageBox>
#include <QMap>
#include <QVector>
#include <QTableWidget>
#include <QTextStream>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
using record = QPair<QString, QString>;
using records = QVector<record>;
class tabChapter {
public:
tabChapter();
tabChapter(QString _name) : m_name(_name) {}
QString m_name;
records m_hash;
};
class myTable : public QTableWidget
{
Q_OBJECT
public:
myTable(const records &hash = {});
private:
void fill(const records &hash);
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
void genTabs();
void on_lineEdit_returnPressed();
void on_pushButton_2_clicked();
void on_pushButton_4_clicked();
void on_pushButton_3_clicked();
private:
Ui::Widget *ui;
void proceedFile(QFile &file);
QVector<tabChapter> tabs;
QHash<int, QString> comments;
void saveDataToFile(QString &fileName);
};
#endif // WIDGET_H

118
widget.ui Normal file
View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>574</width>
<height>792</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>574</width>
<height>792</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>574</width>
<height>792</height>
</size>
</property>
<property name="windowTitle">
<string notr="true">ini_UTILS</string>
</property>
<widget class="QLineEdit" name="lineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>30</x>
<y>70</y>
<width>521</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>30</x>
<y>20</y>
<width>51</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>210</x>
<y>20</y>
<width>51</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>149</x>
<y>20</y>
<width>51</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="pushButton_4">
<property name="geometry">
<rect>
<x>89</x>
<y>20</y>
<width>51</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>30</x>
<y>70</y>
<width>530</width>
<height>711</height>
</rect>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>