add config.xml

This commit is contained in:
ivaquero
2026-04-18 01:53:51 +08:00
parent b3ecb2708a
commit 49b39b74d2
10 changed files with 391 additions and 24 deletions
+2
View File
@@ -14,10 +14,12 @@ qt6_standard_project_setup()
set(SOURCES set(SOURCES
main.cpp main.cpp
clockwidget.cpp clockwidget.cpp
configmanager.cpp
) )
set(HEADERS set(HEADERS
clockwidget.h clockwidget.h
configmanager.h
) )
# Create executable # Create executable
+20 -6
View File
@@ -1,4 +1,4 @@
# ⏰ Flock # ⏰ Flock
![code size](https://img.shields.io/github/languages/code-size/ivaquero/floating-clock.svg) ![code size](https://img.shields.io/github/languages/code-size/ivaquero/floating-clock.svg)
![repo size](https://img.shields.io/github/repo-size/ivaquero/floating-clock.svg) ![repo size](https://img.shields.io/github/repo-size/ivaquero/floating-clock.svg)
@@ -18,16 +18,16 @@ When on macOS / Linux, the clock on the menu bar is too small to be noticeable,
- [ ] Frameless - [ ] Frameless
- [x] Drag and Move - [x] Drag and Move
- [x] Right Click Menu - [x] Right Click Menu
- [ ] Always On Top - [x] Always On Top
- [ ] Show in Fullscreen Mode - [ ] Show in Fullscreen Mode
- [x] **Style** - [x] **Style**
- [x] Set Background Color - [x] Set Background Color
- [x] Set Font Color - [x] Set Font Color
- [x] Set FontSize - [x] Set FontSize
- [ ] **Configuration File** (XML) - [x] **Configuration File** (XML)
- [ ] Read Settings - [x] Read Settings
- [ ] Write Settings - [x] Write Settings
- [ ] Reset Settings - [x] Reset Settings
- [ ] **Time** - [ ] **Time**
- [ ] Select Time Zone - [ ] Select Time Zone
- [ ] Set Alarms - [ ] Set Alarms
@@ -73,11 +73,24 @@ make
./flock ./flock
``` ```
### Configuration
The application now uses XML configuration files instead of QSettings. Configuration is stored in `config.xml` with the following options:
- **FontColor**: Font color in hex format
- **BackgroundColor**: Background color with alpha transparency
- **FontSize**: Font size in points (8-72)
- **AlwaysOnTop**: Window always stays on top
- **WindowPosition**: Window position coordinates
The configuration file is automatically created when you first run the application and make changes to settings.
### Usage ### Usage
- **Move**: Left-click and drag - **Move**: Left-click and drag
- **Menu**: Right-click for context menu - **Menu**: Right-click for context menu
- **Customize**: Change colors, font size, always-on-top behavior - **Customize**: Change colors, font size, always-on-top behavior
- **Configuration**: Settings are saved to `config.xml` and persist between sessions
### Project Structure ### Project Structure
@@ -88,6 +101,7 @@ qflock/
│ ├── *.o # Object files │ ├── *.o # Object files
│ ├── moc_*.cpp # Qt meta-object compiler output │ ├── moc_*.cpp # Qt meta-object compiler output
│ └── Makefile # Build file │ └── Makefile # Build file
├── config.xml # XML configuration file
├── build.sh # One-click build script ├── build.sh # One-click build script
├── clean.sh # Clean script ├── clean.sh # Clean script
├── flock.pro # qmake project file ├── flock.pro # qmake project file
+78
View File
@@ -0,0 +1,78 @@
# XML Configuration Implementation
## Overview
The configuration system has been successfully implemented using XML files instead of QSettings. The new ConfigManager class handles all configuration operations.
## Files Created/Modified
### New Files
- [`configmanager.h`](file:///Users/integzz/Documents/GitHub/qflock/configmanager.h) - Configuration manager header
- [`configmanager.cpp`](file:///Users/integzz/Documents/GitHub/qflock/configmanager.cpp) - Configuration manager implementation
- [`config.xml`](file:///Users/integzz/Documents/GitHub/qflock/config.xml) - Default configuration file
### Modified Files
- [`clockwidget.h`](file:///Users/integzz/Documents/GitHub/qflock/clockwidget.h) - Replaced QSettings with ConfigManager
- [`clockwidget.cpp`](file:///Users/integzz/Documents/GitHub/qflock/clockwidget.cpp) - Updated to use XML configuration
- [`flock.pro`](file:///Users/integzz/Documents/GitHub/qflock/flock.pro) - Added new source files
- [`CMakeLists.txt`](file:///Users/integzz/Documents/GitHub/qflock/CMakeLists.txt) - Added new source files
## XML Configuration Format
The configuration is stored in XML format with the following structure:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<QFlockConfig>
<FontColor>#ffffff</FontColor>
<BackgroundColor>#96000000</BackgroundColor>
<FontSize>24</FontSize>
<AlwaysOnTop>true</AlwaysOnTop>
<WindowPosition>100,100</WindowPosition>
</QFlockConfig>
```
## Configuration Options
- **FontColor**: Font color in hex format (e.g., #ffffff for white)
- **BackgroundColor**: Background color in hex format with alpha (e.g., #96000000 for semi-transparent black)
- **FontSize**: Font size in points (8-72)
- **AlwaysOnTop**: Boolean value (true/false)
- **WindowPosition**: Window position as "x,y" coordinates
## Usage
The configuration is automatically loaded when the application starts and saved when it closes. Users can:
1. **Modify settings through the UI**: Right-click on the clock to access the context menu
2. **Edit config.xml directly**: The file is human-readable and can be edited manually
3. **Reset to defaults**: Use the "Reset Settings" option in the context menu
## Features
- ✅ XML-based configuration storage
- ✅ Automatic loading on startup
- ✅ Automatic saving on exit
- ✅ Default values if config file doesn't exist
- ✅ Human-readable XML format
- ✅ Error handling for corrupted config files
- ✅ Manual editing support
## Build and Test
Use the provided test script to build and verify the XML configuration:
```bash
./test_xml_config.sh
```
This will:
1. Clean previous build files
2. Build the project with XML configuration support
3. Display the current config.xml content
4. Provide instructions to run the application
The configuration file will be created automatically when you first run the application and make changes to the settings.
+45 -13
View File
@@ -1,4 +1,5 @@
#include "clockwidget.h" #include "clockwidget.h"
#include "configmanager.h"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QTime> #include <QTime>
#include <QColorDialog> #include <QColorDialog>
@@ -128,6 +129,7 @@ void ClockWidget::changeFontColor()
if (color.isValid()) if (color.isValid())
{ {
m_fontColor = color; m_fontColor = color;
m_configManager->setFontColor(m_fontColor);
updateStyleSheet(); updateStyleSheet();
} }
} }
@@ -138,6 +140,7 @@ void ClockWidget::changeBackgroundColor()
if (color.isValid()) if (color.isValid())
{ {
m_backgroundColor = color; m_backgroundColor = color;
m_configManager->setBackgroundColor(m_backgroundColor);
updateStyleSheet(); updateStyleSheet();
} }
} }
@@ -149,6 +152,7 @@ void ClockWidget::changeFontSize()
if (ok) if (ok)
{ {
m_fontSize = size; m_fontSize = size;
m_configManager->setFontSize(m_fontSize);
updateStyleSheet(); updateStyleSheet();
} }
} }
@@ -158,7 +162,7 @@ void ClockWidget::resetSettings()
int ret = QMessageBox::question(this, "Reset Settings", "Are you sure you want to reset all settings?"); int ret = QMessageBox::question(this, "Reset Settings", "Are you sure you want to reset all settings?");
if (ret == QMessageBox::Yes) if (ret == QMessageBox::Yes)
{ {
m_settings->clear(); m_configManager->resetToDefaults();
loadSettings(); loadSettings();
updateStyleSheet(); updateStyleSheet();
} }
@@ -171,27 +175,55 @@ void ClockWidget::quitApplication()
void ClockWidget::loadSettings() void ClockWidget::loadSettings()
{ {
m_settings = new QSettings("QFlock", "Clock", this); m_configManager = new ConfigManager(this);
m_fontColor = m_settings->value("fontColor", QColor(255, 255, 255)).value<QColor>(); // Load from XML config file
m_backgroundColor = m_settings->value("backgroundColor", QColor(0, 0, 0, 150)).value<QColor>(); if (!m_configManager->loadSettings())
m_fontSize = m_settings->value("fontSize", 24).toInt(); {
m_alwaysOnTop = m_settings->value("alwaysOnTop", true).toBool(); // If loading fails, config manager already has default values
qDebug() << "Using default settings";
}
// Apply loaded settings
m_fontColor = m_configManager->fontColor();
m_backgroundColor = m_configManager->backgroundColor();
m_fontSize = m_configManager->fontSize();
m_alwaysOnTop = m_configManager->alwaysOnTop();
// Restore window position // Restore window position
QPoint pos = m_settings->value("position", QPoint(100, 100)).toPoint(); move(m_configManager->windowPosition());
move(pos);
// Update always on top checkbox in menu
QList<QAction *> actions = m_contextMenu->actions();
for (QAction *action : actions)
{
if (action->text() == "Always on Top")
{
action->setChecked(m_alwaysOnTop);
break;
}
}
updateStyleSheet(); updateStyleSheet();
} }
void ClockWidget::saveSettings() void ClockWidget::saveSettings()
{ {
m_settings->setValue("fontColor", m_fontColor); if (!m_configManager)
m_settings->setValue("backgroundColor", m_backgroundColor); return;
m_settings->setValue("fontSize", m_fontSize);
m_settings->setValue("alwaysOnTop", m_alwaysOnTop); // Update config manager with current values
m_settings->setValue("position", pos()); m_configManager->setFontColor(m_fontColor);
m_configManager->setBackgroundColor(m_backgroundColor);
m_configManager->setFontSize(m_fontSize);
m_configManager->setAlwaysOnTop(m_alwaysOnTop);
m_configManager->setWindowPosition(pos());
// Save to XML file
if (!m_configManager->saveSettings())
{
qDebug() << "Failed to save settings to config.xml";
}
} }
void ClockWidget::updateStyleSheet() void ClockWidget::updateStyleSheet()
+3 -3
View File
@@ -7,10 +7,10 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QMenu> #include <QMenu>
#include <QAction> #include <QAction>
#include <QSettings>
#include <QFont>
#include <QColor> #include <QColor>
class ConfigManager;
class ClockWidget : public QWidget class ClockWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@@ -49,7 +49,7 @@ private:
bool m_dragging; bool m_dragging;
// Settings // Settings
QSettings *m_settings; ConfigManager *m_configManager;
QColor m_fontColor; QColor m_fontColor;
QColor m_backgroundColor; QColor m_backgroundColor;
int m_fontSize; int m_fontSize;
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<QFlockConfig>
<FontColor>#ffffff</FontColor>
<BackgroundColor>#96000000</BackgroundColor>
<FontSize>24</FontSize>
<AlwaysOnTop>true</AlwaysOnTop>
<WindowPosition>100,100</WindowPosition>
</QFlockConfig>
+146
View File
@@ -0,0 +1,146 @@
#include "configmanager.h"
#include <QFile>
#include <QDebug>
ConfigManager::ConfigManager(QObject *parent)
: QObject(parent)
{
setDefaultValues();
}
bool ConfigManager::loadSettings(const QString &filename)
{
QFile file(filename);
if (!file.exists())
{
qDebug() << "Config file does not exist, using defaults";
return false;
}
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Cannot open config file for reading:" << file.errorString();
return false;
}
QXmlStreamReader reader(&file);
// Check if it's a valid XML file
if (!reader.readNextStartElement() || reader.name() != "QFlockConfig")
{
qDebug() << "Invalid config file format";
file.close();
return false;
}
// Read configuration values
while (reader.readNextStartElement())
{
QString name = reader.name().toString();
QString text = reader.readElementText();
if (name == "FontColor")
{
m_fontColor = QColor(text);
}
else if (name == "BackgroundColor")
{
m_backgroundColor = QColor(text);
}
else if (name == "FontSize")
{
m_fontSize = text.toInt();
}
else if (name == "AlwaysOnTop")
{
m_alwaysOnTop = (text.toLower() == "true");
}
else if (name == "WindowPosition")
{
// Parse position format: "x,y"
QStringList coords = text.split(',');
if (coords.size() == 2)
{
int x = coords[0].toInt();
int y = coords[1].toInt();
m_windowPosition = QPoint(x, y);
}
}
else
{
reader.skipCurrentElement();
}
}
file.close();
if (reader.hasError())
{
qDebug() << "Error reading config file:" << reader.errorString();
return false;
}
return true;
}
bool ConfigManager::saveSettings(const QString &filename)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
qDebug() << "Cannot open config file for writing:" << file.errorString();
return false;
}
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true);
writer.writeStartDocument();
// Root element
writer.writeStartElement("QFlockConfig");
// Font color
writer.writeTextElement("FontColor", m_fontColor.name(QColor::HexArgb));
// Background color
writer.writeTextElement("BackgroundColor", m_backgroundColor.name(QColor::HexArgb));
// Font size
writer.writeTextElement("FontSize", QString::number(m_fontSize));
// Always on top
writer.writeTextElement("AlwaysOnTop", m_alwaysOnTop ? "true" : "false");
// Window position
QString positionStr = QString("%1,%2")
.arg(m_windowPosition.x())
.arg(m_windowPosition.y());
writer.writeTextElement("WindowPosition", positionStr);
// Close root element
writer.writeEndElement();
writer.writeEndDocument();
file.close();
return true;
}
void ConfigManager::resetToDefaults()
{
setDefaultValues();
}
bool ConfigManager::configExists(const QString &filename) const
{
return QFile::exists(filename);
}
void ConfigManager::setDefaultValues()
{
m_fontColor = QColor(255, 255, 255); // White
m_backgroundColor = QColor(0, 0, 0, 150); // Semi-transparent black
m_fontSize = 24;
m_alwaysOnTop = true;
m_windowPosition = QPoint(100, 100);
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef CONFIGMANAGER_H
#define CONFIGMANAGER_H
#include <QObject>
#include <QColor>
#include <QPoint>
#include <QString>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
class ConfigManager : public QObject
{
Q_OBJECT
public:
explicit ConfigManager(QObject *parent = nullptr);
// Load settings from XML file
bool loadSettings(const QString &filename = "config.xml");
// Save settings to XML file
bool saveSettings(const QString &filename = "config.xml");
// Getters
QColor fontColor() const { return m_fontColor; }
QColor backgroundColor() const { return m_backgroundColor; }
int fontSize() const { return m_fontSize; }
bool alwaysOnTop() const { return m_alwaysOnTop; }
QPoint windowPosition() const { return m_windowPosition; }
// Setters
void setFontColor(const QColor &color) { m_fontColor = color; }
void setBackgroundColor(const QColor &color) { m_backgroundColor = color; }
void setFontSize(int size) { m_fontSize = size; }
void setAlwaysOnTop(bool onTop) { m_alwaysOnTop = onTop; }
void setWindowPosition(const QPoint &pos) { m_windowPosition = pos; }
// Reset to default values
void resetToDefaults();
// Check if config file exists
bool configExists(const QString &filename = "config.xml") const;
private:
// Default values
void setDefaultValues();
// Settings data
QColor m_fontColor;
QColor m_backgroundColor;
int m_fontSize;
bool m_alwaysOnTop;
QPoint m_windowPosition;
};
#endif // CONFIGMANAGER_H
+4 -2
View File
@@ -7,10 +7,12 @@ QT = core gui widgets
SOURCES = \ SOURCES = \
$$PWD/main.cpp \ $$PWD/main.cpp \
$$PWD/clockwidget.cpp $$PWD/clockwidget.cpp \
$$PWD/configmanager.cpp
HEADERS = \ HEADERS = \
$$PWD/clockwidget.h $$PWD/clockwidget.h \
$$PWD/configmanager.h
INCLUDEPATH = \ INCLUDEPATH = \
$$PWD/. $$PWD/.
+29
View File
@@ -0,0 +1,29 @@
# Build and Run Test
echo "Building QFlock with XML configuration..."
# Clean previous build
./clean.sh
# Build the project
./build.sh
# Check if build was successful
if [ $? -eq 0 ]; then
echo "Build successful! Testing XML configuration..."
# Show config file content
echo "Config file content:"
if [ -f "config.xml" ]; then
cat config.xml
else
echo "No config.xml found (will be created on first run)"
fi
echo ""
echo "You can now run the application:"
echo "./build/flock.app/Contents/MacOS/flock # macOS"
echo "./build/flock # Linux"
else
echo "Build failed!"
fi