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
main.cpp
clockwidget.cpp
configmanager.cpp
)
set(HEADERS
clockwidget.h
configmanager.h
)
# 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)
![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
- [x] Drag and Move
- [x] Right Click Menu
- [ ] Always On Top
- [x] Always On Top
- [ ] Show in Fullscreen Mode
- [x] **Style**
- [x] Set Background Color
- [x] Set Font Color
- [x] Set FontSize
- [ ] **Configuration File** (XML)
- [ ] Read Settings
- [ ] Write Settings
- [ ] Reset Settings
- [x] **Configuration File** (XML)
- [x] Read Settings
- [x] Write Settings
- [x] Reset Settings
- [ ] **Time**
- [ ] Select Time Zone
- [ ] Set Alarms
@@ -73,11 +73,24 @@ make
./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
- **Move**: Left-click and drag
- **Menu**: Right-click for context menu
- **Customize**: Change colors, font size, always-on-top behavior
- **Configuration**: Settings are saved to `config.xml` and persist between sessions
### Project Structure
@@ -88,6 +101,7 @@ qflock/
│ ├── *.o # Object files
│ ├── moc_*.cpp # Qt meta-object compiler output
│ └── Makefile # Build file
├── config.xml # XML configuration file
├── build.sh # One-click build script
├── clean.sh # Clean script
├── 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 "configmanager.h"
#include <QVBoxLayout>
#include <QTime>
#include <QColorDialog>
@@ -128,6 +129,7 @@ void ClockWidget::changeFontColor()
if (color.isValid())
{
m_fontColor = color;
m_configManager->setFontColor(m_fontColor);
updateStyleSheet();
}
}
@@ -138,6 +140,7 @@ void ClockWidget::changeBackgroundColor()
if (color.isValid())
{
m_backgroundColor = color;
m_configManager->setBackgroundColor(m_backgroundColor);
updateStyleSheet();
}
}
@@ -149,6 +152,7 @@ void ClockWidget::changeFontSize()
if (ok)
{
m_fontSize = size;
m_configManager->setFontSize(m_fontSize);
updateStyleSheet();
}
}
@@ -158,7 +162,7 @@ void ClockWidget::resetSettings()
int ret = QMessageBox::question(this, "Reset Settings", "Are you sure you want to reset all settings?");
if (ret == QMessageBox::Yes)
{
m_settings->clear();
m_configManager->resetToDefaults();
loadSettings();
updateStyleSheet();
}
@@ -171,27 +175,55 @@ void ClockWidget::quitApplication()
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>();
m_backgroundColor = m_settings->value("backgroundColor", QColor(0, 0, 0, 150)).value<QColor>();
m_fontSize = m_settings->value("fontSize", 24).toInt();
m_alwaysOnTop = m_settings->value("alwaysOnTop", true).toBool();
// Load from XML config file
if (!m_configManager->loadSettings())
{
// 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
QPoint pos = m_settings->value("position", QPoint(100, 100)).toPoint();
move(pos);
move(m_configManager->windowPosition());
// 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();
}
void ClockWidget::saveSettings()
{
m_settings->setValue("fontColor", m_fontColor);
m_settings->setValue("backgroundColor", m_backgroundColor);
m_settings->setValue("fontSize", m_fontSize);
m_settings->setValue("alwaysOnTop", m_alwaysOnTop);
m_settings->setValue("position", pos());
if (!m_configManager)
return;
// Update config manager with current values
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()
+3 -3
View File
@@ -7,10 +7,10 @@
#include <QMouseEvent>
#include <QMenu>
#include <QAction>
#include <QSettings>
#include <QFont>
#include <QColor>
class ConfigManager;
class ClockWidget : public QWidget
{
Q_OBJECT
@@ -49,7 +49,7 @@ private:
bool m_dragging;
// Settings
QSettings *m_settings;
ConfigManager *m_configManager;
QColor m_fontColor;
QColor m_backgroundColor;
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 = \
$$PWD/main.cpp \
$$PWD/clockwidget.cpp
$$PWD/clockwidget.cpp \
$$PWD/configmanager.cpp
HEADERS = \
$$PWD/clockwidget.h
$$PWD/clockwidget.h \
$$PWD/configmanager.h
INCLUDEPATH = \
$$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