497 lines
19 KiB
C++
497 lines
19 KiB
C++
#ifndef DEVICE_MENU_H
|
||
#define DEVICE_MENU_H
|
||
|
||
#include <QMenu>
|
||
#include <mutex>
|
||
#include "sane/sane_ex.h"
|
||
#include "sane/sane_option_definitions.h"
|
||
#include "../../../sdk/include/huagao/hgscanner_error.h"
|
||
|
||
#include "cfg/gb_json.h"
|
||
#include "lang/app_language.h"
|
||
|
||
typedef struct _scanner
|
||
{
|
||
std::string name;
|
||
std::string model;
|
||
bool online;
|
||
gb::scanner_cfg *cfg;
|
||
}SCANNER;
|
||
class dev_que
|
||
{
|
||
std::vector<SCANNER> que_;
|
||
std::string root_dir_;
|
||
std::string opened_scanner_;
|
||
std::string applied_scheme_;
|
||
SANE_Handle handle_;
|
||
|
||
|
||
static void trans_number(const char* name, std::string& val, void* param)
|
||
{
|
||
if (strcmp(name, "tl-x") == 0
|
||
|| strcmp(name, "br-x") == 0
|
||
|| strcmp(name, "tl-y") == 0
|
||
|| strcmp(name, "br-y") == 0
|
||
|| strcmp(name, "gamma") == 0
|
||
|| strcmp(name, "search-hole-range-l") == 0
|
||
|| strcmp(name, "search-hole-range-r") == 0
|
||
|| strcmp(name, "search-hole-range-t") == 0
|
||
|| strcmp(name, "search-hole-range-b") == 0
|
||
|| strcmp(name, "feed-strength-value") == 0
|
||
)
|
||
{
|
||
float v = atof(val.c_str());
|
||
SANE_Fixed f = SANE_FIX(v);
|
||
|
||
val = std::string((char*)&f, sizeof(f));
|
||
}
|
||
else if (strcmp(name, "binary-threshold") == 0
|
||
|| strcmp(name, "bkg-color-range") == 0
|
||
|| strcmp(name, "noise-size") == 0
|
||
|| strcmp(name, "blank-sensitivity") == 0
|
||
|| strcmp(name, "resolution") == 0
|
||
|| strcmp(name, "brightness") == 0
|
||
|| strcmp(name, "contrast") == 0
|
||
|| strcmp(name, "threshold") == 0
|
||
|| strcmp(name, "anti-noise-level") == 0
|
||
|| strcmp(name, "margin") == 0
|
||
|| strcmp(name, "scan-count") == 0
|
||
|| strcmp(name, "askew-range") == 0
|
||
|| strcmp(name, "dog-ear-size") == 0
|
||
)
|
||
{
|
||
SANE_Int v = atoi(val.c_str());
|
||
val = std::string((char*)&v, sizeof(v));
|
||
}
|
||
else if (strcmp(val.c_str(), "true") == 0)
|
||
{
|
||
SANE_Bool b = SANE_TRUE;
|
||
val = std::string((char*)&b, sizeof(b));
|
||
}
|
||
else if (strcmp(val.c_str(), "false") == 0)
|
||
{
|
||
SANE_Bool b = SANE_FALSE;
|
||
val = std::string((char*)&b, sizeof(b));
|
||
}
|
||
}
|
||
static const char* title_2_name(const char* title, void* param)
|
||
{
|
||
struct
|
||
{
|
||
const char* name;
|
||
const char* title;
|
||
}g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ}
|
||
, {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ}
|
||
, {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC}
|
||
, {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX}
|
||
, {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS}
|
||
, {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ}
|
||
, {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC}
|
||
, {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ}
|
||
, {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH}
|
||
, {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH}
|
||
, {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC}
|
||
, {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW}
|
||
, {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH}
|
||
, {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW}
|
||
, {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW}
|
||
, {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS}
|
||
, {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH}
|
||
, {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC}
|
||
, {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm}
|
||
, {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm}
|
||
, {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC}
|
||
, {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM}
|
||
, {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD}
|
||
, {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL}
|
||
, {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ}
|
||
, {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ}
|
||
, {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM}
|
||
, {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF }
|
||
, {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP}
|
||
, {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX}
|
||
, {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ}
|
||
, {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ}
|
||
, {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD}
|
||
, {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS}
|
||
, {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK}
|
||
, {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ}
|
||
, {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ}
|
||
, {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ}
|
||
, {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ}
|
||
, {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS}
|
||
, {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST}
|
||
, {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC}
|
||
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL}
|
||
, {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC}
|
||
, {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC}
|
||
, {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL}
|
||
, {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC}
|
||
, {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS}
|
||
, {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL}
|
||
, {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX}
|
||
, {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180}
|
||
, {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC}
|
||
, {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX}
|
||
, {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC}
|
||
, {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD}
|
||
, {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD}
|
||
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD}
|
||
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL}
|
||
, {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM}
|
||
, {SANE_STD_OPT_NAME_FOLD_TYPE , OPTION_TITLE_DZMS}
|
||
},
|
||
g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 黑白图像反色输出(正常颜色为:0-黑色;1-白色)
|
||
, {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 灰度或黑白图像 - 除色
|
||
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 自动搓纸强度
|
||
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 搓纸阈值"
|
||
};
|
||
while (*title == ' ')
|
||
title++;
|
||
|
||
for (size_t i = 0; i < _countof(g_opts); ++i)
|
||
{
|
||
if (strcmp(title, g_opts[i].title) == 0)
|
||
return g_opts[i].name;
|
||
}
|
||
for (size_t i = 0; i < _countof(g_discard); ++i)
|
||
{
|
||
if (strcmp(title, g_discard[i].title) == 0)
|
||
return g_discard[i].name;
|
||
}
|
||
|
||
return title;
|
||
}
|
||
|
||
public:
|
||
dev_que() : handle_(nullptr)
|
||
{}
|
||
~dev_que()
|
||
{
|
||
close_scanner();
|
||
|
||
for(auto& v : que_)
|
||
v.cfg->release();
|
||
}
|
||
|
||
static void update_old_cfg(const char* conf)
|
||
{
|
||
gb::scanner_cfg::UDF func;
|
||
|
||
func.func_param = nullptr;
|
||
func.title2name = &dev_que::title_2_name;
|
||
func.trans_number = &dev_que::trans_number;
|
||
|
||
gb::scanner_cfg::update(conf, &func);
|
||
}
|
||
static void apply_scheme(const SANEAPI* saneApi, SANE_Handle h, gb::sane_config_schm* schm)
|
||
{
|
||
SANE_Int count = 0, none = 0;
|
||
std::string name(""), val("");
|
||
|
||
none = saneApi->sane_io_control_api(h, IO_CTRL_CODE_RESTORE_SETTINGS, NULL, NULL);
|
||
if(schm && schm->id_from_name(SANE_STD_OPT_NAME_COLOR_MODE) == -1)
|
||
{
|
||
SANE_Int dev_options = 0;
|
||
saneApi->sane_control_option_api(h, 0, SANE_ACTION_GET_VALUE, &dev_options, nullptr);
|
||
for(int i = 1; i < dev_options; ++i)
|
||
{
|
||
const SANE_Option_Descriptor* opt = saneApi->sane_get_option_descriptor_api(h, i);
|
||
if(!opt)
|
||
continue;
|
||
|
||
unsigned int n = i;
|
||
if(opt->type == SANE_TYPE_BOOL)
|
||
{
|
||
SANE_Bool v = SANE_TRUE;
|
||
saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, &v, &n);
|
||
schm->set_default_value(i, opt->name, (char*)&v, sizeof(v));
|
||
}
|
||
else if (opt->type == SANE_TYPE_INT) {
|
||
SANE_Int v = 0;
|
||
saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, &v, &n);
|
||
schm->set_default_value(i, opt->name, (char*)&v, sizeof(v));
|
||
}
|
||
else if(opt->type == SANE_TYPE_FIXED)
|
||
{
|
||
SANE_Fixed v = 0;
|
||
saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, &v, &n);
|
||
schm->set_default_value(i, opt->name, (char*)&v, sizeof(v));
|
||
}
|
||
else {
|
||
char *buf = new char[opt->size + 4];
|
||
memset(buf, 0, opt->size + 4);
|
||
saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, buf, &n);
|
||
std::string langCN(to_default_language(buf, nullptr));
|
||
schm->set_default_value(i, opt->name, &langCN[0], langCN.length());
|
||
delete[] buf;
|
||
}
|
||
}
|
||
}
|
||
if(schm && schm->first_config(name, val))
|
||
{
|
||
do
|
||
{
|
||
int id = schm->id_from_name(name.c_str());
|
||
if(id == -1)
|
||
{
|
||
if(gb::sane_config_schm::is_option_data(name))
|
||
{
|
||
if(name == SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA && val.length() == sizeof(SANE_Gamma))
|
||
{
|
||
unsigned int l = val.length();
|
||
saneApi->sane_io_control_api(h, IO_CTRL_CODE_SET_CUSTOM_GAMMA, &val[0], &l);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
const SANE_Option_Descriptor* opt = reinterpret_cast<const SANE_Option_Descriptor*>(saneApi->sane_get_option_descriptor_api(h, id));
|
||
if(opt)
|
||
{
|
||
if(opt->type == SANE_TYPE_STRING)
|
||
{
|
||
char *buf = new char[opt->size + 4];
|
||
memset(buf, 0, opt->size + 4);
|
||
strcpy(buf, val.c_str());
|
||
std::string langCN(from_default_language(buf, nullptr));
|
||
saneApi->sane_control_option_api(h, id, SANE_ACTION_SET_VALUE, &langCN[0], &none);
|
||
delete[] buf;
|
||
}
|
||
else {
|
||
saneApi->sane_control_option_api(h, id, SANE_ACTION_SET_VALUE, &val[0], &none);
|
||
}
|
||
}
|
||
}
|
||
|
||
}while(schm->next_config(name, val));
|
||
}
|
||
}
|
||
|
||
|
||
public:
|
||
void set_root_dir(const char* root)
|
||
{
|
||
root_dir_ = std::string(root) + PATH_SYMBOL;
|
||
}
|
||
void add_scanner(const char* sane_name)
|
||
{
|
||
bool found = false;
|
||
|
||
for(auto& v: que_)
|
||
{
|
||
if(v.name == sane_name)
|
||
{
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(!found)
|
||
{
|
||
SCANNER s;
|
||
size_t pos = 0;
|
||
|
||
s.model = s.name = sane_name;
|
||
s.cfg = nullptr;
|
||
pos = s.model.find(" - ");
|
||
if(pos != std::string::npos)
|
||
{
|
||
pos = s.model.find(" - ", pos + 3);
|
||
if(pos != std::string::npos)
|
||
s.model.erase(pos);
|
||
}
|
||
for(auto& v: que_)
|
||
{
|
||
if(v.model == s.model)
|
||
{
|
||
s.cfg = v.cfg;
|
||
s.cfg->add_ref();
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(!s.cfg)
|
||
{
|
||
s.cfg = new gb::scanner_cfg();
|
||
s.cfg->load_file((root_dir_ + s.model + ".cfg").c_str());
|
||
}
|
||
s.online = true;
|
||
que_.push_back(s);
|
||
}
|
||
}
|
||
void get_schemes(const char* scanner_name, std::vector<std::string>& schemes)
|
||
{
|
||
schemes.clear();
|
||
for(auto& v : que_)
|
||
{
|
||
if(v.name == scanner_name)
|
||
{
|
||
v.cfg->get_all_schemes(schemes);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
SANE_Handle handle(void)
|
||
{
|
||
return handle_;
|
||
}
|
||
std::string opened_scanner_name(void)
|
||
{
|
||
return opened_scanner_;
|
||
}
|
||
std::string applied_scheme(void)
|
||
{
|
||
return applied_scheme_;
|
||
}
|
||
int open_scanner(const SANEAPI* saneAPI, SANE_Handle handle, const char* scanner_name, bool apply, const char* scheme = nullptr)
|
||
{
|
||
handle_ = handle;
|
||
opened_scanner_ = scanner_name;
|
||
if (apply)
|
||
apply_scheme(saneAPI, scheme);
|
||
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
int close_scanner(void)
|
||
{
|
||
handle_ = nullptr;
|
||
opened_scanner_ = "";
|
||
applied_scheme_ = "";
|
||
return SANE_STATUS_GOOD;
|
||
}
|
||
int scanners(void)
|
||
{
|
||
return que_.size();
|
||
}
|
||
SCANNER get_at(int pos)
|
||
{
|
||
SCANNER s;
|
||
|
||
s.name = s.model = "";
|
||
s.cfg = nullptr;
|
||
if(pos >= 0 && pos < que_.size())
|
||
{
|
||
s = que_[pos];
|
||
s.cfg->add_ref();
|
||
}
|
||
|
||
return s;
|
||
}
|
||
bool is_online(const char* scanner = nullptr)
|
||
{
|
||
if(!scanner)
|
||
scanner = opened_scanner_.c_str();
|
||
|
||
for(auto& v : que_)
|
||
{
|
||
if(v.name == scanner)
|
||
return v.online;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
void set_online(bool online, const char* scanner = nullptr)
|
||
{
|
||
if(!scanner)
|
||
scanner = opened_scanner_.c_str();
|
||
|
||
for(auto& v : que_)
|
||
{
|
||
if(v.name == scanner)
|
||
{
|
||
v.online = online;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
void get_scanners(std::vector<std::string>& que)
|
||
{
|
||
for(auto& v: que_)
|
||
que.push_back(v.name);
|
||
}
|
||
int apply_scheme(const SANEAPI* saneApi, const char* scheme_name)
|
||
{
|
||
if(!handle_)
|
||
return SCANNER_ERR_NOT_OPEN;
|
||
|
||
for(auto& v: que_)
|
||
{
|
||
if(v.name == opened_scanner_)
|
||
{
|
||
gb::sane_config_schm* schm = v.cfg->get_scheme(scheme_name);
|
||
dev_que::apply_scheme(saneApi, handle_, schm);
|
||
if(schm)
|
||
{
|
||
v.cfg->select_scheme(schm->get_scheme_name().c_str());
|
||
schm->release();
|
||
}
|
||
else {
|
||
v.cfg->select_scheme(scheme_name);
|
||
}
|
||
applied_scheme_ = v.cfg->get_current_scheme_name();
|
||
v.cfg->save();
|
||
break;
|
||
}
|
||
}
|
||
|
||
return SCANNER_ERR_OK;
|
||
}
|
||
};
|
||
|
||
|
||
class device_menu : public QMenu
|
||
{
|
||
Q_OBJECT
|
||
typedef struct _pop_menu
|
||
{
|
||
QMenu* menu;
|
||
std::vector<QAction*> actions;
|
||
|
||
bool operator==(const QString& menu_title)
|
||
{
|
||
return menu->title() == menu_title;
|
||
}
|
||
}POPMENU;
|
||
std::vector<POPMENU> menus_;
|
||
QAction* cur_action_;
|
||
QAction* none_action_;
|
||
QActionGroup* group_action_;
|
||
std::mutex mutex_;
|
||
|
||
QMenu* find_device_menu(const QString& dev_name);
|
||
QAction* find_device_config(const QString& dev_name, const QString& cfg_name);
|
||
|
||
public:
|
||
device_menu(QWidget* parent = nullptr);
|
||
device_menu(const QString& title, QWidget* parent = nullptr);
|
||
|
||
void deviceMenuUpdate(dev_que* que);
|
||
|
||
void connectedDevice(const QString& device);
|
||
|
||
void disconnectedDevice(const QString& device);
|
||
|
||
void setOptionChecked(const QString& device, const QString& opt, bool checked);
|
||
|
||
void get_online_devices(QList<QString>& dev_names);
|
||
|
||
signals:
|
||
void scanOptionsChanged(const QString& device, const QString& opt, bool checked_now);
|
||
|
||
private slots:
|
||
void on_act_triggered(QAction* act);
|
||
};
|
||
|
||
#endif // DEVICE_MENU_H
|