How to add Alert on buy sell arrow - metatrader5

How to add Alert on Buy_Signal & Sell_Signal arrow, I added below code but getting wrong signals. Can anyone help me out with it. Thanks
if (((TriggerCandle > 0) && (time[rates_total - 1] > LastAlertTime)) || (TriggerCandle == 0))
{
string Text;
// Up Arrow Alert
if ((Buy_Signal[rates_total - 1 - TriggerCandle] > 0) && ((TriggerCandle > 0) || ((TriggerCandle == 0) && (LastAlertDirection != 1))))
{
Text = AlertText + "Alpha Buy: " + Symbol() + " - " + EnumToString(Period()) + " - Up.";
if (EnableNativeAlerts) Alert(Text);
if (EnableEmailAlerts) SendMail(AlertEmailSubject + "Alpha Buy", Text);
if (EnableSoundAlerts) PlaySound(SoundFileName);
if (EnablePushAlerts) SendNotification(Text);
LastAlertTime = time[rates_total - 1];
LastAlertDirection = 1;
}
// Down Arrow Alert
if ((Sell_Signal[rates_total - 1 - TriggerCandle] > 0) && ((TriggerCandle > 0) || ((TriggerCandle == 0) && (LastAlertDirection != -1))))
{
Text = AlertText + "Alpha Sell: " + Symbol() + " - " + EnumToString(Period()) + " - Down.";
if (EnableNativeAlerts) Alert(Text);
if (EnableEmailAlerts) SendMail(AlertEmailSubject + "Alpha Sell", Text);
if (EnableSoundAlerts) PlaySound(SoundFileName);
if (EnablePushAlerts) SendNotification(Text);
LastAlertTime = time[rates_total - 1];
LastAlertDirection = -1;
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}

Related

Qt 5.13 Oracle OCI Result cannot bind to return a SYS_REFCURSOR

I recently built Qt 5.13 statically, along with qsqloci plugin and it came out pretty well. One of the issues I have been working around is how to return a SYS_REFCURSOR object from Oracle base to a QSqlResult or something similar. I found a patch https://bugreports.qt.io/browse/QTBUG-166
I have tried the exact same thing, but somehow, it managed to print out:
ORA-01008: not all variables bound
Unable to execute statement.
I have a crystal clear connection to database and I can execute other statements, as well, not a problem. The only problem is how to return a SYS_REFCURSOR.
Thank you.
Q_DECLARE_METATYPE(QOCIResult *)
QOCIResult *p_cursor = reinterpret_cast<QOCIResult*>(db.driver()->createResult());
QSqlQuery content_query(db);
content_query.prepare("begin ispovedi.get_ord_kategorii_list(:p_cursor); end;");
content_query.addBindValue(qVariantFromValue(p_cursor), QSql::Out);
if (content_query.exec())
{
p_cursor->exec();
}
else
{
qCritical("%s.", qPrintable(content_query.lastError().text()));
}
I try to migrate the patch https://bugreports.qt.io/browse/QTBUG-166 to Qt 5.7 yesterday, and it seems to work, here is my patch:
--- qsql_oci.cpp.orig Thu Aug 29 05:18:48 2019
+++ qsql_oci.cpp Thu Aug 29 11:53:44 2019
## -82,6 +82,9 ##
//#define QOCI_DEBUG
+Q_DECLARE_METATYPE(QSqlResult *)
+
+
Q_DECLARE_OPAQUE_POINTER(OCIEnv*);
Q_DECLARE_METATYPE(OCIEnv*)
Q_DECLARE_OPAQUE_POINTER(OCIStmt*);
## -206,6 +209,8 ##
QVariant lastInsertId() const Q_DECL_OVERRIDE;
bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE;
void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
+ bool isCursor;
+ bool internal_prepare();
};
class QOCIResultPrivate: public QSqlCachedResultPrivate
## -389,6 +394,18 ##
const_cast<OCIRowid **>(&rptr->id),
-1,
SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ } else if (val.canConvert<QSqlResult *>() && isOutValue(pos)) {
+ QOCIResult *res = (QOCIResult *)qvariant_cast<QSqlResult *>(val);
+
+ if (res->internal_prepare()) {
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ const_cast<OCIStmt **>(&res->d_func()->sql),
+ (sb4)0,
+ SQLT_RSET, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+
+ res->isCursor = true;
+ }
} else {
qWarning("Unknown bind variable");
r = OCI_ERROR;
## -1833,6 +1850,7 ##
QOCIResult::QOCIResult(const QOCIDriver *db)
: QSqlCachedResult(*new QOCIResultPrivate(this, db))
{
+ isCursor = false;
}
QOCIResult::~QOCIResult()
## -1931,13 +1949,15 ##
return rowCount;
}
-bool QOCIResult::prepare(const QString& query)
-{
+bool QOCIResult::internal_prepare() {
Q_D(QOCIResult);
int r = 0;
- QSqlResult::prepare(query);
+ QString noStr;
+ QSqlResult::prepare(noStr);
- delete d->cols;
+ if (d->cols)
+ delete d->cols;
+
d->cols = 0;
QSqlCachedResult::cleanup();
## -1946,20 +1966,36 ##
if (r != OCI_SUCCESS)
qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
}
- if (query.isEmpty())
- return false;
+
r = OCIHandleAlloc(d->env,
reinterpret_cast<void **>(&d->sql),
OCI_HTYPE_STMT,
0,
0);
+
if (r != OCI_SUCCESS) {
qOraWarning("QOCIResult::prepare: unable to alloc statement:", d->err);
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
"Unable to alloc statement"), QSqlError::StatementError, d->err));
return false;
}
+
d->setStatementAttributes();
+
+ return true;
+}
+
+bool QOCIResult::prepare(const QString& query)
+{
+ Q_D(QOCIResult);
+
+ if (query.isEmpty())
+ return false;
+
+ if (!internal_prepare())
+ return false;
+
+ int r = 0;
const OraText *txt = reinterpret_cast<const OraText *>(query.utf16());
const int len = query.length() * sizeof(QChar);
r = OCIStmtPrepare(d->sql,
## -2020,23 +2056,26 ##
return false;
}
- // execute
- r = OCIStmtExecute(d->svc,
- d->sql,
- d->err,
- iters,
- 0,
- 0,
- 0,
- mode);
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to execute statement"), QSqlError::StatementError, d->err));
-#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
-#endif
- return false;
+ if (!isCursor)
+ {
+ // execute
+ r = OCIStmtExecute(d->svc,
+ d->sql,
+ d->err,
+ iters,
+ 0,
+ 0,
+ 0,
+ mode);
+ if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
+ qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
+ setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
+ "Unable to execute statement"), QSqlError::StatementError, d->err));
+ #ifdef QOCI_DEBUG
+ qDebug() << "lastQuery()" << lastQuery();
+ #endif
+ return false;
+ }
}
if (stmtType == OCI_STMT_SELECT) {
Modify your code as follows and have a try:
Q_DECLARE_METATYPE(QSqlResult *)
QSqlResult *p_cursor = db.driver()->createResult();
QSqlQuery content_query(db);
content_query.prepare("begin ispovedi.get_ord_kategorii_list(:p_cursor); end;");
content_query.addBindValue(qVariantFromValue(p_cursor), QSql::Out);
if (content_query.exec())
{
QSqlQuery result_query(p_cursor);
result_query.exec();
}
else
{
qCritical("%s.", qPrintable(content_query.lastError().text()));
}

Algorithm - Given a set of pixels with coordinates, how to find all the contiguous lines in an efficient way?

I am working on an extrusion function to create a mesh given a 2D texture and the thickness of it.
Example:
I have achieved finding the outline of the texture by simply looking for the pixels either near the edge or near transparent ones. It works great even for concave (donut-shaped) shapes but now I am left with an array of outline pixels.
Here is the result:
The problem is that the values, by being ordered from top-left to bottom-right, they are not suitable for building an actual 3D outline.
My current idea is the following:
Step 1.
From index [0], look at the right-hand side for the nearest contiguous point different from the starting point.
If found, move it into another array.
If nothing, look at the bottom. Continue until the starting point has been reached.
Step2.
Pick another pixel, if any, from the pixels remained in the array.
Repeat from Step1.
This, in my head, would work but it seems quite inefficient. Researching, I found about the Moore-Neighbor tracing algorithm but I couldn't find anywhere an example where it worked with convex shapes.
Any thoughts?
At the end, I managed to find my own answer, so here I want to share it:
After finding the outline of a given image (using the alpha value of each pixel), the pixels will be ordered in rows, good for drawing them but bad for constructing a mesh.
So, the next step is to find contiguous lines. This is done by checking first if there are any neighbors to the found pixel giving priority to the ones top/left/right/bottom (otherwise it will skip the corners).
Keep going until no pixels are left in the original array.
Here is the actual implementation (for Babylon.js but the idea works with any other engine):
Playground: https://www.babylonjs-playground.com/#9GPMUY#11
var GetTextureOutline = function (data, keepOutline, keepOtherPixels) {
var not_outline = [];
var pixels_list = [];
for (var j = 0; j < data.length; j = j + 4) {
var alpha = data[j + 3];
var current_alpha_index = j + 3;
// Not Invisible
if (alpha != 0) {
var top_alpha = data[current_alpha_index - (canvasWidth * 4)];
var bottom_alpha = data[current_alpha_index + (canvasWidth * 4)];
var left_alpha = data[current_alpha_index - 4];
var right_alpha = data[current_alpha_index + 4];
if ((top_alpha === undefined || top_alpha == 0) ||
(bottom_alpha === undefined || bottom_alpha == 0) ||
(left_alpha === undefined || left_alpha == 0) ||
(right_alpha === undefined || right_alpha == 0)) {
pixels_list.push({
x: (j / 4) % canvasWidth,
y: parseInt((j / 4) / canvasWidth),
color: new BABYLON.Color3(data[j] / 255, data[j + 1] / 255, data[j + 2] / 255),
alpha: data[j + 3] / 255
});
if (!keepOutline) {
data[j] = 255;
data[j + 1] = 0;
data[j + 2] = 255;
}
} else if (!keepOtherPixels) {
not_outline.push(j);
}
}
}
// Remove not-outline pixels
for (var i = 0; i < not_outline.length; i++) {
if (!keepOtherPixels) {
data[not_outline[i]] = 0;
data[not_outline[i] + 1] = 0;
data[not_outline[i] + 2] = 0;
data[not_outline[i] + 3] = 0;
}
}
return pixels_list;
}
var ExtractLinesFromPixelsList = function (pixelsList, sortPixels) {
if (sortPixels) {
// Sort pixelsList
function sortY(a, b) {
if (a.y == b.y) return a.x - b.x;
return a.y - b.y;
}
pixelsList.sort(sortY);
}
var lines = [];
var line = [];
var pixelAdded = true;
var skipDiagonals = true;
line.push(pixelsList[0]);
pixelsList.splice(0, 1);
var countPixels = 0;
while (pixelsList.length != 0) {
if (!pixelAdded && !skipDiagonals) {
lines.push(line);
line = [];
line.push(pixelsList[0]);
pixelsList.splice(0, 1);
} else if (!pixelAdded) {
skipDiagonals = false;
}
pixelAdded = false;
for (var i = 0; i < pixelsList.length; i++) {
if ((skipDiagonals && (
line[line.length - 1].x + 1 == pixelsList[i].x && line[line.length - 1].y == pixelsList[i].y ||
line[line.length - 1].x - 1 == pixelsList[i].x && line[line.length - 1].y == pixelsList[i].y ||
line[line.length - 1].x == pixelsList[i].x && line[line.length - 1].y + 1 == pixelsList[i].y ||
line[line.length - 1].x == pixelsList[i].x && line[line.length - 1].y - 1 == pixelsList[i].y)) || (!skipDiagonals && (
line[line.length - 1].x + 1 == pixelsList[i].x && line[line.length - 1].y + 1 == pixelsList[i].y ||
line[line.length - 1].x + 1 == pixelsList[i].x && line[line.length - 1].y - 1 == pixelsList[i].y ||
line[line.length - 1].x - 1 == pixelsList[i].x && line[line.length - 1].y + 1 == pixelsList[i].y ||
line[line.length - 1].x - 1 == pixelsList[i].x && line[line.length - 1].y - 1 == pixelsList[i].y
))) {
line.push(pixelsList[i]);
pixelsList.splice(i, 1);
i--;
pixelAdded = true;
skipDiagonals = true;
}
}
}
lines.push(line);
return lines;
}
Algorithm Looping over pixels, we only check each pixel once, skipping empty cells, and store it in a list as there won't be duplicates.
isEmpty implementation depends on how transparency works in your case, if a certain color is considered transparent, below is a case where we have an alpha channel.
threshold is the alpha level that represent the least-visibility for a cell to be considered non-empty.
isBorder will check if any of Moore neighbors is empty, in that case it is a border cell, otherwise it's not because it is surrounded by filled cells.
isEmpty(x,y): image[x,y].alpha <= threshold
isBorder(x,y)
: if isEmpty(x , y-1): return true
: if isEmpty(x , y+1): return true
: if isEmpty(x-1, y ): return true
: if isEmpty(x+1, y ): return true
: if isEmpty(x-1, y-1): return true
: if isEmpty(x-1, y+1): return true
: if isEmpty(x+1, y-1): return true
: if isEmpty(x+1, y+1): return true
: otherwise: return false
getBorderCellList()
: l = empty-list
: for x in 0..image.width
: : for y in 0..image.height
: : : if !isEmpty(x,y)
: : : : if isBorder(x,y)
: : : : : l.add(x,y)
: return l
Optimization You could optimize this by having a pre-computed boolean e[image.width][image.height] where e[x,y] = 1 if image[x,y]is not-empty, then use it directly to check, like isBorder(x,y): e[x-1,y] | e[x+1,y] | .. | e[x+1,y+1].
init()
: for x in 0..image.width
: : for y in 0..image.height
: : : e[x,y] = isEmpty(x,y)
isEmpty(x,y): image[x,y].alpha <= threshold
isBorder(x,y): e[x-1,y] | e[x+1,y] | .. | e[x+1,y+1]
getBorderCellList()
: l = empty-list
: for x in 0..image.width
: : for y in 0..image.height
: : : if not e[x,y]
: : : : if isBorder(x,y)
: : : : : l.add(x,y)
: return l

Calculate new release time for files

We have some code that checks each incoming file against 3 different criteria before processing (Not a weekend, not after 6pm, not a holiday). This being said, I need to figure out how to have it check for a half hour now (bolded part). I have tried adding a + mRelease > 30 as well as AND mRelease > 30 and both have failed. I have been altering this line
Do While (WeekDay(dRelease) = 1) OR (WeekDay(dRelease) = 7) OR (UBound(fHoliday) > -1) OR (tRelease >17)
Here is the code currently in place:
result = ""
dRelease = Now
tRelease = CStr(Hour(Now))
mRelease = CStr(Minute(Now))
aHoliday = Array("01/02/2017","01/16/2017","05/29/2017","07/04/2017","09/04/2017","10/09/2017","11/23/2017","11/24/2017","12/25/2017","12/26/2017")
dNow = CStr(DatePart("m",Date)) + "/" + CStr(DatePart("d",Date)) + "/" + CStr(DatePart("yyyy",Date))
dMonth = "0" + CStr(Month(dRelease))
dDay = "0" + CStr(Day(dRelease))
dYear = CStr(Year(dRelease))
fHoliday = Filter(aHoliday,Right(dMonth,2) + "/" + Right(dDay,2) + "/" + dYear)
'fHoliday = Filter(aHoliday,dNow)
'result = UBound(fHoliday)
'result = Left(dRelease,10)
'result = CStr(DatePart("m",Date)) + "/" + CStr(DatePart("d",Date)) + "/" + CStr(DatePart("yyyy",Date))
'While release date is a weekend, or release date is a holiday
Do While (WeekDay(dRelease) = 1) OR (WeekDay(dRelease) = 7) OR (UBound(fHoliday) > -1) OR (tRelease >17)
'increase release date by 1
dRelease = dRelease + 1
'result = dRelease
'check for holiday
dMonth = "0" + CStr(Month(dRelease))
dDay = "0" + CStr(Day(dRelease))
dYear = CStr(Year(dRelease))
'fHoliday = Filter(aHoliday,Left(dRelease,10))
fHoliday = Filter(aHoliday,Right(dMonth,2) + "/" + Right(dDay,2) + "/" + dYear)
tRelease = 00
Loop
'Format the release date to the Esker deferred date/time standard.
dMonth = "0" + CStr(Month(dRelease))
dDay = "0" + CStr(Day(dRelease))
dYear = CStr(Year(dRelease))
dtCurrent = Right(dMonth,2) + "/" + Right(dDay,2) + "/" + dYear
If dRelease > Now Then
tRelease = "00:" + mRelease
Else
tRelease = CStr(Hour(Now)) + ":" + CStr(Minute(Now))
End If
result = dtCurrent + " " + tRelease
Change this:
Do While (WeekDay(dRelease) = 1) OR (WeekDay(dRelease) = 7) OR (UBound(fHoliday) > -1) OR (tRelease >17)
...
Loop
into this:
If (WeekDay(dRelease) = 1) Or (WeekDay(dRelease) = 7) Or (UBound(fHoliday) > -1) Or (Time > CDate("16:30")) Then
...
End If

Cannot find why Stack Overflow error appears

I am trying to make an octree for randomly distributed set of particles. I have been trying to find where Stack Overflow Error appears whole day, but it was in vain. Could you please help me? The problem should be somewhere in (c == [0]) && (a > 0) part, however, I have no idea where. Thank you in advance!
type particle
R::Vector{Float64} # coordinates of the particle
m::Float64 # mass of the particle
a_tree::Float64 # acceleration of particle calculated from tree
a_exact::Float64 # acceleration of particle calculated by exact summation
end
type node
parent::Int64 # node's parent number
children::Vector{Int64} # set of childrens' numbers
l::Float64 # size of the node
R::Vector{Float64} # radius of geometric center
m::Float64 # total mass of the node
ptcl::Int64 # pointer to the particle in it
end
function problem3_2(N::Int64)
particles = Vector{particle}(N) # Basically, our system
tree = Vector{node}(1) # Initial tree (root)
tree[1] = node(0,[0],1.0,[0.0,0.0,0.0],0.0,0)
for i in eachindex(particles)
particles[i] = particle([rand() - 1/2, rand() - 1/2, rand() - 1/2], 1.0, 0.0, 0.0)
tree = InsertParticle(i,1,tree,particles)
end
return tree
end
function InsertParticle(i::Int64,k::Int64,tree,particles)
c = tree[k].children
a = tree[k].ptcl
if (c == [0]) && (a == 0)
tree[k].ptcl = i
elseif (c == [0]) && (a > 0)
j_1 = length(tree) + DetermOctant(particles[tree[k].ptcl],tree[k])
j_2 = length(tree) + DetermOctant(particles[i],tree[k])
tree[k].children = [x for x in length(tree)+1:length(tree)+8]
for p = 1:8
push!(tree,node(k,[0],tree[k].l/2,[0.0,0.0,0.0],0.0,0))
if (p == 1) || (p == 4) || (p == 5) || (p == 8)
tree[k+p].R[1] = tree[k].R[1] + tree[k+p].l/2
else
tree[k+p].R[1] = tree[k].R[1] - tree[k+p].l/2
end
if (p == 1) || (p == 2) || (p == 5) || (p == 6)
tree[k+p].R[2] = tree[k].R[2] + tree[k+p].l/2
else
tree[k+p].R[2] = tree[k].R[2] - tree[k+p].l/2
end
if (p == 1) || (p == 2) || (p == 3) || (p == 4)
tree[k+p].R[3] = tree[k].R[3] + tree[k+p].l/2
else
tree[k+p].R[3] = tree[k].R[3] - tree[k+p].l/2
end
end
InsertParticle(tree[k].ptcl,j_1,tree,particles)
InsertParticle(i,j_2,tree,particles)
tree[k].ptcl = 0
elseif (c != [0])
j = DetermOctant(particles[i],tree[k])
InsertParticle(i,tree[k].children[j],tree,particles)
end
return tree
end
function DetermOctant(x::particle,y::node)
c1 = y.R[1]; c2 = y.R[2]; c3 = y.R[3]
x1 = sign(x.R[1] - c1); x2 = sign(x.R[2] - c2); x3 = sign(x.R[3] - c3)
if (x1 > 0) && (x2 > 0) && (x3 > 0)
n = 1
elseif (x1 < 0) && (x2 > 0) && (x3 > 0)
n = 2
elseif (x1 < 0) && (x2 < 0) && (x3 > 0)
n = 3
elseif (x1 > 0) && (x2 < 0) && (x3 > 0)
n = 4
elseif (x1 > 0) && (x2 > 0) && (x3 < 0)
n = 5
elseif (x1 < 0) && (x2 > 0) && (x3 < 0)
n = 6
elseif (x1 < 0) && (x2 < 0) && (x3 < 0)
n = 7
else
n = 8
end
return n
end
Basically, I do know that the error should be somewhere here:
function InsertParticle(i::Int64,k::Int64,tree,particles)
c = tree[k].children
a = tree[k].ptcl
if (c == [0]) && (a == 0)
tree[k].ptcl = i
elseif (c == [0]) && (a > 0)
j_1 = length(tree) + DetermOctant(particles[tree[k].ptcl],tree[k])
j_2 = length(tree) + DetermOctant(particles[i],tree[k])
tree[k].children = [x for x in length(tree)+1:length(tree)+8]
for p = 1:8
push!(tree,node(k,[0],tree[k].l/2,[0.0,0.0,0.0],0.0,0))
if (p == 1) || (p == 4) || (p == 5) || (p == 8)
tree[k+p].R[1] = tree[k].R[1] + tree[k+p].l/2
else
tree[k+p].R[1] = tree[k].R[1] - tree[k+p].l/2
end
if (p == 1) || (p == 2) || (p == 5) || (p == 6)
tree[k+p].R[2] = tree[k].R[2] + tree[k+p].l/2
else
tree[k+p].R[2] = tree[k].R[2] - tree[k+p].l/2
end
if (p == 1) || (p == 2) || (p == 3) || (p == 4)
tree[k+p].R[3] = tree[k].R[3] + tree[k+p].l/2
else
tree[k+p].R[3] = tree[k].R[3] - tree[k+p].l/2
end
end
InsertParticle(tree[k].ptcl,j_1,tree,particles)
InsertParticle(i,j_2,tree,particles)
tree[k].ptcl = 0
elseif (c != [0])
j = DetermOctant(particles[i],tree[k])
InsertParticle(i,tree[k].children[j],tree,particles)
end
return tree
end
However, I cannot see where the infinite loop appears. Sorry for bringing these all here in a such form, I just want to avoid XY-problem.
Thank you in advance!

How to append click event to handsontable row/column header?

I'm trying to implement some features like excel to click row/column header to select entire row/column, I think I should append a click event to all row/column header, so I tried add code below in core.js, but it was never been trigged:
this.click = function() {
alert("Clicked!");
};
So where should I begin with?
Thanks for any help.
Implemented by myself based on Handsontable 0.9.9:
From 5e2e8f51374741432d34624eb86edce6a802bf80 Mon Sep 17 00:00:00 2001
From: Xinfeng Li <xinfli#gmail.com>
Date: Wed, 17 Jul 2013 12:04:21 +0800
Subject: [PATCH 1/1] Implement select entire row/column when click on
row/column header.
---
src/3rdparty/walkontable/src/event.js | 5 ++++
src/3rdparty/walkontable/src/settings.js | 3 +-
src/pluginHooks.js | 3 ++
src/tableView.js | 50 ++++++++++++++++++++++++++++++++
4 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/src/3rdparty/walkontable/src/event.js b/src/3rdparty/walkontable/src/event.js
index e150fef..a4cbb09 100644
--- a/src/3rdparty/walkontable/src/event.js
+++ b/src/3rdparty/walkontable/src/event.js
## -17,6 +17,11 ## function WalkontableEvent(instance) {
that.instance.getSetting('onCellMouseDown', event, cell.coords, cell.TD);
}
}
+ else if (cell.TD && cell.TD.nodeName === 'TH') {
+ if (that.instance.hasSetting('onHeaderMouseDown')) {
+ that.instance.getSetting('onHeaderMouseDown', event, cell.coords, cell.TD);
+ }
+ }
else if (that.wtDom.hasClass(event.target, 'corner')) {
that.instance.getSetting('onCellCornerMouseDown', event, event.target);
}
diff --git a/src/3rdparty/walkontable/src/settings.js b/src/3rdparty/walkontable/src/settings.js
index 35eb736..b16e4cf 100644
--- a/src/3rdparty/walkontable/src/settings.js
+++ b/src/3rdparty/walkontable/src/settings.js
## -41,8 +41,9 ## function WalkontableSettings(instance, settings) {
//callbacks
onCellMouseDown: null,
+ onHeaderMouseDown: null,
onCellMouseOver: null,
-// onCellMouseOut: null,
+ //onCellMouseOut: null,
onCellDblClick: null,
onCellCornerMouseDown: null,
onCellCornerDblClick: null,
diff --git a/src/pluginHooks.js b/src/pluginHooks.js
index afcc7e2..ececdd1 100644
--- a/src/pluginHooks.js
+++ b/src/pluginHooks.js
## -37,6 +37,9 ## Handsontable.PluginHookClass = (function () {
afterSelectionEndByProp : [],
afterCopyLimit : [],
+ // Customer plugin after row/column header clicked.
+ afterHeaderClick : [],
+
// Modifiers
modifyCol : []
}
diff --git a/src/tableView.js b/src/tableView.js
index 39512c0..ded6b74 100644
--- a/src/tableView.js
+++ b/src/tableView.js
## -242,6 +242,56 ## Handsontable.TableView = function (instance) {
that.settings.afterOnCellMouseDown.call(instance, event, coords, TD);
}
},
+ onHeaderMouseDown: function (event, coords, TD) {
+ var row = coords[0];
+ var col = coords[1];
+ var rangeRowStart, rangeColStart, rangeRowEnd, rangeColEnd;
+
+ //console.log("Clicked on header[row = " + row + ", col = " + col + "], TD.innerHTML.length: " + TD.innerHTML.length);
+ if ((row == 0) && (col == -1) && (TD.innerHTML.length == 0)) {
+ // Click on left upper corner
+ // Since the row and col is same when click on left upper corner and row heder of first row,
+ // The length of current TD.innerHTML must be checked.
+ rangeRowStart = 0;
+ rangeColStart = 0;
+ rangeRowEnd = instance.countRows() - 1;
+ rangeColEnd = instance.countCols() - 1;
+ }
+ else if (row == 0) {
+ if (col >= 0) {
+ // Click on column header
+ rangeRowStart = 0;
+ rangeColStart = col;
+ rangeRowEnd = instance.countRows() - 1;
+ rangeColEnd = col;
+ } else {
+ // Click on row header of first row
+ rangeRowStart = row;
+ rangeColStart = 0;
+ rangeRowEnd = row;
+ rangeColEnd = instance.countCols() - 1;
+ }
+ }
+ else if (col == -1) {
+ // Click on row header
+ rangeRowStart = row;
+ rangeColStart = 0;
+ rangeRowEnd = row;
+ rangeColEnd = instance.countCols() - 1;
+ }
+
+ if ((rangeRowStart != undefined) && (rangeColStart != undefined) && (rangeRowEnd != undefined) && (rangeColEnd != undefined)) {
+ //console.log("Select from [" + rangeRowStart + ", " + rangeColStart + "] to [" + rangeRowEnd + ", " + rangeColEnd + "]");
+ instance.selectCell(rangeRowStart, rangeColStart, rangeRowEnd, rangeColEnd);
+ }
+
+ if (!that.settings.fragmentSelection) {
+ event.preventDefault(); //disable text selection in Chrome
+ clearTextSelection();
+ }
+
+ instance.PluginHooks.run('afterHeaderClick', event, coords, TD);
+ },
/*onCellMouseOut: function (/*event, coords, TD* /) {
if (isMouseDown && that.settings.fragmentSelection === 'single') {
clearTextSelection(); //otherwise text selection blinks during multiple cells selection
--
1.8.1.msysgit.1

Resources